1

Need a function that,

  1. returns a string, which is result of cmdline-completion Ctrl-a, i.e., a list of words seperated by space.
  2. given an input string of partial ex-command.

For example,

  • given :h bufwin, return h bufwinid() bufwinnr() BufWinEnter BufWinLeave
  • given :call getl, return call getline( getloclist(

== further clarification ==

:h cmdline-completion has relevant info about c^a and c^f. (Ctrl-a and Ctrl-f in cmdline-mode)

As said in this answer about find vim-doc efficiently

In normal-mode, type :h bufwin then type Ctrl-a, will show all completion candidates, whereas type Ctrl-f then dd could manually get the result.

But here what I pursuit is an automated version wrapped in a vimscript function.

2 Answers 2

4

Edit:

Sorry, I misunderstood your question. I think you want the getcompletion() function.

For example,

given :h bufwin, return h bufwinid() bufwinnr() BufWinEnter BufWinLeave

You could get this with the following invocation of getcompletion():

echo getcompletion('*bufwin', 'help')

given :call getl, return call getline( getloclist(

And you could get this with:

echo getcompletion('getl', 'function')

The signature of the function is the following:

getcompletion({pat}, {type} [, {filtered}])

It expects 2 mandatory arguments, and accepts 1 optional one. The 1st argument is a pattern, which can include some metacharacters like * (match any sequence of characters; see :help wildcard). The 2nd argument is the type of completion in which you're interested. Currently, there are 33 possible types:

augroup         autocmd groups
buffer          buffer names
behave          :behave suboptions
color           color schemes
command         Ex command (and arguments)
compiler        compilers
cscope          |:cscope| suboptions
dir             directory names
environment     environment variable names
event           autocommand events
expression      Vim expression
file            file and directory names
file_in_path    file and directory names in |'path'|
filetype        filetype names |'filetype'|
function        function name
help            help subjects
highlight       highlight groups
history         :history suboptions
locale          locale names (as output of locale -a)
mapclear        buffer argument
mapping         mapping name
menu            menus
messages        |:messages| suboptions
option          options
packadd         optional package |pack-add| names
shellcmd        Shell command
sign            |:sign| suboptions
syntax          syntax file names |'syntax'|
syntime         |:syntime| suboptions
tag             tags
tag_listfiles   tags, file names
user            user names
var             user variables

When the 3rd optional argument is passed to the function, and is set to 1, the value of your 'wildignore' option is taken into consideration to eliminate some of the matches.

If you wanted to capture the completion matches for several types simultaneously, you could try this custom function:

fu! s:get_cmdline_candidates(pat, types) abort
    let lists = map(a:types, { i,v -> getcompletion(a:pat, v, 1)})
    let candidates = []
    for a_list in lists
        let candidates += a_list
    endfor
    return uniq(sort(candidates))
endfu

Usage example (in a script):

let myvar = s:get_cmdline_candidates('*win', ['command', 'function'])
echo myvar

This should display all commands and functions containing the keyword win.

But all matches are mixed in a single list. If this is an issue, you could try this function instead:

fu! s:get_cmdline_candidates(pat, types) abort
    let dicts = map(a:types, { i,v -> { v : getcompletion(a:pat, v, 1) }})
    call filter(dicts, {i,v -> !empty(v)})
    let candidates = {}
    for a_dict in dicts
        call extend(candidates, a_dict)
    endfor
    return candidates
endfu

Usage example:

let myvar = s:get_cmdline_candidates('*win', ['command', 'function'])
echo myvar

This time, myvar contains a dictionary with 2 keys, 'command' and 'function', whose values are the associated completion matches for the pattern *win. You can access the commands with myvar.command, and the functions with myvar.function.


How to silently ignore failed calls of getcompletion()?

If you think an error may occur, you could use a try conditional to catch and ignore it. Example 1 (the output will be a list):

fu! s:get_cmdline_candidates(pat, types) abort
    let candidates = []
    for a_type in a:types
        try
            let candidates += getcompletion(a:pat, a_type, 1)
        catch
        endtry
    endfor
    return uniq(sort(candidates))
endfu

Example 2 (the output will be a dictionary):

fu! s:get_cmdline_candidates(pat, types) abort
    let candidates = {}
    for a_type in a:types
        try
            call extend(candidates, { a_type: getcompletion(a:pat, a_type, 1)})
        catch
        endtry
    endfor
    return candidates
endfu

Note that you need a Vim version more recent than 7.4.2011, since it's the patch where getcompletion() was added in Vim.

For more information, see :help getcompletion().


Old answer

I came up with this code:

cno <silent> <expr> <c-x><c-d> '<c-a>'.<sid>capture_cmdline_candidates()

fu! s:capture_cmdline_candidates() abort
    call timer_start(0, {-> setreg('"', getcmdline(), 'l')
    \                     + feedkeys("\<c-c>", 'int') })
    return ''
endfu

It installs a mapping using the key sequence C-x C-d, but you could change it for whatever else you like.

When you press it, the s:capture_cmdline_candidates() function should populate the unnamed register (@") with all the candidates which would have been written on the command line if you had pressed C-a. It also makes you directly quit the command line, so that you can put the contents of the unnamed register in the buffer you want, by pressing p.


Actually, you could eliminate the function:

cno <silent> <expr> <c-x><c-d> '<c-a>'.timer_start(0, {-> setreg('"', getcmdline(), 'l') + feedkeys('<c-c>', 'int') })[-1]

You could also try this mapping:

cno <silent> <expr> <c-x><c-d> '<c-a>'.&cedit.'dd:q<cr>'

But when I tested it, the brief appearance of the command line window was a little distracting, because its name was displayed in the tabline.

5
  • I tried in a plain session vim -N -u NONE +"so test.vim", but not work. Or am I missing something in the workflow? could you plz elaborate a little on the workflow with a concrete example?
    – qeatzy
    Commented Dec 3, 2017 at 2:02
  • Also better if I just call a function in the background, and don't have to manually type the command prefix in cmdline-mode, just pass it as argument.
    – qeatzy
    Commented Dec 3, 2017 at 2:03
  • I have a mapping similar to nn <F2> :exec getline(".")<CR>, and use it run line under cursor as ex-command, eg, call a function, or run a chain of command. Which is in my note file of vim.
    – qeatzy
    Commented Dec 3, 2017 at 2:05
  • Also, the initial interactive cmap approach is quite helpful & illuminating too.
    – qeatzy
    Commented Dec 3, 2017 at 2:45
  • Simple abort the function is perhaps not appropriate here. eg, it will fail if passing a list of all 33 string as types. How to silently ignore failed calls of getcompletion()? Otherwise it works perfectly, thank you very much!!!
    – qeatzy
    Commented Dec 3, 2017 at 3:09
2

Nowadays we have no reason to play with c_CTRL-A as we have getcompletion(). See @user852573's answer.

In the past, however, we had to

  1. create a dummy command with the completion mode we're interested into
  2. inject that command and the leading parameter in the command line
  3. ask to see all the possible completions (with c_CTRL-A),
  4. surround the new command-line with let g:whatever=" and "
  5. and finally execute.

Then the whatever global variable would contain the name of the dummy command and all possible completions.

There were a few caveats: double-quotes could mess the result.

To fix that, we could then use getcmdline(). Alas to use it in the flow we had to inject a new cmapping that could add noise when the objective is to find mapppings -- I had the issue.

The result is in my library plugin:

" Function: lh#command#matching_askvim(what, lead) {{{3
if exists('*getcompletion')
  function! lh#command#matching_askvim(what, lead) abort
    return getcompletion(a:lead, a:what)
  endfunction
else
  function! lh#command#matching_askvim(what, lead) abort
    let cleanup = lh#on#exit()
          \.register('delcom LHAskVimMatchingCompletion')
    try
      exe 'command! -complete='.a:what.' -nargs=* LHAskVimMatchingCompletion :echo "<args>"'
      if exists('*getcmdline')
        call cleanup
              \.restore('g:cmds')
              \.restore_buffer_mapping('µ', 'c')
              \.restore_mapping_and_clear_now('<c-a>', 'c')
        cnoremap <buffer> <expr> µ s:register()
        function! s:register()
          let g:cmds = split(getcmdline(), ' ')[1:]
          return ''
        endfunction
        silent! exe "norm :LHAskVimMatchingCompletion ".a:lead."\<c-a>µ"
        return g:cmds
      else
        " The following may lead to problem with unescaped quotes => use
        " getcmdline() when available
        silent! exe "norm! :LHAskVimMatchingCompletion ".a:lead."\<c-a>\"\<home>let\ cmds=\"\<cr>"
        return split(cmds, ' ')[1:]
      endif
    finally
      call cleanup.finalize()
    endtry
  endfunction
endif

Your Answer

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

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