Port message sending
This commit is contained in:
parent
98f51a5a2e
commit
066ea0cb07
4 changed files with 122 additions and 92 deletions
|
|
@ -1,8 +1,12 @@
|
||||||
mod tree;
|
mod tree;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::KeyEvent;
|
||||||
|
use parking_lot::FairMutex;
|
||||||
use toss::frame::{Frame, Size};
|
use toss::frame::{Frame, Size};
|
||||||
|
use toss::terminal::Terminal;
|
||||||
|
|
||||||
use crate::store::{Msg, MsgStore};
|
use crate::store::{Msg, MsgStore};
|
||||||
|
|
||||||
|
|
@ -55,26 +59,20 @@ impl<M: Msg, S: MsgStore<M>> ChatState<M, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub async fn handle_messaging(
|
pub async fn handle_messaging(
|
||||||
// &mut self,
|
&mut self,
|
||||||
// terminal: &mut Terminal,
|
terminal: &mut Terminal,
|
||||||
// crossterm_lock: &Arc<FairMutex<()>>,
|
crossterm_lock: &Arc<FairMutex<()>>,
|
||||||
// event: KeyEvent,
|
event: KeyEvent,
|
||||||
// ) -> Option<(Option<M::Id>, String)> {
|
) -> Option<(Option<M::Id>, String)> {
|
||||||
// match self.mode {
|
match self.mode {
|
||||||
// Mode::Tree => {
|
Mode::Tree => {
|
||||||
// self.tree
|
self.tree
|
||||||
// .handle_messaging(
|
.handle_messaging(terminal, crossterm_lock, event)
|
||||||
// &mut self.store,
|
.await
|
||||||
// &mut self.cursor,
|
}
|
||||||
// terminal,
|
}
|
||||||
// crossterm_lock,
|
}
|
||||||
// event,
|
|
||||||
// )
|
|
||||||
// .await
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////
|
////////////
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// mod action;
|
mod action;
|
||||||
mod blocks;
|
mod blocks;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod layout;
|
mod layout;
|
||||||
|
|
@ -9,8 +9,10 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use crossterm::event::{KeyCode, KeyEvent};
|
use crossterm::event::{KeyCode, KeyEvent};
|
||||||
|
use parking_lot::FairMutex;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use toss::frame::{Frame, Size};
|
use toss::frame::{Frame, Size};
|
||||||
|
use toss::terminal::Terminal;
|
||||||
|
|
||||||
use crate::store::{Msg, MsgStore};
|
use crate::store::{Msg, MsgStore};
|
||||||
use crate::ui::widgets::Widget;
|
use crate::ui::widgets::Widget;
|
||||||
|
|
@ -55,6 +57,22 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_messaging(
|
||||||
|
&self,
|
||||||
|
terminal: &mut Terminal,
|
||||||
|
crossterm_lock: &Arc<FairMutex<()>>,
|
||||||
|
event: KeyEvent,
|
||||||
|
) -> Option<(Option<M::Id>, String)> {
|
||||||
|
match event.code {
|
||||||
|
KeyCode::Char('r') => self.reply_normal(terminal, crossterm_lock).await,
|
||||||
|
KeyCode::Char('R') => self.reply_alternate(terminal, crossterm_lock).await,
|
||||||
|
KeyCode::Char('t') | KeyCode::Char('T') => {
|
||||||
|
Self::create_new_thread(terminal, crossterm_lock)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TreeViewState<M: Msg, S: MsgStore<M>>(Arc<Mutex<InnerTreeViewState<M, S>>>);
|
pub struct TreeViewState<M: Msg, S: MsgStore<M>>(Arc<Mutex<InnerTreeViewState<M, S>>>);
|
||||||
|
|
@ -71,6 +89,19 @@ impl<M: Msg, S: MsgStore<M>> TreeViewState<M, S> {
|
||||||
pub async fn handle_navigation(&mut self, event: KeyEvent) {
|
pub async fn handle_navigation(&mut self, event: KeyEvent) {
|
||||||
self.0.lock().await.handle_navigation(event).await;
|
self.0.lock().await.handle_navigation(event).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn handle_messaging(
|
||||||
|
&self,
|
||||||
|
terminal: &mut Terminal,
|
||||||
|
crossterm_lock: &Arc<FairMutex<()>>,
|
||||||
|
event: KeyEvent,
|
||||||
|
) -> Option<(Option<M::Id>, String)> {
|
||||||
|
self.0
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.handle_messaging(terminal, crossterm_lock, event)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////
|
////////////
|
||||||
|
|
|
||||||
|
|
@ -4,42 +4,33 @@ use parking_lot::FairMutex;
|
||||||
use toss::terminal::Terminal;
|
use toss::terminal::Terminal;
|
||||||
|
|
||||||
use crate::store::{Msg, MsgStore};
|
use crate::store::{Msg, MsgStore};
|
||||||
|
use crate::ui::util;
|
||||||
|
|
||||||
use super::{Cursor, TreeView};
|
use super::{Cursor, InnerTreeViewState};
|
||||||
|
|
||||||
impl<M: Msg> TreeView<M> {
|
impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
fn prompt_msg(crossterm_lock: &Arc<FairMutex<()>>, terminal: &mut Terminal) -> Option<String> {
|
pub async fn reply_normal(
|
||||||
let content = {
|
&self,
|
||||||
let _guard = crossterm_lock.lock();
|
|
||||||
terminal.suspend().expect("could not suspend");
|
|
||||||
let content = edit::edit("").expect("could not edit");
|
|
||||||
terminal.unsuspend().expect("could not unsuspend");
|
|
||||||
content
|
|
||||||
};
|
|
||||||
|
|
||||||
if content.trim().is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn reply_normal<S: MsgStore<M>>(
|
|
||||||
store: &S,
|
|
||||||
cursor: &Option<Cursor<M::Id>>,
|
|
||||||
terminal: &mut Terminal,
|
terminal: &mut Terminal,
|
||||||
crossterm_lock: &Arc<FairMutex<()>>,
|
crossterm_lock: &Arc<FairMutex<()>>,
|
||||||
) -> Option<(Option<M::Id>, String)> {
|
) -> Option<(Option<M::Id>, String)> {
|
||||||
if let Some(cursor) = cursor {
|
match &self.cursor {
|
||||||
let tree = store.tree(store.path(&cursor.id).await.first()).await;
|
Cursor::Bottom => {
|
||||||
let parent_id = if tree.next_sibling(&cursor.id).is_some() {
|
if let Some(content) = util::prompt(terminal, crossterm_lock) {
|
||||||
|
return Some((None, content));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Cursor::Msg(msg) => {
|
||||||
|
let path = self.store.path(msg).await;
|
||||||
|
let tree = self.store.tree(path.first()).await;
|
||||||
|
let parent_id = if tree.next_sibling(msg).is_some() {
|
||||||
// A reply to a message that has further siblings should be a
|
// A reply to a message that has further siblings should be a
|
||||||
// direct reply. An indirect reply might end up a lot further
|
// direct reply. An indirect reply might end up a lot further
|
||||||
// down in the current conversation.
|
// down in the current conversation.
|
||||||
cursor.id.clone()
|
msg.clone()
|
||||||
} else if let Some(parent) = tree.parent(&cursor.id) {
|
} else if let Some(parent) = tree.parent(msg) {
|
||||||
// A reply to a message without further siblings should be an
|
// A reply to a message without younger siblings should be
|
||||||
// indirect reply so as not to create unnecessarily deep
|
// an indirect reply so as not to create unnecessarily deep
|
||||||
// threads. In the case that our message has children, this
|
// threads. In the case that our message has children, this
|
||||||
// might get a bit confusing. I'm not sure yet how well this
|
// might get a bit confusing. I'm not sure yet how well this
|
||||||
// "smart" reply actually works in practice.
|
// "smart" reply actually works in practice.
|
||||||
|
|
@ -47,50 +38,60 @@ impl<M: Msg> TreeView<M> {
|
||||||
} else {
|
} else {
|
||||||
// When replying to a top-level message, it makes sense to avoid
|
// When replying to a top-level message, it makes sense to avoid
|
||||||
// creating unnecessary new threads.
|
// creating unnecessary new threads.
|
||||||
cursor.id.clone()
|
msg.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(content) = Self::prompt_msg(crossterm_lock, terminal) {
|
if let Some(content) = util::prompt(terminal, crossterm_lock) {
|
||||||
return Some((Some(parent_id), content));
|
return Some((Some(parent_id), content));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
None
|
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(
|
||||||
store: &S,
|
&self,
|
||||||
cursor: &Option<Cursor<M::Id>>,
|
|
||||||
terminal: &mut Terminal,
|
terminal: &mut Terminal,
|
||||||
crossterm_lock: &Arc<FairMutex<()>>,
|
crossterm_lock: &Arc<FairMutex<()>>,
|
||||||
) -> Option<(Option<M::Id>, String)> {
|
) -> Option<(Option<M::Id>, String)> {
|
||||||
if let Some(cursor) = cursor {
|
match &self.cursor {
|
||||||
let tree = store.tree(store.path(&cursor.id).await.first()).await;
|
Cursor::Bottom => {
|
||||||
let parent_id = if tree.next_sibling(&cursor.id).is_none() {
|
if let Some(content) = util::prompt(terminal, crossterm_lock) {
|
||||||
|
return Some((None, content));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Cursor::Msg(msg) => {
|
||||||
|
let path = self.store.path(msg).await;
|
||||||
|
let tree = self.store.tree(path.first()).await;
|
||||||
|
let parent_id = if tree.next_sibling(msg).is_none() {
|
||||||
// The opposite of replying normally
|
// The opposite of replying normally
|
||||||
cursor.id.clone()
|
msg.clone()
|
||||||
} else if let Some(parent) = tree.parent(&cursor.id) {
|
} else if let Some(parent) = tree.parent(msg) {
|
||||||
// The opposite of replying normally
|
// The opposite of replying normally
|
||||||
parent
|
parent
|
||||||
} else {
|
} else {
|
||||||
// The same as replying normally, still to avoid creating
|
// The same as replying normally, still to avoid creating
|
||||||
// unnecessary new threads
|
// unnecessary new threads
|
||||||
cursor.id.clone()
|
msg.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(content) = Self::prompt_msg(crossterm_lock, terminal) {
|
if let Some(content) = util::prompt(terminal, crossterm_lock) {
|
||||||
return Some((Some(parent_id), content));
|
return Some((Some(parent_id), content));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_new_thread(
|
pub fn create_new_thread(
|
||||||
terminal: &mut Terminal,
|
terminal: &mut Terminal,
|
||||||
crossterm_lock: &Arc<FairMutex<()>>,
|
crossterm_lock: &Arc<FairMutex<()>>,
|
||||||
) -> Option<(Option<M::Id>, String)> {
|
) -> Option<(Option<M::Id>, String)> {
|
||||||
Self::prompt_msg(crossterm_lock, terminal).map(|c| (None, c))
|
util::prompt(terminal, crossterm_lock).map(|content| (None, content))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -304,13 +304,13 @@ impl EuphRoom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if let Some((parent, content)) = self
|
let potential_message = self
|
||||||
// .chat
|
.chat
|
||||||
// .handle_messaging(terminal, crossterm_lock, event)
|
.handle_messaging(terminal, crossterm_lock, event)
|
||||||
// .await
|
.await;
|
||||||
// {
|
if let Some((parent, content)) = potential_message {
|
||||||
// let _ = room.send(parent, content);
|
let _ = room.send(parent, content);
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue