Make store room-specific

This commit is contained in:
Joscha 2022-06-15 11:29:02 +02:00
parent 15213f8003
commit 23c551a5b7
7 changed files with 85 additions and 173 deletions

View file

@ -32,7 +32,6 @@ impl<I> Cursor<I> {
pub struct Chat<M: Msg, S: MsgStore<M>> {
store: S,
room: String,
cursor: Option<Cursor<M::Id>>,
mode: Mode,
tree: TreeView<M>,
@ -41,10 +40,9 @@ pub struct Chat<M: Msg, S: MsgStore<M>> {
}
impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
pub fn new(store: S, room: String) -> Self {
pub fn new(store: S) -> Self {
Self {
store,
room,
cursor: None,
mode: Mode::Tree,
tree: TreeView::new(),
@ -57,14 +55,7 @@ impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
match self.mode {
Mode::Tree => {
self.tree
.handle_key_event(
&self.room,
&mut self.store,
&mut self.cursor,
frame,
size,
event,
)
.handle_key_event(&mut self.store, &mut self.cursor, frame, size, event)
.await
}
}
@ -74,7 +65,7 @@ impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
match self.mode {
Mode::Tree => {
self.tree
.render(&self.room, &mut self.store, &self.cursor, frame, pos, size)
.render(&mut self.store, &self.cursor, frame, pos, size)
.await
}
}

View file

@ -29,7 +29,6 @@ impl<M: Msg> TreeView<M> {
pub async fn handle_key_event<S: MsgStore<M>>(
&mut self,
r: &str,
s: &mut S,
c: &mut Option<Cursor<M::Id>>,
f: &mut Frame,
@ -37,13 +36,13 @@ impl<M: Msg> TreeView<M> {
event: KeyEvent,
) {
match event.code {
KeyCode::Char('z') | KeyCode::Char('Z') => self.center_cursor(r, s, c, f, z).await,
KeyCode::Char('k') => self.move_up(r, s, c, f, z).await,
KeyCode::Char('j') => self.move_down(r, s, c, f, z).await,
KeyCode::Char('K') => self.move_up_sibling(r, s, c, f, z).await,
KeyCode::Char('J') => self.move_down_sibling(r, s, c, f, z).await,
KeyCode::Char('g') => self.move_to_first(r, s, c, f, z).await,
KeyCode::Char('G') => self.move_to_last(r, s, c, f, z).await,
KeyCode::Char('z') | KeyCode::Char('Z') => self.center_cursor(s, c, f, z).await,
KeyCode::Char('k') => self.move_up(s, c, f, z).await,
KeyCode::Char('j') => self.move_down(s, c, f, z).await,
KeyCode::Char('K') => self.move_up_sibling(s, c, f, z).await,
KeyCode::Char('J') => self.move_down_sibling(s, c, f, z).await,
KeyCode::Char('g') => self.move_to_first(s, c, f, z).await,
KeyCode::Char('G') => self.move_to_last(s, c, f, z).await,
KeyCode::Esc => *c = None, // TODO Make 'G' do the same thing?
_ => {}
}
@ -51,7 +50,6 @@ impl<M: Msg> TreeView<M> {
pub async fn render<S: MsgStore<M>>(
&mut self,
room: &str,
store: &mut S,
cursor: &Option<Cursor<M::Id>>,
frame: &mut Frame,
@ -59,7 +57,7 @@ impl<M: Msg> TreeView<M> {
size: Size,
) {
let blocks = self
.layout_blocks(room, store, cursor.as_ref(), frame, size)
.layout_blocks(store, cursor.as_ref(), frame, size)
.await;
Self::render_blocks(frame, pos, size, &blocks);
}

View file

@ -12,7 +12,6 @@ impl<M: Msg> TreeView<M> {
#[allow(clippy::too_many_arguments)]
async fn correct_cursor_offset<S: MsgStore<M>>(
&mut self,
room: &str,
store: &S,
frame: &mut Frame,
size: Size,
@ -28,8 +27,8 @@ impl<M: Msg> TreeView<M> {
// 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.
let old_path = store.path(room, old_cursor_id).await;
let new_path = store.path(room, &cursor.id).await;
let old_path = store.path(old_cursor_id).await;
let new_path = store.path(&cursor.id).await;
if new_path < old_path {
// Because we moved upwards, the cursor should appear at the top
// of the screen.
@ -49,9 +48,7 @@ impl<M: Msg> TreeView<M> {
// isn't, we need to scroll the screen such that the cursor becomes fully
// visible again. To do this, we'll need to re-layout because the cursor
// could've moved anywhere.
let blocks = self
.layout_blocks(room, store, Some(cursor), frame, size)
.await;
let blocks = self.layout_blocks(store, Some(cursor), frame, size).await;
let cursor_block = blocks.find(&cursor.id).expect("cursor must be in blocks");
// First, ensure the cursor's last line is not below the bottom of the
// screen. Then, ensure its top line is not above the top of the screen.
@ -102,7 +99,6 @@ impl<M: Msg> TreeView<M> {
/// Always stays at the same level of indentation.
async fn find_prev_sibling<S: MsgStore<M>>(
&self,
room: &str,
store: &S,
tree: &mut Tree<M>,
id: &mut M::Id,
@ -122,8 +118,8 @@ impl<M: Msg> TreeView<M> {
} 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;
if let Some(prev_tree_id) = store.prev_tree(tree.root()).await {
*tree = store.tree(&prev_tree_id).await;
*id = prev_tree_id;
true
} else {
@ -137,7 +133,6 @@ impl<M: Msg> TreeView<M> {
/// Always stays at the same level of indentation.
async fn find_next_sibling<S: MsgStore<M>>(
&self,
room: &str,
store: &S,
tree: &mut Tree<M>,
id: &mut M::Id,
@ -157,8 +152,8 @@ impl<M: Msg> TreeView<M> {
} 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;
if let Some(next_tree_id) = store.next_tree(tree.root()).await {
*tree = store.tree(&next_tree_id).await;
*id = next_tree_id;
true
} else {
@ -170,14 +165,13 @@ impl<M: Msg> TreeView<M> {
/// Move to the previous message, or don't move if this is not possible.
async fn find_prev_msg<S: MsgStore<M>>(
&self,
room: &str,
store: &S,
tree: &mut Tree<M>,
id: &mut M::Id,
) -> bool {
// Move to previous sibling, then to its last child
// If not possible, move to parent
if self.find_prev_sibling(room, store, tree, id).await {
if self.find_prev_sibling(store, tree, id).await {
while Self::find_last_child(tree, id) {}
true
} else {
@ -188,7 +182,6 @@ impl<M: Msg> TreeView<M> {
/// Move to the next message, or don't move if this is not possible.
async fn find_next_msg<S: MsgStore<M>>(
&self,
room: &str,
store: &S,
tree: &mut Tree<M>,
id: &mut M::Id,
@ -197,7 +190,7 @@ impl<M: Msg> TreeView<M> {
return true;
}
if self.find_next_sibling(room, store, tree, id).await {
if self.find_next_sibling(store, tree, id).await {
return true;
}
@ -205,7 +198,7 @@ impl<M: Msg> TreeView<M> {
// can be found.
let mut tmp_id = id.clone();
while Self::find_parent(tree, &mut tmp_id) {
if self.find_next_sibling(room, store, tree, &mut tmp_id).await {
if self.find_next_sibling(store, tree, &mut tmp_id).await {
*id = tmp_id;
return true;
}
@ -216,26 +209,24 @@ impl<M: Msg> TreeView<M> {
pub async fn move_up<S: MsgStore<M>>(
&mut self,
room: &str,
store: &S,
cursor: &mut Option<Cursor<M::Id>>,
frame: &mut Frame,
size: Size,
) {
let old_blocks = self
.layout_blocks(room, store, cursor.as_ref(), frame, size)
.layout_blocks(store, cursor.as_ref(), frame, size)
.await;
let old_cursor_id = cursor.as_ref().map(|c| c.id.clone());
if let Some(cursor) = cursor {
// We have a cursor to move around
let path = store.path(room, &cursor.id).await;
let mut tree = store.tree(room, path.first()).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 path = store.path(&cursor.id).await;
let mut tree = store.tree(path.first()).await;
self.find_prev_msg(store, &mut tree, &mut cursor.id).await;
} else if let Some(last_tree) = store.last_tree().await {
// We need to select the last message of the last tree
let tree = store.tree(room, &last_tree).await;
let tree = store.tree(&last_tree).await;
let mut id = last_tree;
while Self::find_last_child(&tree, &mut id) {}
*cursor = Some(Cursor::new(id));
@ -244,74 +235,55 @@ impl<M: Msg> TreeView<M> {
// message to move to.
if let Some(cursor) = cursor {
self.correct_cursor_offset(
room,
store,
frame,
size,
&old_blocks,
&old_cursor_id,
cursor,
)
.await;
self.correct_cursor_offset(store, frame, size, &old_blocks, &old_cursor_id, cursor)
.await;
}
}
pub async fn move_down<S: MsgStore<M>>(
&mut self,
room: &str,
store: &S,
cursor: &mut Option<Cursor<M::Id>>,
frame: &mut Frame,
size: Size,
) {
let old_blocks = self
.layout_blocks(room, store, cursor.as_ref(), frame, size)
.layout_blocks(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 path = store.path(room, &cursor.id).await;
let mut tree = store.tree(room, path.first()).await;
self.find_next_msg(room, store, &mut tree, &mut cursor.id)
.await;
let path = store.path(&cursor.id).await;
let mut tree = store.tree(path.first()).await;
self.find_next_msg(store, &mut tree, &mut cursor.id).await;
}
// If that condition doesn't hold, we're already at the bottom in
// cursor-less mode and can't move further down anyways.
if let Some(cursor) = cursor {
self.correct_cursor_offset(
room,
store,
frame,
size,
&old_blocks,
&old_cursor_id,
cursor,
)
.await;
self.correct_cursor_offset(store, frame, size, &old_blocks, &old_cursor_id, cursor)
.await;
}
}
pub async fn move_up_sibling<S: MsgStore<M>>(
&mut self,
room: &str,
store: &S,
cursor: &mut Option<Cursor<M::Id>>,
frame: &mut Frame,
size: Size,
) {
let old_blocks = self
.layout_blocks(room, store, cursor.as_ref(), frame, size)
.layout_blocks(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 path = store.path(room, &cursor.id).await;
let mut tree = store.tree(room, path.first()).await;
self.find_prev_sibling(room, store, &mut tree, &mut cursor.id)
let path = store.path(&cursor.id).await;
let mut tree = store.tree(path.first()).await;
self.find_prev_sibling(store, &mut tree, &mut cursor.id)
.await;
} else if let Some(last_tree) = store.last_tree(room).await {
} else if let Some(last_tree) = store.last_tree().await {
// I think moving to the root of the last tree makes the most sense
// here. Alternatively, we could just not move the cursor, but that
// wouldn't be very useful.
@ -321,117 +293,82 @@ impl<M: Msg> TreeView<M> {
// message to move to.
if let Some(cursor) = cursor {
self.correct_cursor_offset(
room,
store,
frame,
size,
&old_blocks,
&old_cursor_id,
cursor,
)
.await;
self.correct_cursor_offset(store, frame, size, &old_blocks, &old_cursor_id, cursor)
.await;
}
}
pub async fn move_down_sibling<S: MsgStore<M>>(
&mut self,
room: &str,
store: &S,
cursor: &mut Option<Cursor<M::Id>>,
frame: &mut Frame,
size: Size,
) {
let old_blocks = self
.layout_blocks(room, store, cursor.as_ref(), frame, size)
.layout_blocks(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 path = store.path(room, &cursor.id).await;
let mut tree = store.tree(room, path.first()).await;
self.find_next_sibling(room, store, &mut tree, &mut cursor.id)
let path = store.path(&cursor.id).await;
let mut tree = store.tree(path.first()).await;
self.find_next_sibling(store, &mut tree, &mut cursor.id)
.await;
}
// If that condition doesn't hold, we're already at the bottom in
// cursor-less mode and can't move further down anyways.
if let Some(cursor) = cursor {
self.correct_cursor_offset(
room,
store,
frame,
size,
&old_blocks,
&old_cursor_id,
cursor,
)
.await;
self.correct_cursor_offset(store, frame, size, &old_blocks, &old_cursor_id, cursor)
.await;
}
}
pub async fn move_to_first<S: MsgStore<M>>(
&mut self,
room: &str,
store: &S,
cursor: &mut Option<Cursor<M::Id>>,
frame: &mut Frame,
size: Size,
) {
let old_blocks = self
.layout_blocks(room, store, cursor.as_ref(), frame, size)
.layout_blocks(store, cursor.as_ref(), frame, size)
.await;
let old_cursor_id = cursor.as_ref().map(|c| c.id.clone());
if let Some(tree_id) = store.first_tree(room).await {
if let Some(tree_id) = store.first_tree().await {
*cursor = Some(Cursor::new(tree_id));
}
if let Some(cursor) = cursor {
self.correct_cursor_offset(
room,
store,
frame,
size,
&old_blocks,
&old_cursor_id,
cursor,
)
.await;
self.correct_cursor_offset(store, frame, size, &old_blocks, &old_cursor_id, cursor)
.await;
}
}
pub async fn move_to_last<S: MsgStore<M>>(
&mut self,
room: &str,
store: &S,
cursor: &mut Option<Cursor<M::Id>>,
frame: &mut Frame,
size: Size,
) {
let old_blocks = self
.layout_blocks(room, store, cursor.as_ref(), frame, size)
.layout_blocks(store, cursor.as_ref(), frame, size)
.await;
let old_cursor_id = cursor.as_ref().map(|c| c.id.clone());
if let Some(tree_id) = store.last_tree(room).await {
let tree = store.tree(room, &tree_id).await;
if let Some(tree_id) = store.last_tree().await {
let tree = store.tree(&tree_id).await;
let mut id = tree_id;
while Self::find_last_child(&tree, &mut id) {}
*cursor = Some(Cursor::new(id));
}
if let Some(cursor) = cursor {
self.correct_cursor_offset(
room,
store,
frame,
size,
&old_blocks,
&old_cursor_id,
cursor,
)
.await;
self.correct_cursor_offset(store, frame, size, &old_blocks, &old_cursor_id, cursor)
.await;
}
}
@ -440,7 +377,6 @@ impl<M: Msg> TreeView<M> {
pub async fn center_cursor<S: MsgStore<M>>(
&mut self,
room: &str,
store: &S,
cursor: &mut Option<Cursor<M::Id>>,
frame: &mut Frame,
@ -451,20 +387,10 @@ impl<M: Msg> TreeView<M> {
// Correcting the offset just to make sure that this function
// behaves nicely if the cursor has too many lines.
let old_blocks = self
.layout_blocks(room, store, Some(cursor), frame, size)
.await;
let old_blocks = self.layout_blocks(store, Some(cursor), frame, size).await;
let old_cursor_id = Some(cursor.id.clone());
self.correct_cursor_offset(
room,
store,
frame,
size,
&old_blocks,
&old_cursor_id,
cursor,
)
.await;
self.correct_cursor_offset(store, frame, size, &old_blocks, &old_cursor_id, cursor)
.await;
}
}
}

View file

@ -54,7 +54,6 @@ fn layout_tree<M: Msg>(frame: &mut Frame, size: Size, tree: Tree<M>) -> Blocks<M
impl<M: Msg> TreeView<M> {
pub async fn expand_blocks_up<S: MsgStore<M>>(
room: &str,
store: &S,
frame: &mut Frame,
size: Size,
@ -63,13 +62,13 @@ impl<M: Msg> TreeView<M> {
) {
while blocks.top_line > 0 {
*tree_id = if let Some(tree_id) = tree_id {
store.prev_tree(room, tree_id).await
store.prev_tree(tree_id).await
} else {
break;
};
if let Some(tree_id) = tree_id {
let tree = store.tree(room, tree_id).await;
let tree = store.tree(tree_id).await;
blocks.prepend(layout_tree(frame, size, tree));
} else {
break;
@ -78,7 +77,6 @@ impl<M: Msg> TreeView<M> {
}
pub async fn expand_blocks_down<S: MsgStore<M>>(
room: &str,
store: &S,
frame: &mut Frame,
size: Size,
@ -87,13 +85,13 @@ impl<M: Msg> TreeView<M> {
) {
while blocks.bottom_line < size.height as i32 {
*tree_id = if let Some(tree_id) = tree_id {
store.next_tree(room, tree_id).await
store.next_tree(tree_id).await
} else {
break;
};
if let Some(tree_id) = tree_id {
let tree = store.tree(room, tree_id).await;
let tree = store.tree(tree_id).await;
blocks.append(layout_tree(frame, size, tree));
} else {
break;
@ -104,7 +102,6 @@ impl<M: Msg> TreeView<M> {
// TODO Split up based on cursor presence
pub async fn layout_blocks<S: MsgStore<M>>(
&mut self,
room: &str,
store: &S,
cursor: Option<&Cursor<M::Id>>,
frame: &mut Frame,
@ -115,9 +112,9 @@ impl<M: Msg> TreeView<M> {
// TODO Unfold all messages on path to cursor
// Layout cursor subtree (with correct offsets based on cursor)
let cursor_path = store.path(room, &cursor.id).await;
let cursor_path = store.path(&cursor.id).await;
let cursor_tree_id = cursor_path.first();
let cursor_tree = store.tree(room, cursor_tree_id).await;
let cursor_tree = store.tree(cursor_tree_id).await;
let mut blocks = layout_tree(frame, size, cursor_tree);
blocks.calculate_offsets_with_cursor(cursor, size.height);
@ -136,18 +133,18 @@ impl<M: Msg> TreeView<M> {
//
// TODO Don't expand if there is a focus
let mut top_tree_id = Some(cursor_tree_id.clone());
Self::expand_blocks_up(room, store, frame, size, &mut blocks, &mut top_tree_id).await;
Self::expand_blocks_up(store, frame, size, &mut blocks, &mut top_tree_id).await;
if blocks.top_line > 0 {
blocks.offset(-blocks.top_line);
}
let mut bot_tree_id = Some(cursor_tree_id.clone());
Self::expand_blocks_down(room, store, frame, size, &mut blocks, &mut bot_tree_id).await;
Self::expand_blocks_down(store, frame, size, &mut blocks, &mut bot_tree_id).await;
if blocks.bottom_line < size.height as i32 - 1 {
blocks.offset(size.height as i32 - 1 - blocks.bottom_line);
}
// If we only moved the blocks down, we need to expand upwards again
// to make sure we fill the screen.
Self::expand_blocks_up(room, store, frame, size, &mut blocks, &mut top_tree_id).await;
Self::expand_blocks_up(store, frame, size, &mut blocks, &mut top_tree_id).await;
blocks
} else {
@ -157,12 +154,12 @@ impl<M: Msg> TreeView<M> {
let mut blocks = Blocks::new_below(size.height as i32 - 1);
// Expand upwards from last tree
if let Some(last_tree_id) = store.last_tree(room).await {
let last_tree = store.tree(room, &last_tree_id).await;
if let Some(last_tree_id) = store.last_tree().await {
let last_tree = store.tree(&last_tree_id).await;
blocks.prepend(layout_tree(frame, size, last_tree));
let mut tree_id = Some(last_tree_id);
Self::expand_blocks_up(room, store, frame, size, &mut blocks, &mut tree_id).await;
Self::expand_blocks_up(store, frame, size, &mut blocks, &mut tree_id).await;
}
blocks

View file

@ -103,10 +103,10 @@ impl<M: Msg> Tree<M> {
#[async_trait]
pub trait MsgStore<M: Msg> {
async fn path(&self, room: &str, id: &M::Id) -> Path<M::Id>;
async fn tree(&self, room: &str, root: &M::Id) -> Tree<M>;
async fn prev_tree(&self, room: &str, tree: &M::Id) -> Option<M::Id>;
async fn next_tree(&self, room: &str, tree: &M::Id) -> Option<M::Id>;
async fn first_tree(&self, room: &str) -> Option<M::Id>;
async fn last_tree(&self, room: &str) -> Option<M::Id>;
async fn path(&self, id: &M::Id) -> Path<M::Id>;
async fn tree(&self, root: &M::Id) -> Tree<M>;
async fn prev_tree(&self, tree: &M::Id) -> Option<M::Id>;
async fn next_tree(&self, tree: &M::Id) -> Option<M::Id>;
async fn first_tree(&self) -> Option<M::Id>;
async fn last_tree(&self) -> Option<M::Id>;
}

View file

@ -111,7 +111,7 @@ impl DummyStore {
#[async_trait]
impl MsgStore<DummyMsg> for DummyStore {
async fn path(&self, _room: &str, id: &usize) -> Path<usize> {
async fn path(&self, id: &usize) -> Path<usize> {
let mut id = *id;
let mut segments = vec![id];
while let Some(parent) = self.msgs.get(&id).and_then(|msg| msg.parent) {
@ -122,13 +122,13 @@ impl MsgStore<DummyMsg> for DummyStore {
Path::new(segments)
}
async fn tree(&self, _room: &str, root: &usize) -> Tree<DummyMsg> {
async fn tree(&self, root: &usize) -> Tree<DummyMsg> {
let mut msgs = vec![];
self.collect_tree(*root, &mut msgs);
Tree::new(*root, msgs)
}
async fn prev_tree(&self, _room: &str, tree: &usize) -> Option<usize> {
async fn prev_tree(&self, tree: &usize) -> Option<usize> {
let trees = self.trees();
trees
.iter()
@ -137,7 +137,7 @@ impl MsgStore<DummyMsg> for DummyStore {
.map(|(t, _)| *t)
}
async fn next_tree(&self, _room: &str, tree: &usize) -> Option<usize> {
async fn next_tree(&self, tree: &usize) -> Option<usize> {
let trees = self.trees();
trees
.iter()
@ -146,11 +146,11 @@ impl MsgStore<DummyMsg> for DummyStore {
.map(|(_, t)| *t)
}
async fn first_tree(&self, _room: &str) -> Option<usize> {
async fn first_tree(&self) -> Option<usize> {
self.trees().first().cloned()
}
async fn last_tree(&self, _room: &str) -> Option<usize> {
async fn last_tree(&self) -> Option<usize> {
self.trees().last().cloned()
}
}

View file

@ -55,7 +55,7 @@ impl Ui {
.msg(DummyMsg::new(10, "abc123", "reply to reply to nothing").parent(8))
.msg(DummyMsg::new(11, "nick", "yet another reply to nothing").parent(7))
.msg(DummyMsg::new(12, "abc123", "beep\nboop").parent(11));
let chat = Chat::new(store, "testroom".to_string());
let chat = Chat::new(store);
// Run main UI.
//