vim-patch:8.2.4617: no completion for :scriptnames

Problem:    No completion for :scriptnames.
Solution:   Implement :scriptnames completion. (Yegappan Lakshmanan,
            closes vim/vim#10005)

454ce6737c

Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
zeertzjq 2023-01-17 16:07:38 +08:00
parent 2d71ed9929
commit 3db2139195
7 changed files with 92 additions and 19 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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',
},

View File

@ -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;

View File

@ -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'

View File

@ -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.

View File

@ -155,6 +155,7 @@ enum {
EXPAND_ARGLIST,
EXPAND_DIFF_BUFFERS,
EXPAND_BREAKPOINT,
EXPAND_SCRIPTNAMES,
EXPAND_CHECKHEALTH,
EXPAND_LUA,
};