From a252ecd8c85af5cc16638a4752011e2e920fa652 Mon Sep 17 00:00:00 2001 From: Omnikar Date: Sun, 7 Nov 2021 19:54:39 -0500 Subject: Add WORD textobject (#991) * Add WORD textobject * Document WORD textobject--- helix-term/src/ui/prompt.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index c999ba14..29ca18b1 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -491,6 +491,7 @@ impl Component for Prompt { doc.selection(view.id).primary(), textobject::TextObject::Inside, 1, + false, ); let line = text.slice(range.from()..range.to()).to_string(); if !line.is_empty() { -- cgit v1.2.3-70-g09d2 From 7c9f6202361e38951820d69227eade5f1677be3c Mon Sep 17 00:00:00 2001 From: Bob Date: Tue, 9 Nov 2021 13:43:50 +0800 Subject: add , , , Delete in prompt mode (#1034) --- book/src/keymap.md | 4 +++- helix-term/src/ui/prompt.rs | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'helix-term/src/ui') diff --git a/book/src/keymap.md b/book/src/keymap.md index c6feb44f..6ae1e8d4 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -274,8 +274,10 @@ Keys to use within prompt, Remapping currently not supported. | `Ctrl-e`, `End` | move prompt end | | `Ctrl-a`, `Home` | move prompt start | | `Ctrl-w` | delete previous word | +| `Ctrl-u` | delete to start of line | | `Ctrl-k` | delete to end of line | -| `backspace` | delete previous char | +| `backspace`, `Ctrl-h` | delete previous char | +| `delete`, `Ctrl-d` | delete previous char | | `Ctrl-s` | insert a word under doc cursor, may be changed to Ctrl-r Ctrl-w later | | `Ctrl-p`, `Up` | select previous history | | `Ctrl-n`, `Down` | select next history | diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 29ca18b1..22e4adb8 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -212,6 +212,14 @@ impl Prompt { self.completion = (self.completion_fn)(&self.line); } + pub fn delete_char_forwards(&mut self) { + let pos = self.eval_movement(Movement::ForwardChar(1)); + self.line.replace_range(self.cursor..pos, ""); + + self.exit_selection(); + self.completion = (self.completion_fn)(&self.line); + } + pub fn delete_word_backwards(&mut self) { let pos = self.eval_movement(Movement::BackwardWord(1)); self.line.replace_range(pos..self.cursor, ""); @@ -221,6 +229,15 @@ impl Prompt { self.completion = (self.completion_fn)(&self.line); } + pub fn kill_to_start_of_line(&mut self) { + let pos = self.eval_movement(Movement::StartOfLine); + self.line.replace_range(pos..self.cursor, ""); + self.cursor = pos; + + self.exit_selection(); + self.completion = (self.completion_fn)(&self.line); + } + pub fn kill_to_end_of_line(&mut self) { let pos = self.eval_movement(Movement::EndOfLine); self.line.replace_range(self.cursor..pos, ""); @@ -472,12 +489,31 @@ impl Component for Prompt { modifiers: KeyModifiers::CONTROL, } => self.kill_to_end_of_line(), KeyEvent { + code: KeyCode::Char('u'), + modifiers: KeyModifiers::CONTROL, + } => self.kill_to_start_of_line(), + KeyEvent { + code: KeyCode::Char('h'), + modifiers: KeyModifiers::CONTROL, + } + | KeyEvent { code: KeyCode::Backspace, modifiers: KeyModifiers::NONE, } => { self.delete_char_backwards(); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } + KeyEvent { + code: KeyCode::Char('d'), + modifiers: KeyModifiers::CONTROL, + } + | KeyEvent { + code: KeyCode::Delete, + modifiers: KeyModifiers::NONE, + } => { + self.delete_char_forwards(); + (self.callback_fn)(cx, &self.line, PromptEvent::Update); + } KeyEvent { code: KeyCode::Char('s'), modifiers: KeyModifiers::CONTROL, -- cgit v1.2.3-70-g09d2 From 97893cca641545dc42e6b3ceabc8ed433f66a4d6 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 10 Nov 2021 09:46:55 +0800 Subject: Restore screen position when abort search (#1047) --- helix-term/src/ui/mod.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 24eb7acd..62da0dce 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -35,6 +35,7 @@ pub fn regex_prompt( let (view, doc) = current!(cx.editor); let view_id = view.id; let snapshot = doc.selection(view_id).clone(); + let offset_snapshot = view.offset; Prompt::new( prompt, @@ -45,6 +46,7 @@ pub fn regex_prompt( PromptEvent::Abort => { let (view, doc) = current!(cx.editor); doc.set_selection(view.id, snapshot.clone()); + view.offset = offset_snapshot; } PromptEvent::Validate => { // TODO: push_jump to store selection just before jump -- cgit v1.2.3-70-g09d2 From efc2b4c77be55afad07762cdde9b3b74c8477933 Mon Sep 17 00:00:00 2001 From: Gokul Soumya Date: Wed, 10 Nov 2021 21:28:46 +0530 Subject: Refactor keyevent handling using key, ctrl macros (#1058) Adds ctrl! and alt! macros (which existed before the big keymap refactor) and uses them in event handling of Components. Note that this converts crossterm's KeyEvent to our own KeyEvent on each invocation of handle_event in Components.--- helix-term/src/keymap.rs | 32 ++++++++++ helix-term/src/ui/menu.rs | 57 ++++-------------- helix-term/src/ui/picker.rs | 65 +++----------------- helix-term/src/ui/popup.rs | 28 +++------ helix-term/src/ui/prompt.rs | 144 ++++++++------------------------------------ 5 files changed, 86 insertions(+), 240 deletions(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 4fb0f172..7bed3ddb 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -25,6 +25,38 @@ macro_rules! key { }; } +#[macro_export] +macro_rules! ctrl { + ($key:ident) => { + ::helix_view::input::KeyEvent { + code: ::helix_view::keyboard::KeyCode::$key, + modifiers: ::helix_view::keyboard::KeyModifiers::CONTROL, + } + }; + ($($ch:tt)*) => { + ::helix_view::input::KeyEvent { + code: ::helix_view::keyboard::KeyCode::Char($($ch)*), + modifiers: ::helix_view::keyboard::KeyModifiers::CONTROL, + } + }; +} + +#[macro_export] +macro_rules! alt { + ($key:ident) => { + ::helix_view::input::KeyEvent { + code: ::helix_view::keyboard::KeyCode::$key, + modifiers: ::helix_view::keyboard::KeyModifiers::ALT, + } + }; + ($($ch:tt)*) => { + ::helix_view::input::KeyEvent { + code: ::helix_view::keyboard::KeyCode::Char($($ch)*), + modifiers: ::helix_view::keyboard::KeyModifiers::ALT, + } + }; +} + /// Macro for defining the root of a `Keymap` object. Example: /// /// ``` diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index 3c492d14..8278bd29 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -1,5 +1,8 @@ -use crate::compositor::{Component, Compositor, Context, EventResult}; -use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; +use crate::{ + compositor::{Component, Compositor, Context, EventResult}, + ctrl, key, +}; +use crossterm::event::Event; use tui::{buffer::Buffer as Surface, widgets::Table}; pub use tui::widgets::{Cell, Row}; @@ -192,63 +195,25 @@ impl Component for Menu { compositor.pop(); }))); - match event { + match event.into() { // esc or ctrl-c aborts the completion and closes the menu - KeyEvent { - code: KeyCode::Esc, .. - } - | KeyEvent { - code: KeyCode::Char('c'), - modifiers: KeyModifiers::CONTROL, - } => { + key!(Esc) | ctrl!('c') => { (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Abort); return close_fn; } // arrow up/ctrl-p/shift-tab prev completion choice (including updating the doc) - KeyEvent { - code: KeyCode::BackTab, - .. - } - | KeyEvent { - code: KeyCode::Up, .. - } - | KeyEvent { - code: KeyCode::Char('p'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Char('k'), - modifiers: KeyModifiers::CONTROL, - } => { + key!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => { self.move_up(); (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update); return EventResult::Consumed(None); } - // arrow down/ctrl-n/tab advances completion choice (including updating the doc) - KeyEvent { - code: KeyCode::Tab, - modifiers: KeyModifiers::NONE, - } - | KeyEvent { - code: KeyCode::Down, - .. - } - | KeyEvent { - code: KeyCode::Char('n'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Char('j'), - modifiers: KeyModifiers::CONTROL, - } => { + key!(Tab) | key!(Down) | ctrl!('n') | ctrl!('j') => { + // arrow down/ctrl-n/tab advances completion choice (including updating the doc) self.move_down(); (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update); return EventResult::Consumed(None); } - KeyEvent { - code: KeyCode::Enter, - .. - } => { + key!(Enter) => { if let Some(selection) = self.selection() { (self.callback_fn)(cx.editor, Some(selection), MenuEvent::Validate); } diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 291f1f85..970d3946 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -1,8 +1,9 @@ use crate::{ compositor::{Component, Compositor, Context, EventResult}, + ctrl, key, ui::EditorView, }; -use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; +use crossterm::event::Event; use tui::{ buffer::Buffer as Surface, widgets::{Block, BorderType, Borders}, @@ -402,81 +403,35 @@ impl Component for Picker { compositor.last_picker = compositor.pop(); }))); - match key_event { - KeyEvent { - code: KeyCode::Up, .. - } - | KeyEvent { - code: KeyCode::BackTab, - .. - } - | KeyEvent { - code: KeyCode::Char('k'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Char('p'), - modifiers: KeyModifiers::CONTROL, - } => { + match key_event.into() { + key!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => { self.move_up(); } - KeyEvent { - code: KeyCode::Down, - .. - } - | KeyEvent { - code: KeyCode::Tab, .. - } - | KeyEvent { - code: KeyCode::Char('j'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Char('n'), - modifiers: KeyModifiers::CONTROL, - } => { + key!(Tab) | key!(Down) | ctrl!('n') | ctrl!('j') => { self.move_down(); } - KeyEvent { - code: KeyCode::Esc, .. - } - | KeyEvent { - code: KeyCode::Char('c'), - modifiers: KeyModifiers::CONTROL, - } => { + key!(Esc) | ctrl!('c') => { return close_fn; } - KeyEvent { - code: KeyCode::Enter, - .. - } => { + key!(Enter) => { if let Some(option) = self.selection() { (self.callback_fn)(&mut cx.editor, option, Action::Replace); } return close_fn; } - KeyEvent { - code: KeyCode::Char('s'), - modifiers: KeyModifiers::CONTROL, - } => { + ctrl!('s') => { if let Some(option) = self.selection() { (self.callback_fn)(&mut cx.editor, option, Action::HorizontalSplit); } return close_fn; } - KeyEvent { - code: KeyCode::Char('v'), - modifiers: KeyModifiers::CONTROL, - } => { + ctrl!('v') => { if let Some(option) = self.selection() { (self.callback_fn)(&mut cx.editor, option, Action::VerticalSplit); } return close_fn; } - KeyEvent { - code: KeyCode::Char(' '), - modifiers: KeyModifiers::CONTROL, - } => { + ctrl!(' ') => { self.save_filter(); } _ => { diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index 1bab1eae..8f7921a1 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -1,5 +1,8 @@ -use crate::compositor::{Component, Compositor, Context, EventResult}; -use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; +use crate::{ + compositor::{Component, Compositor, Context, EventResult}, + ctrl, key, +}; +use crossterm::event::Event; use tui::buffer::Buffer as Surface; use helix_core::Position; @@ -95,27 +98,14 @@ impl Component for Popup { compositor.pop(); }))); - match key { + match key.into() { // esc or ctrl-c aborts the completion and closes the menu - KeyEvent { - code: KeyCode::Esc, .. - } - | KeyEvent { - code: KeyCode::Char('c'), - modifiers: KeyModifiers::CONTROL, - } => close_fn, - - KeyEvent { - code: KeyCode::Char('d'), - modifiers: KeyModifiers::CONTROL, - } => { + key!(Esc) | ctrl!('c') => close_fn, + ctrl!('d') => { self.scroll(self.size.1 as usize / 2, true); EventResult::Consumed(None) } - KeyEvent { - code: KeyCode::Char('u'), - modifiers: KeyModifiers::CONTROL, - } => { + ctrl!('u') => { self.scroll(self.size.1 as usize / 2, false); EventResult::Consumed(None) } diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 22e4adb8..4bd5659f 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -1,6 +1,8 @@ use crate::compositor::{Component, Compositor, Context, EventResult}; -use crate::ui; -use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; +use crate::{alt, ctrl, key, ui}; +use crossterm::event::Event; +use helix_view::input::KeyEvent; +use helix_view::keyboard::{KeyCode, KeyModifiers}; use std::{borrow::Cow, ops::RangeFrom}; use tui::buffer::Buffer as Surface; @@ -421,103 +423,29 @@ impl Component for Prompt { compositor.pop(); }))); - match event { - KeyEvent { - code: KeyCode::Char('c'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Esc, .. - } => { + match event.into() { + ctrl!('c') | key!(Esc) => { (self.callback_fn)(cx, &self.line, PromptEvent::Abort); return close_fn; } - KeyEvent { - code: KeyCode::Left, - modifiers: KeyModifiers::ALT, - } - | KeyEvent { - code: KeyCode::Char('b'), - modifiers: KeyModifiers::ALT, - } => self.move_cursor(Movement::BackwardWord(1)), - KeyEvent { - code: KeyCode::Right, - modifiers: KeyModifiers::ALT, - } - | KeyEvent { - code: KeyCode::Char('f'), - modifiers: KeyModifiers::ALT, - } => self.move_cursor(Movement::ForwardWord(1)), - KeyEvent { - code: KeyCode::Char('f'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Right, - .. - } => self.move_cursor(Movement::ForwardChar(1)), - KeyEvent { - code: KeyCode::Char('b'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Left, - .. - } => self.move_cursor(Movement::BackwardChar(1)), - KeyEvent { - code: KeyCode::End, - modifiers: KeyModifiers::NONE, - } - | KeyEvent { - code: KeyCode::Char('e'), - modifiers: KeyModifiers::CONTROL, - } => self.move_end(), - KeyEvent { - code: KeyCode::Home, - modifiers: KeyModifiers::NONE, - } - | KeyEvent { - code: KeyCode::Char('a'), - modifiers: KeyModifiers::CONTROL, - } => self.move_start(), - KeyEvent { - code: KeyCode::Char('w'), - modifiers: KeyModifiers::CONTROL, - } => self.delete_word_backwards(), - KeyEvent { - code: KeyCode::Char('k'), - modifiers: KeyModifiers::CONTROL, - } => self.kill_to_end_of_line(), - KeyEvent { - code: KeyCode::Char('u'), - modifiers: KeyModifiers::CONTROL, - } => self.kill_to_start_of_line(), - KeyEvent { - code: KeyCode::Char('h'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Backspace, - modifiers: KeyModifiers::NONE, - } => { + alt!('b') | alt!(Left) => self.move_cursor(Movement::BackwardWord(1)), + alt!('f') | alt!(Right) => self.move_cursor(Movement::ForwardWord(1)), + ctrl!('b') | ctrl!(Left) => self.move_cursor(Movement::BackwardChar(1)), + ctrl!('f') | ctrl!(Right) => self.move_cursor(Movement::ForwardChar(1)), + ctrl!('e') | key!(End) => self.move_end(), + ctrl!('a') | key!(Home) => self.move_start(), + ctrl!('w') => self.delete_word_backwards(), + ctrl!('k') => self.kill_to_end_of_line(), + ctrl!('u') => self.kill_to_start_of_line(), + ctrl!('h') | key!(Backspace) => { self.delete_char_backwards(); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } - KeyEvent { - code: KeyCode::Char('d'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Delete, - modifiers: KeyModifiers::NONE, - } => { + ctrl!('d') | key!(Delete) => { self.delete_char_forwards(); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } - KeyEvent { - code: KeyCode::Char('s'), - modifiers: KeyModifiers::CONTROL, - } => { + ctrl!('s') => { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); @@ -535,10 +463,7 @@ impl Component for Prompt { (self.callback_fn)(cx, &self.line, PromptEvent::Update); } } - KeyEvent { - code: KeyCode::Enter, - .. - } => { + key!(Enter) => { if self.selection.is_some() && self.line.ends_with('/') { self.completion = (self.completion_fn)(&self.line); self.exit_selection(); @@ -553,50 +478,29 @@ impl Component for Prompt { return close_fn; } } - KeyEvent { - code: KeyCode::Char('p'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Up, .. - } => { + ctrl!('p') | key!(Up) => { if let Some(register) = self.history_register { let register = cx.editor.registers.get_mut(register); self.change_history(register.read(), CompletionDirection::Backward); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } } - KeyEvent { - code: KeyCode::Char('n'), - modifiers: KeyModifiers::CONTROL, - } - | KeyEvent { - code: KeyCode::Down, - .. - } => { + ctrl!('n') | key!(Down) => { if let Some(register) = self.history_register { let register = cx.editor.registers.get_mut(register); self.change_history(register.read(), CompletionDirection::Forward); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } } - KeyEvent { - code: KeyCode::Tab, .. - } => { + key!(Tab) => { self.change_completion_selection(CompletionDirection::Forward); (self.callback_fn)(cx, &self.line, PromptEvent::Update) } - KeyEvent { - code: KeyCode::BackTab, - .. - } => { + key!(BackTab) => { self.change_completion_selection(CompletionDirection::Backward); (self.callback_fn)(cx, &self.line, PromptEvent::Update) } - KeyEvent { - code: KeyCode::Char('q'), - modifiers: KeyModifiers::CONTROL, - } => self.exit_selection(), + ctrl!('q') => self.exit_selection(), // any char event that's not combined with control or mapped to any other combo KeyEvent { code: KeyCode::Char(c), -- cgit v1.2.3-70-g09d2 From c7cb7527bedbd8a49471fcf79216d2f78fe21ae2 Mon Sep 17 00:00:00 2001 From: ath3 Date: Thu, 11 Nov 2021 03:08:19 +0100 Subject: Fix moving with arrow keys in prompt (#1070) --- helix-term/src/ui/prompt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 4bd5659f..9a60196f 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -430,8 +430,8 @@ impl Component for Prompt { } alt!('b') | alt!(Left) => self.move_cursor(Movement::BackwardWord(1)), alt!('f') | alt!(Right) => self.move_cursor(Movement::ForwardWord(1)), - ctrl!('b') | ctrl!(Left) => self.move_cursor(Movement::BackwardChar(1)), - ctrl!('f') | ctrl!(Right) => self.move_cursor(Movement::ForwardChar(1)), + ctrl!('b') | key!(Left) => self.move_cursor(Movement::BackwardChar(1)), + ctrl!('f') | key!(Right) => self.move_cursor(Movement::ForwardChar(1)), ctrl!('e') | key!(End) => self.move_end(), ctrl!('a') | key!(Home) => self.move_start(), ctrl!('w') => self.delete_word_backwards(), -- cgit v1.2.3-70-g09d2 From d131a9dd0efc5ff271f8b78cd65a8dc30c193af4 Mon Sep 17 00:00:00 2001 From: Omnikar Date: Wed, 10 Nov 2021 23:44:50 -0500 Subject: Allow keys to be mapped to sequences of commands (#589) * Allow keys to be mapped to sequences of commands * Handle `Sequence` at the start of `Keymap::get` * Use `"[Multiple commands]"` as command sequence doc * Add command sequence example to `remapping.md`--- book/src/remapping.md | 1 + helix-term/src/keymap.rs | 27 ++++++++++++++++++++++++--- helix-term/src/ui/editor.rs | 5 +++++ 3 files changed, 30 insertions(+), 3 deletions(-) (limited to 'helix-term/src/ui') diff --git a/book/src/remapping.md b/book/src/remapping.md index 5ca6cd1b..532f502a 100644 --- a/book/src/remapping.md +++ b/book/src/remapping.md @@ -15,6 +15,7 @@ a = "move_char_left" # Maps the 'a' key to the move_char_left command w = "move_line_up" # Maps the 'w' key move_line_up "C-S-esc" = "extend_line" # Maps Control-Shift-Escape to extend_line g = { a = "code_action" } # Maps `ga` to show possible code actions +"ret" = ["open_below", "normal_mode"] # Maps the enter key to open_below then re-enter normal mode [keys.insert] "A-x" = "normal_mode" # Maps Alt-X to enter normal mode diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index d7040b88..b2b865e4 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -85,6 +85,10 @@ macro_rules! keymap { keymap!({ $label $(sticky=$sticky)? $($($key)|+ => $value,)+ }) }; + (@trie [$($cmd:ident),* $(,)?]) => { + $crate::keymap::KeyTrie::Sequence(vec![$($crate::commands::Command::$cmd),*]) + }; + ( { $label:literal $(sticky=$sticky:literal)? $($($key:literal)|+ => $value:tt,)+ } ) => { @@ -180,6 +184,7 @@ impl KeyTrieNode { cmd.doc() } KeyTrie::Node(n) => n.name(), + KeyTrie::Sequence(_) => "[Multiple commands]", }; match body.iter().position(|(d, _)| d == &desc) { Some(pos) => { @@ -240,6 +245,7 @@ impl DerefMut for KeyTrieNode { #[serde(untagged)] pub enum KeyTrie { Leaf(Command), + Sequence(Vec), Node(KeyTrieNode), } @@ -247,14 +253,14 @@ impl KeyTrie { pub fn node(&self) -> Option<&KeyTrieNode> { match *self { KeyTrie::Node(ref node) => Some(node), - KeyTrie::Leaf(_) => None, + KeyTrie::Leaf(_) | KeyTrie::Sequence(_) => None, } } pub fn node_mut(&mut self) -> Option<&mut KeyTrieNode> { match *self { KeyTrie::Node(ref mut node) => Some(node), - KeyTrie::Leaf(_) => None, + KeyTrie::Leaf(_) | KeyTrie::Sequence(_) => None, } } @@ -271,7 +277,7 @@ impl KeyTrie { trie = match trie { KeyTrie::Node(map) => map.get(key), // leaf encountered while keys left to process - KeyTrie::Leaf(_) => None, + KeyTrie::Leaf(_) | KeyTrie::Sequence(_) => None, }? } Some(trie) @@ -283,6 +289,8 @@ pub enum KeymapResultKind { /// Needs more keys to execute a command. Contains valid keys for next keystroke. Pending(KeyTrieNode), Matched(Command), + /// Matched a sequence of commands to execute. + MatchedSequence(Vec), /// Key was not found in the root keymap NotFound, /// Key is invalid in combination with previous keys. Contains keys leading upto @@ -365,6 +373,12 @@ impl Keymap { Some(&KeyTrie::Leaf(cmd)) => { return KeymapResult::new(KeymapResultKind::Matched(cmd), self.sticky()) } + Some(&KeyTrie::Sequence(ref cmds)) => { + return KeymapResult::new( + KeymapResultKind::MatchedSequence(cmds.clone()), + self.sticky(), + ) + } None => return KeymapResult::new(KeymapResultKind::NotFound, self.sticky()), Some(t) => t, }; @@ -382,6 +396,13 @@ impl Keymap { self.state.clear(); return KeymapResult::new(KeymapResultKind::Matched(cmd), self.sticky()); } + Some(&KeyTrie::Sequence(ref cmds)) => { + self.state.clear(); + KeymapResult::new( + KeymapResultKind::MatchedSequence(cmds.clone()), + self.sticky(), + ) + } None => KeymapResult::new( KeymapResultKind::Cancelled(self.state.drain(..).collect()), self.sticky(), diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index a7015577..90f09e9c 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -695,6 +695,11 @@ impl EditorView { match &key_result.kind { KeymapResultKind::Matched(command) => command.execute(cxt), KeymapResultKind::Pending(node) => self.autoinfo = Some(node.infobox()), + KeymapResultKind::MatchedSequence(commands) => { + for command in commands { + command.execute(cxt); + } + } KeymapResultKind::NotFound | KeymapResultKind::Cancelled(_) => return Some(key_result), } None -- cgit v1.2.3-70-g09d2 From d3def16584f7f35a64ab2bad578436bd13cc18b6 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Fri, 12 Nov 2021 16:21:03 +0900 Subject: fix: shift-tab mappings broken after efc2b4c7 --- helix-term/src/keymap.rs | 16 ++++++++++++++++ helix-term/src/ui/menu.rs | 4 ++-- helix-term/src/ui/picker.rs | 4 ++-- helix-term/src/ui/prompt.rs | 4 ++-- 4 files changed, 22 insertions(+), 6 deletions(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 1a9ea231..e3e01995 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -25,6 +25,22 @@ macro_rules! key { }; } +#[macro_export] +macro_rules! shift { + ($key:ident) => { + ::helix_view::input::KeyEvent { + code: ::helix_view::keyboard::KeyCode::$key, + modifiers: ::helix_view::keyboard::KeyModifiers::SHIFT, + } + }; + ($($ch:tt)*) => { + ::helix_view::input::KeyEvent { + code: ::helix_view::keyboard::KeyCode::Char($($ch)*), + modifiers: ::helix_view::keyboard::KeyModifiers::SHIFT, + } + }; +} + #[macro_export] macro_rules! ctrl { ($key:ident) => { diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index 8278bd29..e891c149 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -1,6 +1,6 @@ use crate::{ compositor::{Component, Compositor, Context, EventResult}, - ctrl, key, + ctrl, key, shift, }; use crossterm::event::Event; use tui::{buffer::Buffer as Surface, widgets::Table}; @@ -202,7 +202,7 @@ impl Component for Menu { return close_fn; } // arrow up/ctrl-p/shift-tab prev completion choice (including updating the doc) - key!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => { + shift!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => { self.move_up(); (self.callback_fn)(cx.editor, self.selection(), MenuEvent::Update); return EventResult::Consumed(None); diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 970d3946..c44b7625 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -1,6 +1,6 @@ use crate::{ compositor::{Component, Compositor, Context, EventResult}, - ctrl, key, + ctrl, key, shift, ui::EditorView, }; use crossterm::event::Event; @@ -404,7 +404,7 @@ impl Component for Picker { }))); match key_event.into() { - key!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => { + shift!(BackTab) | key!(Up) | ctrl!('p') | ctrl!('k') => { self.move_up(); } key!(Tab) | key!(Down) | ctrl!('n') | ctrl!('j') => { diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 9a60196f..deed1609 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -1,5 +1,5 @@ use crate::compositor::{Component, Compositor, Context, EventResult}; -use crate::{alt, ctrl, key, ui}; +use crate::{alt, ctrl, key, shift, ui}; use crossterm::event::Event; use helix_view::input::KeyEvent; use helix_view::keyboard::{KeyCode, KeyModifiers}; @@ -496,7 +496,7 @@ impl Component for Prompt { self.change_completion_selection(CompletionDirection::Forward); (self.callback_fn)(cx, &self.line, PromptEvent::Update) } - key!(BackTab) => { + shift!(BackTab) => { self.change_completion_selection(CompletionDirection::Backward); (self.callback_fn)(cx, &self.line, PromptEvent::Update) } -- cgit v1.2.3-70-g09d2 From b74912ea78079cde3e1ee3b2dc1a2a6d68568a36 Mon Sep 17 00:00:00 2001 From: Cole Helbling Date: Sat, 13 Nov 2021 12:44:51 -0800 Subject: helix-term/editor: display scratch buffer name in status bar --- helix-term/src/ui/editor.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 90f09e9c..dcf87203 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -16,7 +16,7 @@ use helix_core::{ LineEnding, Position, Range, Selection, }; use helix_view::{ - document::Mode, + document::{Mode, SCRATCH_BUFFER_NAME}, editor::LineNumber, graphics::{CursorKind, Modifier, Rect, Style}, info::Info, @@ -580,18 +580,20 @@ impl EditorView { } surface.set_string(viewport.x + 5, viewport.y, progress, base_style); - if let Some(path) = doc.relative_path() { - let path = path.to_string_lossy(); + let rel_path = doc.relative_path(); + let path = rel_path + .as_ref() + .map(|p| p.to_string_lossy()) + .unwrap_or_else(|| SCRATCH_BUFFER_NAME.into()); - let title = format!("{}{}", path, if doc.is_modified() { "[+]" } else { "" }); - surface.set_stringn( - viewport.x + 8, - viewport.y, - title, - viewport.width.saturating_sub(6) as usize, - base_style, - ); - } + let title = format!("{}{}", path, if doc.is_modified() { "[+]" } else { "" }); + surface.set_stringn( + viewport.x + 8, + viewport.y, + title, + viewport.width.saturating_sub(6) as usize, + base_style, + ); //------------------------------- // Right side of the status line. -- cgit v1.2.3-70-g09d2 From 35c974c9c49f9127da3798c9a8e49795b3c4aadc Mon Sep 17 00:00:00 2001 From: ath3 Date: Sun, 14 Nov 2021 16:11:53 +0100 Subject: Implement "Goto last modification" command (#1067) --- book/src/keymap.md | 1 + helix-core/src/history.rs | 30 +++++++++++++++++++++++++++++- helix-term/src/commands.rs | 14 ++++++++++++++ helix-term/src/keymap.rs | 1 + helix-term/src/ui/editor.rs | 2 +- helix-view/src/document.rs | 2 +- 6 files changed, 47 insertions(+), 3 deletions(-) (limited to 'helix-term/src/ui') diff --git a/book/src/keymap.md b/book/src/keymap.md index c544a472..6155e553 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -165,6 +165,7 @@ Jumps to various locations. | `a` | Go to the last accessed/alternate file | `goto_last_accessed_file` | | `n` | Go to next buffer | `goto_next_buffer` | | `p` | Go to previous buffer | `goto_previous_buffer` | +| `.` | Go to last modification in current file | `goto_last_modification` | #### Match mode diff --git a/helix-core/src/history.rs b/helix-core/src/history.rs index b53c01fe..bf2624e2 100644 --- a/helix-core/src/history.rs +++ b/helix-core/src/history.rs @@ -1,4 +1,4 @@ -use crate::{ChangeSet, Rope, State, Transaction}; +use crate::{Assoc, ChangeSet, Rope, State, Transaction}; use once_cell::sync::Lazy; use regex::Regex; use std::num::NonZeroUsize; @@ -133,6 +133,34 @@ impl History { Some(&self.revisions[last_child.get()].transaction) } + // Get the position of last change + pub fn last_edit_pos(&self) -> Option { + if self.current == 0 { + return None; + } + let current_revision = &self.revisions[self.current]; + let primary_selection = current_revision + .inversion + .selection() + .expect("inversion always contains a selection") + .primary(); + let (_from, to, _fragment) = current_revision + .transaction + .changes_iter() + // find a change that matches the primary selection + .find(|(from, to, _fragment)| { + crate::Range::new(*from, *to).overlaps(&primary_selection) + }) + // or use the first change + .or_else(|| current_revision.transaction.changes_iter().next()) + .unwrap(); + let pos = current_revision + .transaction + .changes() + .map_pos(to, Assoc::After); + Some(pos) + } + fn lowest_common_ancestor(&self, mut a: usize, mut b: usize) -> usize { use std::collections::HashSet; let mut a_path_set = HashSet::new(); diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index d5a48c5f..e37265a8 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -257,6 +257,7 @@ impl Command { goto_window_middle, "Goto window middle", goto_window_bottom, "Goto window bottom", goto_last_accessed_file, "Goto last accessed file", + goto_last_modification, "Goto last modification", goto_line, "Goto line", goto_last_line, "Goto last line", goto_first_diag, "Goto first diagnostic", @@ -3195,6 +3196,19 @@ fn goto_last_accessed_file(cx: &mut Context) { } } +fn goto_last_modification(cx: &mut Context) { + let (view, doc) = current!(cx.editor); + let pos = doc.history.get_mut().last_edit_pos(); + let text = doc.text().slice(..); + if let Some(pos) = pos { + let selection = doc + .selection(view.id) + .clone() + .transform(|range| range.put_cursor(text, pos, doc.mode == Mode::Select)); + doc.set_selection(view.id, selection); + } +} + fn select_mode(cx: &mut Context) { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index e3e01995..b14b1a6f 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -525,6 +525,7 @@ impl Default for Keymaps { "a" => goto_last_accessed_file, "n" => goto_next_buffer, "p" => goto_previous_buffer, + "." => goto_last_modification, }, ":" => command_mode, diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index dcf87203..bcd9f8f0 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -743,7 +743,7 @@ impl EditorView { std::num::NonZeroUsize::new(cxt.editor.count.map_or(i, |c| c.get() * 10 + i)); } // special handling for repeat operator - key!('.') => { + key!('.') if self.keymaps.pending().is_empty() => { // first execute whatever put us into insert mode self.last_insert.0.execute(cxt); // then replay the inputs diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 6b429151..76b19a07 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -98,7 +98,7 @@ pub struct Document { // It can be used as a cell where we will take it out to get some parts of the history and put // it back as it separated from the edits. We could split out the parts manually but that will // be more troublesome. - history: Cell, + pub history: Cell, pub savepoint: Option, -- cgit v1.2.3-70-g09d2 From edc976b6bb36c6017bf59691abbde5c086267bfd Mon Sep 17 00:00:00 2001 From: Ebbe Steenhoudt Date: Sun, 14 Nov 2021 16:12:56 +0100 Subject: Added workspace_symbol_picker (#1041) * Added workspace_symbol_picker * Moved truncation of the symbol pickers to the end. * Fixed typo--- book/src/keymap.md | 1 + helix-term/src/commands.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++- helix-term/src/keymap.rs | 1 + helix-term/src/ui/picker.rs | 8 +++++- 4 files changed, 74 insertions(+), 2 deletions(-) (limited to 'helix-term/src/ui') diff --git a/book/src/keymap.md b/book/src/keymap.md index 6155e553..9f1714f6 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -211,6 +211,7 @@ This layer is a kludge of mappings, mostly pickers. | `b` | Open buffer picker | `buffer_picker` | | `k` | Show documentation for item under cursor (**LSP**) | `hover` | | `s` | Open document symbol picker (**LSP**) | `symbol_picker` | +| `S` | Open workspace symbol picker (**LSP**) | `workspace_symbol_picker` | | `r` | Rename symbol (**LSP**) | `rename_symbol` | | `a` | Apply code action (**LSP**) | `code_action` | | `'` | Open last fuzzy picker | `last_picker` | diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index e37265a8..ebacb377 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -237,6 +237,7 @@ impl Command { code_action, "Perform code action", buffer_picker, "Open buffer picker", symbol_picker, "Open symbol picker", + workspace_symbol_picker, "Open workspace symbol picker", last_picker, "Open last picker", prepend_to_line, "Insert at start of line", append_to_line, "Insert at end of line", @@ -2723,7 +2724,7 @@ fn symbol_picker(cx: &mut Context) { } }; - let picker = FilePicker::new( + let mut picker = FilePicker::new( symbols, |symbol| (&symbol.name).into(), move |editor: &mut Editor, symbol, _action| { @@ -2748,6 +2749,69 @@ fn symbol_picker(cx: &mut Context) { Some((path, line)) }, ); + picker.truncate_start = false; + compositor.push(Box::new(picker)) + } + }, + ) +} + +fn workspace_symbol_picker(cx: &mut Context) { + let (_, doc) = current!(cx.editor); + + let language_server = match doc.language_server() { + Some(language_server) => language_server, + None => return, + }; + let offset_encoding = language_server.offset_encoding(); + + let future = language_server.workspace_symbols("".to_string()); + + let current_path = doc_mut!(cx.editor).path().cloned(); + cx.callback( + future, + move |_editor: &mut Editor, + compositor: &mut Compositor, + response: Option>| { + if let Some(symbols) = response { + let mut picker = FilePicker::new( + symbols, + move |symbol| { + let path = symbol.location.uri.to_file_path().unwrap(); + if current_path.as_ref().map(|p| p == &path).unwrap_or(false) { + (&symbol.name).into() + } else { + let relative_path = helix_core::path::get_relative_path(path.as_path()) + .to_str() + .unwrap() + .to_owned(); + format!("{} ({})", &symbol.name, relative_path).into() + } + }, + move |editor: &mut Editor, symbol, action| { + let path = symbol.location.uri.to_file_path().unwrap(); + editor.open(path, action).expect("editor.open failed"); + let (view, doc) = current!(editor); + + if let Some(range) = + lsp_range_to_range(doc.text(), symbol.location.range, offset_encoding) + { + // we flip the range so that the cursor sits on the start of the symbol + // (for example start of the function). + doc.set_selection(view.id, Selection::single(range.head, range.anchor)); + align_view(doc, view, Align::Center); + } + }, + move |_editor, symbol| { + let path = symbol.location.uri.to_file_path().unwrap(); + let line = Some(( + symbol.location.range.start.line as usize, + symbol.location.range.end.line as usize, + )); + Some((path, line)) + }, + ); + picker.truncate_start = false; compositor.push(Box::new(picker)) } }, diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index b14b1a6f..3280f0f8 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -641,6 +641,7 @@ impl Default for Keymaps { "f" => file_picker, "b" => buffer_picker, "s" => symbol_picker, + "S" => workspace_symbol_picker, "a" => code_action, "'" => last_picker, "w" => { "Window" diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index c44b7625..6b1c5832 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -37,6 +37,7 @@ type FileLocation = (PathBuf, Option<(usize, usize)>); pub struct FilePicker { picker: Picker, + pub truncate_start: bool, /// Caches paths to documents preview_cache: HashMap, read_buffer: Vec, @@ -90,6 +91,7 @@ impl FilePicker { ) -> Self { Self { picker: Picker::new(false, options, format_fn, callback_fn), + truncate_start: true, preview_cache: HashMap::new(), read_buffer: Vec::with_capacity(1024), file_fn: Box::new(preview_fn), @@ -172,6 +174,7 @@ impl Component for FilePicker { }; let picker_area = area.with_width(picker_width); + self.picker.truncate_start = self.truncate_start; self.picker.render(picker_area, surface, cx); if !render_preview { @@ -277,6 +280,8 @@ pub struct Picker { prompt: Prompt, /// Whether to render in the middle of the area render_centered: bool, + /// Wheather to truncate the start (default true) + pub truncate_start: bool, format_fn: Box Cow>, callback_fn: Box, @@ -306,6 +311,7 @@ impl Picker { cursor: 0, prompt, render_centered, + truncate_start: true, format_fn: Box::new(format_fn), callback_fn: Box::new(callback_fn), }; @@ -521,7 +527,7 @@ impl Component for Picker { text_style }, true, - true, + self.truncate_start, ); } } -- cgit v1.2.3-70-g09d2 From 46d9ae2b62f5b8494c527e0f8475509ce5fad095 Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 15 Nov 2021 23:31:20 +0800 Subject: Readline style insert mode (#1039) * readline style insert mode * update keymap.md * don't save change history in insert mode * Revert "don't save change history in insert mode" This reverts commit cb47f946d7fb62ceda68e7d1692a3914d0be7762. * don't affect register and history in insert mode * add insert_register * don't call exit_select_mode in insert mode * avoid set_selection * avoid duplicated current!--- book/src/keymap.md | 30 +++++++++++++++----- helix-term/src/commands.rs | 67 +++++++++++++++++++++++++++++++++++++++++++-- helix-term/src/keymap.rs | 17 ++++++++++++ helix-term/src/ui/prompt.rs | 9 ++++++ 4 files changed, 114 insertions(+), 9 deletions(-) (limited to 'helix-term/src/ui') diff --git a/book/src/keymap.md b/book/src/keymap.md index 88610a77..7a896035 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -243,11 +243,26 @@ Mappings in the style of [vim-unimpaired](https://github.com/tpope/vim-unimpaire ## Insert Mode -| Key | Description | Command | -| ----- | ----------- | ------- | -| `Escape` | Switch to normal mode | `normal_mode` | -| `Ctrl-x` | Autocomplete | `completion` | -| `Ctrl-w` | Delete previous word | `delete_word_backward` | +| Key | Description | Command | +| ----- | ----------- | ------- | +| `Escape` | Switch to normal mode | `normal_mode` | +| `Ctrl-x` | Autocomplete | `completion` | +| `Ctrl-r` | Insert a register content | `insert_register` | +| `Ctrl-w` | Delete previous word | `delete_word_backward` | +| `Alt-d` | Delete next word | `delete_word_forward` | +| `Alt-b`, `Alt-Left` | Backward a word | `move_prev_word_end` | +| `Ctrl-b`, `Left` | Backward a char | `move_char_left` | +| `Alt-f`, `Alt-Right` | Forward a word | `move_next_word_start` | +| `Ctrl-f`, `Right` | Forward a char | `move_char_right` | +| `Ctrl-e`, `End` | move to line end | `goto_line_end_newline` | +| `Ctrl-a`, `Home` | move to line start | `goto_line_start` | +| `Ctrl-w` | delete previous word | `delete_word_backwar` | +| `Ctrl-u` | delete to start of line | `kill_to_line_start` | +| `Ctrl-k` | delete to end of line | `kill_to_line_end` | +| `backspace`, `Ctrl-h` | delete previous char | `delete_char_backward` | +| `delete`, `Ctrl-d` | delete previous char | `delete_char_forward` | +| `Ctrl-p`, `Up` | move to previous line | `move_line_up` | +| `Ctrl-n`, `Down` | move to next line | `move_line_down` | ## Select / extend mode @@ -285,6 +300,7 @@ Keys to use within prompt, Remapping currently not supported. | `Ctrl-e`, `End` | Move prompt end | | `Ctrl-a`, `Home` | Move prompt start | | `Ctrl-w` | Delete previous word | +| `Alt-d` | Delete next word | | `Ctrl-u` | Delete to start of line | | `Ctrl-k` | Delete to end of line | | `backspace`, `Ctrl-h` | Delete previous char | @@ -292,7 +308,7 @@ Keys to use within prompt, Remapping currently not supported. | `Ctrl-s` | Insert a word under doc cursor, may be changed to Ctrl-r Ctrl-w later | | `Ctrl-p`, `Up` | Select previous history | | `Ctrl-n`, `Down` | Select next history | -| `Tab` | Select next completion item | -| `BackTab` | Select previous completion item | +| `Tab` | Select next completion item | +| `BackTab` | Select previous completion item | | `Enter` | Open selected | diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c7aab726..74bc52fd 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -187,6 +187,7 @@ impl Command { copy_selection_on_prev_line, "Copy selection on previous line", move_next_word_start, "Move to beginning of next word", move_prev_word_start, "Move to beginning of previous word", + move_prev_word_end, "Move to end of previous word", move_next_word_end, "Move to end of next word", move_next_long_word_start, "Move to beginning of next long word", move_prev_long_word_start, "Move to beginning of previous long word", @@ -284,6 +285,9 @@ impl Command { delete_char_backward, "Delete previous char", delete_char_forward, "Delete next char", delete_word_backward, "Delete previous word", + delete_word_forward, "Delete next word", + kill_to_line_start, "Delete content till the start of the line", + kill_to_line_end, "Delete content till the end of the line", undo, "Undo change", redo, "Redo change", earlier, "Move backward in history", @@ -330,6 +334,7 @@ impl Command { wclose, "Close window", wonly, "Current window only", select_register, "Select register", + insert_register, "Insert register", align_view_middle, "Align view middle", align_view_top, "Align view top", align_view_center, "Align view center", @@ -572,6 +577,29 @@ fn extend_to_line_start(cx: &mut Context) { goto_line_start_impl(view, doc, Movement::Extend) } +fn kill_to_line_start(cx: &mut Context) { + let (view, doc) = current!(cx.editor); + let text = doc.text().slice(..); + + let selection = doc.selection(view.id).clone().transform(|range| { + let line = range.cursor_line(text); + range.put_cursor(text, text.line_to_char(line), true) + }); + delete_selection_insert_mode(doc, view, &selection); +} + +fn kill_to_line_end(cx: &mut Context) { + let (view, doc) = current!(cx.editor); + let text = doc.text().slice(..); + + let selection = doc.selection(view.id).clone().transform(|range| { + let line = range.cursor_line(text); + let pos = line_end_char_index(&text, line); + range.put_cursor(text, pos, true) + }); + delete_selection_insert_mode(doc, view, &selection); +} + fn goto_first_nonwhitespace(cx: &mut Context) { let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); @@ -684,6 +712,10 @@ fn move_prev_word_start(cx: &mut Context) { move_word_impl(cx, movement::move_prev_word_start) } +fn move_prev_word_end(cx: &mut Context) { + move_word_impl(cx, movement::move_prev_word_end) +} + fn move_next_word_end(cx: &mut Context) { move_word_impl(cx, movement::move_next_word_end) } @@ -1586,6 +1618,17 @@ fn delete_selection_impl(reg: &mut Register, doc: &mut Document, view_id: ViewId doc.apply(&transaction, view_id); } +#[inline] +fn delete_selection_insert_mode(doc: &mut Document, view: &View, selection: &Selection) { + let view_id = view.id; + + // then delete + let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { + (range.from(), range.to(), None) + }); + doc.apply(&transaction, view_id); +} + fn delete_selection(cx: &mut Context) { let reg_name = cx.register.unwrap_or('"'); let (view, doc) = current!(cx.editor); @@ -4010,8 +4053,19 @@ pub mod insert { .selection(view.id) .clone() .transform(|range| movement::move_prev_word_start(text, range, count)); - doc.set_selection(view.id, selection); - delete_selection(cx) + delete_selection_insert_mode(doc, view, &selection); + } + + pub fn delete_word_forward(cx: &mut Context) { + let count = cx.count(); + let (view, doc) = current!(cx.editor); + let text = doc.text().slice(..); + + let selection = doc + .selection(view.id) + .clone() + .transform(|range| movement::move_next_word_start(text, range, count)); + delete_selection_insert_mode(doc, view, &selection); } } @@ -4973,6 +5027,15 @@ fn select_register(cx: &mut Context) { }) } +fn insert_register(cx: &mut Context) { + cx.on_next_key(move |cx, event| { + if let Some(ch) = event.char() { + cx.editor.selected_register = Some(ch); + paste_before(cx); + } + }) +} + fn align_view_top(cx: &mut Context) { let (view, doc) = current!(cx.editor); align_view(doc, view, Align::Top); diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 010714dc..fdf43d87 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -731,21 +731,38 @@ impl Default for Keymaps { "esc" => normal_mode, "backspace" => delete_char_backward, + "C-h" => delete_char_backward, "del" => delete_char_forward, + "C-d" => delete_char_forward, "ret" => insert_newline, "tab" => insert_tab, "C-w" => delete_word_backward, + "A-d" => delete_word_forward, "left" => move_char_left, + "C-b" => move_char_left, "down" => move_line_down, + "C-n" => move_line_down, "up" => move_line_up, + "C-p" => move_line_up, "right" => move_char_right, + "C-f" => move_char_right, + "A-b" => move_prev_word_end, + "A-left" => move_prev_word_end, + "A-f" => move_next_word_start, + "A-right" => move_next_word_start, "pageup" => page_up, "pagedown" => page_down, "home" => goto_line_start, + "C-a" => goto_line_start, "end" => goto_line_end_newline, + "C-e" => goto_line_end_newline, + + "C-k" => kill_to_line_end, + "C-u" => kill_to_line_start, "C-x" => completion, + "C-r" => insert_register, }); Keymaps(hashmap!( Mode::Normal => Keymap::new(normal), diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index deed1609..e90b0772 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -231,6 +231,14 @@ impl Prompt { self.completion = (self.completion_fn)(&self.line); } + pub fn delete_word_forwards(&mut self) { + let pos = self.eval_movement(Movement::ForwardWord(1)); + self.line.replace_range(self.cursor..pos, ""); + + self.exit_selection(); + self.completion = (self.completion_fn)(&self.line); + } + pub fn kill_to_start_of_line(&mut self) { let pos = self.eval_movement(Movement::StartOfLine); self.line.replace_range(pos..self.cursor, ""); @@ -435,6 +443,7 @@ impl Component for Prompt { ctrl!('e') | key!(End) => self.move_end(), ctrl!('a') | key!(Home) => self.move_start(), ctrl!('w') => self.delete_word_backwards(), + alt!('d') => self.delete_word_forwards(), ctrl!('k') => self.kill_to_end_of_line(), ctrl!('u') => self.kill_to_start_of_line(), ctrl!('h') | key!(Backspace) => { -- cgit v1.2.3-70-g09d2 From 8db6fffe90514e38beaf60138c1a8fb8a83ef04c Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Tue, 16 Nov 2021 15:02:48 +0900 Subject: ui: Increase diagnostics sideline width to 100 max and wrap if needed --- helix-term/src/ui/editor.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index bcd9f8f0..03cd0474 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -497,7 +497,7 @@ impl EditorView { use tui::{ layout::Alignment, text::Text, - widgets::{Paragraph, Widget}, + widgets::{Paragraph, Widget, Wrap}, }; let cursor = doc @@ -529,8 +529,10 @@ impl EditorView { lines.extend(text.lines); } - let paragraph = Paragraph::new(lines).alignment(Alignment::Right); - let width = 80.min(viewport.width); + let paragraph = Paragraph::new(lines) + .alignment(Alignment::Right) + .wrap(Wrap { trim: true }); + let width = 100.min(viewport.width); let height = 15.min(viewport.height); paragraph.render( Rect::new(viewport.right() - width, viewport.y + 1, width, height), -- cgit v1.2.3-70-g09d2 From 9dcccb45bbee30011a44fcabaae94a5f6589ff7b Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Thu, 18 Nov 2021 18:40:27 +0900 Subject: ui: Stop hardcoding markdown doc colors --- helix-term/src/ui/markdown.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs index 4144ed3c..72d84271 100644 --- a/helix-term/src/ui/markdown.rs +++ b/helix-term/src/ui/markdown.rs @@ -61,9 +61,15 @@ fn parse<'a>( }) } - let text_style = Style::default().fg(Color::Rgb(164, 160, 232)); // lavender - let code_style = Style::default().fg(Color::Rgb(255, 255, 255)); // white - let heading_style = Style::default().fg(Color::Rgb(219, 191, 239)); // lilac + let text_style = theme.map(|theme| theme.get("ui.text")).unwrap_or_default(); + + // TODO: use better scopes for these, `markup.raw.block`, `markup.heading` + let code_style = theme + .map(|theme| theme.get("ui.text.focus")) + .unwrap_or_default(); // white + let heading_style = theme + .map(|theme| theme.get("ui.linenr.selected")) + .unwrap_or_default(); // lilac for event in parser { match event { -- cgit v1.2.3-70-g09d2 From e9dc658de42aac74cbb3f02a3b2af2c48bb613fb Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Thu, 18 Nov 2021 18:41:44 +0900 Subject: Remove unused imports --- helix-term/src/ui/markdown.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/markdown.rs b/helix-term/src/ui/markdown.rs index 72d84271..61630d55 100644 --- a/helix-term/src/ui/markdown.rs +++ b/helix-term/src/ui/markdown.rs @@ -13,7 +13,7 @@ use helix_core::{ Rope, }; use helix_view::{ - graphics::{Color, Margin, Rect, Style}, + graphics::{Margin, Rect}, Theme, }; -- cgit v1.2.3-70-g09d2