From d81c8d760848899dccd6f1a7e47cedb8c3afb0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Wed, 13 Jan 2016 10:12:38 +0100 Subject: vis: add infrastructure to support per window key bindings --- vis-core.h | 1 + vis-modes.c | 33 +++++++++++++++++++++++++++------ vis.c | 32 ++++++++++++++++++++++---------- vis.h | 2 ++ 4 files changed, 52 insertions(+), 16 deletions(-) diff --git a/vis-core.h b/vis-core.h index 6554410..3093a92 100644 --- a/vis-core.h +++ b/vis-core.h @@ -119,6 +119,7 @@ struct Win { View *view; /* currently displayed part of underlying text */ RingBuffer *jumplist; /* LRU jump management */ ChangeList changelist; /* state for iterating through least recently changes */ + Mode modes[VIS_MODE_LAST]; /* overlay mods used for per window key bindings */ Win *prev, *next; /* neighbouring windows */ }; diff --git a/vis-modes.c b/vis-modes.c index 8e245a3..0b85ed7 100644 --- a/vis-modes.c +++ b/vis-modes.c @@ -20,14 +20,35 @@ void mode_set(Vis *vis, Mode *new_mode) { vis->win->ui->draw_status(vis->win->ui); } -bool vis_mode_map(Vis *vis, enum VisMode modeid, const char *key, const KeyBinding *binding) { - Mode *mode = mode_get(vis, modeid); - return mode && map_put(mode->bindings, key, binding); +static bool mode_map(Mode *mode, const char *key, const KeyBinding *binding) { + if (!mode) + return false; + if (!mode->bindings) { + mode->bindings = map_new(); + if (!mode->bindings) + return false; + } + return map_put(mode->bindings, key, binding); +} + +bool vis_mode_map(Vis *vis, enum VisMode id, const char *key, const KeyBinding *binding) { + return id < LENGTH(vis_modes) && mode_map(&vis_modes[id], key, binding); +} + +bool vis_window_mode_map(Win *win, enum VisMode id, const char *key, const KeyBinding *binding) { + return id < LENGTH(win->modes) && mode_map(&win->modes[id], key, binding); +} + +static bool mode_unmap(Mode *mode, const char *key) { + return mode && mode->bindings && map_delete(mode->bindings, key); +} + +bool vis_mode_unmap(Vis *vis, enum VisMode id, const char *key) { + return id < LENGTH(vis_modes) && mode_unmap(&vis_modes[id], key); } -bool vis_mode_unmap(Vis *vis, enum VisMode modeid, const char *key) { - Mode *mode = mode_get(vis, modeid); - return mode && map_delete(mode->bindings, key); +bool vis_window_mode_unmap(Win *win, enum VisMode id, const char *key) { + return id < LENGTH(win->modes) && mode_unmap(&win->modes[id], key); } /** mode switching event handlers */ diff --git a/vis.c b/vis.c index 7af4654..8e033ca 100644 --- a/vis.c +++ b/vis.c @@ -150,6 +150,8 @@ static void window_free(Win *win) { if (vis && vis->ui) vis->ui->window_free(win->ui); view_free(win->view); + for (size_t i = 0; i < LENGTH(win->modes); i++) + map_free(win->modes[i].bindings); ringbuf_free(win->jumplist); free(win); } @@ -174,6 +176,8 @@ static Win *window_new_file(Vis *vis, File *file) { vis->windows = win; vis->win = win; vis->ui->window_focus(win->ui); + for (size_t i = 0; i < LENGTH(win->modes); i++) + win->modes[i].parent = &vis_modes[i]; if (vis->event && vis->event->win_open) vis->event->win_open(vis, win); return win; @@ -199,6 +203,12 @@ bool vis_window_split(Win *original) { Win *win = window_new_file(original->vis, original->file); if (!win) return false; + for (size_t i = 0; i < LENGTH(win->modes); i++) { + if (original->modes[i].bindings) + win->modes[i].bindings = map_new(); + if (win->modes[i].bindings) + map_copy(win->modes[i].bindings, original->modes[i].bindings); + } win->file = original->file; win->file->refcount++; view_syntax_set(win->view, view_syntax_get(original->view)); @@ -296,11 +306,6 @@ Vis *vis_new(Ui *ui, VisEvent *event) { vis->ui->init(vis->ui, vis); vis->tabwidth = 8; vis->expandtab = false; - for (int i = 0; i < VIS_MODE_LAST; i++) { - Mode *mode = &vis_modes[i]; - if (!(mode->bindings = map_new())) - goto err; - } if (!(vis->prompt = calloc(1, sizeof(Win)))) goto err; if (!(vis->prompt->file = calloc(1, sizeof(File)))) @@ -341,10 +346,8 @@ void vis_free(Vis *vis) { map_free(vis->options); map_free(vis->actions); buffer_release(&vis->input_queue); - for (int i = 0; i < VIS_MODE_LAST; i++) { - Mode *mode = &vis_modes[i]; - map_free(mode->bindings); - } + for (int i = 0; i < VIS_MODE_LAST; i++) + map_free(vis_modes[i].bindings); free(vis); } @@ -694,7 +697,16 @@ static const char *vis_keys_raw(Vis *vis, Buffer *buf, const char *input) { prefix = false; binding = NULL; - for (Mode *mode = vis->mode; mode && !binding && !prefix; mode = mode->parent) { + Mode *mode = vis->mode; + for (size_t i = 0; i < LENGTH(vis->win->modes); i++) { + if (mode == &vis_modes[i]) { + if (vis->win->modes[i].bindings) + mode = &vis->win->modes[i]; + break; + } + } + + for (; mode && !binding && !prefix; mode = mode->parent) { binding = map_get(mode->bindings, start); /* "<" is never treated as a prefix because it is used to denote * special key symbols */ diff --git a/vis.h b/vis.h index 2008724..d783eea 100644 --- a/vis.h +++ b/vis.h @@ -134,8 +134,10 @@ 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, const KeyBinding*); +bool vis_window_mode_map(Win*, 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); +bool vis_window_mode_unmap(Win*, enum VisMode, const char *key); /* 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