diff --git a/src/input_handler.cc b/src/input_handler.cc index 6edc61b5..2f67953b 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -127,13 +127,15 @@ public: { if (m_hooks_disabled) do_restore_hooks = true; - auto it = keymap.find(key); - if (it != keymap.end()) + auto it = std::lower_bound(keymap.begin(), keymap.end(), key, + [](const NormalCmdDesc& lhs, const Key& rhs) + { return lhs.key < rhs; }); + if (it != keymap.end() and it->key == key) { if (context().options()["autoinfo"].get() >= 2 and context().has_ui()) - context().ui().info_show(key_to_str(key), it->second.docstring, CharCoord{}, + context().ui().info_show(key_to_str(key), it->docstring, CharCoord{}, get_face("Information"), InfoStyle::Prompt); - it->second.func(context(), m_params); + it->func(context(), m_params); } m_params = { 0, '"' }; } diff --git a/src/main.cc b/src/main.cc index 7f83f802..aa195d0c 100644 --- a/src/main.cc +++ b/src/main.cc @@ -528,6 +528,10 @@ int main(int argc, char* argv[]) }; try { + std::sort(keymap.begin(), keymap.end(), + [](const NormalCmdDesc& lhs, const NormalCmdDesc& rhs) + { return lhs.key < rhs.key; }); + ParametersParser parser(params, param_desc); if (parser.has_option("p")) diff --git a/src/normal.cc b/src/normal.cc index 2cf066d0..a1d0f55d 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -1350,169 +1350,169 @@ void move(Context& context, NormalParams params) selections.sort_and_merge_overlapping(); } -const KeyMap keymap = +KeyMap keymap = { - { 'h', { "move left", move } }, - { 'j', { "move down", move } }, - { 'k', { "move up", move } }, - { 'l', { "move right", move } }, + { 'h', "move left", move }, + { 'j', "move down", move }, + { 'k', "move up", move }, + { 'l', "move right", move }, - { 'H', { "extend left", move } }, - { 'J', { "extend down", move } }, - { 'K', { "extend up", move } }, - { 'L', { "extend right", move } }, + { 'H', "extend left", move }, + { 'J', "extend down", move }, + { 'K', "extend up", move }, + { 'L', "extend right", move }, - { 't', { "select to next character", select_to_next_char } }, - { 'f', { "select to next character included", select_to_next_char } }, - { 'T', { "extend to next character", select_to_next_char } }, - { 'F', { "extend to next character included", select_to_next_char } }, - { alt('t'), { "select to previous character", select_to_next_char } }, - { alt('f'), { "select to previous character included", select_to_next_char } }, - { alt('T'), { "extend to previous character", select_to_next_char } }, - { alt('F'), { "extend to previous character included", select_to_next_char } }, + { 't', "select to next character", select_to_next_char }, + { 'f', "select to next character included", select_to_next_char }, + { 'T', "extend to next character", select_to_next_char }, + { 'F', "extend to next character included", select_to_next_char }, + { alt('t'), "select to previous character", select_to_next_char }, + { alt('f'), "select to previous character included", select_to_next_char }, + { alt('T'), "extend to previous character", select_to_next_char }, + { alt('F'), "extend to previous character included", select_to_next_char }, - { 'd', { "erase selected text", erase_selections } }, - { 'c', { "change selected text", change } }, - { 'i', { "insert before selected text", enter_insert_mode } }, - { 'I', { "insert at line begin", enter_insert_mode } }, - { 'a', { "insert after selected text", enter_insert_mode } }, - { 'A', { "insert at line end", enter_insert_mode } }, - { 'o', { "insert on new line below", enter_insert_mode } }, - { 'O', { "insert on new line above", enter_insert_mode } }, - { 'r', { "replace with character", replace_with_char } }, + { 'd', "erase selected text", erase_selections }, + { 'c', "change selected text", change }, + { 'i', "insert before selected text", enter_insert_mode }, + { 'I', "insert at line begin", enter_insert_mode }, + { 'a', "insert after selected text", enter_insert_mode }, + { 'A', "insert at line end", enter_insert_mode }, + { 'o', "insert on new line below", enter_insert_mode }, + { 'O', "insert on new line above", enter_insert_mode }, + { 'r', "replace with character", replace_with_char }, - { 'g', { "go to location", goto_commands } }, - { 'G', { "extend to location", goto_commands } }, + { 'g', "go to location", goto_commands }, + { 'G', "extend to location", goto_commands }, - { 'v', { "move view", view_commands } }, + { 'v', "move view", view_commands }, - { 'y', { "yank selected text", yank } }, - { 'p', { "paste after selected text", repeated> } }, - { 'P', { "paste before selected text", repeated> } }, - { alt('p'), { "paste every yanked selection after selected text", paste_all } }, - { alt('P'), { "paste every yanked selection before selected text", paste_all } }, - { 'R', { "replace selected text with yanked text", paste } }, + { 'y', "yank selected text", yank }, + { 'p', "paste after selected text", repeated> }, + { 'P', "paste before selected text", repeated> }, + { alt('p'), "paste every yanked selection after selected text", paste_all }, + { alt('P'), "paste every yanked selection before selected text", paste_all }, + { 'R', "replace selected text with yanked text", paste }, - { 's', { "select regex matches in selected text", select_regex } }, - { 'S', { "split selected text on regex matches", split_regex } }, - { alt('s'), { "split selected text on line ends", split_lines } }, + { 's', "select regex matches in selected text", select_regex }, + { 'S', "split selected text on regex matches", split_regex }, + { alt('s'), "split selected text on line ends", split_lines }, - { '.', { "repeat last insert command", repeat_last_insert } }, + { '.', "repeat last insert command", repeat_last_insert }, - { '%', { "select whole buffer", [](Context& context, NormalParams) { select_buffer(context.selections()); } } }, + { '%', "select whole buffer", [](Context& context, NormalParams) { select_buffer(context.selections()); } }, - { ':', { "enter command prompt", command } }, - { '|', { "pipe each selection through filter and replace with output", pipe } }, - { alt('|'), { "pipe each selection through command and ignore output", pipe } }, - { '!', { "insert command output", insert_output } }, - { alt('!'), { "append command output", insert_output } }, + { ':', "enter command prompt", command }, + { '|', "pipe each selection through filter and replace with output", pipe }, + { alt('|'), "pipe each selection through command and ignore output", pipe }, + { '!', "insert command output", insert_output }, + { alt('!'), "append command output", insert_output }, - { ' ', { "remove all selection except main", [](Context& context, NormalParams p) { keep_selection(context.selections(), p.count ? p.count-1 : context.selections().main_index()); } } }, - { alt(' '), { "remove main selection", [](Context& context, NormalParams p) { remove_selection(context.selections(), p.count ? p.count-1 : context.selections().main_index()); } } }, - { ';', { "reduce selections to their cursor", [](Context& context, NormalParams) { clear_selections(context.selections()); } } }, - { alt(';'), { "swap selections cursor and anchor", [](Context& context, NormalParams) { flip_selections(context.selections()); } } }, + { ' ', "remove all selection except main", [](Context& context, NormalParams p) { keep_selection(context.selections(), p.count ? p.count-1 : context.selections().main_index()); } }, + { alt(' '), "remove main selection", [](Context& context, NormalParams p) { remove_selection(context.selections(), p.count ? p.count-1 : context.selections().main_index()); } }, + { ';', "reduce selections to their cursor", [](Context& context, NormalParams) { clear_selections(context.selections()); } }, + { alt(';'), "swap selections cursor and anchor", [](Context& context, NormalParams) { flip_selections(context.selections()); } }, - { 'w', { "select to next word start", repeated<&select>> } }, - { 'e', { "select to next word end", repeated>> } }, - { 'b', { "select to prevous word start", repeated>> } }, - { 'W', { "extend to next word start", repeated>> } }, - { 'E', { "extend to next word end", repeated>> } }, - { 'B', { "extend to prevous word start", repeated>> } }, + { 'w', "select to next word start", repeated<&select>> }, + { 'e', "select to next word end", repeated>> }, + { 'b', "select to prevous word start", repeated>> }, + { 'W', "extend to next word start", repeated>> }, + { 'E', "extend to next word end", repeated>> }, + { 'B', "extend to prevous word start", repeated>> }, - { alt('w'), { "select to next WORD start", repeated>> } }, - { alt('e'), { "select to next WORD end", repeated>> } }, - { alt('b'), { "select to prevous WORD start", repeated>> } }, - { alt('W'), { "extend to next WORD start", repeated>> } }, - { alt('E'), { "extend to next WORD end", repeated>> } }, - { alt('B'), { "extend to prevous WORD start", repeated>> } }, + { alt('w'), "select to next WORD start", repeated>> }, + { alt('e'), "select to next WORD end", repeated>> }, + { alt('b'), "select to prevous WORD start", repeated>> }, + { alt('W'), "extend to next WORD start", repeated>> }, + { alt('E'), "extend to next WORD end", repeated>> }, + { alt('B'), "extend to prevous WORD start", repeated>> }, - { alt('l'), { "select to line end", repeated> } }, - { alt('L'), { "extend to line end", repeated> } }, - { alt('h'), { "select to line begin", repeated> } }, - { alt('H'), { "extend to line begin", repeated> } }, + { alt('l'), "select to line end", repeated> }, + { alt('L'), "extend to line end", repeated> }, + { alt('h'), "select to line begin", repeated> }, + { alt('H'), "extend to line begin", repeated> }, - { 'x', { "select line", repeated> } }, - { 'X', { "extend line", repeated> } }, - { alt('x'), { "extend selections to whole lines", select } }, - { alt('X'), { "crop selections to whole lines", select } }, + { 'x', "select line", repeated> }, + { 'X', "extend line", repeated> }, + { alt('x'), "extend selections to whole lines", select }, + { alt('X'), "crop selections to whole lines", select }, - { 'm', { "select to matching character", select } }, - { 'M', { "extend to matching character", select } }, + { 'm', "select to matching character", select }, + { 'M', "extend to matching character", select }, - { '/', { "select next given regex match", search } }, - { '?', { "extend with next given regex match", search } }, - { alt('/'), { "select previous given regex match", search } }, - { alt('?'), { "extend with previous given regex match", search } }, - { 'n', { "select next current search pattern match", search_next } }, - { 'N', { "extend with next current search pattern match", search_next } }, - { alt('n'), { "select previous current search pattern match", search_next } }, - { alt('N'), { "extend with previous current search pattern match", search_next } }, - { '*', { "set search pattern to main selection content", use_selection_as_search_pattern } }, - { alt('*'), { "set search pattern to main selection content, do not detect words", use_selection_as_search_pattern } }, + { '/', "select next given regex match", search }, + { '?', "extend with next given regex match", search }, + { alt('/'), "select previous given regex match", search }, + { alt('?'), "extend with previous given regex match", search }, + { 'n', "select next current search pattern match", search_next }, + { 'N', "extend with next current search pattern match", search_next }, + { alt('n'), "select previous current search pattern match", search_next }, + { alt('N'), "extend with previous current search pattern match", search_next }, + { '*', "set search pattern to main selection content", use_selection_as_search_pattern }, + { alt('*'), "set search pattern to main selection content, do not detect words", use_selection_as_search_pattern }, - { 'u', { "undo", undo } }, - { 'U', { "redo", redo } }, + { 'u', "undo", undo }, + { 'U', "redo", redo }, - { alt('i'), { "select inner object", select_object } }, - { alt('a'), { "select whole object", select_object } }, - { '[', { "select to object start", select_object } }, - { ']', { "select to object end", select_object } }, - { '{', { "extend to object start", select_object } }, - { '}', { "extend to object end", select_object } }, - { alt('['), { "select to inner object start", select_object } }, - { alt(']'), { "select to inner object end", select_object } }, - { alt('{'), { "extend to inner object start", select_object } }, - { alt('}'), { "extend to inner object end", select_object } }, + { alt('i'), "select inner object", select_object }, + { alt('a'), "select whole object", select_object }, + { '[', "select to object start", select_object }, + { ']', "select to object end", select_object }, + { '{', "extend to object start", select_object }, + { '}', "extend to object end", select_object }, + { alt('['), "select to inner object start", select_object }, + { alt(']'), "select to inner object end", select_object }, + { alt('{'), "extend to inner object start", select_object }, + { alt('}'), "extend to inner object end", select_object }, - { alt('j'), { "join lines", join_lines } }, - { alt('J'), { "join lines and select spaces", join_lines_select_spaces } }, + { alt('j'), "join lines", join_lines }, + { alt('J'), "join lines and select spaces", join_lines_select_spaces }, - { alt('k'), { "keep selections matching given regex", keep } }, - { alt('K'), { "keep selections not matching given regex", keep } }, - { '$', { "pipe each selection through shell command and keep the ones whose command succeed", keep_pipe } }, + { alt('k'), "keep selections matching given regex", keep }, + { alt('K'), "keep selections not matching given regex", keep }, + { '$', "pipe each selection through shell command and keep the ones whose command succeed", keep_pipe }, - { '<', { "deindent", deindent } }, - { '>', { "indent", indent } }, - { alt('>'), { "indent, including empty lines", indent } }, - { alt('<'), { "deindent, not including incomplete indent", deindent } }, + { '<', "deindent", deindent }, + { '>', "indent", indent }, + { alt('>'), "indent, including empty lines", indent }, + { alt('<'), "deindent, not including incomplete indent", deindent }, - { ctrl('i'), { "jump forward in jump list",jump } }, - { ctrl('o'), { "jump backward in jump list", jump } }, - { ctrl('s'), { "push current selections in jump list", save_selections } }, + { ctrl('i'), "jump forward in jump list",jump }, + { ctrl('o'), "jump backward in jump list", jump }, + { ctrl('s'), "push current selections in jump list", save_selections }, - { alt('r'), { "rotate main selection", rotate_selections } }, - { alt('R'), { "rotate selections content", rotate_selections_content } }, + { alt('r'), "rotate main selection", rotate_selections }, + { alt('R'), "rotate selections content", rotate_selections_content }, - { 'q', { "replay recorded macro", replay_macro } }, - { 'Q', { "start or end macro recording", start_or_end_macro_recording } }, + { 'q', "replay recorded macro", replay_macro }, + { 'Q', "start or end macro recording", start_or_end_macro_recording }, - { Key::Escape, { "end macro recording", end_macro_recording } }, + { Key::Escape, "end macro recording", end_macro_recording }, - { '`', { "convert to lower case in selections", for_each_char } }, - { '~', { "convert to upper case in selections", for_each_char } }, - { alt('`'), { "swap case in selections", for_each_char } }, + { '`', "convert to lower case in selections", for_each_char }, + { '~', "convert to upper case in selections", for_each_char }, + { alt('`'), "swap case in selections", for_each_char }, - { '&', { "align selection cursors", align } }, - { alt('&'), { "copy indentation", copy_indent } }, + { '&', "align selection cursors", align }, + { alt('&'), "copy indentation", copy_indent }, - { '@', { "convert tabs to spaces in selections", tabs_to_spaces } }, - { alt('@'), { "convert spaces to tabs in selections", spaces_to_tabs } }, + { '@', "convert tabs to spaces in selections", tabs_to_spaces }, + { alt('@'), "convert spaces to tabs in selections", spaces_to_tabs }, - { 'C', { "copy selection on next lines", copy_selections_on_next_lines } }, - { alt('C'), { "copy selection on previous lines", copy_selections_on_next_lines } }, + { 'C', "copy selection on next lines", copy_selections_on_next_lines }, + { alt('C'), "copy selection on previous lines", copy_selections_on_next_lines }, - { ',', { "user mappings", exec_user_mappings } }, + { ',', "user mappings", exec_user_mappings }, - { Key::Left, { "move left", move } }, - { Key::Down, { "move down", move } }, - { Key::Up, { "move up", move } }, - { Key::Right, { "move right", move } }, + { Key::Left, "move left", move }, + { Key::Down, "move down", move }, + { Key::Up, "move up", move }, + { Key::Right, "move right", move }, - { ctrl('b'), { "scroll one page up", scroll } }, - { ctrl('f'), { "scroll one page down", scroll } }, + { ctrl('b'), "scroll one page up", scroll }, + { ctrl('f'), "scroll one page down", scroll }, - { Key::PageUp, { "scroll one page up", scroll } }, - { Key::PageDown, { "scroll one page down", scroll } }, + { Key::PageUp, "scroll one page up", scroll }, + { Key::PageDown, "scroll one page down", scroll }, }; } diff --git a/src/normal.hh b/src/normal.hh index 7f90075d..4a453415 100644 --- a/src/normal.hh +++ b/src/normal.hh @@ -18,12 +18,13 @@ struct NormalParams struct NormalCmdDesc { + Key key; StringView docstring; void (*func)(Context& context, NormalParams params); }; -using KeyMap = UnorderedMap; -extern const KeyMap keymap; +using KeyMap = Vector; +extern KeyMap keymap; }