aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2016-01-12 15:48:17 +0100
committerMarc André Tanner <mat@brain-dump.org>2016-01-13 21:38:19 +0100
commit11ede8254974aba6e1ef318ab90374fb85e6bf5c (patch)
tree248276ff41ce2efe9bc0280e54905dc977a45c6d
parent24bf7a500ecad7091f92cf9063d0b6cbbf678db1 (diff)
downloadvis-11ede8254974aba6e1ef318ab90374fb85e6bf5c.tar.gz
vis-11ede8254974aba6e1ef318ab90374fb85e6bf5c.tar.xz
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.
-rw-r--r--config.def.h127
-rw-r--r--main.c24
-rw-r--r--vis-cmds.c24
-rw-r--r--vis-modes.c68
-rw-r--r--vis.c4
-rw-r--r--vis.h12
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[] = {
{ "<C-z>", ACTION(EDITOR_SUSPEND) },
{ "<Left>", ACTION(CURSOR_CHAR_PREV) },
{ "<S-Left>", 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) },
{ "<Backspace>", ALIAS("h") },
{ "<C-h>", ALIAS("<Backspace>") },
@@ -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[] = {
{ "<Escape>", ACTION(CURSORS_REMOVE_ALL) },
{ "<Delete>", ALIAS("x") },
{ "<C-k>", ACTION(CURSORS_NEW_LINE_ABOVE) },
@@ -268,10 +227,14 @@ static KeyBinding vis_mode_normal[] = {
{ "m", ACTION(MARK_SET) },
{ "<F1>", ALIAS(":help<Enter>") },
{ "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[] = {
{ "<C-n>", ACTION(CURSORS_NEW_MATCH_NEXT) },
{ "<C-x>", ACTION(CURSORS_NEW_MATCH_SKIP) },
{ "<C-p>", 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[] = {
{ "<Backspace>", ACTION(DELETE_CHAR_PREV) },
{ "<C-h>", ALIAS("<Backspace>") },
{ "<Delete>", 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[] = {
{ "<Backspace>", ACTION(PROMPT_BACKSPACE) },
{ "<C-h>", ALIAS("<Backspace>") },
{ "<Enter>", 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[] = {
{ "<Escape>", ACTION(MODE_NORMAL) },
{ "<C-c>", ALIAS("<Escape>") },
{ "<C-i>", ALIAS("<Tab>") },
@@ -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 <keyaction->name> with the given key action.