From 7b1f313436c09d4e41ba71fa0ad91326c4e16944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Thu, 21 Apr 2016 08:41:13 +0200 Subject: vis: add infrastructure to register custom :-commands --- sam.c | 6 +++++- vis-cmds.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ vis-core.h | 1 + vis.c | 1 + vis.h | 8 ++++++++ 5 files changed, 59 insertions(+), 1 deletion(-) diff --git a/sam.c b/sam.c index c52b2e1..7227438 100644 --- a/sam.c +++ b/sam.c @@ -109,6 +109,7 @@ static bool cmd_help(Vis*, Win*, Command*, const char *argv[], Cursor*, Filerang static bool cmd_map(Vis*, Win*, Command*, const char *argv[], Cursor*, Filerange*); static bool cmd_unmap(Vis*, Win*, Command*, const char *argv[], Cursor*, Filerange*); static bool cmd_langmap(Vis*, Win*, Command*, const char *argv[], Cursor*, Filerange*); +static bool cmd_user(Vis*, Win*, Command*, const char *argv[], Cursor*, Filerange*); /* command recognized at the ':'-prompt. commands are found using a unique * prefix match. that is if a command should be available under an abbreviation @@ -161,7 +162,10 @@ static const CommandDef cmds[] = { }; static const CommandDef cmddef_select = - { { "s" }, 0, NULL, cmd_select }; + { { NULL }, 0, NULL, cmd_select }; + +static const CommandDef cmddef_user = + { { NULL }, CMD_ARGV|CMD_FORCE|CMD_ONCE, NULL, cmd_user }; bool sam_init(Vis *vis) { if (!(vis->cmds = map_new())) diff --git a/vis-cmds.c b/vis-cmds.c index 7d3e0ab..63f91cb 100644 --- a/vis-cmds.c +++ b/vis-cmds.c @@ -4,6 +4,50 @@ #define VIS_OPEN "vis-open" #endif +typedef struct { + CmdFunc func; + void *data; +} CmdUser; + +bool vis_cmd_register(Vis *vis, const char *name, void *data, CmdFunc func) { + if (!name) + return false; + if (!vis->usercmds && !(vis->usercmds = map_new())) + return false; + CmdUser *cmd = calloc(1, sizeof *cmd); + if (!cmd) + return false; + cmd->func = func; + cmd->data = data; + if (!map_put(vis->cmds, name, &cmddef_user)) + goto err; + if (!map_put(vis->usercmds, name, cmd)) { + map_delete(vis->cmds, name); + goto err; + } + return true; +err: + free(cmd); + return false; +} + +bool vis_cmd_unregister(Vis *vis, const char *name) { + if (!name) + return true; + CmdUser *cmd = map_delete(vis->usercmds, name); + if (!cmd) + return false; + if (!map_delete(vis->cmds, name)) + return false; + free(cmd); + return true; +} + +static bool cmd_user(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor *cur, Filerange *range) { + CmdUser *user = map_get(vis->usercmds, argv[0]); + return user && user->func(vis, win, user->data, cmd->flags == '!', argv, cur, range); +} + static void windows_arrange(Vis *vis, enum UiLayout layout) { vis->ui->arrange(vis->ui, layout); } diff --git a/vis-core.h b/vis-core.h index 5480589..606ff9b 100644 --- a/vis-core.h +++ b/vis-core.h @@ -153,6 +153,7 @@ struct Vis { bool expandtab; /* whether typed tabs should be converted to spaces */ bool autoindent; /* whether indentation should be copied from previous line on newline */ Map *cmds; /* ":"-commands, used for unique prefix queries */ + Map *usercmds; /* user registered ":"-commands */ Map *options; /* ":set"-options */ Map *keymap; /* key translation before any bindings are matched */ Buffer input_queue; /* holds pending input keys */ diff --git a/vis.c b/vis.c index 388bc41..4abba5f 100644 --- a/vis.c +++ b/vis.c @@ -394,6 +394,7 @@ void vis_free(Vis *vis) { register_release(&vis->registers[i]); vis->ui->free(vis->ui); map_free(vis->cmds); + map_free_full(vis->usercmds); map_free(vis->options); map_free(vis->actions); map_free(vis->keymap); diff --git a/vis.h b/vis.h index 6f60e6a..69b2586 100644 --- a/vis.h +++ b/vis.h @@ -396,6 +396,14 @@ void vis_cancel(Vis*); /* execute a :-command (including an optinal range specifier) */ bool vis_cmd(Vis*, const char *cmd); + +/* type of user defined function which can be registered */ +typedef bool (*CmdFunc)(Vis*, Win*, void *data, bool force, + const char *argv[], Cursor*, Filerange*); +/* the function will be invoked whenever a command which matches a + * unique prefix of the given name is executed */ +bool vis_cmd_register(Vis*, const char *name, void *data, CmdFunc); +bool vis_cmd_unregister(Vis*, const char *name); /* execute any kind (:,?,/) of prompt command */ bool vis_prompt_cmd(Vis*, const char *cmd); -- cgit v1.2.3