Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

readline style insert mode #1039

Merged
merged 11 commits into from
Nov 15, 2021
30 changes: 23 additions & 7 deletions book/src/keymap.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,11 +235,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

Expand Down Expand Up @@ -277,14 +292,15 @@ 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 |
| `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 |
| `Tab` | Select next completion item |
| `BackTab` | Select previous completion item |
| `Tab` | Select next completion item |
| `BackTab` | Select previous completion item |
| `Enter` | Open selected |

58 changes: 57 additions & 1 deletion helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,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",
Expand Down Expand Up @@ -279,6 +280,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",
yank, "Yank selection",
Expand Down Expand Up @@ -321,6 +325,7 @@ impl Command {
vsplit, "Vertical right split",
wclose, "Close window",
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",
Expand Down Expand Up @@ -563,6 +568,16 @@ fn extend_to_line_start(cx: &mut Context) {
goto_line_start_impl(view, doc, Movement::Extend)
}

fn kill_to_line_start(cx: &mut Context) {
extend_to_line_start(cx);
delete_selection_insert_mode(cx);
}

fn kill_to_line_end(cx: &mut Context) {
extend_to_line_end(cx);
delete_selection_insert_mode(cx);
}

fn goto_first_nonwhitespace(cx: &mut Context) {
let (view, doc) = current!(cx.editor);
let text = doc.text().slice(..);
Expand Down Expand Up @@ -639,6 +654,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)
}
Expand Down Expand Up @@ -1541,6 +1560,21 @@ fn delete_selection_impl(reg: &mut Register, doc: &mut Document, view_id: ViewId
doc.apply(&transaction, view_id);
}

fn delete_selection_insert_mode(cx: &mut Context) {
let (view, doc) = current!(cx.editor);
let view_id = view.id;
let selection = doc.selection(view_id);

// then delete
let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
(range.from(), range.to(), None)
});
doc.apply(&transaction, view_id);

// exit select mode, if currently in select mode
exit_select_mode(cx);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please just use delete_selection_impl. In insert mode we don't want to do any logic related to exiting select mode.

Copy link
Contributor Author

@QiBaobin QiBaobin Nov 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The delete_selection_impl would yank the text to a register, is there a _ register for this? And I think we need create a selection to use delete_selection_impl too, does it mean that we already touch selection data?

fn delete_selection_impl(reg: &mut Register, doc: &mut Document, view_id: ViewId) {
    let text = doc.text().slice(..);
    let selection = doc.selection(view_id);

    // first yank the selection
    let values: Vec<String> = selection.fragments(text).map(Cow::into_owned).collect();
    reg.write(values);

    // then delete
    let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
        (range.from(), range.to(), None)
    });
    doc.apply(&transaction, view_id);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe use

    let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
        (range.from(), range.to(), None)
    });
    doc.apply(&transaction, view_id);

directly in your implementations then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still need to make a selection to pass in change_by_selection, right? So I just need remove the exit_select_mode(cx);?

}

fn delete_selection(cx: &mut Context) {
let reg_name = cx.register.unwrap_or('"');
let (view, doc) = current!(cx.editor);
Expand Down Expand Up @@ -3830,7 +3864,20 @@ pub mod insert {
.clone()
.transform(|range| movement::move_prev_word_start(text, range, count));
doc.set_selection(view.id, selection);
delete_selection(cx)
delete_selection_insert_mode(cx)
}

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));
doc.set_selection(view.id, selection);
delete_selection_insert_mode(cx)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah you still need to build a selection, but rather than use set_selection you can just use it directly:

Suggested change
let selection = doc
.selection(view.id)
.clone()
.transform(|range| movement::move_next_word_start(text, range, count));
doc.set_selection(view.id, selection);
delete_selection_insert_mode(cx)
let selection = doc
.selection(view.id)
.clone()
.transform(|range| movement::move_next_word_start(text, range, count));
// then delete
let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
(range.from(), range.to(), None)
});
doc.apply(&transaction, view_id);

You can just inline the delete_selection_insert_mode code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestions, updated the code.

}
}

Expand Down Expand Up @@ -4731,6 +4778,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);
}
})
}
sudormrfbin marked this conversation as resolved.
Show resolved Hide resolved

fn align_view_top(cx: &mut Context) {
let (view, doc) = current!(cx.editor);
align_view(doc, view, Align::Top);
Expand Down
17 changes: 17 additions & 0 deletions helix-term/src/keymap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -651,21 +651,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),
Expand Down
12 changes: 12 additions & 0 deletions helix-term/src/ui/prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,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, "");
Expand Down Expand Up @@ -484,6 +492,10 @@ impl Component for Prompt {
code: KeyCode::Char('w'),
modifiers: KeyModifiers::CONTROL,
} => self.delete_word_backwards(),
KeyEvent {
code: KeyCode::Char('d'),
modifiers: KeyModifiers::ALT,
} => self.delete_word_forwards(),
KeyEvent {
code: KeyCode::Char('k'),
modifiers: KeyModifiers::CONTROL,
Expand Down