From 11ede8254974aba6e1ef318ab90374fb85e6bf5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Tue, 12 Jan 2016 15:48:17 +0100 Subject: vis: cleanup key binding definitions This removes the tree based mode structures and instead merges all keybindings in flat modes which uses some more memory but will allow (per mode) run-time configurable key bindings. Make sure to update/remove config.h. --- config.def.h | 127 ++++++++++++++++++++++++++++++++++------------------------- main.c | 24 +++-------- vis-cmds.c | 24 ++++------- vis-modes.c | 68 +++----------------------------- vis.c | 4 +- vis.h | 12 +----- 6 files changed, 96 insertions(+), 163 deletions(-) diff --git a/config.def.h b/config.def.h index 918e5ce..73a0193 100644 --- a/config.def.h +++ b/config.def.h @@ -1,46 +1,9 @@ -/* Configure your desired default key bindings. - * - * Vis stores modes in a tree structure. Key lookup starts in the currently active - * mode and continues recursively towards the root of the tree until a match is found. - * This reduces duplication since shared key bindings can be stored in a common - * ancestor mode. - * - * The tree of modes is depicted below. The double line between OPERATOR-OPTION - * and OPERATOR is only in effect once an operator is detected. That is when - * entering the OPERATOR mode its parent is set to OPERATOR-OPTION which makes - * TEXTOBJ reachable. Once the operator is processed (i.e. OPERATOR mode is left) - * its parent mode is reset back to MOVE. - * - * Similarly the +-ed line between OPERATOR and TEXTOBJ is only active within - * the visual modes. - * - * BASIC - * (arrow keys etc.) - * / | - * /-------------------/ | - * READLINE MOVE - * / \ (h,j,k,l ...) - * / \ | \-----------------\ - * / \ | | - * INSERT PROMPT OPERATOR ++++ -TEXTOBJ - * | (history etc) (d,c,y,p ..) + (ia [wsp[]()b<>{}B"'`] ) - * | | \\ + + | - * | | \\ + + | - * REPLACE NORMAL \\ + + | - * | \\ ++ | - * | \\ | - * | \\ | - * VISUAL \\ OPERATOR-OPTION - * | \\ (v,V) - * | \\ // - * | \\======// - * VISUAL-LINE - */ +/* Configure your desired default key bindings. */ #define ALIAS(name) .alias = name, #define ACTION(id) .action = &vis_action[VIS_ACTION_##id], -static KeyBinding basic_movement[] = { +static const KeyBinding bindings_basic[] = { { "", ACTION(EDITOR_SUSPEND) }, { "", ACTION(CURSOR_CHAR_PREV) }, { "", ACTION(CURSOR_LONGWORD_START_PREV) }, @@ -57,7 +20,7 @@ static KeyBinding basic_movement[] = { { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_movements[] = { +static const KeyBinding bindings_motions[] = { { "h", ACTION(CURSOR_CHAR_PREV) }, { "", ALIAS("h") }, { "", ALIAS("") }, @@ -119,7 +82,7 @@ static KeyBinding vis_movements[] = { { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_textobjs[] = { +static const KeyBinding bindings_textobjects[] = { { "aw", ACTION(TEXT_OBJECT_WORD_OUTER) }, { "aW", ACTION(TEXT_OBJECT_LONGWORD_OUTER) }, { "as", ACTION(TEXT_OBJECT_SENTENCE) }, @@ -163,7 +126,7 @@ static KeyBinding vis_textobjs[] = { { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_operators[] = { +static const KeyBinding bindings_operators[] = { { "0", ACTION(COUNT) }, { "1", ACTION(COUNT) }, { "2", ACTION(COUNT) }, @@ -177,10 +140,6 @@ static KeyBinding vis_operators[] = { { "d", ACTION(OPERATOR_DELETE) }, { "c", ACTION(OPERATOR_CHANGE) }, { "y", ACTION(OPERATOR_YANK) }, - { "p", ACTION(PUT_AFTER) }, - { "P", ACTION(PUT_BEFORE) }, - { "gp", ACTION(PUT_AFTER_END) }, - { "gP", ACTION(PUT_BEFORE_END) }, { ">", ACTION(OPERATOR_SHIFT_RIGHT) }, { "<", ACTION(OPERATOR_SHIFT_LEFT) }, { "gU", ACTION(OPERATOR_CASE_UPPER) }, @@ -193,13 +152,13 @@ static KeyBinding vis_operators[] = { { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_operator_options[] = { +static const KeyBinding bindings_operator_options[] = { { "v", ACTION(MOTION_CHARWISE) }, { "V", ACTION(MOTION_LINEWISE) }, { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_mode_normal[] = { +static const KeyBinding bindings_normal[] = { { "", ACTION(CURSORS_REMOVE_ALL) }, { "", ALIAS("x") }, { "", ACTION(CURSORS_NEW_LINE_ABOVE) }, @@ -268,10 +227,14 @@ static KeyBinding vis_mode_normal[] = { { "m", ACTION(MARK_SET) }, { "", ALIAS(":help") }, { "ga", ACTION(UNICODE_INFO) }, + { "p", ACTION(PUT_AFTER) }, + { "P", ACTION(PUT_BEFORE) }, + { "gp", ACTION(PUT_AFTER_END) }, + { "gP", ACTION(PUT_BEFORE_END) }, { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_mode_visual[] = { +static const KeyBinding bindings_visual[] = { { "", ACTION(CURSORS_NEW_MATCH_NEXT) }, { "", ACTION(CURSORS_NEW_MATCH_SKIP) }, { "", ACTION(CURSORS_REMOVE_LAST) }, @@ -293,13 +256,13 @@ static KeyBinding vis_mode_visual[] = { { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_mode_visual_line[] = { +static const KeyBinding bindings_visual_line[] = { { "v", ACTION(MODE_VISUAL) }, { "V", ACTION(MODE_NORMAL) }, { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_mode_readline[] = { +static const KeyBinding bindings_readline[] = { { "", ACTION(DELETE_CHAR_PREV) }, { "", ALIAS("") }, { "", ACTION(DELETE_CHAR_NEXT) }, @@ -312,7 +275,7 @@ static KeyBinding vis_mode_readline[] = { { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_mode_prompt[] = { +static const KeyBinding bindings_prompt[] = { { "", ACTION(PROMPT_BACKSPACE) }, { "", ALIAS("") }, { "", ACTION(PROMPT_ENTER) }, @@ -321,7 +284,7 @@ static KeyBinding vis_mode_prompt[] = { { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_mode_insert[] = { +static const KeyBinding bindings_insert[] = { { "", ACTION(MODE_NORMAL) }, { "", ALIAS("") }, { "", ALIAS("") }, @@ -338,6 +301,62 @@ static KeyBinding vis_mode_insert[] = { { 0 /* empty last element, array terminator */ }, }; -static KeyBinding vis_mode_replace[] = { +static const KeyBinding bindings_replace[] = { { 0 /* empty last element, array terminator */ }, }; + +/* For each mode we list a all key bindings, if a key is bound in more than + * one array the first definition is used and further ones are ignored. */ +static const KeyBinding **default_bindings[] = { + [VIS_MODE_OPERATOR_PENDING] = (const KeyBinding*[]){ + bindings_operator_options, + bindings_operators, + bindings_textobjects, + bindings_motions, + bindings_basic, + NULL, + }, + [VIS_MODE_NORMAL] = (const KeyBinding*[]){ + bindings_normal, + bindings_operators, + bindings_motions, + bindings_basic, + NULL, + }, + [VIS_MODE_VISUAL] = (const KeyBinding*[]){ + bindings_visual, + bindings_textobjects, + bindings_operators, + bindings_motions, + bindings_basic, + NULL, + }, + [VIS_MODE_VISUAL_LINE] = (const KeyBinding*[]){ + bindings_visual_line, + bindings_visual, + bindings_textobjects, + bindings_operators, + bindings_motions, + bindings_basic, + NULL, + }, + [VIS_MODE_INSERT] = (const KeyBinding*[]){ + bindings_insert, + bindings_readline, + bindings_basic, + NULL, + }, + [VIS_MODE_REPLACE] = (const KeyBinding*[]){ + bindings_replace, + bindings_insert, + bindings_readline, + bindings_basic, + NULL, + }, + [VIS_MODE_PROMPT] = (const KeyBinding*[]){ + bindings_prompt, + bindings_readline, + bindings_basic, + NULL, + }, +}; diff --git a/main.c b/main.c index 92ca439..fc4f383 100644 --- a/main.c +++ b/main.c @@ -527,7 +527,7 @@ static KeyAction vis_action[] = { [VIS_ACTION_MODE_OPERATOR_PENDING] = { "vis-mode-operator-pending", "Enter to operator pending mode", - switchmode, { .i = VIS_MODE_OPERATOR } + switchmode, { .i = VIS_MODE_OPERATOR_PENDING } }, [VIS_ACTION_DELETE_CHAR_PREV] = { "delete-char-prev", @@ -1627,21 +1627,6 @@ static const char *unicode_info(Vis *vis, const char *keys, const Arg *arg) { static Vis *vis; -static KeyBinding *default_bindings[] = { - [VIS_MODE_BASIC] = basic_movement, - [VIS_MODE_MOVE] = vis_movements, - [VIS_MODE_TEXTOBJ] = vis_textobjs, - [VIS_MODE_OPERATOR_OPTION] = vis_operator_options, - [VIS_MODE_OPERATOR] = vis_operators, - [VIS_MODE_NORMAL] = vis_mode_normal, - [VIS_MODE_VISUAL] = vis_mode_visual, - [VIS_MODE_VISUAL_LINE] = vis_mode_visual_line, - [VIS_MODE_READLINE] = vis_mode_readline, - [VIS_MODE_PROMPT] = vis_mode_prompt, - [VIS_MODE_INSERT] = vis_mode_insert, - [VIS_MODE_REPLACE] = vis_mode_replace, -}; - static void signal_handler(int signum, siginfo_t *siginfo, void *context) { vis_signal_handler(vis, signum, siginfo, context); } @@ -1669,8 +1654,11 @@ int main(int argc, char *argv[]) { } for (int i = 0; i < LENGTH(default_bindings); i++) { - if (!vis_mode_bindings(vis, i, &default_bindings[i])) - vis_die(vis, "Could not load default bindings\n"); + for (const KeyBinding **binding = default_bindings[i]; binding && *binding; binding++) { + for (const KeyBinding *kb = *binding; kb->key; kb++) { + vis_mode_map(vis, i, kb->key, kb); + } + } } /* install signal handlers etc. */ diff --git a/vis-cmds.c b/vis-cmds.c index f7af52d..7b1e0e7 100644 --- a/vis-cmds.c +++ b/vis-cmds.c @@ -864,9 +864,9 @@ bool print_keybinding(const char *key, void *value, void *data) { return text_appendf(txt, " %-15s\t%s\n", key, desc ? desc : ""); } -static void print_mode(Mode *mode, Text *txt, bool recursive) { - if (recursive && mode->parent) - print_mode(mode->parent, txt, recursive); +static void print_mode(Mode *mode, Text *txt) { + if (!map_empty(mode->bindings)) + text_appendf(txt, "\n %s\n\n", mode->name); map_iterate(mode->bindings, print_keybinding, txt); } @@ -885,20 +885,10 @@ static bool cmd_help(Vis *vis, Filerange *range, enum CmdOpt opt, const char *ar text_appendf(txt, " %-15s\t%s\n", mode->name, mode->help); } - for (int i = 0; i < LENGTH(vis_modes); i++) { - Mode *mode = &vis_modes[i]; - if (mode->isuser && !map_empty(mode->bindings)) { - text_appendf(txt, "\n %s\n\n", mode->name); - print_mode(mode, txt, i == VIS_MODE_NORMAL || - i == VIS_MODE_INSERT); - } - } - - text_appendf(txt, "\n Text objects\n\n"); - print_mode(&vis_modes[VIS_MODE_TEXTOBJ], txt, false); - - text_appendf(txt, "\n Motions\n\n"); - print_mode(&vis_modes[VIS_MODE_MOVE], txt, false); + print_mode(&vis_modes[VIS_MODE_NORMAL], txt); + print_mode(&vis_modes[VIS_MODE_OPERATOR_PENDING], txt); + print_mode(&vis_modes[VIS_MODE_VISUAL], txt); + print_mode(&vis_modes[VIS_MODE_INSERT], txt); text_appendf(txt, "\n :-Commands\n\n"); for (Command *cmd = cmds; cmd && cmd->name[0]; cmd++) diff --git a/vis-modes.c b/vis-modes.c index 7a9d63b..8e245a3 100644 --- a/vis-modes.c +++ b/vis-modes.c @@ -20,25 +20,9 @@ void mode_set(Vis *vis, Mode *new_mode) { vis->win->ui->draw_status(vis->win->ui); } -static bool mode_map(Mode *mode, const char *key, KeyBinding *binding) { - return map_put(mode->bindings, key, binding); -} - -bool vis_mode_map(Vis *vis, enum VisMode modeid, const char *key, KeyBinding *binding) { - Mode *mode = mode_get(vis, modeid); - return mode && mode_map(mode, key, binding); -} - -bool vis_mode_bindings(Vis *vis, enum VisMode modeid, KeyBinding **bindings) { +bool vis_mode_map(Vis *vis, enum VisMode modeid, const char *key, const KeyBinding *binding) { Mode *mode = mode_get(vis, modeid); - if (!mode) - return false; - bool success = true; - for (KeyBinding *kb = *bindings; kb->key; kb++) { - if (!mode_map(mode, kb->key, kb)) - success = false; - } - return success; + return mode && map_put(mode->bindings, key, binding); } bool vis_mode_unmap(Vis *vis, enum VisMode modeid, const char *key) { @@ -48,14 +32,6 @@ bool vis_mode_unmap(Vis *vis, enum VisMode modeid, const char *key) { /** mode switching event handlers */ -static void vis_mode_operator_enter(Vis *vis, Mode *old) { - vis_modes[VIS_MODE_OPERATOR].parent = &vis_modes[VIS_MODE_OPERATOR_OPTION]; -} - -static void vis_mode_operator_leave(Vis *vis, Mode *new) { - vis_modes[VIS_MODE_OPERATOR].parent = &vis_modes[VIS_MODE_MOVE]; -} - static void vis_mode_operator_input(Vis *vis, const char *str, size_t len) { /* invalid operator */ vis_cancel(vis); @@ -68,7 +44,6 @@ static void vis_mode_visual_enter(Vis *vis, Mode *old) { for (Cursor *c = view_cursors(vis->win->view); c; c = view_cursors_next(c)) view_cursors_selection_start(c); } - vis_modes[VIS_MODE_OPERATOR].parent = &vis_modes[VIS_MODE_TEXTOBJ]; } } @@ -78,14 +53,12 @@ static void vis_mode_visual_line_enter(Vis *vis, Mode *old) { for (Cursor *c = view_cursors(vis->win->view); c; c = view_cursors_next(c)) view_cursors_selection_start(c); } - vis_modes[VIS_MODE_OPERATOR].parent = &vis_modes[VIS_MODE_TEXTOBJ]; } vis_motion(vis, VIS_MOVE_LINE_END); } static void vis_mode_visual_line_leave(Vis *vis, Mode *new) { if (!new->visual) { - vis_modes[VIS_MODE_OPERATOR].parent = &vis_modes[VIS_MODE_MOVE]; File *file = vis->win->file; Filerange sel = view_cursors_selection_get(view_cursors(vis->win->view)); file->marks[VIS_MARK_SELECTION_START] = text_mark_set(file->text, sel.start); @@ -99,7 +72,6 @@ static void vis_mode_visual_line_leave(Vis *vis, Mode *new) { static void vis_mode_visual_leave(Vis *vis, Mode *new) { if (!new->visual) { - vis_modes[VIS_MODE_OPERATOR].parent = &vis_modes[VIS_MODE_MOVE]; File *file = vis->win->file; Filerange sel = view_cursors_selection_get(view_cursors(vis->win->view)); file->marks[VIS_MARK_SELECTION_START] = text_mark_set(file->text, sel.start); @@ -178,44 +150,24 @@ static void vis_mode_replace_input(Vis *vis, const char *str, size_t len) { vis_replace_key(vis, str, len); } -/** definition of mode tree structure */ Mode vis_modes[] = { - [VIS_MODE_BASIC] = { - .name = "BASIC", - .parent = NULL, - }, - [VIS_MODE_MOVE] = { - .name = "MOVE", - .parent = &vis_modes[VIS_MODE_BASIC], - }, - [VIS_MODE_TEXTOBJ] = { - .name = "TEXT-OBJECTS", - .parent = &vis_modes[VIS_MODE_MOVE], - }, - [VIS_MODE_OPERATOR_OPTION] = { - .name = "OPERATOR-OPTION", - .parent = &vis_modes[VIS_MODE_TEXTOBJ], - }, - [VIS_MODE_OPERATOR] = { - .name = "OPERATOR", - .parent = &vis_modes[VIS_MODE_MOVE], - .enter = vis_mode_operator_enter, - .leave = vis_mode_operator_leave, + [VIS_MODE_OPERATOR_PENDING] = { + .name = "OPERATOR-PENDING", .input = vis_mode_operator_input, + .help = "", + .isuser = false, }, [VIS_MODE_NORMAL] = { .name = "NORMAL", .status = "", .help = "", .isuser = true, - .parent = &vis_modes[VIS_MODE_OPERATOR], }, [VIS_MODE_VISUAL] = { .name = "VISUAL", .status = "--VISUAL--", .help = "", .isuser = true, - .parent = &vis_modes[VIS_MODE_OPERATOR], .enter = vis_mode_visual_enter, .leave = vis_mode_visual_leave, .visual = true, @@ -225,20 +177,14 @@ Mode vis_modes[] = { .status = "--VISUAL LINE--", .help = "", .isuser = true, - .parent = &vis_modes[VIS_MODE_VISUAL], .enter = vis_mode_visual_line_enter, .leave = vis_mode_visual_line_leave, .visual = true, }, - [VIS_MODE_READLINE] = { - .name = "READLINE", - .parent = &vis_modes[VIS_MODE_BASIC], - }, [VIS_MODE_PROMPT] = { .name = "PROMPT", .help = "", .isuser = true, - .parent = &vis_modes[VIS_MODE_READLINE], .input = vis_mode_prompt_input, .enter = vis_mode_prompt_enter, .leave = vis_mode_prompt_leave, @@ -248,7 +194,6 @@ Mode vis_modes[] = { .status = "--INSERT--", .help = "", .isuser = true, - .parent = &vis_modes[VIS_MODE_READLINE], .enter = vis_mode_insert_enter, .leave = vis_mode_insert_leave, .input = vis_mode_insert_input, @@ -260,7 +205,6 @@ Mode vis_modes[] = { .status = "--REPLACE--", .help = "", .isuser = true, - .parent = &vis_modes[VIS_MODE_INSERT], .enter = vis_mode_replace_enter, .leave = vis_mode_replace_leave, .input = vis_mode_replace_input, diff --git a/vis.c b/vis.c index 6ccd584..7af4654 100644 --- a/vis.c +++ b/vis.c @@ -604,7 +604,7 @@ static void action_do(Vis *vis, Action *a) { } else { vis_prompt_show(vis, ":", "'<,'>!"); } - } else if (vis->mode == &vis_modes[VIS_MODE_OPERATOR]) { + } else if (vis->mode == &vis_modes[VIS_MODE_OPERATOR_PENDING]) { mode_set(vis, vis->mode_prev); } else if (vis->mode->visual) { vis_mode_switch(vis, VIS_MODE_NORMAL); @@ -966,7 +966,7 @@ bool vis_operator(Vis *vis, enum VisOperator id, ...) { /* switch to operator mode inorder to make operator options and * text-object available */ - vis_mode_switch(vis, VIS_MODE_OPERATOR); + vis_mode_switch(vis, VIS_MODE_OPERATOR_PENDING); if (vis->action.op == op) { /* hacky way to handle double operators i.e. things like * dd, yy etc where the second char isn't a movement */ diff --git a/vis.h b/vis.h index e007710..2008724 100644 --- a/vis.h +++ b/vis.h @@ -120,15 +120,10 @@ void vis_die(Vis*, const char *msg, ...) __attribute__((noreturn)); /* user facing modes are: NORMAL, VISUAL, VISUAL_LINE, INSERT, REPLACE. * the others should be considered as implementation details (TODO: do not expose them?) */ enum VisMode { - VIS_MODE_BASIC, - VIS_MODE_MOVE, - VIS_MODE_OPERATOR, - VIS_MODE_OPERATOR_OPTION, VIS_MODE_NORMAL, - VIS_MODE_TEXTOBJ, + VIS_MODE_OPERATOR_PENDING, VIS_MODE_VISUAL, VIS_MODE_VISUAL_LINE, - VIS_MODE_READLINE, VIS_MODE_PROMPT, VIS_MODE_INSERT, VIS_MODE_REPLACE, @@ -138,12 +133,9 @@ enum VisMode { void vis_mode_switch(Vis*, enum VisMode); /* in the specified mode: map a given key to a binding (binding->key is ignored), * fails if key is already mapped */ -bool vis_mode_map(Vis*, enum VisMode, const char *key, KeyBinding*); +bool vis_mode_map(Vis*, enum VisMode, const char *key, const KeyBinding*); /* in the specified mode: unmap a given key, fails if the key is not currently mapped */ bool vis_mode_unmap(Vis*, enum VisMode, const char *key); -/* map a NULL-terminated array of key bindings, return value indicates whether *all* - * bindings were succesfully performed */ -bool vis_mode_bindings(Vis*, enum VisMode, KeyBinding **bindings); /* get the current mode's status line indicator */ const char *vis_mode_status(Vis*); /* associates the special pseudo key name> with the given key action. -- cgit v1.2.3