Render messages with less async

This commit is contained in:
Joscha 2023-04-17 18:59:16 +02:00
parent 8182cc5d38
commit a638caadcb
5 changed files with 62 additions and 100 deletions

12
Cargo.lock generated
View file

@ -68,17 +68,6 @@ version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
[[package]]
name = "async-recursion"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.13",
]
[[package]]
name = "async-trait"
version = "0.1.68"
@ -251,7 +240,6 @@ name = "cove"
version = "0.6.1"
dependencies = [
"anyhow",
"async-recursion",
"async-trait",
"clap",
"cookie",

View file

@ -5,7 +5,6 @@ edition = "2021"
[dependencies]
anyhow = "1.0.70"
async-recursion = "1.0.4"
async-trait = "0.1.68"
clap = { version = "4.2.1", features = ["derive", "deprecated"] }
cookie = "0.17.0"

View file

@ -2,10 +2,9 @@
use std::convert::Infallible;
use async_recursion::async_recursion;
use async_trait::async_trait;
use toss::widgets::{EditorState, Empty, Predrawn, Resize};
use toss::{AsyncWidget, Size, WidthDb};
use toss::{Size, Widget, WidthDb};
use crate::store::{Msg, MsgStore, Tree};
use crate::ui::chat::blocks::{Block, Blocks, Range};
@ -122,26 +121,24 @@ where
}
}
async fn predraw<W>(widget: W, size: Size, widthdb: &mut WidthDb) -> Predrawn
fn predraw<W>(widget: W, size: Size, widthdb: &mut WidthDb) -> Predrawn
where
W: AsyncWidget<Infallible> + Send + Sync,
W: Widget<Infallible>,
{
Predrawn::new_async(Resize::new(widget).with_max_width(size.width), widthdb)
.await
.infallible()
Predrawn::new(Resize::new(widget).with_max_width(size.width), widthdb).infallible()
}
async fn zero_height_block(&mut self, parent: Option<&M::Id>) -> TreeBlock<M::Id> {
fn zero_height_block(&mut self, parent: Option<&M::Id>) -> TreeBlock<M::Id> {
let id = match parent {
Some(parent) => TreeBlockId::After(parent.clone()),
None => TreeBlockId::Bottom,
};
let widget = Self::predraw(Empty::new(), self.context.size, self.widthdb).await;
let widget = Self::predraw(Empty::new(), self.context.size, self.widthdb);
Block::new(id, widget, false)
}
async fn editor_block(&mut self, indent: usize, parent: Option<&M::Id>) -> TreeBlock<M::Id> {
fn editor_block(&mut self, indent: usize, parent: Option<&M::Id>) -> TreeBlock<M::Id> {
let id = match parent {
Some(parent) => TreeBlockId::After(parent.clone()),
None => TreeBlockId::Bottom,
@ -149,7 +146,7 @@ where
// TODO Unhighlighted version when focusing on nick list
let widget = widgets::editor::<M>(indent, &self.context.nick, self.editor);
let widget = Self::predraw(widget, self.context.size, self.widthdb).await;
let widget = Self::predraw(widget, self.context.size, self.widthdb);
let mut block = Block::new(id, widget, false);
// Since the editor was rendered when the `Predrawn` was created, the
@ -160,7 +157,7 @@ where
block
}
async fn pseudo_block(&mut self, indent: usize, parent: Option<&M::Id>) -> TreeBlock<M::Id> {
fn pseudo_block(&mut self, indent: usize, parent: Option<&M::Id>) -> TreeBlock<M::Id> {
let id = match parent {
Some(parent) => TreeBlockId::After(parent.clone()),
None => TreeBlockId::Bottom,
@ -168,11 +165,11 @@ where
// TODO Unhighlighted version when focusing on nick list
let widget = widgets::pseudo::<M>(indent, &self.context.nick, self.editor);
let widget = Self::predraw(widget, self.context.size, self.widthdb).await;
let widget = Self::predraw(widget, self.context.size, self.widthdb);
Block::new(id, widget, false)
}
async fn message_block(&mut self, indent: usize, msg: &M) -> TreeBlock<M::Id> {
fn message_block(&mut self, indent: usize, msg: &M) -> TreeBlock<M::Id> {
let msg_id = msg.id();
let highlighted = match self.cursor {
@ -182,15 +179,11 @@ where
// TODO Amount of folded messages
let widget = widgets::msg(self.context.focused && highlighted, indent, msg, None);
let widget = Self::predraw(widget, self.context.size, self.widthdb).await;
let widget = Self::predraw(widget, self.context.size, self.widthdb);
Block::new(TreeBlockId::Msg(msg_id), widget, true)
}
async fn message_placeholder_block(
&mut self,
indent: usize,
msg_id: &M::Id,
) -> TreeBlock<M::Id> {
fn message_placeholder_block(&mut self, indent: usize, msg_id: &M::Id) -> TreeBlock<M::Id> {
let highlighted = match self.cursor {
Cursor::Msg(id) => id == msg_id,
_ => false,
@ -198,28 +191,23 @@ where
// TODO Amount of folded messages
let widget = widgets::msg_placeholder(self.context.focused && highlighted, indent, None);
let widget = Self::predraw(widget, self.context.size, self.widthdb).await;
let widget = Self::predraw(widget, self.context.size, self.widthdb);
Block::new(TreeBlockId::Msg(msg_id.clone()), widget, true)
}
async fn layout_bottom(&mut self) -> TreeBlocks<M::Id> {
fn layout_bottom(&mut self) -> TreeBlocks<M::Id> {
let mut blocks = Blocks::new(0);
match self.cursor {
Cursor::Editor { parent: None, .. } => {
blocks.push_bottom(self.editor_block(0, None).await)
}
Cursor::Pseudo { parent: None, .. } => {
blocks.push_bottom(self.pseudo_block(0, None).await)
}
_ => blocks.push_bottom(self.zero_height_block(None).await),
Cursor::Editor { parent: None, .. } => blocks.push_bottom(self.editor_block(0, None)),
Cursor::Pseudo { parent: None, .. } => blocks.push_bottom(self.pseudo_block(0, None)),
_ => blocks.push_bottom(self.zero_height_block(None)),
}
blocks
}
#[async_recursion]
async fn layout_subtree(
fn layout_subtree(
&mut self,
tree: &Tree<M>,
indent: usize,
@ -228,16 +216,16 @@ where
) {
// Message itself
let block = if let Some(msg) = tree.msg(msg_id) {
self.message_block(indent, msg).await
self.message_block(indent, msg)
} else {
self.message_placeholder_block(indent, msg_id).await
self.message_placeholder_block(indent, msg_id)
};
blocks.push_bottom(block);
// Children, recursively
if let Some(children) = tree.children(msg_id) {
for child in children {
self.layout_subtree(tree, indent + 1, child, blocks).await;
self.layout_subtree(tree, indent + 1, child, blocks);
}
}
@ -245,21 +233,20 @@ where
let block = match self.cursor {
Cursor::Editor {
parent: Some(id), ..
} if id == msg_id => self.editor_block(indent + 1, Some(msg_id)).await,
} if id == msg_id => self.editor_block(indent + 1, Some(msg_id)),
Cursor::Pseudo {
parent: Some(id), ..
} if id == msg_id => self.pseudo_block(indent + 1, Some(msg_id)).await,
} if id == msg_id => self.pseudo_block(indent + 1, Some(msg_id)),
_ => self.zero_height_block(Some(msg_id)).await,
_ => self.zero_height_block(Some(msg_id)),
};
blocks.push_bottom(block);
}
async fn layout_tree(&mut self, tree: Tree<M>) -> TreeBlocks<M::Id> {
fn layout_tree(&mut self, tree: Tree<M>) -> TreeBlocks<M::Id> {
let mut blocks = Blocks::new(0);
self.layout_subtree(&tree, 0, tree.root(), &mut blocks)
.await;
self.layout_subtree(&tree, 0, tree.root(), &mut blocks);
blocks
}
@ -275,9 +262,9 @@ where
let blocks = if let Some(root_id) = root_id {
let tree = self.store.tree(root_id).await?;
self.layout_tree(tree).await
self.layout_tree(tree)
} else {
self.layout_bottom().await
self.layout_bottom()
};
self.blocks.append_bottom(blocks);
@ -429,7 +416,7 @@ where
if let Some(prev_root_id) = prev_root_id {
let tree = self.store.tree(&prev_root_id).await?;
let blocks = self.layout_tree(tree).await;
let blocks = self.layout_tree(tree);
self.blocks.append_top(blocks);
self.top_root_id = Some(prev_root_id);
} else {
@ -448,11 +435,11 @@ where
let next_root_id = self.store.next_root_id(bottom_root_id).await?;
if let Some(next_root_id) = next_root_id {
let tree = self.store.tree(&next_root_id).await?;
let blocks = self.layout_tree(tree).await;
let blocks = self.layout_tree(tree);
self.blocks.append_bottom(blocks);
self.bottom_root_id = Some(next_root_id);
} else {
let blocks = self.layout_bottom().await;
let blocks = self.layout_bottom();
self.blocks.append_bottom(blocks);
self.blocks.end_bottom();
self.bottom_root_id = None;

View file

@ -1,7 +1,7 @@
use std::convert::Infallible;
use crossterm::style::Stylize;
use toss::widgets::{BoxedAsync, EditorState, Join2, Join4, Join5, Text};
use toss::widgets::{Boxed, EditorState, Join2, Join4, Join5, Text};
use toss::{Style, Styled, WidgetExt};
use crate::store::Msg;
@ -47,7 +47,7 @@ pub fn msg<M: Msg + ChatMsg>(
indent: usize,
msg: &M,
folded_info: Option<usize>,
) -> BoxedAsync<'static, Infallible> {
) -> Boxed<'static, Infallible> {
let (nick, mut content) = msg.styled();
if let Some(amount) = folded_info {
@ -81,14 +81,14 @@ pub fn msg<M: Msg + ChatMsg>(
// TODO Minimizing and maximizing messages
Text::new(content).segment(),
)
.boxed_async()
.boxed()
}
pub fn msg_placeholder(
highlighted: bool,
indent: usize,
folded_info: Option<usize>,
) -> BoxedAsync<'static, Infallible> {
) -> Boxed<'static, Infallible> {
let mut content = Styled::new(PLACEHOLDER, style_placeholder());
if let Some(amount) = folded_info {
@ -110,14 +110,14 @@ pub fn msg_placeholder(
.with_fixed(true),
Text::new(content).segment(),
)
.boxed_async()
.boxed()
}
pub fn editor<'a, M: ChatMsg>(
indent: usize,
nick: &str,
editor: &'a mut EditorState,
) -> BoxedAsync<'a, Infallible> {
) -> Boxed<'a, Infallible> {
let (nick, content) = M::edit(nick, editor.text());
let editor = editor.widget().with_highlight(|_| content);
@ -144,14 +144,14 @@ pub fn editor<'a, M: ChatMsg>(
.with_fixed(true),
editor.segment(),
)
.boxed_async()
.boxed()
}
pub fn pseudo<'a, M: ChatMsg>(
indent: usize,
nick: &str,
editor: &'a mut EditorState,
) -> BoxedAsync<'a, Infallible> {
) -> Boxed<'a, Infallible> {
let (nick, content) = M::edit(nick, editor.text());
Join5::horizontal(
@ -177,5 +177,5 @@ pub fn pseudo<'a, M: ChatMsg>(
.with_fixed(true),
Text::new(content).segment(),
)
.boxed_async()
.boxed()
}

View file

@ -1,12 +1,11 @@
use std::convert::Infallible;
use async_trait::async_trait;
use crossterm::style::Stylize;
use time::format_description::FormatItem;
use time::macros::format_description;
use time::OffsetDateTime;
use toss::widgets::{BoxedAsync, Empty, Text};
use toss::{AsyncWidget, Frame, Pos, Size, Style, WidgetExt, WidthDb};
use toss::widgets::{Boxed, Empty, Text};
use toss::{Frame, Pos, Size, Style, Widget, WidgetExt, WidthDb};
use crate::util::InfallibleExt;
@ -24,9 +23,8 @@ impl Indent {
}
}
#[async_trait]
impl<E> AsyncWidget<E> for Indent {
async fn size(
impl<E> Widget<E> for Indent {
fn size(
&self,
_widthdb: &mut WidthDb,
_max_width: Option<u16>,
@ -36,7 +34,7 @@ impl<E> AsyncWidget<E> for Indent {
Ok(Size::new(width, 0))
}
async fn draw(self, frame: &mut Frame) -> Result<(), E> {
fn draw(self, frame: &mut Frame) -> Result<(), E> {
let size = frame.size();
let indent_string = INDENT_STR.repeat(self.level);
@ -51,7 +49,7 @@ impl<E> AsyncWidget<E> for Indent {
const TIME_FORMAT: &[FormatItem<'_>] = format_description!("[year]-[month]-[day] [hour]:[minute]");
const TIME_WIDTH: u16 = 16;
pub struct Time(BoxedAsync<'static, Infallible>);
pub struct Time(Boxed<'static, Infallible>);
impl Time {
pub fn new(time: Option<OffsetDateTime>, style: Style) -> Self {
@ -60,70 +58,60 @@ impl Time {
Text::new((text, style))
.background()
.with_style(style)
.boxed_async()
.boxed()
} else {
Empty::new()
.with_width(TIME_WIDTH)
.background()
.with_style(style)
.boxed_async()
.boxed()
};
Self(widget)
}
}
#[async_trait]
impl<E> AsyncWidget<E> for Time {
async fn size(
impl<E> Widget<E> for Time {
fn size(
&self,
widthdb: &mut WidthDb,
max_width: Option<u16>,
max_height: Option<u16>,
) -> Result<Size, E> {
Ok(self
.0
.size(widthdb, max_width, max_height)
.await
.infallible())
Ok(self.0.size(widthdb, max_width, max_height).infallible())
}
async fn draw(self, frame: &mut Frame) -> Result<(), E> {
self.0.draw(frame).await.infallible();
fn draw(self, frame: &mut Frame) -> Result<(), E> {
self.0.draw(frame).infallible();
Ok(())
}
}
pub struct Seen(BoxedAsync<'static, Infallible>);
pub struct Seen(Boxed<'static, Infallible>);
impl Seen {
pub fn new(seen: bool) -> Self {
let widget = if seen {
Empty::new().with_width(1).boxed_async()
Empty::new().with_width(1).boxed()
} else {
let style = Style::new().black().on_green();
Text::new("*").background().with_style(style).boxed_async()
Text::new("*").background().with_style(style).boxed()
};
Self(widget)
}
}
#[async_trait]
impl<E> AsyncWidget<E> for Seen {
async fn size(
impl<E> Widget<E> for Seen {
fn size(
&self,
widthdb: &mut WidthDb,
max_width: Option<u16>,
max_height: Option<u16>,
) -> Result<Size, E> {
Ok(self
.0
.size(widthdb, max_width, max_height)
.await
.infallible())
Ok(self.0.size(widthdb, max_width, max_height).infallible())
}
async fn draw(self, frame: &mut Frame) -> Result<(), E> {
self.0.draw(frame).await.infallible();
fn draw(self, frame: &mut Frame) -> Result<(), E> {
self.0.draw(frame).infallible();
Ok(())
}
}