Show available key bindings with F1/?
This commit is contained in:
parent
a51bb60342
commit
6c1ce49236
6 changed files with 355 additions and 87 deletions
|
|
@ -13,7 +13,7 @@ use toss::frame::{Frame, Pos, Size};
|
|||
use toss::terminal::Terminal;
|
||||
|
||||
use crate::store::{Msg, MsgStore};
|
||||
use crate::ui::input::{key, KeyEvent};
|
||||
use crate::ui::input::{key, KeyBindingsList, KeyEvent};
|
||||
use crate::ui::widgets::editor::EditorState;
|
||||
use crate::ui::widgets::Widget;
|
||||
|
||||
|
|
@ -59,6 +59,107 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn list_movement_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
||||
bindings.binding("j/k, ↓/↑", "move cursor up/down");
|
||||
bindings.binding("h/l, ←/→", "move cursor chronologically");
|
||||
bindings.binding("g, home", "move cursor to top");
|
||||
bindings.binding("G, end", "move cursor to bottom");
|
||||
bindings.binding("ctrl+y/e", "scroll up/down a line");
|
||||
bindings.binding("ctrl+u/d", "scroll up/down half a screen");
|
||||
bindings.binding("ctrl+b/f", "scroll up/down one screen");
|
||||
}
|
||||
|
||||
async fn handle_movement_key_event(&mut self, frame: &mut Frame, event: KeyEvent) -> bool {
|
||||
let chat_height = frame.size().height - 3;
|
||||
|
||||
match event {
|
||||
key!('k') | key!(Up) => self.move_cursor_up().await,
|
||||
key!('j') | key!(Down) => self.move_cursor_down().await,
|
||||
key!('h') | key!(Left) => self.move_cursor_older().await,
|
||||
key!('l') | key!(Right) => self.move_cursor_newer().await,
|
||||
key!('g') | key!(Home) => self.move_cursor_to_top().await,
|
||||
key!('G') | key!(End) => self.move_cursor_to_bottom().await,
|
||||
key!(Ctrl + 'y') => self.scroll_up(1),
|
||||
key!(Ctrl + 'e') => self.scroll_down(1),
|
||||
key!(Ctrl + 'u') => self.scroll_up((chat_height / 2).into()),
|
||||
key!(Ctrl + 'd') => self.scroll_down((chat_height / 2).into()),
|
||||
key!(Ctrl + 'b') => self.scroll_up(chat_height.saturating_sub(1).into()),
|
||||
key!(Ctrl + 'f') => self.scroll_down(chat_height.saturating_sub(1).into()),
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn list_edit_initiating_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
||||
bindings.empty();
|
||||
bindings.binding("r", "reply to message");
|
||||
bindings.binding_ctd("(inline if possible, otherwise directly)");
|
||||
bindings.binding("R", "reply to message (opposite of R)");
|
||||
bindings.binding("t", "start a new thread");
|
||||
}
|
||||
|
||||
async fn handle_edit_initiating_key_event(
|
||||
&mut self,
|
||||
event: KeyEvent,
|
||||
id: Option<M::Id>,
|
||||
) -> bool {
|
||||
match event {
|
||||
key!('r') => {
|
||||
if let Some(parent) = self.parent_for_normal_reply().await {
|
||||
self.cursor = Cursor::editor(id, parent);
|
||||
self.correction = Some(Correction::MakeCursorVisible);
|
||||
}
|
||||
}
|
||||
key!('R') => {
|
||||
if let Some(parent) = self.parent_for_alternate_reply().await {
|
||||
self.cursor = Cursor::editor(id, parent);
|
||||
self.correction = Some(Correction::MakeCursorVisible);
|
||||
}
|
||||
}
|
||||
key!('t') | key!('T') => {
|
||||
self.cursor = Cursor::editor(id, None);
|
||||
self.correction = Some(Correction::MakeCursorVisible);
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn list_normal_key_bindings(&self, bindings: &mut KeyBindingsList, can_compose: bool) {
|
||||
self.list_movement_key_bindings(bindings);
|
||||
if can_compose {
|
||||
self.list_edit_initiating_key_bindings(bindings);
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_normal_key_event(
|
||||
&mut self,
|
||||
frame: &mut Frame,
|
||||
event: KeyEvent,
|
||||
can_compose: bool,
|
||||
id: Option<M::Id>,
|
||||
) -> bool {
|
||||
if self.handle_movement_key_event(frame, event).await {
|
||||
true
|
||||
} else if can_compose {
|
||||
self.handle_edit_initiating_key_event(event, id).await
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_editor_key_bindings(&self, bindings: &mut KeyBindingsList) {
|
||||
bindings.binding("esc", "close editor");
|
||||
bindings.binding("enter", "send message");
|
||||
bindings.binding("←/→", "move cursor left/right");
|
||||
bindings.binding("backspace", "delete before cursor");
|
||||
bindings.binding("delete", "delete after cursor");
|
||||
bindings.binding("ctrl+e", "edit in $EDITOR");
|
||||
bindings.binding("ctrl+l", "clear editor contents");
|
||||
}
|
||||
|
||||
fn handle_editor_key_event(
|
||||
&mut self,
|
||||
terminal: &mut Terminal,
|
||||
|
|
@ -93,9 +194,9 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
} => self.editor.insert_char('\n'),
|
||||
|
||||
key!(Char ch) => self.editor.insert_char(ch),
|
||||
key!(Backspace) => self.editor.backspace(),
|
||||
key!(Left) => self.editor.move_cursor_left(),
|
||||
key!(Right) => self.editor.move_cursor_right(),
|
||||
key!(Backspace) => self.editor.backspace(),
|
||||
key!(Delete) => self.editor.delete(),
|
||||
key!(Ctrl + 'e') => self.editor.edit_externally(terminal, crossterm_lock),
|
||||
key!(Ctrl + 'l') => self.editor.clear(),
|
||||
|
|
@ -106,69 +207,16 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
|||
Reaction::Handled
|
||||
}
|
||||
|
||||
async fn handle_movement_key_event(&mut self, frame: &mut Frame, event: KeyEvent) -> bool {
|
||||
let chat_height = frame.size().height - 3;
|
||||
|
||||
match event {
|
||||
key!('k') | key!(Up) => self.move_cursor_up().await,
|
||||
key!('j') | key!(Down) => self.move_cursor_down().await,
|
||||
key!('h') | key!(Left) => self.move_cursor_older().await,
|
||||
key!('l') | key!(Right) => self.move_cursor_newer().await,
|
||||
key!('g') | key!(Home) => self.move_cursor_to_top().await,
|
||||
key!('G') | key!(End) => self.move_cursor_to_bottom().await,
|
||||
key!(Ctrl + 'y') => self.scroll_up(1),
|
||||
key!(Ctrl + 'e') => self.scroll_down(1),
|
||||
key!(Ctrl + 'u') => self.scroll_up((chat_height / 2).into()),
|
||||
key!(Ctrl + 'd') => self.scroll_down((chat_height / 2).into()),
|
||||
key!(Ctrl + 'b') => self.scroll_up(chat_height.saturating_sub(1).into()),
|
||||
key!(Ctrl + 'f') => self.scroll_down(chat_height.saturating_sub(1).into()),
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
async fn handle_edit_initiating_key_event(
|
||||
&mut self,
|
||||
event: KeyEvent,
|
||||
id: Option<M::Id>,
|
||||
) -> bool {
|
||||
match event {
|
||||
key!('r') => {
|
||||
if let Some(parent) = self.parent_for_normal_reply().await {
|
||||
self.cursor = Cursor::editor(id, parent);
|
||||
self.correction = Some(Correction::MakeCursorVisible);
|
||||
}
|
||||
pub fn list_key_bindings(&self, bindings: &mut KeyBindingsList, can_compose: bool) {
|
||||
bindings.heading("Chat");
|
||||
match &self.cursor {
|
||||
Cursor::Bottom | Cursor::Msg(_) => {
|
||||
self.list_normal_key_bindings(bindings, can_compose);
|
||||
}
|
||||
key!('R') => {
|
||||
if let Some(parent) = self.parent_for_alternate_reply().await {
|
||||
self.cursor = Cursor::editor(id, parent);
|
||||
self.correction = Some(Correction::MakeCursorVisible);
|
||||
}
|
||||
Cursor::Editor { .. } => self.list_editor_key_bindings(bindings),
|
||||
Cursor::Pseudo { .. } => {
|
||||
self.list_movement_key_bindings(bindings);
|
||||
}
|
||||
key!('t') | key!('T') => {
|
||||
self.cursor = Cursor::editor(id, None);
|
||||
self.correction = Some(Correction::MakeCursorVisible);
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
async fn handle_normal_key_event(
|
||||
&mut self,
|
||||
frame: &mut Frame,
|
||||
event: KeyEvent,
|
||||
can_compose: bool,
|
||||
id: Option<M::Id>,
|
||||
) -> bool {
|
||||
if self.handle_movement_key_event(frame, event).await {
|
||||
true
|
||||
} else if can_compose {
|
||||
self.handle_edit_initiating_key_event(event, id).await
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,6 +302,10 @@ impl<M: Msg, S: MsgStore<M>> TreeViewState<M, S> {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn list_key_bindings(&self, bindings: &mut KeyBindingsList, can_compose: bool) {
|
||||
self.0.lock().await.list_key_bindings(bindings, can_compose);
|
||||
}
|
||||
|
||||
pub async fn handle_key_event(
|
||||
&mut self,
|
||||
terminal: &mut Terminal,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue