Separate navigation and messaging

This commit is contained in:
Joscha 2022-06-18 17:22:57 +02:00
parent 416b5bf31e
commit 03dfe10f3e
4 changed files with 53 additions and 51 deletions

View file

@ -54,28 +54,36 @@ impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
} }
} }
pub enum Handled<I> {
Ok,
NewMessage { parent: Option<I>, content: String },
}
impl<M: Msg, S: MsgStore<M>> Chat<M, S> { impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
pub async fn handle_key_event( pub async fn handle_navigation(
&mut self, &mut self,
event: KeyEvent,
terminal: &mut Terminal, terminal: &mut Terminal,
size: Size, size: Size,
crossterm_lock: &Arc<FairMutex<()>>, event: KeyEvent,
) -> Handled<M::Id> { ) {
match self.mode { match self.mode {
Mode::Tree => { Mode::Tree => {
self.tree self.tree
.handle_key_event( .handle_navigation(&mut self.store, &mut self.cursor, terminal, size, event)
crossterm_lock, .await
}
}
}
pub async fn handle_messaging(
&mut self,
terminal: &mut Terminal,
crossterm_lock: &Arc<FairMutex<()>>,
event: KeyEvent,
) -> Option<(Option<M::Id>, String)> {
match self.mode {
Mode::Tree => {
self.tree
.handle_messaging(
&mut self.store, &mut self.store,
&mut self.cursor, &mut self.cursor,
terminal, terminal,
size, crossterm_lock,
event, event,
) )
.await .await

View file

@ -15,7 +15,7 @@ use toss::terminal::Terminal;
use crate::store::{Msg, MsgStore}; use crate::store::{Msg, MsgStore};
use super::{Cursor, Handled}; use super::Cursor;
pub struct TreeView<M: Msg> { pub struct TreeView<M: Msg> {
// pub focus: Option<M::Id>, // pub focus: Option<M::Id>,
@ -31,17 +31,15 @@ impl<M: Msg> TreeView<M> {
} }
} }
pub async fn handle_key_event<S: MsgStore<M>>( pub async fn handle_navigation<S: MsgStore<M>>(
&mut self, &mut self,
l: &Arc<FairMutex<()>>,
s: &mut S, s: &mut S,
c: &mut Option<Cursor<M::Id>>, c: &mut Option<Cursor<M::Id>>,
t: &mut Terminal, t: &mut Terminal,
z: Size, z: Size,
event: KeyEvent, event: KeyEvent,
) -> Handled<M::Id> { ) {
match event.code { match event.code {
// Cursor movement
KeyCode::Char('k') => self.move_up(s, c, t.frame(), z).await, KeyCode::Char('k') => self.move_up(s, c, t.frame(), z).await,
KeyCode::Char('j') => self.move_down(s, c, t.frame(), z).await, KeyCode::Char('j') => self.move_down(s, c, t.frame(), z).await,
KeyCode::Char('K') => self.move_up_sibling(s, c, t.frame(), z).await, KeyCode::Char('K') => self.move_up_sibling(s, c, t.frame(), z).await,
@ -50,14 +48,24 @@ impl<M: Msg> TreeView<M> {
KeyCode::Char('g') => self.move_to_first(s, c, t.frame(), z).await, KeyCode::Char('g') => self.move_to_first(s, c, t.frame(), z).await,
KeyCode::Char('G') => self.move_to_last(s, c, t.frame(), z).await, KeyCode::Char('G') => self.move_to_last(s, c, t.frame(), z).await,
KeyCode::Esc => *c = None, // TODO Make 'G' do the same thing? KeyCode::Esc => *c = None, // TODO Make 'G' do the same thing?
// Writing messages
KeyCode::Char('r') => return Self::reply_normal(l, s, c, t).await,
KeyCode::Char('R') => return Self::reply_alternate(l, s, c, t).await,
KeyCode::Char('t') | KeyCode::Char('T') => return Self::create_new_thread(l, t).await,
_ => {} _ => {}
} }
}
Handled::Ok pub async fn handle_messaging<S: MsgStore<M>>(
&mut self,
s: &mut S,
c: &mut Option<Cursor<M::Id>>,
t: &mut Terminal,
l: &Arc<FairMutex<()>>,
event: KeyEvent,
) -> Option<(Option<M::Id>, String)> {
match event.code {
KeyCode::Char('r') => Self::reply_normal(s, c, t, l).await,
KeyCode::Char('R') => Self::reply_alternate(s, c, t, l).await,
KeyCode::Char('t') | KeyCode::Char('T') => Self::create_new_thread(t, l).await,
_ => None,
}
} }
pub async fn render<S: MsgStore<M>>( pub async fn render<S: MsgStore<M>>(

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use parking_lot::FairMutex; use parking_lot::FairMutex;
use toss::terminal::Terminal; use toss::terminal::Terminal;
use crate::chat::{Cursor, Handled}; use crate::chat::Cursor;
use crate::store::{Msg, MsgStore}; use crate::store::{Msg, MsgStore};
use super::TreeView; use super::TreeView;
@ -26,11 +26,11 @@ impl<M: Msg> TreeView<M> {
} }
pub async fn reply_normal<S: MsgStore<M>>( pub async fn reply_normal<S: MsgStore<M>>(
crossterm_lock: &Arc<FairMutex<()>>,
store: &S, store: &S,
cursor: &Option<Cursor<M::Id>>, cursor: &Option<Cursor<M::Id>>,
terminal: &mut Terminal, terminal: &mut Terminal,
) -> Handled<M::Id> { crossterm_lock: &Arc<FairMutex<()>>,
) -> Option<(Option<M::Id>, String)> {
if let Some(cursor) = cursor { if let Some(cursor) = cursor {
let tree = store.tree(store.path(&cursor.id).await.first()).await; let tree = store.tree(store.path(&cursor.id).await.first()).await;
let parent_id = if tree.next_sibling(&cursor.id).is_some() { let parent_id = if tree.next_sibling(&cursor.id).is_some() {
@ -52,23 +52,20 @@ impl<M: Msg> TreeView<M> {
}; };
if let Some(content) = Self::prompt_msg(crossterm_lock, terminal) { if let Some(content) = Self::prompt_msg(crossterm_lock, terminal) {
return Handled::NewMessage { return Some((Some(parent_id), content));
parent: Some(parent_id),
content,
};
} }
} }
Handled::Ok None
} }
/// Does approximately the opposite of [`Self::reply_normal`]. /// Does approximately the opposite of [`Self::reply_normal`].
pub async fn reply_alternate<S: MsgStore<M>>( pub async fn reply_alternate<S: MsgStore<M>>(
crossterm_lock: &Arc<FairMutex<()>>,
store: &S, store: &S,
cursor: &Option<Cursor<M::Id>>, cursor: &Option<Cursor<M::Id>>,
terminal: &mut Terminal, terminal: &mut Terminal,
) -> Handled<M::Id> { crossterm_lock: &Arc<FairMutex<()>>,
) -> Option<(Option<M::Id>, String)> {
if let Some(cursor) = cursor { if let Some(cursor) = cursor {
let tree = store.tree(store.path(&cursor.id).await.first()).await; let tree = store.tree(store.path(&cursor.id).await.first()).await;
let parent_id = if tree.next_sibling(&cursor.id).is_none() { let parent_id = if tree.next_sibling(&cursor.id).is_none() {
@ -84,27 +81,17 @@ impl<M: Msg> TreeView<M> {
}; };
if let Some(content) = Self::prompt_msg(crossterm_lock, terminal) { if let Some(content) = Self::prompt_msg(crossterm_lock, terminal) {
return Handled::NewMessage { return Some((Some(parent_id), content));
parent: Some(parent_id),
content,
};
} }
} }
Handled::Ok None
} }
pub async fn create_new_thread( pub async fn create_new_thread(
crossterm_lock: &Arc<FairMutex<()>>,
terminal: &mut Terminal, terminal: &mut Terminal,
) -> Handled<M::Id> { crossterm_lock: &Arc<FairMutex<()>>,
if let Some(content) = Self::prompt_msg(crossterm_lock, terminal) { ) -> Option<(Option<M::Id>, String)> {
Handled::NewMessage { Self::prompt_msg(crossterm_lock, terminal).map(|c| (None, c))
parent: None,
content,
}
} else {
Handled::Ok
}
} }
} }

View file

@ -192,14 +192,13 @@ impl Ui {
match self.visible { match self.visible {
Visible::Main => { Visible::Main => {
self.chat.handle_navigation(terminal, size, event).await;
self.chat self.chat
.handle_key_event(event, terminal, size, crossterm_lock) .handle_messaging(terminal, crossterm_lock, event)
.await; .await;
} }
Visible::Log => { Visible::Log => {
self.log_chat self.log_chat.handle_navigation(terminal, size, event).await;
.handle_key_event(event, terminal, size, crossterm_lock)
.await;
} }
} }