mirror of
https://github.com/neovim/neovim
synced 2025-07-15 16:51:49 +00:00
Merge pull request #34852 from zeertzjq/vim-9.1.1526
vim-patch:9.1.{1526,1528}
This commit is contained in:
@ -7173,6 +7173,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
< 'wildchar' also enables completion in search pattern contexts such as
|
||||
|/|, |?|, |:s|, |:g|, |:v|, and |:vim|. To insert a literal <Tab>
|
||||
instead of triggering completion, type <C-V><Tab> or "\t".
|
||||
See also |'wildoptions'|.
|
||||
|
||||
*'wildcharm'* *'wcm'*
|
||||
'wildcharm' 'wcm' number (default 0)
|
||||
@ -7319,6 +7320,20 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
global
|
||||
A list of words that change how |cmdline-completion| is done.
|
||||
The following values are supported:
|
||||
exacttext When this flag is present, search pattern completion
|
||||
(e.g., in |/|, |?|, |:s|, |:g|, |:v|, and |:vim|)
|
||||
shows exact buffer text as menu items, without
|
||||
preserving regex artifacts like position
|
||||
anchors (e.g., |/\<|). This provides more intuitive
|
||||
menu items that match the actual buffer text.
|
||||
However, searches may be less accurate since the
|
||||
pattern is not preserved exactly.
|
||||
By default, Vim preserves the typed pattern (with
|
||||
anchors) and appends the matched word. This preserves
|
||||
search correctness, especially when using regular
|
||||
expressions or with 'smartcase' enabled. However, the
|
||||
case of the appended matched word may not exactly
|
||||
match the case of the word in the buffer.
|
||||
fuzzy Use |fuzzy-matching| to find completion matches. When
|
||||
this value is specified, wildcard expansion will not
|
||||
be used for completion. The matches will be sorted by
|
||||
|
15
runtime/lua/vim/_meta/options.lua
generated
15
runtime/lua/vim/_meta/options.lua
generated
@ -7818,6 +7818,7 @@ vim.go.ww = vim.go.whichwrap
|
||||
--- 'wildchar' also enables completion in search pattern contexts such as
|
||||
--- `/`, `?`, `:s`, `:g`, `:v`, and `:vim`. To insert a literal <Tab>
|
||||
--- instead of triggering completion, type <C-V><Tab> or "\t".
|
||||
--- See also `'wildoptions'`.
|
||||
---
|
||||
--- @type integer
|
||||
vim.o.wildchar = 9
|
||||
@ -8012,6 +8013,20 @@ vim.go.wim = vim.go.wildmode
|
||||
|
||||
--- A list of words that change how `cmdline-completion` is done.
|
||||
--- The following values are supported:
|
||||
--- exacttext When this flag is present, search pattern completion
|
||||
--- (e.g., in `/`, `?`, `:s`, `:g`, `:v`, and `:vim`)
|
||||
--- shows exact buffer text as menu items, without
|
||||
--- preserving regex artifacts like position
|
||||
--- anchors (e.g., `/\\<`). This provides more intuitive
|
||||
--- menu items that match the actual buffer text.
|
||||
--- However, searches may be less accurate since the
|
||||
--- pattern is not preserved exactly.
|
||||
--- By default, Vim preserves the typed pattern (with
|
||||
--- anchors) and appends the matched word. This preserves
|
||||
--- search correctness, especially when using regular
|
||||
--- expressions or with 'smartcase' enabled. However, the
|
||||
--- case of the appended matched word may not exactly
|
||||
--- match the case of the word in the buffer.
|
||||
--- fuzzy Use `fuzzy-matching` to find completion matches. When
|
||||
--- this value is specified, wildcard expansion will not
|
||||
--- be used for completion. The matches will be sorted by
|
||||
|
@ -249,13 +249,14 @@ int nextwild(expand_T *xp, int type, int options, bool escape)
|
||||
char *p;
|
||||
|
||||
if (xp->xp_numfiles == -1) {
|
||||
may_expand_pattern = options & WILD_MAY_EXPAND_PATTERN;
|
||||
pre_incsearch_pos = xp->xp_pre_incsearch_pos;
|
||||
if (ccline->input_fn && ccline->xp_context == EXPAND_COMMANDS) {
|
||||
// Expand commands typed in input() function
|
||||
set_cmd_context(xp, ccline->cmdbuff, ccline->cmdlen, ccline->cmdpos, false);
|
||||
} else {
|
||||
may_expand_pattern = options & WILD_MAY_EXPAND_PATTERN;
|
||||
set_expand_context(xp);
|
||||
may_expand_pattern = false;
|
||||
}
|
||||
if (xp->xp_context == EXPAND_LUA) {
|
||||
nlua_expand_pat(xp);
|
||||
@ -3893,6 +3894,8 @@ void f_cmdcomplete_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
/// matched text is returned in '*match_end'.
|
||||
static int copy_substring_from_pos(pos_T *start, pos_T *end, char **match, pos_T *match_end)
|
||||
{
|
||||
bool exacttext = wop_flags & kOptWopFlagExacttext;
|
||||
|
||||
if (start->lnum > end->lnum
|
||||
|| (start->lnum == end->lnum && start->col >= end->col)) {
|
||||
return FAIL; // invalid range
|
||||
@ -3909,19 +3912,27 @@ static int copy_substring_from_pos(pos_T *start, pos_T *end, char **match, pos_T
|
||||
|
||||
int segment_len = is_single_line ? (int)(end->col - start->col)
|
||||
: (int)strlen(start_ptr);
|
||||
ga_grow(&ga, segment_len + 1);
|
||||
ga_grow(&ga, segment_len + 2);
|
||||
ga_concat_len(&ga, start_ptr, (size_t)segment_len);
|
||||
if (!is_single_line) {
|
||||
ga_append(&ga, '\n');
|
||||
if (exacttext) {
|
||||
ga_concat_len(&ga, "\\n", 2);
|
||||
} else {
|
||||
ga_append(&ga, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Append full lines between start and end
|
||||
if (!is_single_line) {
|
||||
for (linenr_T lnum = start->lnum + 1; lnum < end->lnum; lnum++) {
|
||||
char *line = ml_get(lnum);
|
||||
ga_grow(&ga, ml_get_len(lnum) + 1);
|
||||
ga_grow(&ga, ml_get_len(lnum) + 2);
|
||||
ga_concat(&ga, line);
|
||||
ga_append(&ga, '\n');
|
||||
if (exacttext) {
|
||||
ga_concat_len(&ga, "\\n", 2);
|
||||
} else {
|
||||
ga_append(&ga, '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4004,6 +4015,7 @@ static char *concat_pattern_with_buffer_match(char *pat, int pat_len, pos_T *end
|
||||
/// @param[out] numMatches number of matches
|
||||
static int expand_pattern_in_buf(char *pat, Direction dir, char ***matches, int *numMatches)
|
||||
{
|
||||
bool exacttext = wop_flags & kOptWopFlagExacttext;
|
||||
bool has_range = search_first_line != 0;
|
||||
|
||||
*matches = NULL;
|
||||
@ -4090,22 +4102,26 @@ static int expand_pattern_in_buf(char *pat, Direction dir, char ***matches, int
|
||||
break;
|
||||
}
|
||||
|
||||
// Construct a new match from completed word appended to pattern itself
|
||||
match = concat_pattern_with_buffer_match(pat, pat_len, &end_match_pos, false);
|
||||
if (exacttext) {
|
||||
match = full_match;
|
||||
} else {
|
||||
// Construct a new match from completed word appended to pattern itself
|
||||
match = concat_pattern_with_buffer_match(pat, pat_len, &end_match_pos, false);
|
||||
|
||||
// The regex pattern may include '\C' or '\c'. First, try matching the
|
||||
// buffer word as-is. If it doesn't match, try again with the lowercase
|
||||
// version of the word to handle smartcase behavior.
|
||||
if (!is_regex_match(match, full_match)) {
|
||||
xfree(match);
|
||||
match = concat_pattern_with_buffer_match(pat, pat_len, &end_match_pos, true);
|
||||
// The regex pattern may include '\C' or '\c'. First, try matching the
|
||||
// buffer word as-is. If it doesn't match, try again with the lowercase
|
||||
// version of the word to handle smartcase behavior.
|
||||
if (!is_regex_match(match, full_match)) {
|
||||
xfree(match);
|
||||
xfree(full_match);
|
||||
continue;
|
||||
match = concat_pattern_with_buffer_match(pat, pat_len, &end_match_pos, true);
|
||||
if (!is_regex_match(match, full_match)) {
|
||||
xfree(match);
|
||||
xfree(full_match);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
xfree(full_match);
|
||||
}
|
||||
xfree(full_match);
|
||||
|
||||
// Include this match if it is not a duplicate
|
||||
for (int i = 0; i < ga.ga_len; i++) {
|
||||
|
@ -10117,6 +10117,7 @@ local options = {
|
||||
< 'wildchar' also enables completion in search pattern contexts such as
|
||||
|/|, |?|, |:s|, |:g|, |:v|, and |:vim|. To insert a literal <Tab>
|
||||
instead of triggering completion, type <C-V><Tab> or "\t".
|
||||
See also |'wildoptions'|.
|
||||
]=],
|
||||
full_name = 'wildchar',
|
||||
scope = { 'global' },
|
||||
@ -10311,12 +10312,26 @@ local options = {
|
||||
{
|
||||
abbreviation = 'wop',
|
||||
defaults = 'pum,tagfile',
|
||||
values = { 'fuzzy', 'tagfile', 'pum' },
|
||||
values = { 'fuzzy', 'tagfile', 'pum', 'exacttext' },
|
||||
flags = true,
|
||||
deny_duplicates = true,
|
||||
desc = [=[
|
||||
A list of words that change how |cmdline-completion| is done.
|
||||
The following values are supported:
|
||||
exacttext When this flag is present, search pattern completion
|
||||
(e.g., in |/|, |?|, |:s|, |:g|, |:v|, and |:vim|)
|
||||
shows exact buffer text as menu items, without
|
||||
preserving regex artifacts like position
|
||||
anchors (e.g., |/\\<|). This provides more intuitive
|
||||
menu items that match the actual buffer text.
|
||||
However, searches may be less accurate since the
|
||||
pattern is not preserved exactly.
|
||||
By default, Vim preserves the typed pattern (with
|
||||
anchors) and appends the matched word. This preserves
|
||||
search correctness, especially when using regular
|
||||
expressions or with 'smartcase' enabled. However, the
|
||||
case of the appended matched word may not exactly
|
||||
match the case of the word in the buffer.
|
||||
fuzzy Use |fuzzy-matching| to find completion matches. When
|
||||
this value is specified, wildcard expansion will not
|
||||
be used for completion. The matches will be sorted by
|
||||
|
@ -4499,14 +4499,16 @@ func Test_search_complete()
|
||||
" Match case correctly
|
||||
%d
|
||||
call setline(1, ["foobar", "Foobar", "fooBAr", "FooBARR"])
|
||||
|
||||
call feedkeys("gg/f\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['fooBAr', 'foobar'], g:compl_info.matches)
|
||||
call feedkeys("gg/Fo\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['Foobar', 'FooBARR'], g:compl_info.matches)
|
||||
call feedkeys("gg/FO\<tab>\<f9>", 'tx')
|
||||
call assert_equal({}, g:compl_info)
|
||||
call assert_equal({}, g:compl_info)
|
||||
call feedkeys("gg/\\cFo\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['\cFoobar', '\cFooBAr', '\cFooBARR'], g:compl_info.matches)
|
||||
|
||||
set ignorecase
|
||||
call feedkeys("gg/f\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['foobar', 'fooBAr', 'fooBARR'], g:compl_info.matches)
|
||||
@ -4516,23 +4518,55 @@ func Test_search_complete()
|
||||
call assert_equal(['FOobar', 'FOoBAr', 'FOoBARR'], g:compl_info.matches)
|
||||
call feedkeys("gg/\\Cfo\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['\CfooBAr', '\Cfoobar'], g:compl_info.matches)
|
||||
|
||||
set smartcase
|
||||
call feedkeys("gg/f\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['foobar', 'fooBAr', 'foobarr'], g:compl_info.matches)
|
||||
call feedkeys("gg/Fo\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['Foobar', 'FooBARR'], g:compl_info.matches)
|
||||
call feedkeys("gg/FO\<tab>\<f9>", 'tx')
|
||||
call assert_equal({}, g:compl_info)
|
||||
call assert_equal({}, g:compl_info)
|
||||
|
||||
" Issue #17680 (getcompletion() does not support search completion)
|
||||
let result = getcompletion('%s/', 'cmdline')
|
||||
call assert_equal([], result)
|
||||
|
||||
call feedkeys("gg/foob\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['foobar', 'foobarr'], g:compl_info.matches)
|
||||
call feedkeys("gg/\\Cfo\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['\CfooBAr', '\Cfoobar'], g:compl_info.matches)
|
||||
call feedkeys("gg/\\cFo\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['\cFoobar', '\cFooBAr', '\cFooBARR'], g:compl_info.matches)
|
||||
|
||||
set wildoptions+=exacttext ignorecase& smartcase&
|
||||
call feedkeys("gg/F\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['Foobar', 'FooBARR'], g:compl_info.matches)
|
||||
call feedkeys("gg/foob\<tab>\<f9>", 'tx')
|
||||
call assert_equal([], g:compl_info.matches)
|
||||
call feedkeys("gg/r\\n.\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['r\nFoobar', 'r\nfooBAr', 'r\nFooBARR'], g:compl_info.matches)
|
||||
|
||||
set ignorecase
|
||||
call feedkeys("gg/F\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['Foobar', 'fooBAr', 'FooBARR', 'foobar'], g:compl_info.matches)
|
||||
call feedkeys("gg/R\\n.\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['r\nFoobar', 'r\nfooBAr', 'r\nFooBARR'], g:compl_info.matches)
|
||||
|
||||
set smartcase
|
||||
call feedkeys("gg/f\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['Foobar', 'fooBAr', 'FooBARR', 'foobar'], g:compl_info.matches)
|
||||
call feedkeys("gg/foob\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['Foobar', 'fooBAr', 'FooBARR', 'foobar'], g:compl_info.matches)
|
||||
call feedkeys("gg/R\\n.\<tab>\<f9>", 'tx')
|
||||
call assert_equal({}, g:compl_info)
|
||||
call feedkeys("gg/r\\n.*\\n\<tab>\<f9>", 'tx')
|
||||
call assert_equal(['r\nFoobar\nfooBAr', 'r\nfooBAr\nFooBARR'], g:compl_info.matches)
|
||||
|
||||
bw!
|
||||
call Ntest_override("char_avail", 0)
|
||||
delfunc GetComplInfo
|
||||
unlet! g:compl_info
|
||||
set wildcharm=0 incsearch& ignorecase& smartcase&
|
||||
set wildcharm=0 incsearch& ignorecase& smartcase& wildoptions&
|
||||
endfunc
|
||||
|
||||
func Test_search_wildmenu_screendump()
|
||||
@ -4601,44 +4635,44 @@ func Test_range_complete()
|
||||
|
||||
for trig in ["\<tab>", "\<c-z>"]
|
||||
call feedkeys($":%s/a{trig}\<f9>", 'xt')
|
||||
call assert_equal(['ab', 'a', 'af'], g:compl_info.matches)
|
||||
call assert_equal(['ab', 'a', 'af'], g:compl_info.matches)
|
||||
" call feedkeys($":vim9cmd :%s/a{trig}\<f9>", 'xt')
|
||||
call feedkeys($":verbose :%s/a{trig}\<f9>", 'xt')
|
||||
call assert_equal(['ab', 'a', 'af'], g:compl_info.matches)
|
||||
call assert_equal(['ab', 'a', 'af'], g:compl_info.matches)
|
||||
endfor
|
||||
|
||||
call feedkeys(":%s/\<c-z>\<f9>", 'xt')
|
||||
call assert_equal({}, g:compl_info)
|
||||
call assert_equal({}, g:compl_info)
|
||||
|
||||
for cmd in ['s', 'g']
|
||||
call feedkeys(":1,2" . cmd . "/a\<c-z>\<f9>", 'xt')
|
||||
call assert_equal(['ab', 'a'], g:compl_info.matches)
|
||||
call feedkeys($":1,2{cmd}/a\<c-z>\<f9>", 'xt')
|
||||
call assert_equal(['ab', 'a'], g:compl_info.matches)
|
||||
endfor
|
||||
|
||||
1
|
||||
call feedkeys(":.,+2s/a\<c-z>\<f9>", 'xt')
|
||||
call assert_equal(['ab', 'a'], g:compl_info.matches)
|
||||
call assert_equal(['ab', 'a'], g:compl_info.matches)
|
||||
|
||||
/f
|
||||
call feedkeys(":1,s/b\<c-z>\<f9>", 'xt')
|
||||
call assert_equal(['b', 'ba'], g:compl_info.matches)
|
||||
call assert_equal(['b', 'ba'], g:compl_info.matches)
|
||||
|
||||
/c
|
||||
call feedkeys(":\\?,4s/a\<c-z>\<f9>", 'xt')
|
||||
call assert_equal(['a', 'af'], g:compl_info.matches)
|
||||
call assert_equal(['a', 'af'], g:compl_info.matches)
|
||||
|
||||
%s/c/c/
|
||||
call feedkeys(":1,\\&s/a\<c-z>\<f9>", 'xt')
|
||||
call assert_equal(['ab', 'a'], g:compl_info.matches)
|
||||
call assert_equal(['ab', 'a'], g:compl_info.matches)
|
||||
|
||||
3
|
||||
normal! ma
|
||||
call feedkeys(":'a,$s/a\<c-z>\<f9>", 'xt')
|
||||
call assert_equal(['a', 'af'], g:compl_info.matches)
|
||||
call assert_equal(['a', 'af'], g:compl_info.matches)
|
||||
|
||||
" Line number followed by a search pattern ([start]/pattern/[command])
|
||||
call feedkeys("3/a\<c-z>\<f9>", 'xt')
|
||||
call assert_equal(['a', 'af', 'ab'], g:compl_info.matches)
|
||||
call assert_equal(['a', 'af', 'ab'], g:compl_info.matches)
|
||||
|
||||
bw!
|
||||
call Ntest_override("char_avail", 0)
|
||||
|
Reference in New Issue
Block a user