1

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.

2 Answers 2

5

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.

4
  • Thanks for your answer. I added an example, I want to achieve that.
    – doraemon
    Sep 20, 2018 at 11:10
  • @LiuSha So something like command! -nargs=* Ls execute ":!ls " . expand("<args>")?
    – statox
    Sep 20, 2018 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.
    – doraemon
    Sep 20, 2018 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, 2018 at 11:30
2

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 ';;'
  endif
  let line = line[0:(pos-2)]
  let match = matchlist(line, '\s\(\(%\|#\|#<\?[0-9]\+\|##\)\(:\S\+\)\?\)$')
  if len(match) < 2 || match[1] == ''
    return ';;'
  else
    return repeat("\<bs>", len(match[1])) . expand(match[1])
  endif
endfunction
cnoremap <expr> ;; <SID>expand()

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.