From 35a140e21fececd5ca3b76463f51412a475629c1 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 12 Feb 2023 21:08:38 +0100 Subject: [PATCH] Make MsgStore fallible --- src/logger.rs | 67 ++++++++------- src/store.rs | 37 ++++---- src/ui.rs | 20 +++-- src/ui/chat.rs | 5 +- src/ui/chat/tree.rs | 103 +++++++++++++---------- src/ui/chat/tree/cursor.rs | 168 +++++++++++++++++++++---------------- src/ui/chat/tree/layout.rs | 82 +++++++++--------- src/ui/euph/room.rs | 11 ++- src/vault/euph.rs | 73 ++++++++-------- 9 files changed, 324 insertions(+), 242 deletions(-) diff --git a/src/logger.rs b/src/logger.rs index 692c0b6..c80d794 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,3 +1,4 @@ +use std::convert::Infallible; use std::sync::Arc; use std::vec; @@ -100,81 +101,87 @@ pub struct Logger { #[async_trait] impl MsgStore for Logger { - async fn path(&self, id: &usize) -> Path { - Path::new(vec![*id]) + type Error = Infallible; + + async fn path(&self, id: &usize) -> Result, Self::Error> { + Ok(Path::new(vec![*id])) } - async fn msg(&self, id: &usize) -> Option { - self.messages.lock().get(*id).cloned() + async fn msg(&self, id: &usize) -> Result, Self::Error> { + Ok(self.messages.lock().get(*id).cloned()) } - async fn tree(&self, root_id: &usize) -> Tree { + async fn tree(&self, root_id: &usize) -> Result, Self::Error> { let msgs = self .messages .lock() .get(*root_id) .map(|msg| vec![msg.clone()]) .unwrap_or_default(); - Tree::new(*root_id, msgs) + Ok(Tree::new(*root_id, msgs)) } - async fn first_root_id(&self) -> Option { + async fn first_root_id(&self) -> Result, Self::Error> { let empty = self.messages.lock().is_empty(); - Some(0).filter(|_| !empty) + Ok(Some(0).filter(|_| !empty)) } - async fn last_root_id(&self) -> Option { - self.messages.lock().len().checked_sub(1) + async fn last_root_id(&self) -> Result, Self::Error> { + Ok(self.messages.lock().len().checked_sub(1)) } - async fn prev_root_id(&self, root_id: &usize) -> Option { - root_id.checked_sub(1) + async fn prev_root_id(&self, root_id: &usize) -> Result, Self::Error> { + Ok(root_id.checked_sub(1)) } - async fn next_root_id(&self, root_id: &usize) -> Option { + async fn next_root_id(&self, root_id: &usize) -> Result, Self::Error> { let len = self.messages.lock().len(); - root_id.checked_add(1).filter(|t| *t < len) + Ok(root_id.checked_add(1).filter(|t| *t < len)) } - async fn oldest_msg_id(&self) -> Option { + async fn oldest_msg_id(&self) -> Result, Self::Error> { self.first_root_id().await } - async fn newest_msg_id(&self) -> Option { + async fn newest_msg_id(&self) -> Result, Self::Error> { self.last_root_id().await } - async fn older_msg_id(&self, id: &usize) -> Option { + async fn older_msg_id(&self, id: &usize) -> Result, Self::Error> { self.prev_root_id(id).await } - async fn newer_msg_id(&self, id: &usize) -> Option { + async fn newer_msg_id(&self, id: &usize) -> Result, Self::Error> { self.next_root_id(id).await } - async fn oldest_unseen_msg_id(&self) -> Option { - None + async fn oldest_unseen_msg_id(&self) -> Result, Self::Error> { + Ok(None) } - async fn newest_unseen_msg_id(&self) -> Option { - None + async fn newest_unseen_msg_id(&self) -> Result, Self::Error> { + Ok(None) } - async fn older_unseen_msg_id(&self, _id: &usize) -> Option { - None + async fn older_unseen_msg_id(&self, _id: &usize) -> Result, Self::Error> { + Ok(None) } - async fn newer_unseen_msg_id(&self, _id: &usize) -> Option { - None + async fn newer_unseen_msg_id(&self, _id: &usize) -> Result, Self::Error> { + Ok(None) } - async fn unseen_msgs_count(&self) -> usize { - 0 + async fn unseen_msgs_count(&self) -> Result { + Ok(0) } - async fn set_seen(&self, _id: &usize, _seen: bool) {} + async fn set_seen(&self, _id: &usize, _seen: bool) -> Result<(), Self::Error> { + Ok(()) + } - async fn set_older_seen(&self, _id: &usize, _seen: bool) {} + async fn set_older_seen(&self, _id: &usize, _seen: bool) -> Result<(), Self::Error> { + Ok(()) + } } impl Log for Logger { diff --git a/src/store.rs b/src/store.rs index 9625c74..d762752 100644 --- a/src/store.rs +++ b/src/store.rs @@ -132,22 +132,23 @@ impl Tree { #[async_trait] pub trait MsgStore { - async fn path(&self, id: &M::Id) -> Path; - async fn msg(&self, id: &M::Id) -> Option; - async fn tree(&self, root_id: &M::Id) -> Tree; - async fn first_root_id(&self) -> Option; - async fn last_root_id(&self) -> Option; - async fn prev_root_id(&self, root_id: &M::Id) -> Option; - async fn next_root_id(&self, root_id: &M::Id) -> Option; - async fn oldest_msg_id(&self) -> Option; - async fn newest_msg_id(&self) -> Option; - async fn older_msg_id(&self, id: &M::Id) -> Option; - async fn newer_msg_id(&self, id: &M::Id) -> Option; - async fn oldest_unseen_msg_id(&self) -> Option; - async fn newest_unseen_msg_id(&self) -> Option; - async fn older_unseen_msg_id(&self, id: &M::Id) -> Option; - async fn newer_unseen_msg_id(&self, id: &M::Id) -> Option; - async fn unseen_msgs_count(&self) -> usize; - async fn set_seen(&self, id: &M::Id, seen: bool); - async fn set_older_seen(&self, id: &M::Id, seen: bool); + type Error; + async fn path(&self, id: &M::Id) -> Result, Self::Error>; + async fn msg(&self, id: &M::Id) -> Result, Self::Error>; + async fn tree(&self, root_id: &M::Id) -> Result, Self::Error>; + async fn first_root_id(&self) -> Result, Self::Error>; + async fn last_root_id(&self) -> Result, Self::Error>; + async fn prev_root_id(&self, root_id: &M::Id) -> Result, Self::Error>; + async fn next_root_id(&self, root_id: &M::Id) -> Result, Self::Error>; + async fn oldest_msg_id(&self) -> Result, Self::Error>; + async fn newest_msg_id(&self) -> Result, Self::Error>; + async fn older_msg_id(&self, id: &M::Id) -> Result, Self::Error>; + async fn newer_msg_id(&self, id: &M::Id) -> Result, Self::Error>; + async fn oldest_unseen_msg_id(&self) -> Result, Self::Error>; + async fn newest_unseen_msg_id(&self) -> Result, Self::Error>; + async fn older_unseen_msg_id(&self, id: &M::Id) -> Result, Self::Error>; + async fn newer_unseen_msg_id(&self, id: &M::Id) -> Result, Self::Error>; + async fn unseen_msgs_count(&self) -> Result; + async fn set_seen(&self, id: &M::Id, seen: bool) -> Result<(), Self::Error>; + async fn set_older_seen(&self, id: &M::Id, seen: bool) -> Result<(), Self::Error>; } diff --git a/src/ui.rs b/src/ui.rs index a24061e..8ff3e13 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -10,6 +10,7 @@ use std::io; use std::sync::{Arc, Weak}; use std::time::{Duration, Instant}; +use log::error; use parking_lot::FairMutex; use tokio::sync::mpsc::error::TryRecvError; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; @@ -286,11 +287,20 @@ impl Ui { .handle_input_event(terminal, crossterm_lock, &event) .await } - Mode::Log => self - .log_chat - .handle_input_event(terminal, crossterm_lock, &event, false) - .await - .handled(), + Mode::Log => { + let reaction = match self + .log_chat + .handle_input_event(terminal, crossterm_lock, &event, false) + .await + { + Ok(reaction) => reaction, + Err(err) => { + error!("{err}"); + panic!("{err}"); + } + }; + reaction.handled() + } }; // Pressing '?' should only open the key bindings list if it doesn't diff --git a/src/ui/chat.rs b/src/ui/chat.rs index 7e7021c..124d95d 100644 --- a/src/ui/chat.rs +++ b/src/ui/chat.rs @@ -5,8 +5,8 @@ mod blocks; mod tree; -use std::io; use std::sync::Arc; +use std::{fmt, io}; use async_trait::async_trait; use parking_lot::FairMutex; @@ -102,7 +102,7 @@ impl> ChatState { crossterm_lock: &Arc>, event: &InputEvent, can_compose: bool, - ) -> Reaction { + ) -> Result, S::Error> { match self.mode { Mode::Tree => { self.tree @@ -144,6 +144,7 @@ where M: Msg + ChatMsg, M::Id: Send + Sync, S: MsgStore + Send + Sync, + S::Error: fmt::Display, { fn size(&self, frame: &mut Frame, max_width: Option, max_height: Option) -> Size { match self { diff --git a/src/ui/chat/tree.rs b/src/ui/chat/tree.rs index 18942d4..9325d3e 100644 --- a/src/ui/chat/tree.rs +++ b/src/ui/chat/tree.rs @@ -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> InnerTreeViewState { // 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 { 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> InnerTreeViewState { 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> InnerTreeViewState { 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 { 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> InnerTreeViewState { &mut self, event: &InputEvent, id: Option, - ) -> bool { + ) -> Result { 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> InnerTreeViewState { 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> InnerTreeViewState { event: &InputEvent, can_compose: bool, id: Option, - ) -> bool { + ) -> Result { #[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> InnerTreeViewState { crossterm_lock: &Arc>, event: &InputEvent, can_compose: bool, - ) -> Reaction { - match &self.cursor { + ) -> Result, 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> InnerTreeViewState { 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> InnerTreeViewState { Cursor::Pseudo { .. } => { if self .handle_movement_input_event(terminal.frame(), event) - .await + .await? { Reaction::Handled } else { Reaction::NotHandled } } - } + }) } fn cursor(&self) -> Option { @@ -388,7 +398,7 @@ impl> TreeViewState { crossterm_lock: &Arc>, event: &InputEvent, can_compose: bool, - ) -> Reaction { + ) -> Result, S::Error> { self.0 .lock() .await @@ -421,6 +431,7 @@ where M: Msg + ChatMsg, M::Id: Send + Sync, S: MsgStore + Send + Sync, + S::Error: fmt::Display, { fn size(&self, _frame: &mut Frame, _max_width: Option, _max_height: Option) -> Size { Size::ZERO @@ -428,7 +439,13 @@ where async fn render(self: Box, 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 { diff --git a/src/ui/chat/tree/cursor.rs b/src/ui/chat/tree/cursor.rs index bd303a0..e154708 100644 --- a/src/ui/chat/tree/cursor.rs +++ b/src/ui/chat/tree/cursor.rs @@ -94,15 +94,19 @@ impl> InnerTreeViewState { /// 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, id: &mut M::Id) -> bool { - if let Some(prev_sibling) = tree.prev_sibling(id) { + async fn find_prev_sibling( + store: &S, + tree: &mut Tree, + id: &mut M::Id, + ) -> Result { + 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> InnerTreeViewState { } } 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, id: &mut M::Id) -> bool { - if let Some(next_sibling) = tree.next_sibling(id) { + async fn find_next_sibling( + store: &S, + tree: &mut Tree, + id: &mut M::Id, + ) -> Result { + 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> InnerTreeViewState { } } else { false - } + }; + Ok(moved) } /// Move to the previous message, or don't move if this is not possible. @@ -141,15 +151,16 @@ impl> InnerTreeViewState { folded: &HashSet, tree: &mut Tree, id: &mut M::Id, - ) -> bool { + ) -> Result { // 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> InnerTreeViewState { folded: &HashSet, tree: &mut Tree, id: &mut M::Id, - ) -> bool { + ) -> Result { 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> InnerTreeViewState { 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> InnerTreeViewState { _ => {} } 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> InnerTreeViewState { } } 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> InnerTreeViewState { _ => {} } 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> InnerTreeViewState { 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> InnerTreeViewState { _ => {} } 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> InnerTreeViewState { _ => {} } 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> InnerTreeViewState { self.correction = Some(Correction::CenterCursor); } - pub async fn parent_for_normal_reply(&self) -> Option> { - 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>, 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> InnerTreeViewState { })) } _ => None, - } + }) } - pub async fn parent_for_alternate_reply(&self) -> Option> { - 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>, 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> InnerTreeViewState { })) } _ => None, - } + }) } } diff --git a/src/ui/chat/tree/layout.rs b/src/ui/chat/tree/layout.rs index bc6f4de..baccfbe 100644 --- a/src/ui/chat/tree/layout.rs +++ b/src/ui/chat/tree/layout.rs @@ -22,9 +22,9 @@ struct Context { } impl> InnerTreeViewState { - async fn cursor_path(&self, cursor: &Cursor) -> Path { - match cursor { - Cursor::Msg(id) => self.store.path(id).await, + async fn cursor_path(&self, cursor: &Cursor) -> Result, 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> InnerTreeViewState { 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) { @@ -202,22 +202,24 @@ impl> InnerTreeViewState { context: &Context, frame: &mut Frame, blocks: &mut TreeBlocks, - ) { + ) -> 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> InnerTreeViewState { context: &Context, frame: &mut Frame, blocks: &mut TreeBlocks, - ) { + ) -> 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> InnerTreeViewState { context: &Context, frame: &mut Frame, blocks: &mut TreeBlocks, - ) { + ) -> 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> InnerTreeViewState { context: &Context, frame: &mut Frame, last_cursor_path: &Path, - ) -> TreeBlocks { - match &self.last_cursor { + ) -> Result, S::Error> { + Ok(match &self.last_cursor { Cursor::Bottom => { let mut blocks = self.layout_bottom(context, frame); @@ -299,7 +305,7 @@ impl> InnerTreeViewState { 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> InnerTreeViewState { blocks } - } + }) } async fn layout_cursor_seed( @@ -317,10 +323,10 @@ impl> InnerTreeViewState { frame: &mut Frame, last_cursor_path: &Path, cursor_path: &Path, - ) -> TreeBlocks { + ) -> Result, 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> InnerTreeViewState { 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> InnerTreeViewState { blocks } - } + }) } async fn layout_initial_seed( @@ -358,7 +364,7 @@ impl> InnerTreeViewState { frame: &mut Frame, last_cursor_path: &Path, cursor_path: &Path, - ) -> TreeBlocks { + ) -> Result, 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> InnerTreeViewState { nick: String, focused: bool, frame: &mut Frame, - ) -> TreeBlocks { + ) -> Result, S::Error> { // The basic idea is this: // // First, layout a full screen of blocks around self.last_cursor, using @@ -534,30 +540,30 @@ impl> InnerTreeViewState { 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> InnerTreeViewState { 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> InnerTreeViewState { self.scroll = 0; self.correction = None; - blocks + Ok(blocks) } } diff --git a/src/ui/euph/room.rs b/src/ui/euph/room.rs index 0639a4a..4572cf6 100644 --- a/src/ui/euph/room.rs +++ b/src/ui/euph/room.rs @@ -5,6 +5,7 @@ use crossterm::style::{ContentStyle, Stylize}; use euphoxide::api::{Data, Message, MessageId, PacketType, SessionId}; use euphoxide::bot::instance::{Event, ServerConfig}; use euphoxide::conn::{self, Joined, Joining, SessionInfo}; +use log::error; use parking_lot::FairMutex; use tokio::sync::oneshot::error::TryRecvError; use tokio::sync::{mpsc, oneshot}; @@ -326,11 +327,19 @@ impl EuphRoom { Some(euph::State::Connected(_, conn::State::Joined(_))) ); - match self + let reaction = match self .chat .handle_input_event(terminal, crossterm_lock, event, can_compose) .await { + Ok(reaction) => reaction, + Err(err) => { + error!("{err}"); + panic!("{err}"); + } + }; + + match reaction { Reaction::NotHandled => {} Reaction::Handled => return true, Reaction::Composed { parent, content } => { diff --git a/src/vault/euph.rs b/src/vault/euph.rs index 897a2fd..9fd5fdc 100644 --- a/src/vault/euph.rs +++ b/src/vault/euph.rs @@ -1,3 +1,4 @@ +use std::convert::Infallible; use std::mem; use std::str::FromStr; @@ -86,76 +87,80 @@ impl EuphRoomVault { #[async_trait] impl MsgStore for EuphRoomVault { - async fn path(&self, id: &MessageId) -> Path { - self.path(*id).await + type Error = Infallible; + + async fn path(&self, id: &MessageId) -> Result, Self::Error> { + Ok(self.path(*id).await) } - async fn msg(&self, id: &MessageId) -> Option { - self.msg(*id).await + async fn msg(&self, id: &MessageId) -> Result, Self::Error> { + Ok(self.msg(*id).await) } - async fn tree(&self, root_id: &MessageId) -> Tree { - self.tree(*root_id).await + async fn tree(&self, root_id: &MessageId) -> Result, Self::Error> { + Ok(self.tree(*root_id).await) } - async fn first_root_id(&self) -> Option { - self.first_root_id().await + async fn first_root_id(&self) -> Result, Self::Error> { + Ok(self.first_root_id().await) } - async fn last_root_id(&self) -> Option { - self.last_root_id().await + async fn last_root_id(&self) -> Result, Self::Error> { + Ok(self.last_root_id().await) } - async fn prev_root_id(&self, root_id: &MessageId) -> Option { - self.prev_root_id(*root_id).await + async fn prev_root_id(&self, root_id: &MessageId) -> Result, Self::Error> { + Ok(self.prev_root_id(*root_id).await) } - async fn next_root_id(&self, root_id: &MessageId) -> Option { - self.next_root_id(*root_id).await + async fn next_root_id(&self, root_id: &MessageId) -> Result, Self::Error> { + Ok(self.next_root_id(*root_id).await) } - async fn oldest_msg_id(&self) -> Option { - self.oldest_msg_id().await + async fn oldest_msg_id(&self) -> Result, Self::Error> { + Ok(self.oldest_msg_id().await) } - async fn newest_msg_id(&self) -> Option { - self.newest_msg_id().await + async fn newest_msg_id(&self) -> Result, Self::Error> { + Ok(self.newest_msg_id().await) } - async fn older_msg_id(&self, id: &MessageId) -> Option { - self.older_msg_id(*id).await + async fn older_msg_id(&self, id: &MessageId) -> Result, Self::Error> { + Ok(self.older_msg_id(*id).await) } - async fn newer_msg_id(&self, id: &MessageId) -> Option { - self.newer_msg_id(*id).await + async fn newer_msg_id(&self, id: &MessageId) -> Result, Self::Error> { + Ok(self.newer_msg_id(*id).await) } - async fn oldest_unseen_msg_id(&self) -> Option { - self.oldest_unseen_msg_id().await + async fn oldest_unseen_msg_id(&self) -> Result, Self::Error> { + Ok(self.oldest_unseen_msg_id().await) } - async fn newest_unseen_msg_id(&self) -> Option { - self.newest_unseen_msg_id().await + async fn newest_unseen_msg_id(&self) -> Result, Self::Error> { + Ok(self.newest_unseen_msg_id().await) } - async fn older_unseen_msg_id(&self, id: &MessageId) -> Option { - self.older_unseen_msg_id(*id).await + async fn older_unseen_msg_id(&self, id: &MessageId) -> Result, Self::Error> { + Ok(self.older_unseen_msg_id(*id).await) } - async fn newer_unseen_msg_id(&self, id: &MessageId) -> Option { - self.newer_unseen_msg_id(*id).await + async fn newer_unseen_msg_id(&self, id: &MessageId) -> Result, Self::Error> { + Ok(self.newer_unseen_msg_id(*id).await) } - async fn unseen_msgs_count(&self) -> usize { - self.unseen_msgs_count().await + async fn unseen_msgs_count(&self) -> Result { + Ok(self.unseen_msgs_count().await) } - async fn set_seen(&self, id: &MessageId, seen: bool) { + async fn set_seen(&self, id: &MessageId, seen: bool) -> Result<(), Self::Error> { self.set_seen(*id, seen); + Ok(()) } - async fn set_older_seen(&self, id: &MessageId, seen: bool) { + async fn set_older_seen(&self, id: &MessageId, seen: bool) -> Result<(), Self::Error> { self.set_older_seen(*id, seen); + Ok(()) } }