aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-01-17 20:49:08 +0800
committerGitHub <noreply@github.com>2023-01-17 20:49:08 +0800
commit99186508d9a1b7536441112f9bbe48690592b5d7 (patch)
tree8d9c872732f56feb3175819b1f532250f7e0717c
parent2d71ed9929d6393ed46f9d0c218ed9ef37b67f1f (diff)
parentc416da9d1a41b919412d88aecf827aebb8ea973b (diff)
downloadrneovim-99186508d9a1b7536441112f9bbe48690592b5d7.tar.gz
rneovim-99186508d9a1b7536441112f9bbe48690592b5d7.tar.bz2
rneovim-99186508d9a1b7536441112f9bbe48690592b5d7.zip
Merge pull request #21859 from zeertzjq/vim-8.2.4617
vim-patch:8.2.{4617,4618,4620,5126}
-rw-r--r--runtime/doc/builtin.txt6
-rw-r--r--src/nvim/cmdexpand.c63
-rw-r--r--src/nvim/ex_cmds.lua2
-rw-r--r--src/nvim/ex_docmd.c63
-rw-r--r--src/nvim/runtime.c11
-rw-r--r--src/nvim/testdir/test_cmdline.vim27
-rw-r--r--src/nvim/testdir/test_substitute.vim13
-rw-r--r--src/nvim/usercmd.c1
-rw-r--r--src/nvim/vim.h1
9 files changed, 142 insertions, 45 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index bdbd026a09..ca4518d1cc 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -2983,6 +2983,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
messages |:messages| suboptions
option options
packadd optional package |pack-add| names
+ scriptnames sourced script names |:scriptnames|
shellcmd Shell command
sign |:sign| suboptions
syntax syntax file names |'syntax'|
@@ -3002,7 +3003,10 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
If the 'wildoptions' option contains "fuzzy", then fuzzy
matching is used to get the completion matches. Otherwise
- regular expression matching is used.
+ regular expression matching is used. Thus this function
+ follows the user preference, what happens on the command line.
+ If you do not want this you can make 'wildoptions' empty
+ before calling getcompletion() and restore it afterwards.
If {type} is "cmdline", then the |cmdline-completion| result is
returned. For example, to complete the possible values after
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 4f6936958f..b5956d75ab 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -1760,6 +1760,22 @@ static const char *set_context_in_breakadd_cmd(expand_T *xp, const char *arg, cm
return NULL;
}
+static const char *set_context_in_scriptnames_cmd(expand_T *xp, const char *arg)
+{
+ xp->xp_context = EXPAND_NOTHING;
+ xp->xp_pattern = NULL;
+
+ char *p = skipwhite(arg);
+ if (ascii_isdigit(*p)) {
+ return NULL;
+ }
+
+ xp->xp_context = EXPAND_SCRIPTNAMES;
+ xp->xp_pattern = p;
+
+ return NULL;
+}
+
/// Set the completion context in "xp" for command "cmd" with index "cmdidx".
/// The argument to the command is "arg" and the argument flags is "argt".
/// For user-defined commands and for environment variables, "context" has the
@@ -2119,6 +2135,9 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa
case CMD_breakdel:
return set_context_in_breakadd_cmd(xp, arg, cmdidx);
+ case CMD_scriptnames:
+ return set_context_in_scriptnames_cmd(xp, arg);
+
case CMD_lua:
xp->xp_context = EXPAND_LUA;
break;
@@ -2496,6 +2515,19 @@ static char *get_breakadd_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
return NULL;
}
+/// Function given to ExpandGeneric() to obtain the possible arguments for the
+/// ":scriptnames" command.
+static char *get_scriptnames_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
+{
+ if (!SCRIPT_ID_VALID(idx + 1)) {
+ return NULL;
+ }
+
+ scriptitem_T *si = &SCRIPT_ITEM(idx + 1);
+ home_replace(NULL, si->sn_name, NameBuff, MAXPATHL, true);
+ return NameBuff;
+}
+
/// Function given to ExpandGeneric() to obtain the possible arguments of the
/// ":messages {clear}" command.
static char *get_messages_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
@@ -2581,6 +2613,7 @@ static int ExpandOther(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches
{ EXPAND_USER, get_users, true, false },
{ EXPAND_ARGLIST, get_arglist_name, true, false },
{ EXPAND_BREAKPOINT, get_breakadd_arg, true, true },
+ { EXPAND_SCRIPTNAMES, get_scriptnames_arg, true, false },
{ EXPAND_CHECKHEALTH, get_healthcheck_names, true, false },
};
int ret = FAIL;
@@ -2823,11 +2856,22 @@ static void ExpandGeneric(const char *const pat, expand_T *xp, regmatch_T *regma
return;
}
- // Sort the results. Keep menu's in the specified order.
- if (!fuzzy && xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS) {
- if (xp->xp_context == EXPAND_EXPRESSION
- || xp->xp_context == EXPAND_FUNCTIONS
- || xp->xp_context == EXPAND_USER_FUNC) {
+ // Sort the matches when using regular expression matching and sorting
+ // applies to the completion context. Menus and scriptnames should be kept
+ // in the specified order.
+ const bool sort_matches = !fuzzy
+ && xp->xp_context != EXPAND_MENUNAMES
+ && xp->xp_context != EXPAND_MENUS
+ && xp->xp_context != EXPAND_SCRIPTNAMES;
+
+ // <SNR> functions should be sorted to the end.
+ const bool funcsort = xp->xp_context == EXPAND_EXPRESSION
+ || xp->xp_context == EXPAND_FUNCTIONS
+ || xp->xp_context == EXPAND_USER_FUNC;
+
+ // Sort the matches.
+ if (sort_matches) {
+ if (funcsort) {
// <SNR> functions should be sorted to the end.
qsort(ga.ga_data, (size_t)ga.ga_len, sizeof(char *), sort_func_compare);
} else {
@@ -2839,15 +2883,6 @@ static void ExpandGeneric(const char *const pat, expand_T *xp, regmatch_T *regma
*matches = ga.ga_data;
*numMatches = ga.ga_len;
} else {
- bool funcsort = false;
-
- if (xp->xp_context == EXPAND_EXPRESSION
- || xp->xp_context == EXPAND_FUNCTIONS
- || xp->xp_context == EXPAND_USER_FUNC) {
- // <SNR> functions should be sorted to the end.
- funcsort = true;
- }
-
fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len, funcsort);
*numMatches = ga.ga_len;
}
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 68db03bd7d..c8b6ceab69 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -2387,7 +2387,7 @@ module.cmds = {
},
{
command='scriptnames',
- flags=bit.bor(BANG, RANGE, COUNT, TRLBAR, CMDWIN, LOCK_OK),
+ flags=bit.bor(BANG, FILES, RANGE, COUNT, TRLBAR, CMDWIN, LOCK_OK),
addr_type='ADDR_OTHER',
func='ex_scriptnames',
},
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index e11dd0a2f6..511251f0b5 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -2890,6 +2890,33 @@ static void append_command(char *cmd)
*d = NUL;
}
+/// Return true and set "*idx" if "p" points to a one letter command.
+/// - The 'k' command can directly be followed by any character.
+/// - The 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
+/// but :sre[wind] is another command, as are :scr[iptnames],
+/// :scs[cope], :sim[alt], :sig[ns] and :sil[ent].
+static int one_letter_cmd(const char *p, cmdidx_T *idx)
+{
+ if (*p == 'k') {
+ *idx = CMD_k;
+ return true;
+ }
+ if (p[0] == 's'
+ && ((p[1] == 'c'
+ && (p[2] == NUL
+ || (p[2] != 's' && p[2] != 'r'
+ && (p[3] == NUL
+ || (p[3] != 'i' && p[4] != 'p')))))
+ || p[1] == 'g'
+ || (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g')
+ || p[1] == 'I'
+ || (p[1] == 'r' && p[2] != 'e'))) {
+ *idx = CMD_substitute;
+ return true;
+ }
+ return false;
+}
+
/// Find an Ex command by its name, either built-in or user.
/// Start of the name can be found at eap->cmd.
/// Sets eap->cmdidx and returns a pointer to char after the command name.
@@ -2900,27 +2927,8 @@ char *find_ex_command(exarg_T *eap, int *full)
FUNC_ATTR_NONNULL_ARG(1)
{
// Isolate the command and search for it in the command table.
- // Exceptions:
- // - the 'k' command can directly be followed by any character.
- // - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
- // but :sre[wind] is another command, as are :scr[iptnames],
- // :scs[cope], :sim[alt], :sig[ns] and :sil[ent].
- // - the "d" command can directly be followed by 'l' or 'p' flag.
char *p = eap->cmd;
- if (*p == 'k') {
- eap->cmdidx = CMD_k;
- p++;
- } else if (p[0] == 's'
- && ((p[1] == 'c'
- && (p[2] == NUL
- || (p[2] != 's' && p[2] != 'r'
- && (p[3] == NUL
- || (p[3] != 'i' && p[4] != 'p')))))
- || p[1] == 'g'
- || (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g')
- || p[1] == 'I'
- || (p[1] == 'r' && p[2] != 'e'))) {
- eap->cmdidx = CMD_substitute;
+ if (one_letter_cmd(p, &eap->cmdidx)) {
p++;
} else {
while (ASCII_ISALPHA(*p)) {
@@ -2938,6 +2946,7 @@ char *find_ex_command(exarg_T *eap, int *full)
p++;
}
int len = (int)(p - eap->cmd);
+ // The "d" command can directly be followed by 'l' or 'p' flag.
if (*eap->cmd == 'd' && (p[-1] == 'l' || p[-1] == 'p')) {
// Check for ":dl", ":dell", etc. to ":deletel": that's
// :delete with the 'l' flag. Same for 'p'.
@@ -3135,9 +3144,11 @@ cmdidx_T excmd_get_cmdidx(const char *cmd, size_t len)
{
cmdidx_T idx;
- for (idx = (cmdidx_T)0; (int)idx < CMD_SIZE; idx = (cmdidx_T)((int)idx + 1)) {
- if (strncmp(cmdnames[(int)idx].cmd_name, cmd, len) == 0) {
- break;
+ if (!one_letter_cmd(cmd, &idx)) {
+ for (idx = (cmdidx_T)0; (int)idx < CMD_SIZE; idx = (cmdidx_T)((int)idx + 1)) {
+ if (strncmp(cmdnames[(int)idx].cmd_name, cmd, len) == 0) {
+ break;
+ }
}
}
@@ -5238,9 +5249,9 @@ void do_exedit(exarg_T *eap, win_T *old_curwin)
old_curwin == NULL ? curwin : NULL);
} else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit)
|| *eap->arg != NUL) {
- // Can't edit another file when "curbuf->b_ro_locked" is set. Only ":edit"
- // can bring us here, others are stopped earlier.
- if (*eap->arg != NUL && curbuf_locked()) {
+ // Can't edit another file when "textlock" or "curbuf->b_ro_locked" is set.
+ // Only ":edit" or ":script" can bring us here, others are stopped earlier.
+ if (*eap->arg != NUL && text_or_buf_locked()) {
return;
}
n = readonlymode;
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index ea975042ed..321023bce2 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -2160,12 +2160,17 @@ scriptitem_T *get_current_script_id(char **fnamep, sctx_T *ret_sctx)
/// ":scriptnames"
void ex_scriptnames(exarg_T *eap)
{
- if (eap->addr_count > 0) {
+ if (eap->addr_count > 0 || *eap->arg != NUL) {
// :script {scriptId}: edit the script
- if (eap->line2 < 1 || eap->line2 > script_items.ga_len) {
+ if (eap->addr_count > 0 && !SCRIPT_ID_VALID(eap->line2)) {
emsg(_(e_invarg));
} else {
- eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
+ if (eap->addr_count > 0) {
+ eap->arg = SCRIPT_ITEM(eap->line2).sn_name;
+ } else {
+ expand_env(eap->arg, NameBuff, MAXPATHL);
+ eap->arg = NameBuff;
+ }
do_exedit(eap, NULL);
}
return;
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index ea7bfae639..ebcbc8177e 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -3378,6 +3378,33 @@ func Test_cmdline_complete_breakdel()
call assert_equal("\"breakdel here ", @:)
endfunc
+" Test for :scriptnames argument completion
+func Test_cmdline_complete_scriptnames()
+ set wildmenu
+ call writefile(['let a = 1'], 'Xa1b2c3.vim')
+ source Xa1b2c3.vim
+ call feedkeys(":script \<Tab>\<Left>\<Left>\<C-B>\"\<CR>", 'tx')
+ call assert_match("\"script .*Xa1b2c3.vim$", @:)
+ call feedkeys(":script \<Tab>\<Left>\<Left>\<C-B>\"\<CR>", 'tx')
+ call assert_match("\"script .*Xa1b2c3.vim$", @:)
+ call feedkeys(":script b2c3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"script b2c3", @:)
+ call feedkeys(":script 2\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match("\"script 2\<Tab>$", @:)
+ call feedkeys(":script \<Tab>\<Left>\<Left> \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match("\"script .*Xa1b2c3.vim $", @:)
+ call feedkeys(":script \<Tab>\<Left>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"script ", @:)
+ call assert_match('Xa1b2c3.vim$', getcompletion('.*Xa1b2.*', 'scriptnames')[0])
+ call assert_equal([], getcompletion('Xa1b2', 'scriptnames'))
+ new
+ call feedkeys(":script \<Tab>\<Left>\<Left>\<CR>", 'tx')
+ call assert_equal('Xa1b2c3.vim', fnamemodify(@%, ':t'))
+ bw!
+ call delete('Xa1b2c3.vim')
+ set wildmenu&
+endfunc
+
" this was going over the end of IObuff
func Test_report_error_with_composing()
let caught = 'no'
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index 5fd30c7da7..c99a0d456d 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -1076,6 +1076,19 @@ func Test_sub_open_cmdline_win()
call delete('Xresult')
endfunc
+" This was editing a script file from the expression
+func Test_sub_edit_scriptfile()
+ new
+ norm o0000000000000000000000000000000000000000000000000000
+ func EditScript()
+ silent! scr! Xfile
+ endfunc
+ s/\%')/\=EditScript()
+
+ delfunc EditScript
+ bwipe!
+endfunc
+
" Test for the 2-letter and 3-letter :substitute commands
func Test_substitute_short_cmd()
new
diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c
index 22e092781c..9c4fdd4ead 100644
--- a/src/nvim/usercmd.c
+++ b/src/nvim/usercmd.c
@@ -96,6 +96,7 @@ static const char *command_complete[] = {
[EXPAND_USER] = "user",
[EXPAND_USER_VARS] = "var",
[EXPAND_BREAKPOINT] = "breakpoint",
+ [EXPAND_SCRIPTNAMES] = "scriptnames",
};
/// List of names of address types. Must be alphabetical for completion.
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 0ab9d96173..c4baa911f1 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -155,6 +155,7 @@ enum {
EXPAND_ARGLIST,
EXPAND_DIFF_BUFFERS,
EXPAND_BREAKPOINT,
+ EXPAND_SCRIPTNAMES,
EXPAND_CHECKHEALTH,
EXPAND_LUA,
};