Skip to content

Add cmdline tab-completion for setting string options #13182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from

Conversation

ychin
Copy link
Contributor

@ychin ychin commented Sep 25, 2023

Add tab-completion for setting string options on the cmdline using :set= (along with :set+= and :set-=).

The existing tab completion for setting options currently only works when nothing is typed yet, and it only fills in with the existing value, e.g. when the user does :set diffopt=<Tab> it will be completed to set diffopt=internal,filler,closeoff and nothing else. This isn't too useful as a user usually wants auto-complete to suggest all the possible values, such as 'iblank', or 'algorithm:patience'.

For set= and set+=, this adds a new optional callback function for each option that can be invoked when doing completion. This allows for each option to have control over how completion works. For example, in 'diffopt', it will suggest the default enumeration, but if algorithm: is selected, it will further suggest different algorithm types like 'meyers' and 'patience'. When using set=, the existing option value will be filled in as the first choice to preserve the existing behavior (this helps doing small edits to the option value). When using set+= this won't happen as it doesn't make sense to append an option by its own value in general.

For flag list options (e.g. 'mouse' and 'guioptions'), completion will take into account existing typed values (and in the case of set+=, the existing option value) to make sure it doesn't suggest duplicates.

For set-=, there is a new ExpandSettingSubtract function which will handle flag list and comma-separated options smartly, by only suggesting values that currently exist in the option so you won't try to subtract the wrong value.

Note that Vim has some existing code that adds special handling for 'filetype', 'syntax', and misc dir options like 'backupdir'. This change preserves them as they already work, instead of converting to the new callback API for each option.

Add tab-completion for setting string options on the cmdline using
`:set=` (along with `:set+=` and `:set-=`).

The existing tab completion for setting options currently only works
when nothing is typed yet, and it only fills in with the existing value,
e.g. when the user does `:set diffopt=<Tab>` it will be completed to
`set diffopt=internal,filler,closeoff` and nothing else. This isn't too
useful as a user usually wants auto-complete to suggest all the possible
values, such as 'iblank', or 'algorithm:patience'.

For set= and set+=, this adds a new optional callback function for each
option that can be invoked when doing completion. This allows for each
option to have control over how completion works. For example, in
'diffopt', it will suggest the default enumeration, but if `algorithm:`
is selected, it will further suggest different algorithm types like
'meyers' and 'patience'. When using set=, the existing option value will
be filled in as the first choice to preserve the existing behavior. When
using set+= this won't happen as it doesn't make sense.

For flag list options (e.g. 'mouse' and 'guioptions'), completion will
take into account existing typed values (and in the case of set+=, the
existing option value) to make sure it doesn't suggest duplicates.

For set-=, there is a new `ExpandSettingSubtract` function which will
handle flag list and comma-separated options smartly, by only suggesting
values that currently exist in the option.

Note that Vim has some existing code that adds special handling for
'filetype', 'syntax', and misc dir options like 'backupdir'. This change
preserves them as they already work, instead of converting to the new
callback API for each option.
@ychin
Copy link
Contributor Author

ychin commented Sep 25, 2023

Marking this as draft to gather some feedback first. I still need to do a couple things but would like to the basic feedback before proceeding. The couple things are:

  • Implement more options. Currently I only implemented a few as a proof of concept, and I tried to cover the ones that have complicated auto-complete rules like diffopt and spellsuggest and also the flag list options like mouse to make sure this system works. Most of the other options could be implemented with just a few lines if there is already a const char* pointer with the names, with some others maybe needing a more complicated code path to expose the possible names (if we don't want to duplicate them in code).
  • Add tests
  • Documentation

For the API design, I decided to add a generic function to each option (similar to what we did with opt_did_set_cb_T) that can do any expansion logic they like. I originally thought about an API that just returns a list of name or syntax tree instead of doing the regex matching itself (this is similar to how user functions work when using :command -complete) but I decided it may not provide enough flexibility, as the callback function may want to call other existing expansion functions.

I also decided not to touch 'filetype', 'syntax', 'backupdir' etc for now. Those have special handling and I left them be.

There are also some interesting behaviors I found with commas. E.g. if you have a file with a comma in it (e.g. file,with,comma, auto-complete currently fills the name as-is, which is wrong as it should be file\\,with\\,comma instead), but I don't want to fix that for now. There are other minor existing comma parsing issues. May file PR after this to fix it.

@ychin
Copy link
Contributor Author

ychin commented Sep 25, 2023

Some example screenshots:

set diffopt=<Tab>:

image

(special handling for individual algorithms):

image

set encoding=u<Tab>:

image

set shortmess+=rmsasw<Tab> (where shortmess has the default value filnxtToOS)

You can see that only the values not in the existing value and the currently typed value will be suggested to the user:

image

set shortmess=rmsasw<Tab>

You can see that when using set= instead of set+= for flags, the suggested options ignore the existing value and provide a lot more options, since the command is going to replace the entire existing value anyway.

image

set-=:

(note that these are grabbing the existing values that is set by the user and spit by comma)

image

(for flags, it also only presents the existing option values only. Example below has :set mouse=vn followed by set mouse-=<Tab>)

image

@chrisbra
Copy link
Member

Oh, I really like this

@benknoble
Copy link
Contributor

Awesome! Now I wonder if it’s possible to do something like completeopt’s popup for info: that is, when suggesting myers or a shortmess flag, display (a snip of) the relevant help text?

Probably would only be enabled for wop containing pum (bah, nonsense syllables).

@ychin
Copy link
Contributor Author

ychin commented Sep 25, 2023

Awesome! Now I wonder if it’s possible to do something like completeopt’s popup for info: that is, when suggesting myers or a shortmess flag, display (a snip of) the relevant help text?

Probably would only be enabled for wop containing pum (bah, nonsense syllables).

That's a good idea! It's definitely possible within this framework to be added later. I think the callback can return some info on the opt_expand_cb_T struct which tells Vim what to show in the popup menu (e.g. a help tag).

The more annoying problem is actually figuring out what to show. The 'shortmess' option has individiual help tags for each flag (e.g. shm-i), but not so for most other options (flags or comma-separated). I don't think we want each expansion callback to be overly long or intricate and having to do complicated logic, so I think a generic way to find the correct snippet could be implemented to show the relevant bits given some basic data (e.g. "diffopt" -> "meyers" will find the relevant docs and determine how many lines it is).

I do think if we want to do this (in a later commit), we may as well go all the way. Make it so that we could add popup docs for completing option names (e.g. :set dif<Tab>), or command names (:nno<Tab>), and user-provided completions when they define their own commands. Also, would be nice to expose that to getcompletion(), but I think that is more secondary.

Edit: (this makes me envious of Emacs… they have nice builtin documentation for a lot of builtin functions)

@benknoble
Copy link
Contributor

Yep, agreed with all you said, esp. the bits about later :)

Copy link
Member

@yegappan yegappan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very nice. Thanks for working on this. This will require quite a few new tests to make sure all the expansion cases are covered.

src/option.c Outdated
if ((nextchar == '-' || nextchar == '+' || nextchar == '^') && p[1] == '=')
{
if (nextchar == '-')
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be consistent the style followed for the next if statement, can you remove the braces for this if statement?

Copy link
Contributor Author

@ychin ychin Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can fix up the misc code styles issues. I do think it will be nice if at some point Vim can add a proper code formatter/linter that we can just run instead of having to manually conform. It's always a fair bit of work for the initial setup and code cleanups though so not suggesting right now.

src/option.c Outdated
*numMatches = 1;
return OK;
}

// Expansion handler for :set=/:set+= when the option has a custom expansion handler.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For function headers, the style is to use the three part "/* */" comments.

'whichwrap': This option is quite weird as it's a comma-separated flag
list (the commas are actually optional). Fix up the logic for set-= to
handle it properly, and remove the ',' from WW_ALL so auto-complete
works properly.

'concealcursor': This option is a flag list option but wasn't tagged
correctly. Make sure to tag it as a P_FLAGLIST to make sure it follows
the same logic as other similar options (e.g. 'mouse').
Some of these require keeping in sync with the parsing code, as the
expansion code is using a separate char* array.

List of options:
- breakindentopt
- clipboard
- complete
- cursorlineopt
  - If we change the parsing code to use `opt_strings_flags()` instead,
    we wouldn't have to duplicate the array. But it works for now.
- eventignore
- keyprotocol
  - Only the protocol (the second part after the colon) is matched. The
    first part (term name) is not matched, since there is no good weay
    to do so.
- lispoptions
- printoptions
- rightleftcmd
- spelloptions
- wildmode

Also, make the options that use ExpandGeneric not sort the results to
give us more control.
@ychin
Copy link
Contributor Author

ychin commented Sep 28, 2023

Just pushed an update. I have now implemented all the options that I intended to. Among them, most of them are simple enumeration type options, or flags, and just consist of a few lines of additions. Some other options are a little more involved, and I tried to split the commits up to make them easier to review. If it's too much, I could split them into separate PRs to do later.

Among them, highlight is probably the most complicated, but diffopt / previewpopup / completepopup / keyprotocol are non-trivial as well.

Among the remaining options, I think some of them could have auto-complete added to them but I don't feel like adding them for now:

  • mouseshape / guicursor (possible, just need custom parsing for the dashes)
  • Misc font options like guifont (platform-dependent)
  • renderoptions (too niche)
  • viminfo (complicated to parse)
  • statusline (just… no)

@ychin ychin force-pushed the cmdline-tab-complete-set-options branch 2 times, most recently from 33390a5 to be30d74 Compare September 29, 2023 06:55
- Fix optiondef to make sure it works on tiny / gui builds
- Fix misc warnings
@ychin ychin force-pushed the cmdline-tab-complete-set-options branch from be30d74 to 388570f Compare September 29, 2023 07:21
Make sure to clean up the match array if we found no matches because the
caller doesn't clean up returned array if the number of matches is 0.

Also, fix a bug in immediately returning instead of just setting a ret
variable.
Deal with Windows escaping slashes differently on cmdline

Also fix 'bg' could either be dark or light.
@codecov
Copy link

codecov bot commented Sep 29, 2023

Codecov Report

Merging #13182 (12b6b18) into master (ec8deb0) will increase coverage by 0.01%.
Report is 20 commits behind head on master.
The diff coverage is 88.94%.

@@            Coverage Diff             @@
##           master   #13182      +/-   ##
==========================================
+ Coverage   82.12%   82.14%   +0.01%     
==========================================
  Files         160      160              
  Lines      195360   196007     +647     
  Branches    43823    43921      +98     
==========================================
+ Hits       160446   161014     +568     
- Misses      22076    22133      +57     
- Partials    12838    12860      +22     
Flag Coverage Δ
huge-clang-Array 82.78% <88.61%> (+0.04%) ⬆️
linux 82.78% <88.61%> (+0.04%) ⬆️
mingw-x64-HUGE 76.75% <85.60%> (+0.03%) ⬆️
mingw-x86-HUGE 77.25% <85.40%> (+0.03%) ⬆️
windows 78.33% <85.64%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
src/autocmd.c 87.68% <100.00%> (+0.01%) ⬆️
src/clipboard.c 73.83% <ø> (+0.10%) ⬆️
src/cmdexpand.c 91.06% <100.00%> (+0.14%) ⬆️
src/diff.c 83.32% <ø> (ø)
src/ex_getln.c 86.35% <ø> (ø)
src/highlight.c 81.56% <ø> (ø)
src/indent.c 87.19% <ø> (ø)
src/mbyte.c 73.16% <100.00%> (+0.07%) ⬆️
src/popupwin.c 86.55% <ø> (ø)
src/screen.c 80.85% <100.00%> (-0.04%) ⬇️
... and 4 more

... and 20 files with indirect coverage changes

@ychin ychin force-pushed the cmdline-tab-complete-set-options branch 4 times, most recently from 3a12c75 to a446b8b Compare September 29, 2023 12:46
@ychin ychin force-pushed the cmdline-tab-complete-set-options branch from a446b8b to 12b6b18 Compare September 29, 2023 13:12
@ychin ychin marked this pull request as ready for review September 29, 2023 13:12
@ychin
Copy link
Contributor Author

ychin commented Sep 29, 2023

Ok, I think this PR is ready to be reviewed. It should work, with the tests implemented, docs updated, etc.

Comment on lines 368 to 374
" Expand value for 'key'
set key=abcd
call feedkeys(":set key=\<Tab>\<C-B>\"\<CR>", 'xt')
call assert_equal('"set key=*****', @:)
call feedkeys(":set key-=\<Tab>\<C-B>\"\<CR>", 'xt')
call assert_equal('"set key-=*****', @:)
set key=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to also need if has('+key'). 'key' option doesn't work if FEAT_CRYPT isn't enabled.

Copy link
Member

@chrisbra chrisbra Sep 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove the whole completion for set key (I mean what sense does it make to autocomplete *****) and I also don't want to accidentally leak the crypt-key. ah this already seems to happen with the current vim. So probably fine. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was actually going to suggest that in a separate PR! Since I was looking into cmdline completion, I think key needs some hardening.

I was going to propose removing completion for set key, and also remove set-= / set+= / set^=. Those have some security ramifications since they allow you to guess a substring of the key. We can just keep set=.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, yes makes sense!

@chrisbra chrisbra closed this in 900894b Sep 29, 2023
@ychin ychin deleted the cmdline-tab-complete-set-options branch September 29, 2023 19:51
@@ -382,6 +386,278 @@ func Test_set_completion()
call assert_equal('"set syntax=' .. getcompletion('a*', 'syntax')->join(), @:)
endfunc

" Test handling of expanding individual string option values
func Test_set_completion_string_values()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the assert_equal() calls in this function have wrong order of arguments. This will make error message confusing if test fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right… the first item is the expected value. I internalized the weirdness when I was debugging this but didn't correct it. I could fix it in a follow-up commit.

Comment on lines +4971 to +4982
/*
* Function given to ExpandGeneric() to obtain possible arguments of the
* 'listchars' option.
*/
char_u *
get_listchars_name(expand_T *xp UNUSED, int idx)
{
if (idx >= (int)(sizeof(lcstab) / sizeof(lcstab[0])))
return NULL;

return (char_u*)lcstab[idx].name;
}
Copy link
Member

@zeertzjq zeertzjq Sep 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These don't include multispace and leadmultispace

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created PR #13225 to fix this.

@@ -1837,7 +1837,7 @@ stropt_get_newval(
&(options[opt_idx]), OPT_GLOBAL));
else
{
++arg; // jump to after the '=' or ':'
++arg; // joption_value2stringump to after the '=' or ':'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like an accidental mistake

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it was pointed out in 900894b#r128808467 as well. I have a follow-up PR that will fix this.

while (s > xp->xp_pattern && *(s - 1) == '\\')
--s;
if ((*p == ' ' && (xp->xp_backslash == XP_BS_THREE && (p - s) < 3))
|| (*p == ',' && (flags & P_COMMA) && ((p - s) % 1) == 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (p - s) % 1 looks strange. Isn't any number module 1 always 0?

Copy link
Contributor Author

@ychin ychin Oct 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are absolutely right. I only moved this code around and added the P_COLON check below it but I didn't change the logic for handling commas here. As you said, the logic here is wrong. I didn't want the scope of PR to grow any more which is why I didn't fix it.

I think the correct logic here is actually (p - s) >= 2. Currently, if you have a file/folder of the name foo,bar, the correct way to specify it in an option is do so something like :set backupdir=dir1,foo\\,bar,dir2 (note that this is equivalent to :set backupdir=dir1,foo\\\,bar,dir2). Note that you will see that in the test cases that I added, they actually check that set-= will correctly escape the commas to insert those "\" when doing set path-=<Tab>.

Note: there's another cmd auto-complete bug (that's why I wanted to fix this in another PR instead of growing in scope). In the above example, if you do auto-complete as follows: set backupdir=fo<Tab>, if will complete to set backupdir=foo,bar, forgetting to insert the \\ there. In general the option setting syntax is a little weird regarding commas, as I believe the syntax is incomplete and doesn't allow certain types of names to be entered (you cannot enter a folder/file that ends with "", because that slash will end up escaping the comma instead).

tldr: Yes it's broken, but it's broken before my change and I could submit another PR to fix it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commas will be fixed in #13303

@yegappan
Copy link
Member

yegappan commented Oct 1, 2023

The following warning messages are displayed in the Appveyor CI build (introduced by this PR):

option.c(7992): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(866): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(1768): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(2453): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(2939): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(2950): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(2961): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data

@ychin
Copy link
Contributor Author

ychin commented Oct 1, 2023

The following warning messages are displayed in the Appveyor CI build (introduced by this PR):

option.c(7992): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(866): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(1768): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(2453): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(2939): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(2950): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data
optionstr.c(2961): warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data

Ok, I will fix them up in #13237. Found a couple other places that trigger warnings as well if I turn on -Wsign-conversion. I wish warnings like these are turned into errors though (like in the main GitHub CI build). Otherwise it's quite hard to find out.

zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Oct 1, 2023
Problem:  cannot complete option values
Solution: Add completion functions for several options

Add cmdline tab-completion for setting string options

Add tab-completion for setting string options on the cmdline using
`:set=` (along with `:set+=` and `:set-=`).

The existing tab completion for setting options currently only works
when nothing is typed yet, and it only fills in with the existing value,
e.g. when the user does `:set diffopt=<Tab>` it will be completed to
`set diffopt=internal,filler,closeoff` and nothing else. This isn't too
useful as a user usually wants auto-complete to suggest all the possible
values, such as 'iblank', or 'algorithm:patience'.

For set= and set+=, this adds a new optional callback function for each
option that can be invoked when doing completion. This allows for each
option to have control over how completion works. For example, in
'diffopt', it will suggest the default enumeration, but if `algorithm:`
is selected, it will further suggest different algorithm types like
'meyers' and 'patience'. When using set=, the existing option value will
be filled in as the first choice to preserve the existing behavior. When
using set+= this won't happen as it doesn't make sense.

For flag list options (e.g. 'mouse' and 'guioptions'), completion will
take into account existing typed values (and in the case of set+=, the
existing option value) to make sure it doesn't suggest duplicates.

For set-=, there is a new `ExpandSettingSubtract` function which will
handle flag list and comma-separated options smartly, by only suggesting
values that currently exist in the option.

Note that Vim has some existing code that adds special handling for
'filetype', 'syntax', and misc dir options like 'backupdir'. This change
preserves them as they already work, instead of converting to the new
callback API for each option.

closes: vim/vim#13182

vim/vim@900894b

Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Oct 1, 2023
Problem:  cannot complete option values
Solution: Add completion functions for several options

Add cmdline tab-completion for setting string options

Add tab-completion for setting string options on the cmdline using
`:set=` (along with `:set+=` and `:set-=`).

The existing tab completion for setting options currently only works
when nothing is typed yet, and it only fills in with the existing value,
e.g. when the user does `:set diffopt=<Tab>` it will be completed to
`set diffopt=internal,filler,closeoff` and nothing else. This isn't too
useful as a user usually wants auto-complete to suggest all the possible
values, such as 'iblank', or 'algorithm:patience'.

For set= and set+=, this adds a new optional callback function for each
option that can be invoked when doing completion. This allows for each
option to have control over how completion works. For example, in
'diffopt', it will suggest the default enumeration, but if `algorithm:`
is selected, it will further suggest different algorithm types like
'meyers' and 'patience'. When using set=, the existing option value will
be filled in as the first choice to preserve the existing behavior. When
using set+= this won't happen as it doesn't make sense.

For flag list options (e.g. 'mouse' and 'guioptions'), completion will
take into account existing typed values (and in the case of set+=, the
existing option value) to make sure it doesn't suggest duplicates.

For set-=, there is a new `ExpandSettingSubtract` function which will
handle flag list and comma-separated options smartly, by only suggesting
values that currently exist in the option.

Note that Vim has some existing code that adds special handling for
'filetype', 'syntax', and misc dir options like 'backupdir'. This change
preserves them as they already work, instead of converting to the new
callback API for each option.

closes: vim/vim#13182

vim/vim@900894b

Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Oct 1, 2023
Problem:  cannot complete option values
Solution: Add completion functions for several options

Add cmdline tab-completion for setting string options

Add tab-completion for setting string options on the cmdline using
`:set=` (along with `:set+=` and `:set-=`).

The existing tab completion for setting options currently only works
when nothing is typed yet, and it only fills in with the existing value,
e.g. when the user does `:set diffopt=<Tab>` it will be completed to
`set diffopt=internal,filler,closeoff` and nothing else. This isn't too
useful as a user usually wants auto-complete to suggest all the possible
values, such as 'iblank', or 'algorithm:patience'.

For set= and set+=, this adds a new optional callback function for each
option that can be invoked when doing completion. This allows for each
option to have control over how completion works. For example, in
'diffopt', it will suggest the default enumeration, but if `algorithm:`
is selected, it will further suggest different algorithm types like
'meyers' and 'patience'. When using set=, the existing option value will
be filled in as the first choice to preserve the existing behavior. When
using set+= this won't happen as it doesn't make sense.

For flag list options (e.g. 'mouse' and 'guioptions'), completion will
take into account existing typed values (and in the case of set+=, the
existing option value) to make sure it doesn't suggest duplicates.

For set-=, there is a new `ExpandSettingSubtract` function which will
handle flag list and comma-separated options smartly, by only suggesting
values that currently exist in the option.

Note that Vim has some existing code that adds special handling for
'filetype', 'syntax', and misc dir options like 'backupdir'. This change
preserves them as they already work, instead of converting to the new
callback API for each option.

closes: vim/vim#13182

vim/vim@900894b

Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
zeertzjq added a commit to zeertzjq/neovim that referenced this pull request Oct 1, 2023
Problem:  cannot complete option values
Solution: Add completion functions for several options

Add cmdline tab-completion for setting string options

Add tab-completion for setting string options on the cmdline using
`:set=` (along with `:set+=` and `:set-=`).

The existing tab completion for setting options currently only works
when nothing is typed yet, and it only fills in with the existing value,
e.g. when the user does `:set diffopt=<Tab>` it will be completed to
`set diffopt=internal,filler,closeoff` and nothing else. This isn't too
useful as a user usually wants auto-complete to suggest all the possible
values, such as 'iblank', or 'algorithm:patience'.

For set= and set+=, this adds a new optional callback function for each
option that can be invoked when doing completion. This allows for each
option to have control over how completion works. For example, in
'diffopt', it will suggest the default enumeration, but if `algorithm:`
is selected, it will further suggest different algorithm types like
'meyers' and 'patience'. When using set=, the existing option value will
be filled in as the first choice to preserve the existing behavior. When
using set+= this won't happen as it doesn't make sense.

For flag list options (e.g. 'mouse' and 'guioptions'), completion will
take into account existing typed values (and in the case of set+=, the
existing option value) to make sure it doesn't suggest duplicates.

For set-=, there is a new `ExpandSettingSubtract` function which will
handle flag list and comma-separated options smartly, by only suggesting
values that currently exist in the option.

Note that Vim has some existing code that adds special handling for
'filetype', 'syntax', and misc dir options like 'backupdir'. This change
preserves them as they already work, instead of converting to the new
callback API for each option.

closes: vim/vim#13182

vim/vim@900894b

Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
ychin added a commit to ychin/vim that referenced this pull request Oct 4, 2023
Currently cmdline expansion for setting option values that take a list
of file names (as a comma-separated list) isn't accounting for file
names with commas. For such options, the commas need to be escaped, as a
reverse of `copy_option_part()` which will unescape it.

Fix as follows:
- Cmdline expansion for options with comma-separated file/folder names
  will not start a new match when seeing `\\,` and will instead consider
  it as one value.
- File/folder matching code will strip the `\\` when seeing `\\,` to
  make sure it can find the correct files/folders.
- The expanded value will escape `,` with `\\,`, similar to how spaces
  are escaped.

Also fix up documentation to be clearer. The existing docs are
misleading in how it discusses triple slashes for 'tags'.

Also, see: vim#13182 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants