vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

commit 86d9ad0e6ae04679ac35cfa211d9e3044973748d
parent 3e679c586493c400e38c3598d80f7d7899ccd0d1
Author: Marc André Tanner <mat@brain-dump.org>
Date:   Tue, 27 Dec 2016 23:22:01 +0100

vis: properly free dynamic key bindings

The handling of :unmap needs to be revisited at some point.

Diffstat:
Mvis-cmds.c | 4++--
Mvis-core.h | 1+
Mvis-lua.c | 10+++++-----
Mvis-modes.c | 29+++++++++++++++++++++++++++++
Mvis.c | 4++++
Mvis.h | 3+++
6 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/vis-cmds.c b/vis-cmds.c @@ -791,7 +791,7 @@ static bool cmd_map(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor const char *lhs = argv[2]; char *rhs = strdup(argv[3]); - if (!rhs || !(binding = calloc(1, sizeof *binding))) + if (!rhs || !(binding = vis_binding_new(vis))) goto err; binding->alias = rhs; @@ -804,7 +804,7 @@ static bool cmd_map(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor err: if (!mapped) { free(rhs); - free(binding); + vis_binding_free(vis, binding); } return mapped; } diff --git a/vis-core.h b/vis-core.h @@ -188,6 +188,7 @@ struct Vis { VisEvent *event; Array motions; Array textobjects; + Array bindings; }; enum VisEvents { diff --git a/vis-lua.c b/vis-lua.c @@ -669,8 +669,11 @@ static int keymap(lua_State *L, Vis *vis, Win *win) { if (!key || !lua_isfunction(L, 4)) goto err; const char *help = luaL_optstring(L, 5, NULL); - if (!(binding = calloc(1, sizeof *binding)) || !(action = calloc(1, sizeof *action))) + if (!(binding = vis_binding_new(vis))) goto err; + if (!(action = calloc(1, sizeof *action))) + goto err; + binding->action = action; /* store reference to function in the registry */ lua_pushvalue(L, 4); @@ -687,8 +690,6 @@ static int keymap(lua_State *L, Vis *vis, Win *win) { }, }; - binding->action = action; - if (win) { if (!vis_window_mode_map(win, mode, true, key, binding)) goto err; @@ -700,8 +701,7 @@ static int keymap(lua_State *L, Vis *vis, Win *win) { lua_pushboolean(L, true); return 1; err: - free(binding); - free(action); + vis_binding_free(vis, binding); lua_pushboolean(L, false); return 1; } diff --git a/vis-modes.c b/vis-modes.c @@ -2,6 +2,35 @@ #include "vis-core.h" #include "util.h" +KeyBinding *vis_binding_new(Vis *vis) { + KeyBinding *binding = calloc(1, sizeof *binding); + if (binding && array_add_ptr(&vis->bindings, binding)) + return binding; + free(binding); + return NULL; +} + +void vis_binding_free(Vis *vis, KeyBinding *binding) { + if (!binding) + return; + size_t len = array_length(&vis->bindings); + for (size_t i = 0; i < len; i++) { + if (binding == array_get_ptr(&vis->bindings, i)) { + if (binding->alias) + free((char*)binding->alias); + const KeyAction *action = binding->action; + if (action) { + free((char*)action->name); + free((char*)action->help); + free((KeyAction*)action); + } + free(binding); + array_remove(&vis->bindings, i); + break; + } + } +} + static Mode *mode_get(Vis *vis, enum VisMode mode) { if (mode < LENGTH(vis_modes)) return &vis_modes[mode]; diff --git a/vis.c b/vis.c @@ -510,6 +510,7 @@ Vis *vis_new(Ui *ui, VisEvent *event) { vis->registers[VIS_REG_CLIPBOARD].type = REGISTER_CLIPBOARD; array_init(&vis->motions); array_init(&vis->textobjects); + array_init(&vis->bindings); action_reset(&vis->action); buffer_init(&vis->input_queue); vis->keys = &vis->input_queue; @@ -570,6 +571,9 @@ void vis_free(Vis *vis) { map_free(vis_modes[i].bindings); array_release_full(&vis->motions); array_release_full(&vis->textobjects); + while (array_length(&vis->bindings)) + vis_binding_free(vis, array_get_ptr(&vis->bindings, 0)); + array_release(&vis->bindings); free(vis->shell); free(vis); } diff --git a/vis.h b/vis.h @@ -152,6 +152,9 @@ void vis_exit(Vis*, int status); /* emergency exit, print given message, perform minimal ui cleanup and exit process */ void vis_die(Vis*, const char *msg, ...) __attribute__((noreturn,format(printf, 2, 3))); +KeyBinding *vis_binding_new(Vis*); +void vis_binding_free(Vis*, KeyBinding*); + enum VisMode { VIS_MODE_NORMAL, VIS_MODE_OPERATOR_PENDING,