mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #21859 from zeertzjq/vim-8.2.4617
vim-patch:8.2.{4617,4618,4620,5126}
This commit is contained in:
commit
99186508d9
@ -2983,6 +2983,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
|
|||||||
messages |:messages| suboptions
|
messages |:messages| suboptions
|
||||||
option options
|
option options
|
||||||
packadd optional package |pack-add| names
|
packadd optional package |pack-add| names
|
||||||
|
scriptnames sourced script names |:scriptnames|
|
||||||
shellcmd Shell command
|
shellcmd Shell command
|
||||||
sign |:sign| suboptions
|
sign |:sign| suboptions
|
||||||
syntax syntax file names |'syntax'|
|
syntax syntax file names |'syntax'|
|
||||||
@ -3002,7 +3003,10 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
|
|||||||
|
|
||||||
If the 'wildoptions' option contains "fuzzy", then fuzzy
|
If the 'wildoptions' option contains "fuzzy", then fuzzy
|
||||||
matching is used to get the completion matches. Otherwise
|
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
|
If {type} is "cmdline", then the |cmdline-completion| result is
|
||||||
returned. For example, to complete the possible values after
|
returned. For example, to complete the possible values after
|
||||||
|
@ -1760,6 +1760,22 @@ static const char *set_context_in_breakadd_cmd(expand_T *xp, const char *arg, cm
|
|||||||
return NULL;
|
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".
|
/// 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".
|
/// The argument to the command is "arg" and the argument flags is "argt".
|
||||||
/// For user-defined commands and for environment variables, "context" has the
|
/// 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:
|
case CMD_breakdel:
|
||||||
return set_context_in_breakadd_cmd(xp, arg, cmdidx);
|
return set_context_in_breakadd_cmd(xp, arg, cmdidx);
|
||||||
|
|
||||||
|
case CMD_scriptnames:
|
||||||
|
return set_context_in_scriptnames_cmd(xp, arg);
|
||||||
|
|
||||||
case CMD_lua:
|
case CMD_lua:
|
||||||
xp->xp_context = EXPAND_LUA;
|
xp->xp_context = EXPAND_LUA;
|
||||||
break;
|
break;
|
||||||
@ -2496,6 +2515,19 @@ static char *get_breakadd_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
|
|||||||
return NULL;
|
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
|
/// Function given to ExpandGeneric() to obtain the possible arguments of the
|
||||||
/// ":messages {clear}" command.
|
/// ":messages {clear}" command.
|
||||||
static char *get_messages_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
|
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_USER, get_users, true, false },
|
||||||
{ EXPAND_ARGLIST, get_arglist_name, true, false },
|
{ EXPAND_ARGLIST, get_arglist_name, true, false },
|
||||||
{ EXPAND_BREAKPOINT, get_breakadd_arg, true, true },
|
{ EXPAND_BREAKPOINT, get_breakadd_arg, true, true },
|
||||||
|
{ EXPAND_SCRIPTNAMES, get_scriptnames_arg, true, false },
|
||||||
{ EXPAND_CHECKHEALTH, get_healthcheck_names, true, false },
|
{ EXPAND_CHECKHEALTH, get_healthcheck_names, true, false },
|
||||||
};
|
};
|
||||||
int ret = FAIL;
|
int ret = FAIL;
|
||||||
@ -2823,11 +2856,22 @@ static void ExpandGeneric(const char *const pat, expand_T *xp, regmatch_T *regma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the results. Keep menu's in the specified order.
|
// Sort the matches when using regular expression matching and sorting
|
||||||
if (!fuzzy && xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS) {
|
// applies to the completion context. Menus and scriptnames should be kept
|
||||||
if (xp->xp_context == EXPAND_EXPRESSION
|
// in the specified order.
|
||||||
|| xp->xp_context == EXPAND_FUNCTIONS
|
const bool sort_matches = !fuzzy
|
||||||
|| xp->xp_context == EXPAND_USER_FUNC) {
|
&& 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.
|
// <SNR> functions should be sorted to the end.
|
||||||
qsort(ga.ga_data, (size_t)ga.ga_len, sizeof(char *), sort_func_compare);
|
qsort(ga.ga_data, (size_t)ga.ga_len, sizeof(char *), sort_func_compare);
|
||||||
} else {
|
} else {
|
||||||
@ -2839,15 +2883,6 @@ static void ExpandGeneric(const char *const pat, expand_T *xp, regmatch_T *regma
|
|||||||
*matches = ga.ga_data;
|
*matches = ga.ga_data;
|
||||||
*numMatches = ga.ga_len;
|
*numMatches = ga.ga_len;
|
||||||
} else {
|
} 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);
|
fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len, funcsort);
|
||||||
*numMatches = ga.ga_len;
|
*numMatches = ga.ga_len;
|
||||||
}
|
}
|
||||||
|
@ -2387,7 +2387,7 @@ module.cmds = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
command='scriptnames',
|
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',
|
addr_type='ADDR_OTHER',
|
||||||
func='ex_scriptnames',
|
func='ex_scriptnames',
|
||||||
},
|
},
|
||||||
|
@ -2890,6 +2890,33 @@ static void append_command(char *cmd)
|
|||||||
*d = NUL;
|
*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.
|
/// Find an Ex command by its name, either built-in or user.
|
||||||
/// Start of the name can be found at eap->cmd.
|
/// Start of the name can be found at eap->cmd.
|
||||||
/// Sets eap->cmdidx and returns a pointer to char after the command name.
|
/// 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)
|
FUNC_ATTR_NONNULL_ARG(1)
|
||||||
{
|
{
|
||||||
// Isolate the command and search for it in the command table.
|
// 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;
|
char *p = eap->cmd;
|
||||||
if (*p == 'k') {
|
if (one_letter_cmd(p, &eap->cmdidx)) {
|
||||||
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;
|
|
||||||
p++;
|
p++;
|
||||||
} else {
|
} else {
|
||||||
while (ASCII_ISALPHA(*p)) {
|
while (ASCII_ISALPHA(*p)) {
|
||||||
@ -2938,6 +2946,7 @@ char *find_ex_command(exarg_T *eap, int *full)
|
|||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
int len = (int)(p - eap->cmd);
|
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')) {
|
if (*eap->cmd == 'd' && (p[-1] == 'l' || p[-1] == 'p')) {
|
||||||
// Check for ":dl", ":dell", etc. to ":deletel": that's
|
// Check for ":dl", ":dell", etc. to ":deletel": that's
|
||||||
// :delete with the 'l' flag. Same for 'p'.
|
// :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;
|
cmdidx_T idx;
|
||||||
|
|
||||||
for (idx = (cmdidx_T)0; (int)idx < CMD_SIZE; idx = (cmdidx_T)((int)idx + 1)) {
|
if (!one_letter_cmd(cmd, &idx)) {
|
||||||
if (strncmp(cmdnames[(int)idx].cmd_name, cmd, len) == 0) {
|
for (idx = (cmdidx_T)0; (int)idx < CMD_SIZE; idx = (cmdidx_T)((int)idx + 1)) {
|
||||||
break;
|
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);
|
old_curwin == NULL ? curwin : NULL);
|
||||||
} else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit)
|
} else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit)
|
||||||
|| *eap->arg != NUL) {
|
|| *eap->arg != NUL) {
|
||||||
// Can't edit another file when "curbuf->b_ro_locked" is set. Only ":edit"
|
// Can't edit another file when "textlock" or "curbuf->b_ro_locked" is set.
|
||||||
// can bring us here, others are stopped earlier.
|
// Only ":edit" or ":script" can bring us here, others are stopped earlier.
|
||||||
if (*eap->arg != NUL && curbuf_locked()) {
|
if (*eap->arg != NUL && text_or_buf_locked()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
n = readonlymode;
|
n = readonlymode;
|
||||||
|
@ -2160,12 +2160,17 @@ scriptitem_T *get_current_script_id(char **fnamep, sctx_T *ret_sctx)
|
|||||||
/// ":scriptnames"
|
/// ":scriptnames"
|
||||||
void ex_scriptnames(exarg_T *eap)
|
void ex_scriptnames(exarg_T *eap)
|
||||||
{
|
{
|
||||||
if (eap->addr_count > 0) {
|
if (eap->addr_count > 0 || *eap->arg != NUL) {
|
||||||
// :script {scriptId}: edit the script
|
// :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));
|
emsg(_(e_invarg));
|
||||||
} else {
|
} 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);
|
do_exedit(eap, NULL);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -3378,6 +3378,33 @@ func Test_cmdline_complete_breakdel()
|
|||||||
call assert_equal("\"breakdel here ", @:)
|
call assert_equal("\"breakdel here ", @:)
|
||||||
endfunc
|
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
|
" this was going over the end of IObuff
|
||||||
func Test_report_error_with_composing()
|
func Test_report_error_with_composing()
|
||||||
let caught = 'no'
|
let caught = 'no'
|
||||||
|
@ -1076,6 +1076,19 @@ func Test_sub_open_cmdline_win()
|
|||||||
call delete('Xresult')
|
call delete('Xresult')
|
||||||
endfunc
|
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
|
" Test for the 2-letter and 3-letter :substitute commands
|
||||||
func Test_substitute_short_cmd()
|
func Test_substitute_short_cmd()
|
||||||
new
|
new
|
||||||
|
@ -96,6 +96,7 @@ static const char *command_complete[] = {
|
|||||||
[EXPAND_USER] = "user",
|
[EXPAND_USER] = "user",
|
||||||
[EXPAND_USER_VARS] = "var",
|
[EXPAND_USER_VARS] = "var",
|
||||||
[EXPAND_BREAKPOINT] = "breakpoint",
|
[EXPAND_BREAKPOINT] = "breakpoint",
|
||||||
|
[EXPAND_SCRIPTNAMES] = "scriptnames",
|
||||||
};
|
};
|
||||||
|
|
||||||
/// List of names of address types. Must be alphabetical for completion.
|
/// List of names of address types. Must be alphabetical for completion.
|
||||||
|
@ -155,6 +155,7 @@ enum {
|
|||||||
EXPAND_ARGLIST,
|
EXPAND_ARGLIST,
|
||||||
EXPAND_DIFF_BUFFERS,
|
EXPAND_DIFF_BUFFERS,
|
||||||
EXPAND_BREAKPOINT,
|
EXPAND_BREAKPOINT,
|
||||||
|
EXPAND_SCRIPTNAMES,
|
||||||
EXPAND_CHECKHEALTH,
|
EXPAND_CHECKHEALTH,
|
||||||
EXPAND_LUA,
|
EXPAND_LUA,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user