11

I cannot count the number of times I have tried to do this:

:set foldmethod=syn^I

It seems that completion doesn't work on option values!

In some cases options are complex strings where completion might not make sense. (E.g. 'comments'.)

But have there been any efforts to provide wildchar-completion for the common use-cases?

If not, how could I make the example above work? (Assuming I wanted to complete to one of the strings ['manual', 'indent', 'expr', 'marker', 'syntax'].)

3 Answers 3

3

You could try the following code:

let s:option_values = {'foldmethod'  : ['manual', 'indent', 'expr', 'marker', 'syntax'],
                     \ 'bufhidden'   : ['hide', 'unload', 'delete', 'wipe'],
                     \ 'virtualedit' : ['block', 'insert', 'all', 'onemore'] ,}

set wildcharm=<c-z>

cnoremap <expr> <tab>
            \ getcmdline() !~# '^\s*set\s\+\w\+=' <bar><bar> wildmenumode() ?
            \ '<c-z>' :
            \ '<c-u>' . substitute(getcmdline(), 'set', 'Set', '') . '<c-z>'

command! -nargs=1 -complete=customlist,s:SetComplete Set exe 'set' <q-args>

function! s:SetComplete(A, L, P) abort
    let option = matchstr(a:A, '^.*\ze=')
    if !has_key(s:option_values, option)
        return
    endif
    let candidates = copy(s:option_values[option])
    call map(candidates, 'option . "=" . v:val')
    return filter(candidates, 'v:val =~ "^" . a:A')
endfunction

It first defines a dictionary s:option_values whose purpose is to contain your options (as its keys) and their values (as its values which are lists). Here, as an example, 3 options + values are stored:
'foldmethod', 'bufhidden', 'virtualedit'.

set wildcharm=<c-z>

This line sets the 'wildcharm' option and tells Vim that if it sees <c-z> in a mapping it must activate the wildmenu. Without setting this option, if you write <tab> in a mapping, it will simply insert a literal tab character.

cnoremap <expr> <tab>

Begin the definition of a mapping which will type the evaluation of an expression whenever you hit <tab> on the command-line.

\ getcmdline() !~# '^\s*set\s\+\w\+=' <bar><bar> wildmenumode() ?

The mapping tests if the command-line matches the pattern ^\s*set\s\+\w\+=, which is a line following the form set option=, or if the wildmenu is active.

\ '<c-z>' :

If the previous test succeeds, the mapping activates the wildmenu.

\ '<c-u>' . substitute(getcmdline(), 'set', 'Set', '') . '<c-z>'

Otherwise, it replaces the system command :set with the custom command :Set, and activates the wildmenu.

command! -nargs=1 -complete=customlist,s:SetComplete Set exe 'set' <q-args>

Define the custom command :Set which does the same thing as :set, except it can use a custom completion function whose name is here s:SetComplete().

function! s:SetComplete(A, L, P) abort

Begin the definition of the custom completion function.

It must return suggestions/candidates through a list.
The :Set command will automatically send 3 arguments to it:

  • the leading portion of the argument currently being completed on (i.e. option=...)
  • the entire command line
  • the cursor position in it

See :h :command-completion-customlist for more information.

let option = matchstr(a:A, '^.*\ze=')

Extract the name of the option from the argument being completed on.

if !has_key(s:option_values, option)
    return
endif

Check whether option is in your dictionary. If it's not, the function doesn't return anything.

let candidates = copy(s:option_values[option])

Get a copy of the list of values that the option can take from your dictionary.

call map(candidates, 'option . "=" . v:val')

For each value in the list candidates, prepend the string option= (where option will be evaluated).

return filter(candidates, 'v:val =~ "^" . a:A')

Remove the items from candidates whose beginning don't match the argument being completed on, and return the result.

2

AFAIK, we can't add cmdline-completion to builtin commands that don't provide it. Either we "override" the command with another one that'll support completion (here, you could define :Set with a capital S), or we hack into vim source code to add what is missing.

2

This was recently implemented. Just update to Vim 9.0.1958 and it will just work.

Relevant commit:

patch 9.0.1958: cannot complete option values
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.