diff --git a/cove-tui/src/chat/tree/cursor.rs b/cove-tui/src/chat/tree/cursor.rs index 7629ed5..a18a271 100644 --- a/cove-tui/src/chat/tree/cursor.rs +++ b/cove-tui/src/chat/tree/cursor.rs @@ -3,7 +3,7 @@ use toss::frame::{Frame, Size}; use crate::chat::Cursor; -use crate::store::{Msg, MsgStore}; +use crate::store::{Msg, MsgStore, Tree}; use super::blocks::Blocks; use super::{util, TreeView}; @@ -16,14 +16,14 @@ impl TreeView { frame: &mut Frame, size: Size, old_blocks: &Blocks, - old_cursor_id: &M::Id, + old_cursor_id: &Option, cursor: &mut Cursor, ) { if let Some(block) = old_blocks.find(&cursor.id) { // The cursor is still visible in the old blocks, so we just need to // adjust the proportion such that the blocks stay still. cursor.proportion = util::line_to_proportion(size.height, block.line); - } else { + } else if let Some(old_cursor_id) = old_cursor_id { // The cursor is not visible any more. However, we can estimate // whether it is above or below the previous cursor position by // lexicographically comparing both positions' paths. @@ -38,6 +38,10 @@ impl TreeView { // bottom of the screen. cursor.proportion = 1.0; } + } else { + // We were scrolled all the way to the bottom, so the cursor must + // have been offscreen somewhere above. + cursor.proportion = 0.0; } // The cursor should be visible in its entirety on the screen now. If it @@ -65,16 +69,265 @@ impl TreeView { // goes for the other direction. } - pub async fn move_up() { - todo!() + /// 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>( + &self, + room: &str, + store: &S, + tree: &mut Tree, + id: &mut M::Id, + ) { + if let Some(siblings) = tree.siblings(id) { + let prev_sibling = siblings + .iter() + .zip(siblings.iter().skip(1)) + .find(|(_, s)| *s == id) + .map(|(s, _)| s); + if let Some(prev_sibling) = prev_sibling { + *id = prev_sibling.clone(); + } + } else { + // We're at the root of our tree, so we need to move to the root of + // the previous tree. + if let Some(prev_tree_id) = store.prev_tree(room, tree.root()).await { + *tree = store.tree(room, &prev_tree_id).await; + *id = prev_tree_id; + } + } } - pub async fn move_down() { - todo!() + /// 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>( + &self, + room: &str, + store: &S, + tree: &mut Tree, + id: &mut M::Id, + ) { + if let Some(siblings) = tree.siblings(id) { + let next_sibling = siblings + .iter() + .zip(siblings.iter().skip(1)) + .find(|(s, _)| *s == id) + .map(|(_, s)| s); + if let Some(next_sibling) = next_sibling { + *id = next_sibling.clone(); + } + } else { + // We're at the root of our tree, so we need to move to the root of + // the next tree. + if let Some(next_tree_id) = store.next_tree(room, tree.root()).await { + *tree = store.tree(room, &next_tree_id).await; + *id = next_tree_id; + } + } } - pub async fn move_up_sibling() { - todo!() + fn find_innermost_child(tree: &Tree, id: &mut M::Id) { + while let Some(children) = tree.children(id) { + if let Some(child) = children.last() { + *id = child.clone() + } else { + break; + } + } + } + + /// Move to the previous message, or don't move if this is not possible. + async fn find_prev_msg>( + &self, + room: &str, + store: &S, + tree: &mut Tree, + id: &mut M::Id, + ) { + if let Some(siblings) = tree.siblings(id) { + let prev_sibling = siblings + .iter() + .zip(siblings.iter().skip(1)) + .find(|(_, s)| *s == id) + .map(|(s, _)| s); + if let Some(prev_sibling) = prev_sibling { + *id = prev_sibling.clone(); + } else { + // We need to move up one parent and *not* down again. If there + // was no parent, we should be in the `else` case below instead. + if let Some(parent) = tree.parent(id) { + *id = parent; + return; + } + } + } else { + // We're at the root of our tree, so we need to move to the root of + // the previous tree. + if let Some(prev_tree_id) = store.prev_tree(room, tree.root()).await { + *tree = store.tree(room, &prev_tree_id).await; + *id = prev_tree_id; + } + } + + // Now, we just need to move to the deepest and last child. + Self::find_innermost_child(tree, id); + } + + /// Move to the next message, or don't move if this is not possible. + async fn find_next_msg>( + &self, + room: &str, + store: &S, + tree: &mut Tree, + id: &mut M::Id, + ) { + if let Some(children) = tree.children(id) { + if let Some(child) = children.first() { + *id = child.clone(); + return; + } + } + + if let Some(siblings) = tree.siblings(id) { + let prev_sibling = siblings + .iter() + .zip(siblings.iter().skip(1)) + .find(|(_, s)| *s == id) + .map(|(s, _)| s); + if let Some(next_sibling) = prev_sibling { + *id = prev_sibling.clone(); + } else { + // We need to move up one parent and *not* down again. If there + // was no parent, we should be in the `else` case below instead. + if let Some(parent) = tree.msg(id).and_then(|m| m.parent()) { + *id = parent; + return; + } + } + } else { + // We're at the root of our tree, so we need to move to the root of + // the previous tree. + if let Some(prev_tree_id) = store.prev_tree(room, tree.root()).await { + *tree = store.tree(room, &prev_tree_id).await; + *id = prev_tree_id; + } + } + + // Now, we just need to move to the deepest and last child. + Self::find_innermost_child(tree, id); + } + + pub async fn move_up>( + &mut self, + room: &str, + store: &S, + cursor: &mut Option>, + frame: &mut Frame, + size: Size, + ) { + let old_blocks = self + .layout_blocks(room, store, cursor.as_ref(), frame, size) + .await; + let old_cursor_id = cursor.as_ref().map(|c| c.id.clone()); + + if let Some(cursor) = cursor { + let mut tree = store.tree(room, &cursor.id).await; + self.find_prev_msg(room, store, &mut tree, &mut cursor.id) + .await; + } else if let Some(last_tree) = store.last_tree(room).await { + let tree = store.tree(room, &last_tree).await; + let mut id = last_tree; + Self::find_innermost_child(&tree, &mut id); + *cursor = Some(Cursor { + id, + proportion: 1.0, + }); + } + + if let Some(cursor) = cursor { + self.correct_cursor_offset( + room, + store, + frame, + size, + &old_blocks, + &old_cursor_id, + cursor, + ) + .await; + } + } + + pub async fn move_down>( + &mut self, + room: &str, + store: &S, + cursor: &mut Option>, + frame: &mut Frame, + size: Size, + ) { + let old_blocks = self + .layout_blocks(room, store, cursor.as_ref(), frame, size) + .await; + let old_cursor_id = cursor.as_ref().map(|c| c.id.clone()); + + if let Some(cursor) = cursor { + let mut tree = store.tree(room, &cursor.id).await; + self.find_next_msg(room, store, &mut tree, &mut cursor.id) + .await; + } + + if let Some(cursor) = cursor { + self.correct_cursor_offset( + room, + store, + frame, + size, + &old_blocks, + &old_cursor_id, + cursor, + ) + .await; + } + } + + pub async fn move_up_sibling>( + &mut self, + room: &str, + store: &S, + cursor: &mut Option>, + frame: &mut Frame, + size: Size, + ) { + let old_blocks = self + .layout_blocks(room, store, cursor.as_ref(), frame, size) + .await; + let old_cursor_id = cursor.as_ref().map(|c| c.id.clone()); + + if let Some(cursor) = cursor { + let mut tree = store.tree(room, &cursor.id).await; + self.find_prev_sibling(room, store, &mut tree, &mut cursor.id) + .await; + } else if let Some(last_tree) = store.last_tree(room).await { + *cursor = Some(Cursor { + id: last_tree, + proportion: 1.0, + }); + } + + if let Some(cursor) = cursor { + self.correct_cursor_offset( + room, + store, + frame, + size, + &old_blocks, + &old_cursor_id, + cursor, + ) + .await; + } } pub async fn move_down_sibling() {