aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2022-06-29 09:12:01 +0200
committerGitHub <noreply@github.com>2022-06-29 09:12:01 +0200
commit21a1f1f552c1d79165cdb51e9e1297d4a4fe9eb6 (patch)
tree820cdbb0a08e643753960fe6be91f47f4e181e6f /src
parent01fc5097d3b6921fce5c159e5c772dc1590eb847 (diff)
parent606ec8b70874095a62289f1df3934eca78625742 (diff)
downloadrneovim-21a1f1f552c1d79165cdb51e9e1297d4a4fe9eb6.tar.gz
rneovim-21a1f1f552c1d79165cdb51e9e1297d4a4fe9eb6.tar.bz2
rneovim-21a1f1f552c1d79165cdb51e9e1297d4a4fe9eb6.zip
Merge pull request #19133 from famiu/feat/api/cmd_support_filter
feat(api): make `nvim_parse_cmd` and `nvim_cmd` support :filter
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/command.c43
-rw-r--r--src/nvim/api/keysets.lua5
-rw-r--r--src/nvim/ex_cmds_defs.h1
-rw-r--r--src/nvim/ex_docmd.c30
-rw-r--r--src/nvim/ex_getln.c2
5 files changed, 66 insertions, 15 deletions
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 80a5449d29..e6a055995e 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -49,6 +49,9 @@
/// - bar: (boolean) The "|" character is treated as a command separator and the double
/// quote character (\") is treated as the start of a comment.
/// - mods: (dictionary) |:command-modifiers|.
+/// - filter: (dictionary) |:filter|.
+/// - pattern: (string) Filter pattern. Empty string if there is no filter.
+/// - force: (boolean) Whether filter is inverted or not.
/// - silent: (boolean) |:silent|.
/// - emsg_silent: (boolean) |:silent!|.
/// - sandbox: (boolean) |:sandbox|.
@@ -95,7 +98,6 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err)
}
goto end;
}
- vim_regfree(cmdinfo.cmdmod.cmod_filter_regmatch.regprog);
// Parse arguments
Array args = ARRAY_DICT_INIT;
@@ -220,6 +222,14 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err)
PUT(result, "nextcmd", CSTR_TO_OBJ((char *)ea.nextcmd));
Dictionary mods = ARRAY_DICT_INIT;
+
+ Dictionary filter = ARRAY_DICT_INIT;
+ PUT(filter, "pattern", cmdinfo.cmdmod.cmod_filter_pat
+ ? CSTR_TO_OBJ(cmdinfo.cmdmod.cmod_filter_pat)
+ : STRING_OBJ(STATIC_CSTR_TO_STRING("")));
+ PUT(filter, "force", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_filter_force));
+ PUT(mods, "filter", DICTIONARY_OBJ(filter));
+
PUT(mods, "silent", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_SILENT));
PUT(mods, "emsg_silent", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_ERRSILENT));
PUT(mods, "sandbox", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_SANDBOX));
@@ -257,6 +267,8 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err)
PUT(magic, "file", BOOLEAN_OBJ(cmdinfo.magic.file));
PUT(magic, "bar", BOOLEAN_OBJ(cmdinfo.magic.bar));
PUT(result, "magic", DICTIONARY_OBJ(magic));
+
+ undo_cmdmod(&cmdinfo.cmdmod);
end:
xfree(cmdline);
return result;
@@ -513,6 +525,35 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
goto end;
}
+ if (HAS_KEY(mods.filter)) {
+ if (mods.filter.type != kObjectTypeDictionary) {
+ VALIDATION_ERROR("'mods.filter' must be a Dictionary");
+ }
+
+ Dict(cmd_mods_filter) filter = { 0 };
+
+ if (!api_dict_to_keydict(&filter, KeyDict_cmd_mods_filter_get_field,
+ mods.filter.data.dictionary, err)) {
+ goto end;
+ }
+
+ if (HAS_KEY(filter.pattern)) {
+ if (filter.pattern.type != kObjectTypeString) {
+ VALIDATION_ERROR("'mods.filter.pattern' must be a String");
+ }
+
+ OBJ_TO_BOOL(cmdinfo.cmdmod.cmod_filter_force, filter.force, false, "'mods.filter.force'");
+
+ // "filter! // is not no-op, so add a filter if either the pattern is non-empty or if filter
+ // is inverted.
+ if (*filter.pattern.data.string.data != NUL || cmdinfo.cmdmod.cmod_filter_force) {
+ cmdinfo.cmdmod.cmod_filter_pat = string_to_cstr(filter.pattern.data.string);
+ cmdinfo.cmdmod.cmod_filter_regmatch.regprog = vim_regcomp(cmdinfo.cmdmod.cmod_filter_pat,
+ RE_MAGIC);
+ }
+ }
+ }
+
if (HAS_KEY(mods.tab)) {
if (mods.tab.type != kObjectTypeInteger || mods.tab.data.integer < 0) {
VALIDATION_ERROR("'mods.tab' must be a non-negative Integer");
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index 70e91dd844..1c071eaf48 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -181,6 +181,7 @@ return {
cmd_mods = {
"silent";
"emsg_silent";
+ "filter";
"sandbox";
"noautocmd";
"browse";
@@ -197,6 +198,10 @@ return {
"vertical";
"split";
};
+ cmd_mods_filter = {
+ "pattern";
+ "force";
+ };
cmd_opts = {
"output";
};
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index 9350a9f60b..6798f7693b 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -268,6 +268,7 @@ typedef struct {
int cmod_split; ///< flags for win_split()
int cmod_tab; ///< > 0 when ":tab" was used
+ char *cmod_filter_pat;
regmatch_T cmod_filter_regmatch; ///< set by :filter /pat/
bool cmod_filter_force; ///< set for :filter!
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 48e6dad720..fee98a18dc 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1405,8 +1405,8 @@ bool is_cmd_ni(cmdidx_T cmdidx)
}
/// Parse command line and return information about the first command.
-/// If parsing is done successfully, need to free cmod_filter_regmatch.regprog after calling,
-/// usually done using undo_cmdmod() or execute_cmd().
+/// If parsing is done successfully, need to free cmod_filter_pat and cmod_filter_regmatch.regprog
+/// after calling, usually done using undo_cmdmod() or execute_cmd().
///
/// @param cmdline Command line string
/// @param[out] eap Ex command arguments
@@ -1434,8 +1434,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
// Parse command modifiers
if (parse_command_modifiers(eap, errormsg, &cmdinfo->cmdmod, false) == FAIL) {
- vim_regfree(cmdinfo->cmdmod.cmod_filter_regmatch.regprog);
- return false;
+ goto err;
}
after_modifier = eap->cmd;
@@ -1449,21 +1448,21 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
p = find_ex_command(eap, NULL);
if (p == NULL) {
*errormsg = _(e_ambiguous_use_of_user_defined_command);
- return false;
+ goto err;
}
// Set command address type and parse command range
set_cmd_addr_type(eap, p);
eap->cmd = cmd;
if (parse_cmd_address(eap, errormsg, false) == FAIL) {
- return false;
+ goto err;
}
// Skip colon and whitespace
eap->cmd = skip_colon_white(eap->cmd, true);
// Fail if command is a comment or if command doesn't exist
if (*eap->cmd == NUL || *eap->cmd == '"') {
- return false;
+ goto err;
}
// Fail if command is invalid
if (eap->cmdidx == CMD_SIZE) {
@@ -1472,7 +1471,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
char *cmdname = after_modifier ? after_modifier : cmdline;
append_command(cmdname);
*errormsg = (char *)IObuff;
- return false;
+ goto err;
}
// Correctly set 'forceit' for commands
@@ -1511,12 +1510,12 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
// Fail if command doesn't support bang but is used with a bang
if (!(eap->argt & EX_BANG) && eap->forceit) {
*errormsg = _(e_nobang);
- return false;
+ goto err;
}
// Fail if command doesn't support a range but it is given a range
if (!(eap->argt & EX_RANGE) && eap->addr_count > 0) {
*errormsg = _(e_norange);
- return false;
+ goto err;
}
// Set default range for command if required
if ((eap->argt & EX_DFLALL) && eap->addr_count == 0) {
@@ -1526,7 +1525,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
// Parse register and count
parse_register(eap);
if (parse_count(eap, errormsg, false) == FAIL) {
- return false;
+ goto err;
}
// Remove leading whitespace and colon from next command
@@ -1543,6 +1542,9 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
}
return true;
+err:
+ undo_cmdmod(&cmdinfo->cmdmod);
+ return false;
}
/// Execute an Ex command using parsed command line information.
@@ -2393,7 +2395,7 @@ char *ex_errmsg(const char *const msg, const char *const arg)
/// - Set ex_pressedreturn for an empty command line.
///
/// @param skip_only if false, undo_cmdmod() must be called later to free
-/// any cmod_filter_regmatch.regprog.
+/// any cmod_filter_pat and cmod_filter_regmatch.regprog.
/// @param[out] errormsg potential error message.
///
/// Call apply_cmdmod() to get the side effects of the modifiers:
@@ -2512,6 +2514,7 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, bool
break;
}
if (!skip_only) {
+ cmod->cmod_filter_pat = xstrdup(reg_pat);
cmod->cmod_filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC);
if (cmod->cmod_filter_regmatch.regprog == NULL) {
break;
@@ -2673,7 +2676,7 @@ static void apply_cmdmod(cmdmod_T *cmod)
}
/// Undo and free contents of "cmod".
-static void undo_cmdmod(cmdmod_T *cmod)
+void undo_cmdmod(cmdmod_T *cmod)
FUNC_ATTR_NONNULL_ALL
{
if (cmod->cmod_verbose_save > 0) {
@@ -2693,6 +2696,7 @@ static void undo_cmdmod(cmdmod_T *cmod)
cmod->cmod_save_ei = NULL;
}
+ xfree(cmod->cmod_filter_pat);
vim_regfree(cmod->cmod_filter_regmatch.regprog);
if (cmod->cmod_save_msg_silent > 0) {
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 154086b82c..01f16f3383 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -2404,7 +2404,7 @@ static bool cmdpreview_may_show(CommandLineState *s)
// Check if command is previewable, if not, don't attempt to show preview
if (!(ea.argt & EX_PREVIEW)) {
- vim_regfree(cmdinfo.cmdmod.cmod_filter_regmatch.regprog);
+ undo_cmdmod(&cmdinfo.cmdmod);
goto end;
}