Move cursor upwards
This commit is contained in:
parent
f36f205a40
commit
bb6169e315
4 changed files with 119 additions and 18 deletions
|
|
@ -43,16 +43,20 @@ impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
|
impl<M: Msg, S: MsgStore<M>> Chat<M, S> {
|
||||||
pub fn handle_key_event(&mut self, event: KeyEvent, frame: &mut Frame, size: Size) {
|
pub async fn handle_key_event(&mut self, event: KeyEvent, frame: &mut Frame, size: Size) {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::Tree => self.tree.handle_key_event(
|
Mode::Tree => {
|
||||||
|
self.tree
|
||||||
|
.handle_key_event(
|
||||||
&mut self.store,
|
&mut self.store,
|
||||||
&self.room,
|
&self.room,
|
||||||
&mut self.cursor,
|
&mut self.cursor,
|
||||||
event,
|
event,
|
||||||
frame,
|
frame,
|
||||||
size,
|
size,
|
||||||
),
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use std::collections::VecDeque;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::{KeyCode, KeyEvent};
|
||||||
use crossterm::style::ContentStyle;
|
use crossterm::style::{ContentStyle, Stylize};
|
||||||
use toss::frame::{Frame, Pos, Size};
|
use toss::frame::{Frame, Pos, Size};
|
||||||
|
|
||||||
use crate::store::{Msg, MsgStore, Tree};
|
use crate::store::{Msg, MsgStore, Tree};
|
||||||
|
|
@ -317,11 +317,16 @@ impl<M: Msg> TreeView<M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_indentation(&mut self, frame: &mut Frame, pos: Pos, indent: usize) {
|
fn render_indentation(&mut self, frame: &mut Frame, pos: Pos, indent: usize, cursor: bool) {
|
||||||
for i in 0..indent {
|
for i in 0..indent {
|
||||||
let x = TIME_WIDTH + 1 + INDENT_WIDTH * i;
|
let x = TIME_WIDTH + 1 + INDENT_WIDTH * i;
|
||||||
let pos = Pos::new(pos.x + x as i32, pos.y);
|
let pos = Pos::new(pos.x + x as i32, pos.y);
|
||||||
frame.write(pos, INDENT, ContentStyle::default());
|
let style = if cursor {
|
||||||
|
ContentStyle::default().black().on_white()
|
||||||
|
} else {
|
||||||
|
ContentStyle::default()
|
||||||
|
};
|
||||||
|
frame.write(pos, INDENT, style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -336,7 +341,12 @@ impl<M: Msg> TreeView<M> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.render_indentation(frame, Pos::new(pos.x, y), block.indent);
|
self.render_indentation(
|
||||||
|
frame,
|
||||||
|
Pos::new(pos.x, y),
|
||||||
|
block.indent,
|
||||||
|
block.cursor,
|
||||||
|
);
|
||||||
let after_indent =
|
let after_indent =
|
||||||
pos.x + (TIME_WIDTH + 1 + INDENT_WIDTH * block.indent) as i32;
|
pos.x + (TIME_WIDTH + 1 + INDENT_WIDTH * block.indent) as i32;
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
|
|
@ -350,7 +360,7 @@ impl<M: Msg> TreeView<M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BlockContent::Placeholder => {
|
BlockContent::Placeholder => {
|
||||||
self.render_indentation(frame, pos, block.indent);
|
self.render_indentation(frame, pos, block.indent, block.cursor);
|
||||||
let x = pos.x + (TIME_WIDTH + 1 + INDENT_WIDTH * block.indent) as i32;
|
let x = pos.x + (TIME_WIDTH + 1 + INDENT_WIDTH * block.indent) as i32;
|
||||||
let y = pos.y + block.line;
|
let y = pos.y + block.line;
|
||||||
frame.write(Pos::new(x, y), "[...]", ContentStyle::default());
|
frame.write(Pos::new(x, y), "[...]", ContentStyle::default());
|
||||||
|
|
@ -359,7 +369,43 @@ impl<M: Msg> TreeView<M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_key_event<S: MsgStore<M>>(
|
async fn move_to_prev_msg<S: MsgStore<M>>(
|
||||||
|
&mut self,
|
||||||
|
store: &mut S,
|
||||||
|
room: &str,
|
||||||
|
cursor: &mut Option<Cursor<M::Id>>,
|
||||||
|
) {
|
||||||
|
let tree = if let Some(cursor) = cursor {
|
||||||
|
let path = store.path(room, &cursor.id).await;
|
||||||
|
let tree = store.tree(room, path.first()).await;
|
||||||
|
if let Some(prev_sibling) = tree.prev_sibling(&cursor.id) {
|
||||||
|
cursor.id = prev_sibling.clone();
|
||||||
|
return;
|
||||||
|
} else if let Some(parent) = tree.parent(&cursor.id) {
|
||||||
|
cursor.id = parent;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
store.prev_tree(room, path.first()).await
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
store.last_tree(room).await
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(tree) = tree {
|
||||||
|
let tree = store.tree(room, &tree).await;
|
||||||
|
let cursor_id = tree.last_child(tree.root().clone());
|
||||||
|
if let Some(cursor) = cursor {
|
||||||
|
cursor.id = cursor_id;
|
||||||
|
} else {
|
||||||
|
*cursor = Some(Cursor {
|
||||||
|
id: cursor_id,
|
||||||
|
proportion: 1.0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_key_event<S: MsgStore<M>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
store: &mut S,
|
store: &mut S,
|
||||||
room: &str,
|
room: &str,
|
||||||
|
|
@ -368,7 +414,10 @@ impl<M: Msg> TreeView<M> {
|
||||||
frame: &mut Frame,
|
frame: &mut Frame,
|
||||||
size: Size,
|
size: Size,
|
||||||
) {
|
) {
|
||||||
// TODO
|
match event.code {
|
||||||
|
KeyCode::Char('k') => self.move_to_prev_msg(store, room, cursor).await,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn render<S: MsgStore<M>>(
|
pub async fn render<S: MsgStore<M>>(
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ impl<M: Msg> Tree<M> {
|
||||||
|
|
||||||
let mut children: HashMap<M::Id, Vec<M::Id>> = HashMap::new();
|
let mut children: HashMap<M::Id, Vec<M::Id>> = HashMap::new();
|
||||||
for msg in msgs.values() {
|
for msg in msgs.values() {
|
||||||
|
children.entry(msg.id()).or_default();
|
||||||
if let Some(parent) = msg.parent() {
|
if let Some(parent) = msg.parent() {
|
||||||
children.entry(parent).or_default().push(msg.id());
|
children.entry(parent).or_default().push(msg.id());
|
||||||
}
|
}
|
||||||
|
|
@ -77,9 +78,56 @@ impl<M: Msg> Tree<M> {
|
||||||
self.msgs.get(id)
|
self.msgs.get(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parent(&self, id: &M::Id) -> Option<M::Id> {
|
||||||
|
self.msg(id).and_then(|m| m.parent())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn children(&self, id: &M::Id) -> Option<&[M::Id]> {
|
pub fn children(&self, id: &M::Id) -> Option<&[M::Id]> {
|
||||||
self.children.get(id).map(|c| c as &[M::Id])
|
self.children.get(id).map(|c| c as &[M::Id])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn siblings(&self, id: &M::Id) -> Option<&[M::Id]> {
|
||||||
|
if let Some(parent) = self.parent(id) {
|
||||||
|
self.children(&parent)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prev_sibling(&self, id: &M::Id) -> Option<&M::Id> {
|
||||||
|
if let Some(siblings) = self.siblings(id) {
|
||||||
|
siblings
|
||||||
|
.iter()
|
||||||
|
.zip(siblings.iter().skip(1))
|
||||||
|
.find(|(_, s)| *s == id)
|
||||||
|
.map(|(s, _)| s)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_sibling(&self, id: &M::Id) -> Option<&M::Id> {
|
||||||
|
if let Some(siblings) = self.siblings(id) {
|
||||||
|
siblings
|
||||||
|
.iter()
|
||||||
|
.zip(siblings.iter().skip(1))
|
||||||
|
.find(|(s, _)| *s == id)
|
||||||
|
.map(|(_, s)| s)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn last_child(&self, mut id: M::Id) -> M::Id {
|
||||||
|
while let Some(children) = self.children(&id) {
|
||||||
|
if let Some(last_child) = children.last() {
|
||||||
|
id = last_child.clone();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ impl Ui {
|
||||||
if let KeyCode::Char('Q') = event.code {
|
if let KeyCode::Char('Q') = event.code {
|
||||||
return EventHandleResult::Stop;
|
return EventHandleResult::Stop;
|
||||||
}
|
}
|
||||||
self.chat.handle_key_event(event, frame, size);
|
self.chat.handle_key_event(event, frame, size).await;
|
||||||
EventHandleResult::Continue
|
EventHandleResult::Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue