Skip to content

Commit

Permalink
Add command completion with tab key
Browse files Browse the repository at this point in the history
In the command prompt, press <tab> to get a list of all available
commands and pick one (using vis-menu). This works also after typing the
first letters of a command (p.e. `:la<tab>`).

Co-authored-by: Matěj Cepl <[email protected]>
  • Loading branch information
MaxGyver83 and mcepl committed Mar 31, 2024
1 parent 6f537f3 commit bb3ab4e
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 4 deletions.
18 changes: 14 additions & 4 deletions lua/plugins/complete-filename.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,19 @@ local complete_filename = function(expand)
range.finish = pos
end

local cmdfmt = "vis-complete --file '%s'"
if expand then cmdfmt = "vis-open -- '%s'*" end
local status, out, err = vis:pipe(cmdfmt:format(prefix:gsub("'", "'\\''")))
local status, out, err
if prefix:sub(1, 1) == ":" then
status, out, err = vis:complete_command(prefix:sub(2))
if out then
out = out:gsub("\n$", ""):sub(#prefix) .. " "
end
pos = range.start + #prefix
expand = false
else
local cmdfmt = "vis-complete --file '%s'"
if expand then cmdfmt = "vis-open -- '%s'*" end
status, out, err = vis:pipe(cmdfmt:format(prefix:gsub("'", "'\\''")))
end
if status ~= 0 or not out then
if err then vis:info(err) end
return
Expand All @@ -48,4 +58,4 @@ end, "Complete file name")
-- complete file path at primary selection location using vis-open(1)
vis:map(vis.modes.INSERT, "<C-x><C-o>", function()
complete_filename(true);
end, "Complete file name (expands path)")
end, "Complete file name (expands path) or command")
13 changes: 13 additions & 0 deletions vis-cmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,19 @@ static bool print_cmd(const char *key, void *value, void *data) {
return text_appendf(data, " %-30s %s\n", usage, help ? help : "");
}

static bool print_cmd_name(const char *key, void *value, void *data) {
CommandDef *cmd = value;
size_t len_data = strlen(data);
size_t remaining_capacity = VIS_COMMAND_BUFFER_MAX - len_data;
if (remaining_capacity >= strlen(cmd->name) + 2) /* adding 2 for \n and \0 */
snprintf((char *)data + len_data, remaining_capacity, "%s\n", cmd->name);
return true;
}

void vis_print_cmds(Vis *vis, char *cmd_list) {
map_iterate(vis->cmds, print_cmd_name, cmd_list);
}

static bool print_option(const char *key, void *value, void *txt) {
char desc[256];
const OptionDef *opt = value;
Expand Down
39 changes: 39 additions & 0 deletions vis-lua.c
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,44 @@ static int command_register(lua_State *L) {
return 1;
}

/***
* Let user pick a command matching the given prefix.
*
* The editor core will be blocked while the external process is running.
*
* @function complete_command
* @tparam string prefix the prefix of the command to be completed
* @treturn int code the exit status of the executed command
* @treturn string stdout the data written to stdout
* @treturn string stderr the data written to stderr
*/
static int complete_command(lua_State *L) {
Vis *vis = obj_ref_check(L, 1, "vis");
const char *prefix = luaL_checkstring(L, 2);
char *out = NULL, *err = NULL;
File *file = vis->win ? vis->win->file : NULL;
Filerange range = text_range_new(0, 0);

char cmd_list[VIS_COMMAND_BUFFER_MAX] = {0};
vis_print_cmds(vis, cmd_list);
char cmd[VIS_COMMAND_BUFFER_MAX + 32] = {0}; /* 32 for echo/grep/vis-menu */
sprintf(cmd, "echo '%s' | grep '^%s' | vis-menu -b", cmd_list, prefix);

int status = vis_pipe_collect(vis, file, &range, (const char*[]){ cmd, NULL }, &out, &err, false);
lua_pushinteger(L, status);
if (out)
lua_pushstring(L, out);
else
lua_pushnil(L);
free(out);
if (err)
lua_pushstring(L, err);
else
lua_pushnil(L);
free(err);
return 3;
}

/***
* Push keys to input queue and interpret them.
*
Expand Down Expand Up @@ -1638,6 +1676,7 @@ static const struct luaL_Reg vis_lua[] = {
{ "option_register", option_register },
{ "option_unregister", option_unregister },
{ "command_register", command_register },
{ "complete_command", complete_command },
{ "feedkeys", feedkeys },
{ "insert", insert },
{ "replace", replace },
Expand Down
6 changes: 6 additions & 0 deletions vis.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ typedef struct Win Win;
/* maximum bytes needed for string representation of a (pseudo) key */
#define VIS_KEY_LENGTH_MAX 64

/* maximum bytes used for list of available commands */
#define VIS_COMMAND_BUFFER_MAX 1000

/**
* Editor event handlers.
*/
Expand Down Expand Up @@ -895,6 +898,9 @@ bool vis_option_unregister(Vis*, const char *name);
/** Execute any kind (``:``, ``?``, ``/``) of prompt command */
bool vis_prompt_cmd(Vis*, const char *cmd);

/** Write newline separated list of available commands to ``cmd_list`` */
void vis_print_cmds(Vis*, char *cmd_list);

/**
* Pipe a given file range to an external process.
*
Expand Down

0 comments on commit bb3ab4e

Please sign in to comment.