aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2016-12-29 17:58:00 +0100
committerMarc André Tanner <mat@brain-dump.org>2016-12-29 17:58:00 +0100
commiteda4ab0e8e2f97225e4c0470318e9427e09bbfb9 (patch)
treebd988ad26c4dd7825cb5ab7635d16c81c82b6edb
parenta8116c57341f87b293d35ef7e1d140ceb01ed8b1 (diff)
downloadvis-eda4ab0e8e2f97225e4c0470318e9427e09bbfb9.tar.gz
vis-eda4ab0e8e2f97225e4c0470318e9427e09bbfb9.tar.xz
vis: cleanup key action lifetime management
-rw-r--r--vis-core.h1
-rw-r--r--vis-lua.c18
-rw-r--r--vis-modes.c45
-rw-r--r--vis.c4
-rw-r--r--vis.h17
5 files changed, 59 insertions, 26 deletions
diff --git a/vis-core.h b/vis-core.h
index 3abe1f5..ea7396a 100644
--- a/vis-core.h
+++ b/vis-core.h
@@ -184,6 +184,7 @@ struct Vis {
volatile sig_atomic_t terminate; /* need to terminate we were being killed by SIGTERM */
sigjmp_buf sigbus_jmpbuf; /* used to jump back to a known good state in the mainloop after (SIGBUS) */
Map *actions; /* registered editor actions / special keys commands */
+ Array actions_user; /* dynamically allocated editor actions */
lua_State *lua; /* lua context used for syntax highligthing */
VisEvent *event;
Array motions;
diff --git a/vis-lua.c b/vis-lua.c
index 5c52cce..96fe7ea 100644
--- a/vis-lua.c
+++ b/vis-lua.c
@@ -665,23 +665,14 @@ static int keymap(lua_State *L, Vis *vis, Win *win) {
const char *key = luaL_checkstring(L, 3);
const void *func = func_ref_new(L, 4);
const char *help = luaL_optstring(L, 5, NULL);
- KeyBinding *binding = vis_binding_new(vis);
- if (!binding)
- goto err;
- KeyAction *action = calloc(1, sizeof *action);
+ KeyBinding *binding = NULL;
+ KeyAction *action = vis_action_new(vis, NULL, help, keymapping, (Arg){ .v = func });
if (!action)
goto err;
+ if (!(binding = vis_binding_new(vis)))
+ goto err;
binding->action = action;
- *action = (KeyAction){
- .name = NULL,
- .help = help ? strdup(help) : help,
- .func = keymapping,
- .arg = (const Arg){
- .v = func,
- },
- };
-
if (win) {
if (!vis_window_mode_map(win, mode, true, key, binding))
goto err;
@@ -694,6 +685,7 @@ static int keymap(lua_State *L, Vis *vis, Win *win) {
return 1;
err:
vis_binding_free(vis, binding);
+ vis_action_free(vis, action);
lua_pushboolean(L, false);
return 1;
}
diff --git a/vis-modes.c b/vis-modes.c
index 86c86f0..1fe460d 100644
--- a/vis-modes.c
+++ b/vis-modes.c
@@ -2,6 +2,41 @@
#include "vis-core.h"
#include "util.h"
+KeyAction *vis_action_new(Vis *vis, const char *name, const char *help, KeyActionFunction *func, Arg arg) {
+ KeyAction *action = calloc(1, sizeof *action);
+ if (!action)
+ return NULL;
+ if (name && !(action->name = strdup(name)))
+ goto err;
+ if (help && !(action->help = strdup(help)))
+ goto err;
+ action->func = func;
+ action->arg = arg;
+ if (!array_add_ptr(&vis->actions_user, action))
+ goto err;
+ return action;
+err:
+ free((char*)action->name);
+ free((char*)action->help);
+ free(action);
+ return NULL;
+}
+
+void vis_action_free(Vis *vis, KeyAction *action) {
+ if (!action)
+ return;
+ size_t len = array_length(&vis->actions_user);
+ for (size_t i = 0; i < len; i++) {
+ if (action == array_get_ptr(&vis->actions_user, i)) {
+ free((char*)action->name);
+ free((char*)action->help);
+ free(action);
+ array_remove(&vis->actions_user, i);
+ return;
+ }
+ }
+}
+
KeyBinding *vis_binding_new(Vis *vis) {
KeyBinding *binding = calloc(1, sizeof *binding);
if (binding && array_add_ptr(&vis->bindings, binding))
@@ -18,15 +53,11 @@ void vis_binding_free(Vis *vis, KeyBinding *binding) {
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);
- }
+ if (binding->action && !binding->action->name)
+ vis_action_free(vis, (KeyAction*)binding->action);
free(binding);
array_remove(&vis->bindings, i);
- break;
+ return;
}
}
}
diff --git a/vis.c b/vis.c
index 4943280..444d56e 100644
--- a/vis.c
+++ b/vis.c
@@ -511,6 +511,7 @@ Vis *vis_new(Ui *ui, VisEvent *event) {
array_init(&vis->motions);
array_init(&vis->textobjects);
array_init(&vis->bindings);
+ array_init(&vis->actions_user);
action_reset(&vis->action);
buffer_init(&vis->input_queue);
vis->keys = &vis->input_queue;
@@ -574,6 +575,9 @@ void vis_free(Vis *vis) {
while (array_length(&vis->bindings))
vis_binding_free(vis, array_get_ptr(&vis->bindings, 0));
array_release(&vis->bindings);
+ while (array_length(&vis->actions_user))
+ vis_action_free(vis, array_get_ptr(&vis->actions_user, 0));
+ array_release(&vis->actions_user);
free(vis->shell);
free(vis);
}
diff --git a/vis.h b/vis.h
index ef8897d..312da4b 100644
--- a/vis.h
+++ b/vis.h
@@ -53,15 +53,17 @@ typedef union { /* various types of arguments passed to key action functions */
void (*f)(Vis*);
} Arg;
+/* action handling function, keys refers to the next characters found in the input queue
+ * (an empty string "" indicates an empty queue). The return value of func has to point to
+ * the first non consumed key. Returning NULL indicates that not enough keys were available
+ * to complete the action. In this case the function will be called again when more input
+ * becomes available */
+typedef const char *KeyActionFunction(Vis*, const char *keys, const Arg*);
+
typedef struct { /* a KeyAction can be bound to a key binding */
const char *name; /* aliases can refer to this action by means of a pseudo key <name> */
const char *help; /* short (one line) human readable description, displayed by :help */
- /* action handling function, keys refers to the next characters found in the input queue
- * (an empty string "" indicates an empty queue). The return value of func has to point to
- * the first non consumed key. Returning NULL indicates that not enough keys were available
- * to complete the action. In this case the function will be called again when more input
- * becomes available */
- const char* (*func)(Vis*, const char *keys, const Arg*);
+ KeyActionFunction *func; /* action implementation */
Arg arg; /* additional arguments which will be passed as to func */
} KeyAction;
@@ -175,6 +177,9 @@ bool vis_window_mode_map(Win*, enum VisMode, bool force, const char *key, const
/* 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);
+
+KeyAction *vis_action_new(Vis*, const char *name, const char *help, KeyActionFunction*, Arg);
+void vis_action_free(Vis*, KeyAction*);
/* associates the special pseudo key <keyaction->name> with the given key action.
* after successfull registration the pseudo key can be used key binding aliases */
bool vis_action_register(Vis*, const KeyAction*);