In Ex mode, ## can be expanded to the files in the args list when files are expected, see :h cmdline-special

In Ex commands, at places where a file name can be used, the following characters have a special meaning. These can also be used in the expression function expand().

Like !ls ## will expand ## But echo ## will not.

However, if I am going to define my own command, how to tell vim that I want files here so please expand my ##?

Is there a way to expand them in place (like how zsh expands * when you press Tab after it)?

An example

command! -nargs=1 Echo :exe "echo '" . <q-args> . "'"

Now I want to run Echo I am here ## with ## expanded.


You could use :h expand() in your command:

command! -nargs=+ Test echo expand("<args>")

This way :Test foo bar will echo foo bar and :Test ## will echo your argument list.

About the in-place expansion as far as I know this is not possible out of the box.

|improve this answer|||||
  • Thanks for your answer. I added an example, I want to achieve that. – Liu Sha Sep 20 '18 at 11:10
  • @LiuSha So something like command! -nargs=* Ls execute ":!ls " . expand("<args>")? – statox Sep 20 '18 at 11:14
  • Sorry to have confused you, Ls is not a good example, because it is a shell command, so that vim already knows it should expand it. Here my command is a general purpose command, sometimes I want to show ##, sometimes it is some other things, like options -x. – Liu Sha Sep 20 '18 at 11:17
  • @LiuSha Ok with your new example I see what you want to do. I'm not sure there is an elegant way to do it: maybe you could make the command call a function which will treat the arguments as a list and then expand them in a for loop, but that's not really efficient. Maybe someone will come up with a better solution :) – statox Sep 20 '18 at 11:30

I ended in using cabbr. This is one way.

cnoreabbrev <expr> ##; getcmdtype()==':'?expand('##'):'##;'
cnoreabbrev <expr> #; getcmdtype()==':'?expand('#'):'#;'
cnoreabbrev <expr> %; getcmdtype()==':'?expand('%'):'%;'

Another way is to use cnoremap <expr>

function! s:expand()
  let line = getcmdline()
  let pos = getcmdpos()  " cursor pos
  if pos <= 1
    return ';;'
  let line = line[0:(pos-2)]
  let match = matchlist(line, '\s\(\(%\|#\|#<\?[0-9]\+\|##\)\(:\S\+\)\?\)$')
  if len(match) < 2 || match[1] == ''
    return ';;'
    return repeat("\<bs>", len(match[1])) . expand(match[1])
cnoremap <expr> ;; <SID>expand()
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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