helix-mods/helix-term/src/keymap.rs

351 lines
11 KiB
Rust
Raw Normal View History

use crate::commands::{self, Command};
2020-10-23 06:51:08 +02:00
use helix_core::hashmap;
use helix_view::document::Mode;
2020-06-07 17:28:17 +02:00
use std::collections::HashMap;
// Kakoune-inspired:
// mode = {
// normal = {
// q = record_macro
// w = (next) word
2020-09-28 18:00:35 +02:00
// W = next WORD
2020-06-07 17:28:17 +02:00
// e = end of word
2020-09-28 18:00:35 +02:00
// E = end of WORD
2020-06-07 17:28:17 +02:00
// r =
// t = 'till char
// y = yank
// u = undo
// U = redo
// i = insert
// I = INSERT (start of line)
// o = open below (insert on new line below)
// O = open above (insert on new line above)
// p = paste (before cursor)
// P = PASTE (after cursor)
// ` =
// [ = select to text object start (alt = select whole object)
// ] = select to text object end
// { = extend to inner object start
// } = extend to inner object end
// a = append
// A = APPEND (end of line)
// s = split
// S = select
// d = delete()
// f = find_char()
// g = goto (gg, G, gc, gd, etc)
//
// h = move_char_left(n) || arrow-left = move_char_left(n)
// j = move_line_down(n) || arrow-down = move_line_down(n)
// k = move_line_up(n) || arrow_up = move_line_up(n)
// l = move_char_right(n) || arrow-right = move_char_right(n)
2020-06-07 17:28:17 +02:00
// : = command line
// ; = collapse selection to cursor
// " = use register
// ` = convert case? (to lower) (alt = swap case)
// ~ = convert to upper case
// . = repeat last command
// \ = disable hook?
// / = search
// > = indent
// < = deindent
// % = select whole buffer (in vim = jump to matching bracket)
// * = search pattern in selection
// ( = rotate main selection backward
// ) = rotate main selection forward
// - = trim selections? (alt = merge contiguous sel together)
// @ = convert tabs to spaces
// & = align cursor
// ? = extend to next given regex match (alt = to prev)
//
2020-09-28 18:00:35 +02:00
// in kakoune these are alt-h alt-l / gh gl
// select from curs to begin end / move curs to begin end
// 0 = start of line
// ^ = start of line (first non blank char)
// $ = end of line
//
2020-06-07 17:28:17 +02:00
// z = save selections
// Z = restore selections
// x = select line
// X = extend line
// c = change selected text
// C = copy selection?
// v = view menu (viewport manipulation)
// b = select to previous word start
// B = select to previous WORD start
//
//
//
//
//
//
// = = align?
// + =
// }
//
// gd = goto definition
// gr = goto reference
2020-06-07 17:28:17 +02:00
// }
// #[cfg(feature = "term")]
2021-03-30 11:19:27 +02:00
pub use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
2020-06-07 17:28:17 +02:00
2021-03-30 11:19:27 +02:00
pub type Keymap = HashMap<KeyEvent, Command>;
pub type Keymaps = HashMap<Mode, Keymap>;
2021-03-30 11:19:27 +02:00
#[macro_export]
2020-10-01 09:06:42 +02:00
macro_rules! key {
2021-03-30 11:19:27 +02:00
($($ch:tt)*) => {
KeyEvent {
code: KeyCode::Char($($ch)*),
modifiers: KeyModifiers::NONE,
2020-10-01 09:06:42 +02:00
}
};
}
2020-10-05 17:58:16 +02:00
macro_rules! ctrl {
2021-03-30 11:19:27 +02:00
($($ch:tt)*) => {
KeyEvent {
code: KeyCode::Char($($ch)*),
modifiers: KeyModifiers::CONTROL,
2020-10-05 17:58:16 +02:00
}
};
}
2021-01-22 09:13:14 +01:00
macro_rules! alt {
2021-03-30 11:19:27 +02:00
($($ch:tt)*) => {
KeyEvent {
code: KeyCode::Char($($ch)*),
modifiers: KeyModifiers::ALT,
2021-01-22 09:13:14 +01:00
}
};
}
2020-10-09 09:58:43 +02:00
pub fn default() -> Keymaps {
2021-03-01 06:31:34 +01:00
let normal = hashmap!(
key!('h') => commands::move_char_left as Command,
key!('j') => commands::move_line_down,
key!('k') => commands::move_line_up,
key!('l') => commands::move_char_right,
KeyEvent {
code: KeyCode::Left,
modifiers: KeyModifiers::NONE
} => commands::move_char_left,
KeyEvent {
code: KeyCode::Down,
modifiers: KeyModifiers::NONE
} => commands::move_line_down,
KeyEvent {
code: KeyCode::Up,
modifiers: KeyModifiers::NONE
} => commands::move_line_up,
KeyEvent {
code: KeyCode::Right,
modifiers: KeyModifiers::NONE
} => commands::move_char_right,
key!('t') => commands::find_till_char,
key!('f') => commands::find_next_char,
2021-06-02 22:45:36 +02:00
key!('T') => commands::till_prev_char,
key!('F') => commands::find_prev_char,
2021-03-01 06:31:34 +01:00
// and matching set for select mode (extend)
2021-03-19 10:01:08 +01:00
//
key!('r') => commands::replace,
2021-03-01 06:31:34 +01:00
key!('w') => commands::move_next_word_start,
key!('b') => commands::move_prev_word_start,
key!('e') => commands::move_next_word_end,
key!('v') => commands::select_mode,
key!('g') => commands::goto_mode,
key!(':') => commands::command_mode,
key!('i') => commands::insert_mode,
2021-06-02 22:45:36 +02:00
key!('I') => commands::prepend_to_line,
2021-03-01 06:31:34 +01:00
key!('a') => commands::append_mode,
2021-06-02 22:45:36 +02:00
key!('A') => commands::append_to_line,
2021-03-01 06:31:34 +01:00
key!('o') => commands::open_below,
2021-06-02 22:45:36 +02:00
key!('O') => commands::open_above,
2021-03-01 06:31:34 +01:00
// [<space> ]<space> equivalents too (add blank new line, no edit)
key!('d') => commands::delete_selection,
// TODO: also delete without yanking
key!('c') => commands::change_selection,
// TODO: also change delete without yanking
// key!('r') => commands::replace_with_char,
key!('s') => commands::select_regex,
alt!('s') => commands::split_selection_on_newline,
2021-06-02 22:45:36 +02:00
key!('S') => commands::split_selection,
2021-03-01 06:31:34 +01:00
key!(';') => commands::collapse_selection,
alt!(';') => commands::flip_selections,
key!('%') => commands::select_all,
key!('x') => commands::select_line,
2021-06-02 22:45:36 +02:00
key!('X') => commands::extend_line,
2021-03-01 06:31:34 +01:00
// or select mode X?
// extend_to_whole_line, crop_to_whole_line
key!('m') => commands::match_brackets,
// TODO: refactor into
2021-03-01 06:31:34 +01:00
// key!('m') => commands::select_to_matching,
// key!('M') => commands::back_select_to_matching,
// select mode extend equivalents
// key!('.') => commands::repeat_insert,
// repeat_select
// TODO: figure out what key to use
key!('[') => commands::expand_selection,
key!('/') => commands::search,
// ? for search_reverse
2021-03-01 06:31:34 +01:00
key!('n') => commands::search_next,
2021-06-02 22:45:36 +02:00
key!('N') => commands::extend_search_next,
// N for search_prev
2021-03-01 06:31:34 +01:00
key!('*') => commands::search_selection,
key!('u') => commands::undo,
2021-06-02 22:45:36 +02:00
key!('U') => commands::redo,
2021-03-01 06:31:34 +01:00
key!('y') => commands::yank,
// yank_all
2021-04-07 10:03:29 +02:00
key!('p') => commands::paste_after,
2021-03-01 06:31:34 +01:00
// paste_all
2021-06-02 22:45:36 +02:00
key!('P') => commands::paste_before,
2021-03-01 06:31:34 +01:00
key!('>') => commands::indent,
key!('<') => commands::unindent,
key!('=') => commands::format_selections,
2021-06-02 22:45:36 +02:00
key!('J') => commands::join_selections,
// TODO: conflicts hover/doc
2021-06-02 22:45:36 +02:00
key!('K') => commands::keep_selections,
// TODO: and another method for inverse
2021-04-09 17:21:54 +02:00
// TODO: clashes with space mode
key!(' ') => commands::keep_primary_selection,
2021-03-01 06:31:34 +01:00
// key!('q') => commands::record_macro,
// key!('Q') => commands::replay_macro,
// ~ / apostrophe => change case
// & align selections
// _ trim selections
// C / altC = copy (repeat) selections on prev/next lines
2021-03-30 11:19:27 +02:00
KeyEvent {
2021-03-01 06:31:34 +01:00
code: KeyCode::Esc,
2021-03-30 11:19:27 +02:00
modifiers: KeyModifiers::NONE
2021-03-01 06:31:34 +01:00
} => commands::normal_mode,
2021-03-30 11:19:27 +02:00
KeyEvent {
2021-03-01 06:31:34 +01:00
code: KeyCode::PageUp,
2021-03-30 11:19:27 +02:00
modifiers: KeyModifiers::NONE
2021-03-01 06:31:34 +01:00
} => commands::page_up,
ctrl!('b') => commands::page_up,
2021-03-30 11:19:27 +02:00
KeyEvent {
2021-03-01 06:31:34 +01:00
code: KeyCode::PageDown,
2021-03-30 11:19:27 +02:00
modifiers: KeyModifiers::NONE
2021-03-01 06:31:34 +01:00
} => commands::page_down,
ctrl!('f') => commands::page_down,
2021-03-01 06:31:34 +01:00
ctrl!('u') => commands::half_page_up,
ctrl!('d') => commands::half_page_down,
2021-03-30 11:19:27 +02:00
KeyEvent {
2021-03-01 06:31:34 +01:00
code: KeyCode::Tab,
2021-03-30 11:19:27 +02:00
modifiers: KeyModifiers::NONE
2021-03-01 06:31:34 +01:00
} => commands::next_view,
// move under <space>c
ctrl!('c') => commands::toggle_comments,
2021-06-02 22:45:36 +02:00
key!('K') => commands::hover,
2021-03-01 06:31:34 +01:00
// z family for save/restore/combine from/to sels from register
2021-03-24 10:01:26 +01:00
ctrl!('i') => commands::jump_forward, // TODO: ctrl-i conflicts tab
ctrl!('o') => commands::jump_backward,
// ctrl!('s') => commands::save_selection,
key!(' ') => commands::space_mode,
2021-04-14 10:15:11 +02:00
key!('z') => commands::view_mode,
2021-03-01 06:31:34 +01:00
);
// TODO: decide whether we want normal mode to also be select mode (kakoune-like), or whether
// we keep this separate select mode. More keys can fit into normal mode then, but it's weird
// because some selection operations can now be done from normal mode, some from select mode.
let mut select = normal.clone();
select.extend(
hashmap!(
key!('h') => commands::extend_char_left as Command,
key!('j') => commands::extend_line_down,
key!('k') => commands::extend_line_up,
key!('l') => commands::extend_char_right,
KeyEvent {
code: KeyCode::Left,
modifiers: KeyModifiers::NONE
} => commands::extend_char_left,
KeyEvent {
code: KeyCode::Down,
modifiers: KeyModifiers::NONE
} => commands::extend_line_down,
KeyEvent {
code: KeyCode::Up,
modifiers: KeyModifiers::NONE
} => commands::extend_line_up,
KeyEvent {
code: KeyCode::Right,
modifiers: KeyModifiers::NONE
} => commands::extend_char_right,
2021-03-01 06:31:34 +01:00
key!('w') => commands::extend_next_word_start,
key!('b') => commands::extend_prev_word_start,
key!('e') => commands::extend_next_word_end,
key!('t') => commands::extend_till_char,
key!('f') => commands::extend_next_char,
2021-06-02 22:45:36 +02:00
key!('T') => commands::extend_till_prev_char,
key!('F') => commands::extend_prev_char,
2021-03-30 11:19:27 +02:00
KeyEvent {
2021-03-01 06:31:34 +01:00
code: KeyCode::Esc,
2021-03-30 11:19:27 +02:00
modifiers: KeyModifiers::NONE
2021-03-01 06:31:34 +01:00
} => commands::exit_select_mode as Command,
)
.into_iter(),
);
2020-06-07 17:28:17 +02:00
hashmap!(
2021-03-01 06:31:34 +01:00
// as long as you cast the first item, rust is able to infer the other cases
// TODO: select could be normal mode with some bindings merged over
Mode::Normal => normal,
Mode::Select => select,
Mode::Insert => hashmap!(
2021-03-30 11:19:27 +02:00
KeyEvent {
2021-03-01 06:31:34 +01:00
code: KeyCode::Esc,
2021-03-30 11:19:27 +02:00
modifiers: KeyModifiers::NONE
2021-03-01 06:31:34 +01:00
} => commands::normal_mode as Command,
2021-03-30 11:19:27 +02:00
KeyEvent {
2021-03-01 06:31:34 +01:00
code: KeyCode::Backspace,
2021-03-30 11:19:27 +02:00
modifiers: KeyModifiers::NONE
2021-03-01 06:31:34 +01:00
} => commands::insert::delete_char_backward,
2021-03-30 11:19:27 +02:00
KeyEvent {
2021-03-01 06:31:34 +01:00
code: KeyCode::Delete,
2021-03-30 11:19:27 +02:00
modifiers: KeyModifiers::NONE
2021-03-01 06:31:34 +01:00
} => commands::insert::delete_char_forward,
2021-03-30 11:19:27 +02:00
KeyEvent {
2021-03-01 06:31:34 +01:00
code: KeyCode::Enter,
2021-03-30 11:19:27 +02:00
modifiers: KeyModifiers::NONE
2021-03-01 06:31:34 +01:00
} => commands::insert::insert_newline,
2021-03-30 11:19:27 +02:00
KeyEvent {
2021-03-01 06:31:34 +01:00
code: KeyCode::Tab,
2021-03-30 11:19:27 +02:00
modifiers: KeyModifiers::NONE
2021-03-01 06:31:34 +01:00
} => commands::insert::insert_tab,
ctrl!('x') => commands::completion,
),
2020-06-07 17:31:11 +02:00
)
2020-06-07 17:28:17 +02:00
}