diff --git a/src/app.rs b/src/app.rs index 2bfd543..d13d9a3 100644 --- a/src/app.rs +++ b/src/app.rs @@ -889,10 +889,12 @@ impl App { fn handle_key(mut self, key: Key) -> Result { let kb = self.mode.key_bindings.clone(); + let key_str = key.to_string(); let default = kb.default.clone(); let msgs = kb .on_key - .get(&key.to_string()) + .get(&key_str) + .or_else(|| kb.remaps.get(&key_str).and_then(|k| kb.on_key.get(k))) .map(|a| Some(a.messages.clone())) .unwrap_or_else(|| { if key.is_alphabet() { @@ -1419,14 +1421,23 @@ impl App { .map(|l| match l { HelpMenuLine::Paragraph(p) => format!("\t{}\n", p), HelpMenuLine::KeyMap(k, h) => { - format!(" {:15} | {}\n", k, h) + let remaps = self + .mode() + .key_bindings + .remaps + .iter() + .filter(|(_, t)| t == &k) + .map(|(f, _)| f.clone()) + .collect::>() + .join(", "); + format!(" {:15} | {:25} | {}\n", k, remaps, h) } }) .collect::>() .join(""); format!( - "### {}\n\n key | action\n --------------- | ------\n{}\n", + "### {}\n\n key | remaps | action\n --------------- | ------------------------- |------\n{}\n", name, help ) }) diff --git a/src/config.rs b/src/config.rs index 2be6ad2..f0d4747 100644 --- a/src/config.rs +++ b/src/config.rs @@ -160,6 +160,14 @@ pub struct UiElement { pub style: Style, } +impl UiElement { + fn extend(mut self, other: Self) -> Self { + self.format = other.format.or(self.format); + self.style = other.style.extend(self.style); + self + } +} + #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct TableRowConfig { @@ -250,6 +258,12 @@ pub struct GeneralConfig { #[serde(default)] pub show_hidden: Option, + #[serde(default)] + pub cursor: UiElement, + + #[serde(default)] + pub prompt: UiElement, + #[serde(default)] pub table: TableConfig, @@ -266,6 +280,8 @@ pub struct GeneralConfig { impl GeneralConfig { pub fn extend(mut self, other: Self) -> Self { self.show_hidden = other.show_hidden.or(self.show_hidden); + self.cursor = other.cursor.extend(self.cursor); + self.prompt = other.prompt.extend(self.prompt); self.table = other.table.extend(self.table); self.default_ui = other.default_ui.extend(self.default_ui); self.focus_ui = other.focus_ui.extend(self.focus_ui); @@ -277,6 +293,9 @@ impl GeneralConfig { #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct KeyBindings { + #[serde(default)] + pub remaps: BTreeMap, + #[serde(default)] pub on_key: BTreeMap, @@ -295,6 +314,8 @@ pub struct KeyBindings { impl KeyBindings { pub fn extend(mut self, mut other: Self) -> Self { + other.remaps.extend(self.remaps); + self.remaps = other.remaps; other.on_key.extend(self.on_key); self.on_key = other.on_key; self.on_alphabet = other.on_alphabet.or(self.on_alphabet); diff --git a/src/config.yml b/src/config.yml index 65a656d..a26c444 100644 --- a/src/config.yml +++ b/src/config.yml @@ -1,6 +1,10 @@ version: v0.4.0 general: show_hidden: false + prompt: + format: "> " + cursor: + format: █ table: header: cols: @@ -180,6 +184,7 @@ modes: help: null extra_help: null key_bindings: + remaps: {} on_key: c: help: copy here @@ -226,6 +231,7 @@ modes: help: null extra_help: null key_bindings: + remaps: {} on_key: enter: help: create file @@ -266,6 +272,7 @@ modes: help: null extra_help: null key_bindings: + remaps: {} on_key: enter: help: create directory @@ -306,6 +313,7 @@ modes: help: null extra_help: null key_bindings: + remaps: {} on_key: ctrl-c: help: cancel & quit @@ -337,6 +345,7 @@ modes: help: null extra_help: null key_bindings: + remaps: {} on_key: enter: help: rename @@ -377,6 +386,15 @@ modes: help: null extra_help: null key_bindings: + remaps: + /: ctrl-f + h: left + j: down + k: up + l: right + v: space + q: ctrl-c + on_key: '#': help: null @@ -390,12 +408,6 @@ modes: input: . case_sensitive: false - Explore - /: - help: null - messages: - - SwitchMode: search - - SetInputBuffer: '' - - Explore ':': help: action messages: @@ -405,16 +417,22 @@ modes: messages: - BashExec: | ${PAGER:-less} "${XPLR_PIPE_GLOBAL_HELP_MENU_OUT}" + '~': + help: go home + messages: + - BashExecSilently: | + echo "ChangeDirectory: ${HOME:?}" >> "${XPLR_PIPE_MSG_IN:?}" + echo "Explore" >> "${XPLR_PIPE_MSG_IN:?}" G: help: go to bottom messages: - FocusLast ctrl-c: - help: cancel & quit [q] + help: cancel & quit messages: - Terminate ctrl-f: - help: search [/] + help: search messages: - SwitchMode: search - SetInputBuffer: '' @@ -424,7 +442,7 @@ modes: messages: - SwitchMode: delete down: - help: down [j] + help: down messages: - FocusNext enter: @@ -435,55 +453,29 @@ modes: help: go to messages: - SwitchMode: go to - h: - help: null - messages: - - Back - j: - help: null - messages: - - FocusNext - k: - help: null - messages: - - FocusPrevious - l: - help: null - messages: - - Enter left: - help: back [h] + help: back messages: - Back - q: - help: null - messages: - - Terminate r: help: rename messages: - SwitchMode: rename - BashExecSilently: | echo "SetInputBuffer: $(basename ${XPLR_FOCUS_PATH})" >> "${XPLR_PIPE_MSG_IN:?}" - right: - help: enter [l] + help: enter messages: - Enter space: - help: toggle selection [v] + help: toggle selection messages: - ToggleSelection - FocusNext up: - help: up [k] + help: up messages: - FocusPrevious - v: - help: null - messages: - - ToggleSelection - - FocusNext on_alphabet: null on_number: help: input @@ -501,6 +493,7 @@ modes: help: null extra_help: null key_bindings: + remaps: {} on_key: ctrl-c: help: cancel & quit @@ -532,6 +525,9 @@ modes: help: null extra_help: null key_bindings: + remaps: + j: down + k: up on_key: backspace: help: clear @@ -542,7 +538,7 @@ modes: messages: - Terminate down: - help: to down [j] + help: to down messages: - FocusNextByRelativeIndexFromInput - SwitchMode: default @@ -551,18 +547,8 @@ modes: messages: - FocusByIndexFromInput - SwitchMode: default - j: - help: null - messages: - - FocusNextByRelativeIndexFromInput - - SwitchMode: default - k: - help: null - messages: - - FocusPreviousByRelativeIndexFromInput - - SwitchMode: default up: - help: to up [k] + help: to up messages: - FocusPreviousByRelativeIndexFromInput - SwitchMode: default @@ -581,6 +567,7 @@ modes: help: null extra_help: null key_bindings: + remaps: {} on_key: d: help: delete @@ -637,6 +624,9 @@ modes: help: null extra_help: null key_bindings: + remaps: + q: ctrl-c + on_number: help: go to index messages: @@ -679,11 +669,7 @@ modes: - SwitchMode: default ctrl-c: - help: cancel & quit [q] - messages: - - Terminate - - q: + help: cancel & quit messages: - Terminate @@ -695,6 +681,7 @@ modes: help: null extra_help: null key_bindings: + remaps: {} on_key: backspace: help: clear diff --git a/src/ui.rs b/src/ui.rs index 4990be7..bcd9912 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -9,6 +9,7 @@ use tui::backend::Backend; use tui::layout::Rect; use tui::layout::{Constraint as TuiConstraint, Direction, Layout}; use tui::style::{Color, Style}; +use tui::text::{Span, Spans}; use tui::widgets::{ Block, Borders, Cell, List, ListItem, ListState, Paragraph, Row, Table, TableState, }; @@ -282,7 +283,18 @@ fn draw_help_menu(f: &mut Frame, rect: Rect, app: &app::App, _: & .into_iter() .map(|l| match l { HelpMenuLine::Paragraph(p) => Row::new([Cell::from(p)].to_vec()), - HelpMenuLine::KeyMap(k, h) => Row::new([Cell::from(k), Cell::from(h)].to_vec()), + HelpMenuLine::KeyMap(k, h) => { + let remaps = app + .mode() + .key_bindings + .remaps + .iter() + .filter(|(_, t)| t == &&k) + .map(|(f, _)| f.clone()) + .collect::>() + .join("|"); + Row::new([Cell::from(k), Cell::from(remaps), Cell::from(h)].to_vec()) + } }) .collect::>(); @@ -292,15 +304,36 @@ fn draw_help_menu(f: &mut Frame, rect: Rect, app: &app::App, _: & .borders(Borders::ALL) .title(format!(" Help [{}] ", &app.mode().name)), ) - .widths(&[TuiConstraint::Percentage(30), TuiConstraint::Percentage(70)]); + .widths(&[ + TuiConstraint::Percentage(20), + TuiConstraint::Percentage(20), + TuiConstraint::Percentage(60), + ]); f.render_widget(help_menu, rect); } fn draw_input_buffer(f: &mut Frame, rect: Rect, app: &app::App, _: &Handlebars) { - let input_buf = Paragraph::new(format!( - "> {}", - app.input_buffer().unwrap_or_else(|| "".into()) - )) + let input_buf = Paragraph::new(Spans::from(vec![ + Span::styled( + app.config() + .general + .prompt + .format + .clone() + .unwrap_or_default(), + app.config().general.prompt.style.into(), + ), + Span::raw(app.input_buffer().unwrap_or_else(|| "".into())), + Span::styled( + app.config() + .general + .cursor + .format + .clone() + .unwrap_or_default(), + app.config().general.cursor.style.into(), + ), + ])) .block(Block::default().borders(Borders::ALL).title(" Input ")); f.render_widget(input_buf, rect); }