Make MsgStore fallible

This commit is contained in:
Joscha 2023-02-12 21:08:38 +01:00
parent 5581fc1fc2
commit 35a140e21f
9 changed files with 324 additions and 242 deletions

View file

@ -6,9 +6,11 @@ mod tree_blocks;
mod widgets;
use std::collections::HashSet;
use std::fmt;
use std::sync::Arc;
use async_trait::async_trait;
use log::error;
use parking_lot::FairMutex;
use tokio::sync::Mutex;
use toss::frame::{Frame, Pos, Size};
@ -82,21 +84,25 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
// TODO Bindings inspired by vim's ()/[]/{} bindings?
}
async fn handle_movement_input_event(&mut self, frame: &mut Frame, event: &InputEvent) -> bool {
async fn handle_movement_input_event(
&mut self,
frame: &mut Frame,
event: &InputEvent,
) -> Result<bool, S::Error> {
let chat_height = frame.size().height - 3;
match event {
key!('k') | key!(Up) => self.move_cursor_up().await,
key!('j') | key!(Down) => self.move_cursor_down().await,
key!('K') | key!(Ctrl + Up) => self.move_cursor_up_sibling().await,
key!('J') | key!(Ctrl + Down) => self.move_cursor_down_sibling().await,
key!('p') => self.move_cursor_to_parent().await,
key!('P') => self.move_cursor_to_root().await,
key!('h') | key!(Left) => self.move_cursor_older().await,
key!('l') | key!(Right) => self.move_cursor_newer().await,
key!('H') | key!(Ctrl + Left) => self.move_cursor_older_unseen().await,
key!('L') | key!(Ctrl + Right) => self.move_cursor_newer_unseen().await,
key!('g') | key!(Home) => self.move_cursor_to_top().await,
key!('k') | key!(Up) => self.move_cursor_up().await?,
key!('j') | key!(Down) => self.move_cursor_down().await?,
key!('K') | key!(Ctrl + Up) => self.move_cursor_up_sibling().await?,
key!('J') | key!(Ctrl + Down) => self.move_cursor_down_sibling().await?,
key!('p') => self.move_cursor_to_parent().await?,
key!('P') => self.move_cursor_to_root().await?,
key!('h') | key!(Left) => self.move_cursor_older().await?,
key!('l') | key!(Right) => self.move_cursor_newer().await?,
key!('H') | key!(Ctrl + Left) => self.move_cursor_older_unseen().await?,
key!('L') | key!(Ctrl + Right) => self.move_cursor_newer_unseen().await?,
key!('g') | key!(Home) => self.move_cursor_to_top().await?,
key!('G') | key!(End) => self.move_cursor_to_bottom().await,
key!(Ctrl + 'y') => self.scroll_up(1),
key!(Ctrl + 'e') => self.scroll_down(1),
@ -107,10 +113,10 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
self.scroll_down(chat_height.saturating_sub(1).into())
}
key!('z') => self.center_cursor(),
_ => return false,
_ => return Ok(false),
}
true
Ok(true)
}
pub fn list_action_key_bindings(&self, bindings: &mut KeyBindingsList) {
@ -120,43 +126,47 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
bindings.binding("ctrl+s", "mark all older messages as seen");
}
async fn handle_action_input_event(&mut self, event: &InputEvent, id: Option<&M::Id>) -> bool {
async fn handle_action_input_event(
&mut self,
event: &InputEvent,
id: Option<&M::Id>,
) -> Result<bool, S::Error> {
match event {
key!(' ') => {
if let Some(id) = id {
if !self.folded.remove(id) {
self.folded.insert(id.clone());
}
return true;
return Ok(true);
}
}
key!('s') => {
if let Some(id) = id {
if let Some(msg) = self.store.tree(id).await.msg(id) {
self.store.set_seen(id, !msg.seen()).await;
if let Some(msg) = self.store.tree(id).await?.msg(id) {
self.store.set_seen(id, !msg.seen()).await?;
}
return true;
return Ok(true);
}
}
key!('S') => {
for id in &self.last_visible_msgs {
self.store.set_seen(id, true).await;
self.store.set_seen(id, true).await?;
}
return true;
return Ok(true);
}
key!(Ctrl + 's') => {
if let Some(id) = id {
self.store.set_older_seen(id, true).await;
self.store.set_older_seen(id, true).await?;
} else {
self.store
.set_older_seen(&M::last_possible_id(), true)
.await;
.await?;
}
return true;
return Ok(true);
}
_ => {}
}
false
Ok(false)
}
pub fn list_edit_initiating_key_bindings(&self, bindings: &mut KeyBindingsList) {
@ -169,16 +179,16 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
&mut self,
event: &InputEvent,
id: Option<M::Id>,
) -> bool {
) -> Result<bool, S::Error> {
match event {
key!('r') => {
if let Some(parent) = self.parent_for_normal_reply().await {
if let Some(parent) = self.parent_for_normal_reply().await? {
self.cursor = Cursor::editor(id, parent);
self.correction = Some(Correction::MakeCursorVisible);
}
}
key!('R') => {
if let Some(parent) = self.parent_for_alternate_reply().await {
if let Some(parent) = self.parent_for_alternate_reply().await? {
self.cursor = Cursor::editor(id, parent);
self.correction = Some(Correction::MakeCursorVisible);
}
@ -187,10 +197,10 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
self.cursor = Cursor::editor(id, None);
self.correction = Some(Correction::MakeCursorVisible);
}
_ => return false,
_ => return Ok(false),
}
true
Ok(true)
}
pub fn list_normal_key_bindings(&self, bindings: &mut KeyBindingsList, can_compose: bool) {
@ -209,17 +219,17 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
event: &InputEvent,
can_compose: bool,
id: Option<M::Id>,
) -> bool {
) -> Result<bool, S::Error> {
#[allow(clippy::if_same_then_else)]
if self.handle_movement_input_event(frame, event).await {
Ok(if self.handle_movement_input_event(frame, event).await? {
true
} else if self.handle_action_input_event(event, id.as_ref()).await {
} else if self.handle_action_input_event(event, id.as_ref()).await? {
true
} else if can_compose {
self.handle_edit_initiating_input_event(event, id).await
self.handle_edit_initiating_input_event(event, id).await?
} else {
false
}
})
}
fn list_editor_key_bindings(&self, bindings: &mut KeyBindingsList) {
@ -294,12 +304,12 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
crossterm_lock: &Arc<FairMutex<()>>,
event: &InputEvent,
can_compose: bool,
) -> Reaction<M> {
match &self.cursor {
) -> Result<Reaction<M>, S::Error> {
Ok(match &self.cursor {
Cursor::Bottom => {
if self
.handle_normal_input_event(terminal.frame(), event, can_compose, None)
.await
.await?
{
Reaction::Handled
} else {
@ -310,7 +320,7 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
let id = id.clone();
if self
.handle_normal_input_event(terminal.frame(), event, can_compose, Some(id))
.await
.await?
{
Reaction::Handled
} else {
@ -330,14 +340,14 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
Cursor::Pseudo { .. } => {
if self
.handle_movement_input_event(terminal.frame(), event)
.await
.await?
{
Reaction::Handled
} else {
Reaction::NotHandled
}
}
}
})
}
fn cursor(&self) -> Option<M::Id> {
@ -388,7 +398,7 @@ impl<M: Msg, S: MsgStore<M>> TreeViewState<M, S> {
crossterm_lock: &Arc<FairMutex<()>>,
event: &InputEvent,
can_compose: bool,
) -> Reaction<M> {
) -> Result<Reaction<M>, S::Error> {
self.0
.lock()
.await
@ -421,6 +431,7 @@ where
M: Msg + ChatMsg,
M::Id: Send + Sync,
S: MsgStore<M> + Send + Sync,
S::Error: fmt::Display,
{
fn size(&self, _frame: &mut Frame, _max_width: Option<u16>, _max_height: Option<u16>) -> Size {
Size::ZERO
@ -428,7 +439,13 @@ where
async fn render(self: Box<Self>, frame: &mut Frame) {
let mut guard = self.inner.lock().await;
let blocks = guard.relayout(self.nick, self.focused, frame).await;
let blocks = match guard.relayout(self.nick, self.focused, frame).await {
Ok(blocks) => blocks,
Err(err) => {
error!("{err}");
panic!("{err}");
}
};
let size = frame.size();
for block in blocks.into_blocks().blocks {

View file

@ -94,15 +94,19 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
/// Move to the previous sibling, or don't move if this is not possible.
///
/// Always stays at the same level of indentation.
async fn find_prev_sibling(store: &S, tree: &mut Tree<M>, id: &mut M::Id) -> bool {
if let Some(prev_sibling) = tree.prev_sibling(id) {
async fn find_prev_sibling(
store: &S,
tree: &mut Tree<M>,
id: &mut M::Id,
) -> Result<bool, S::Error> {
let moved = if let Some(prev_sibling) = tree.prev_sibling(id) {
*id = prev_sibling;
true
} else if tree.parent(id).is_none() {
// We're at the root of our tree, so we need to move to the root of
// the previous tree.
if let Some(prev_root_id) = store.prev_root_id(tree.root()).await {
*tree = store.tree(&prev_root_id).await;
if let Some(prev_root_id) = store.prev_root_id(tree.root()).await? {
*tree = store.tree(&prev_root_id).await?;
*id = prev_root_id;
true
} else {
@ -110,21 +114,26 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
}
} else {
false
}
};
Ok(moved)
}
/// Move to the next sibling, or don't move if this is not possible.
///
/// Always stays at the same level of indentation.
async fn find_next_sibling(store: &S, tree: &mut Tree<M>, id: &mut M::Id) -> bool {
if let Some(next_sibling) = tree.next_sibling(id) {
async fn find_next_sibling(
store: &S,
tree: &mut Tree<M>,
id: &mut M::Id,
) -> Result<bool, S::Error> {
let moved = if let Some(next_sibling) = tree.next_sibling(id) {
*id = next_sibling;
true
} else if tree.parent(id).is_none() {
// We're at the root of our tree, so we need to move to the root of
// the next tree.
if let Some(next_root_id) = store.next_root_id(tree.root()).await {
*tree = store.tree(&next_root_id).await;
if let Some(next_root_id) = store.next_root_id(tree.root()).await? {
*tree = store.tree(&next_root_id).await?;
*id = next_root_id;
true
} else {
@ -132,7 +141,8 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
}
} else {
false
}
};
Ok(moved)
}
/// Move to the previous message, or don't move if this is not possible.
@ -141,15 +151,16 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
folded: &HashSet<M::Id>,
tree: &mut Tree<M>,
id: &mut M::Id,
) -> bool {
) -> Result<bool, S::Error> {
// Move to previous sibling, then to its last child
// If not possible, move to parent
if Self::find_prev_sibling(store, tree, id).await {
let moved = if Self::find_prev_sibling(store, tree, id).await? {
while Self::find_last_child(folded, tree, id) {}
true
} else {
Self::find_parent(tree, id)
}
};
Ok(moved)
}
/// Move to the next message, or don't move if this is not possible.
@ -158,63 +169,64 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
folded: &HashSet<M::Id>,
tree: &mut Tree<M>,
id: &mut M::Id,
) -> bool {
) -> Result<bool, S::Error> {
if Self::find_first_child(folded, tree, id) {
return true;
return Ok(true);
}
if Self::find_next_sibling(store, tree, id).await {
return true;
if Self::find_next_sibling(store, tree, id).await? {
return Ok(true);
}
// Temporary id to avoid modifying the original one if no parent-sibling
// can be found.
let mut tmp_id = id.clone();
while Self::find_parent(tree, &mut tmp_id) {
if Self::find_next_sibling(store, tree, &mut tmp_id).await {
if Self::find_next_sibling(store, tree, &mut tmp_id).await? {
*id = tmp_id;
return true;
return Ok(true);
}
}
false
Ok(false)
}
pub async fn move_cursor_up(&mut self) {
pub async fn move_cursor_up(&mut self) -> Result<(), S::Error> {
match &mut self.cursor {
Cursor::Bottom | Cursor::Pseudo { parent: None, .. } => {
if let Some(last_root_id) = self.store.last_root_id().await {
let tree = self.store.tree(&last_root_id).await;
if let Some(last_root_id) = self.store.last_root_id().await? {
let tree = self.store.tree(&last_root_id).await?;
let mut id = last_root_id;
while Self::find_last_child(&self.folded, &tree, &mut id) {}
self.cursor = Cursor::Msg(id);
}
}
Cursor::Msg(msg) => {
let path = self.store.path(msg).await;
let mut tree = self.store.tree(path.first()).await;
Self::find_prev_msg(&self.store, &self.folded, &mut tree, msg).await;
let path = self.store.path(msg).await?;
let mut tree = self.store.tree(path.first()).await?;
Self::find_prev_msg(&self.store, &self.folded, &mut tree, msg).await?;
}
Cursor::Editor { .. } => {}
Cursor::Pseudo {
parent: Some(parent),
..
} => {
let tree = self.store.tree(parent).await;
let tree = self.store.tree(parent).await?;
let mut id = parent.clone();
while Self::find_last_child(&self.folded, &tree, &mut id) {}
self.cursor = Cursor::Msg(id);
}
}
self.correction = Some(Correction::MakeCursorVisible);
Ok(())
}
pub async fn move_cursor_down(&mut self) {
pub async fn move_cursor_down(&mut self) -> Result<(), S::Error> {
match &mut self.cursor {
Cursor::Msg(msg) => {
let path = self.store.path(msg).await;
let mut tree = self.store.tree(path.first()).await;
if !Self::find_next_msg(&self.store, &self.folded, &mut tree, msg).await {
let path = self.store.path(msg).await?;
let mut tree = self.store.tree(path.first()).await?;
if !Self::find_next_msg(&self.store, &self.folded, &mut tree, msg).await? {
self.cursor = Cursor::Bottom;
}
}
@ -225,11 +237,11 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
parent: Some(parent),
..
} => {
let mut tree = self.store.tree(parent).await;
let mut tree = self.store.tree(parent).await?;
let mut id = parent.clone();
while Self::find_last_child(&self.folded, &tree, &mut id) {}
// Now we're at the previous message
if Self::find_next_msg(&self.store, &self.folded, &mut tree, &mut id).await {
if Self::find_next_msg(&self.store, &self.folded, &mut tree, &mut id).await? {
self.cursor = Cursor::Msg(id);
} else {
self.cursor = Cursor::Bottom;
@ -238,27 +250,28 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
_ => {}
}
self.correction = Some(Correction::MakeCursorVisible);
Ok(())
}
pub async fn move_cursor_up_sibling(&mut self) {
pub async fn move_cursor_up_sibling(&mut self) -> Result<(), S::Error> {
match &mut self.cursor {
Cursor::Bottom | Cursor::Pseudo { parent: None, .. } => {
if let Some(last_root_id) = self.store.last_root_id().await {
if let Some(last_root_id) = self.store.last_root_id().await? {
self.cursor = Cursor::Msg(last_root_id);
}
}
Cursor::Msg(msg) => {
let path = self.store.path(msg).await;
let mut tree = self.store.tree(path.first()).await;
Self::find_prev_sibling(&self.store, &mut tree, msg).await;
let path = self.store.path(msg).await?;
let mut tree = self.store.tree(path.first()).await?;
Self::find_prev_sibling(&self.store, &mut tree, msg).await?;
}
Cursor::Editor { .. } => {}
Cursor::Pseudo {
parent: Some(parent),
..
} => {
let path = self.store.path(parent).await;
let tree = self.store.tree(path.first()).await;
let path = self.store.path(parent).await?;
let tree = self.store.tree(path.first()).await?;
if let Some(children) = tree.children(parent) {
if let Some(last_child) = children.last() {
self.cursor = Cursor::Msg(last_child.clone());
@ -267,14 +280,15 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
}
}
self.correction = Some(Correction::MakeCursorVisible);
Ok(())
}
pub async fn move_cursor_down_sibling(&mut self) {
pub async fn move_cursor_down_sibling(&mut self) -> Result<(), S::Error> {
match &mut self.cursor {
Cursor::Msg(msg) => {
let path = self.store.path(msg).await;
let mut tree = self.store.tree(path.first()).await;
if !Self::find_next_sibling(&self.store, &mut tree, msg).await
let path = self.store.path(msg).await?;
let mut tree = self.store.tree(path.first()).await?;
if !Self::find_next_sibling(&self.store, &mut tree, msg).await?
&& tree.parent(msg).is_none()
{
self.cursor = Cursor::Bottom;
@ -286,9 +300,10 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
_ => {}
}
self.correction = Some(Correction::MakeCursorVisible);
Ok(())
}
pub async fn move_cursor_to_parent(&mut self) {
pub async fn move_cursor_to_parent(&mut self) -> Result<(), S::Error> {
match &mut self.cursor {
Cursor::Pseudo {
parent: Some(parent),
@ -297,53 +312,56 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
Cursor::Msg(id) => {
// Could also be done via retrieving the path, but it doesn't
// really matter here
let tree = self.store.tree(id).await;
let tree = self.store.tree(id).await?;
Self::find_parent(&tree, id);
}
_ => {}
}
self.correction = Some(Correction::MakeCursorVisible);
Ok(())
}
pub async fn move_cursor_to_root(&mut self) {
pub async fn move_cursor_to_root(&mut self) -> Result<(), S::Error> {
match &mut self.cursor {
Cursor::Pseudo {
parent: Some(parent),
..
} => {
let path = self.store.path(parent).await;
let path = self.store.path(parent).await?;
self.cursor = Cursor::Msg(path.first().clone());
}
Cursor::Msg(msg) => {
let path = self.store.path(msg).await;
let path = self.store.path(msg).await?;
*msg = path.first().clone();
}
_ => {}
}
self.correction = Some(Correction::MakeCursorVisible);
Ok(())
}
pub async fn move_cursor_older(&mut self) {
pub async fn move_cursor_older(&mut self) -> Result<(), S::Error> {
match &mut self.cursor {
Cursor::Msg(id) => {
if let Some(prev_id) = self.store.older_msg_id(id).await {
if let Some(prev_id) = self.store.older_msg_id(id).await? {
*id = prev_id;
}
}
Cursor::Bottom | Cursor::Pseudo { .. } => {
if let Some(id) = self.store.newest_msg_id().await {
if let Some(id) = self.store.newest_msg_id().await? {
self.cursor = Cursor::Msg(id);
}
}
_ => {}
}
self.correction = Some(Correction::MakeCursorVisible);
Ok(())
}
pub async fn move_cursor_newer(&mut self) {
pub async fn move_cursor_newer(&mut self) -> Result<(), S::Error> {
match &mut self.cursor {
Cursor::Msg(id) => {
if let Some(prev_id) = self.store.newer_msg_id(id).await {
if let Some(prev_id) = self.store.newer_msg_id(id).await? {
*id = prev_id;
} else {
self.cursor = Cursor::Bottom;
@ -355,29 +373,31 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
_ => {}
}
self.correction = Some(Correction::MakeCursorVisible);
Ok(())
}
pub async fn move_cursor_older_unseen(&mut self) {
pub async fn move_cursor_older_unseen(&mut self) -> Result<(), S::Error> {
match &mut self.cursor {
Cursor::Msg(id) => {
if let Some(prev_id) = self.store.older_unseen_msg_id(id).await {
if let Some(prev_id) = self.store.older_unseen_msg_id(id).await? {
*id = prev_id;
}
}
Cursor::Bottom | Cursor::Pseudo { .. } => {
if let Some(id) = self.store.newest_unseen_msg_id().await {
if let Some(id) = self.store.newest_unseen_msg_id().await? {
self.cursor = Cursor::Msg(id);
}
}
_ => {}
}
self.correction = Some(Correction::MakeCursorVisible);
Ok(())
}
pub async fn move_cursor_newer_unseen(&mut self) {
pub async fn move_cursor_newer_unseen(&mut self) -> Result<(), S::Error> {
match &mut self.cursor {
Cursor::Msg(id) => {
if let Some(prev_id) = self.store.newer_unseen_msg_id(id).await {
if let Some(prev_id) = self.store.newer_unseen_msg_id(id).await? {
*id = prev_id;
} else {
self.cursor = Cursor::Bottom;
@ -389,13 +409,15 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
_ => {}
}
self.correction = Some(Correction::MakeCursorVisible);
Ok(())
}
pub async fn move_cursor_to_top(&mut self) {
if let Some(first_root_id) = self.store.first_root_id().await {
pub async fn move_cursor_to_top(&mut self) -> Result<(), S::Error> {
if let Some(first_root_id) = self.store.first_root_id().await? {
self.cursor = Cursor::Msg(first_root_id);
self.correction = Some(Correction::MakeCursorVisible);
}
Ok(())
}
pub async fn move_cursor_to_bottom(&mut self) {
@ -418,12 +440,14 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
self.correction = Some(Correction::CenterCursor);
}
pub async fn parent_for_normal_reply(&self) -> Option<Option<M::Id>> {
match &self.cursor {
/// The outer `Option` shows whether a parent exists or not. The inner
/// `Option` shows if that parent has an id.
pub async fn parent_for_normal_reply(&self) -> Result<Option<Option<M::Id>>, S::Error> {
Ok(match &self.cursor {
Cursor::Bottom => Some(None),
Cursor::Msg(id) => {
let path = self.store.path(id).await;
let tree = self.store.tree(path.first()).await;
let path = self.store.path(id).await?;
let tree = self.store.tree(path.first()).await?;
Some(Some(if tree.next_sibling(id).is_some() {
// A reply to a message that has further siblings should be a
@ -444,15 +468,17 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
}))
}
_ => None,
}
})
}
pub async fn parent_for_alternate_reply(&self) -> Option<Option<M::Id>> {
match &self.cursor {
/// The outer `Option` shows whether a parent exists or not. The inner
/// `Option` shows if that parent has an id.
pub async fn parent_for_alternate_reply(&self) -> Result<Option<Option<M::Id>>, S::Error> {
Ok(match &self.cursor {
Cursor::Bottom => Some(None),
Cursor::Msg(id) => {
let path = self.store.path(id).await;
let tree = self.store.tree(path.first()).await;
let path = self.store.path(id).await?;
let tree = self.store.tree(path.first()).await?;
Some(Some(if tree.next_sibling(id).is_none() {
// The opposite of replying normally
@ -467,6 +493,6 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
}))
}
_ => None,
}
})
}
}

View file

@ -22,9 +22,9 @@ struct Context {
}
impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
async fn cursor_path(&self, cursor: &Cursor<M::Id>) -> Path<M::Id> {
match cursor {
Cursor::Msg(id) => self.store.path(id).await,
async fn cursor_path(&self, cursor: &Cursor<M::Id>) -> Result<Path<M::Id>, S::Error> {
Ok(match cursor {
Cursor::Msg(id) => self.store.path(id).await?,
Cursor::Bottom
| Cursor::Editor { parent: None, .. }
| Cursor::Pseudo { parent: None, .. } => Path::new(vec![M::last_possible_id()]),
@ -36,11 +36,11 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
parent: Some(parent),
..
} => {
let mut path = self.store.path(parent).await;
let mut path = self.store.path(parent).await?;
path.push(M::last_possible_id());
path
}
}
})
}
fn make_path_visible(&mut self, path: &Path<M::Id>) {
@ -202,22 +202,24 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
context: &Context,
frame: &mut Frame,
blocks: &mut TreeBlocks<M::Id>,
) {
) -> Result<(), S::Error> {
let top_line = 0;
while blocks.blocks().top_line > top_line {
let top_root = blocks.top_root();
let prev_root_id = match top_root {
Root::Bottom => self.store.last_root_id().await,
Root::Tree(root_id) => self.store.prev_root_id(root_id).await,
Root::Bottom => self.store.last_root_id().await?,
Root::Tree(root_id) => self.store.prev_root_id(root_id).await?,
};
let prev_root_id = match prev_root_id {
Some(id) => id,
None => break,
};
let prev_tree = self.store.tree(&prev_root_id).await;
let prev_tree = self.store.tree(&prev_root_id).await?;
blocks.prepend(self.layout_tree(context, frame, prev_tree));
}
Ok(())
}
async fn expand_to_bottom(
@ -225,22 +227,24 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
context: &Context,
frame: &mut Frame,
blocks: &mut TreeBlocks<M::Id>,
) {
) -> Result<(), S::Error> {
let bottom_line = frame.size().height as i32 - 1;
while blocks.blocks().bottom_line < bottom_line {
let bottom_root = blocks.bottom_root();
let next_root_id = match bottom_root {
Root::Bottom => break,
Root::Tree(root_id) => self.store.next_root_id(root_id).await,
Root::Tree(root_id) => self.store.next_root_id(root_id).await?,
};
if let Some(next_root_id) = next_root_id {
let next_tree = self.store.tree(&next_root_id).await;
let next_tree = self.store.tree(&next_root_id).await?;
blocks.append(self.layout_tree(context, frame, next_tree));
} else {
blocks.append(self.layout_bottom(context, frame));
}
}
Ok(())
}
async fn fill_screen_and_clamp_scrolling(
@ -248,23 +252,25 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
context: &Context,
frame: &mut Frame,
blocks: &mut TreeBlocks<M::Id>,
) {
) -> Result<(), S::Error> {
let top_line = 0;
let bottom_line = frame.size().height as i32 - 1;
self.expand_to_top(context, frame, blocks).await;
self.expand_to_top(context, frame, blocks).await?;
if blocks.blocks().top_line > top_line {
blocks.blocks_mut().set_top_line(0);
}
self.expand_to_bottom(context, frame, blocks).await;
self.expand_to_bottom(context, frame, blocks).await?;
if blocks.blocks().bottom_line < bottom_line {
blocks.blocks_mut().set_bottom_line(bottom_line);
}
self.expand_to_top(context, frame, blocks).await;
self.expand_to_top(context, frame, blocks).await?;
Ok(())
}
async fn layout_last_cursor_seed(
@ -272,8 +278,8 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
context: &Context,
frame: &mut Frame,
last_cursor_path: &Path<M::Id>,
) -> TreeBlocks<M::Id> {
match &self.last_cursor {
) -> Result<TreeBlocks<M::Id>, S::Error> {
Ok(match &self.last_cursor {
Cursor::Bottom => {
let mut blocks = self.layout_bottom(context, frame);
@ -299,7 +305,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
parent: Some(_), ..
} => {
let root = last_cursor_path.first();
let tree = self.store.tree(root).await;
let tree = self.store.tree(root).await?;
let mut blocks = self.layout_tree(context, frame, tree);
blocks
@ -308,7 +314,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
blocks
}
}
})
}
async fn layout_cursor_seed(
@ -317,10 +323,10 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
frame: &mut Frame,
last_cursor_path: &Path<M::Id>,
cursor_path: &Path<M::Id>,
) -> TreeBlocks<M::Id> {
) -> Result<TreeBlocks<M::Id>, S::Error> {
let bottom_line = frame.size().height as i32 - 1;
match &self.cursor {
Ok(match &self.cursor {
Cursor::Bottom
| Cursor::Editor { parent: None, .. }
| Cursor::Pseudo { parent: None, .. } => {
@ -338,7 +344,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
parent: Some(_), ..
} => {
let root = cursor_path.first();
let tree = self.store.tree(root).await;
let tree = self.store.tree(root).await?;
let mut blocks = self.layout_tree(context, frame, tree);
let cursor_above_last = cursor_path < last_cursor_path;
@ -349,7 +355,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
blocks
}
}
})
}
async fn layout_initial_seed(
@ -358,7 +364,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
frame: &mut Frame,
last_cursor_path: &Path<M::Id>,
cursor_path: &Path<M::Id>,
) -> TreeBlocks<M::Id> {
) -> Result<TreeBlocks<M::Id>, S::Error> {
if let Cursor::Bottom = self.cursor {
self.layout_cursor_seed(context, frame, last_cursor_path, cursor_path)
.await
@ -513,7 +519,7 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
nick: String,
focused: bool,
frame: &mut Frame,
) -> TreeBlocks<M::Id> {
) -> Result<TreeBlocks<M::Id>, S::Error> {
// The basic idea is this:
//
// First, layout a full screen of blocks around self.last_cursor, using
@ -534,30 +540,30 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
let context = Context { nick, focused };
let last_cursor_path = self.cursor_path(&self.last_cursor).await;
let cursor_path = self.cursor_path(&self.cursor).await;
let last_cursor_path = self.cursor_path(&self.last_cursor).await?;
let cursor_path = self.cursor_path(&self.cursor).await?;
self.make_path_visible(&cursor_path);
let mut blocks = self
.layout_initial_seed(&context, frame, &last_cursor_path, &cursor_path)
.await;
.await?;
blocks.blocks_mut().offset(self.scroll);
self.fill_screen_and_clamp_scrolling(&context, frame, &mut blocks)
.await;
.await?;
if !self.contains_cursor(&blocks) {
blocks = self
.layout_cursor_seed(&context, frame, &last_cursor_path, &cursor_path)
.await;
.await?;
self.fill_screen_and_clamp_scrolling(&context, frame, &mut blocks)
.await;
.await?;
}
match self.correction {
Some(Correction::MakeCursorVisible) => {
self.scroll_so_cursor_is_visible(frame, &mut blocks);
self.fill_screen_and_clamp_scrolling(&context, frame, &mut blocks)
.await;
.await?;
}
Some(Correction::MoveCursorToVisibleArea) => {
let new_cursor_msg_id = self.move_cursor_so_it_is_visible(frame, &blocks);
@ -572,18 +578,18 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
self.scroll = 0;
self.correction = None;
let last_cursor_path = self.store.path(&cursor_msg_id).await;
let last_cursor_path = self.store.path(&cursor_msg_id).await?;
blocks = self
.layout_last_cursor_seed(&context, frame, &last_cursor_path)
.await;
.await?;
self.fill_screen_and_clamp_scrolling(&context, frame, &mut blocks)
.await;
.await?;
}
}
Some(Correction::CenterCursor) => {
self.scroll_so_cursor_is_centered(frame, &mut blocks);
self.fill_screen_and_clamp_scrolling(&context, frame, &mut blocks)
.await;
.await?;
}
None => {}
}
@ -594,6 +600,6 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
self.scroll = 0;
self.correction = None;
blocks
Ok(blocks)
}
}