Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Vim autoreply

A modified version of Romain's gist.

See prior revisions for functionality closer to the original. This is now a simplification that aims only to provide prompts that would typically follow basic commands.

function! ExpandCommand(pattern) abort
  let aliases =
    \ { 'cn' : 'cnext'
    \ , 'cp' : 'cprevious'
    \ , 'g'  : 'global'
    \ , 's'  : 'substitute'
    \ , 'v'  : 'vglobal'
    \ }

  let completion = getcompletion(a:pattern, 'command')
  if &ignorecase
    call filter(completion, "v:val !~# a:pattern")
  let completion = len(completion) == 1 ? join(completion) : ''

  return get(aliases, a:pattern, completion)

augroup AutoReply
  autocmd CmdlineLeave :
    \ execute 'silent doautocmd AutoReply User'
    \          ExpandCommand(getcmdline())

  autocmd User marks     call feedkeys(':normal!`', 'n')
  autocmd User oldfiles  call feedkeys(':edit#<',   'n')

  autocmd User buffers   call feedkeys(':buffer'      . "\<Space>",  'n')
  autocmd User files     call feedkeys(':buffer'      . "\<Space>",  'n')
  autocmd User ls        call feedkeys(':buffer'      . "\<Space>",  'n')

  autocmd User clist     call feedkeys(':silent cc'   . "\<Space>",  'n')
  autocmd User llist     call feedkeys(':silent ll'   . "\<Space>",  'n')
  autocmd User registers call feedkeys(':silent put'  . "\<Space>",  'n')
  autocmd User tags      call feedkeys(':tjump'       . "\<Space>",  'n')
  autocmd User undolist  call feedkeys(':silent undo' . "\<Space>",  'n')

  autocmd User changes   call feedkeys(':normal! g;'  . "\<S-Left>", 'n')
  autocmd User jumps     call feedkeys(':normal! �'  . "\<S-Left>", 'n')

  autocmd User chistory
    \ if getqflist({'nr' : '$'}).nr > 1
    \ |   call feedkeys(':silent chistory | copen',  'n')
    \ |   call feedkeys("\<Home>\<S-Right>\<Right>", 'n')
    \ | endif
augroup END
Copy link

benknoble commented Jan 5, 2020

One way to handle :g/foo/# is to take split(previous_cmdline, '\A')[0]. Technically, a :command may have digits in the name, but no builtins that I'm aware of do, and no plugins that I use do.

The only problem is that entering, say, :23 fails, since 'split('23', '\A') == []

Copy link

benknoble commented Jan 5, 2020

Ok, so I added

  • :tags and :registers replies
  • cancellable replies (i.e., if, after :g /foo/#, you don't want to do :23, you can just use <Esc> or <C-c> as normal, and we won't stick you in an infinite loop)

Copy link

zekzekus commented Apr 24, 2020

It seems neovim implemented this CmdlineLeave differently because histget('cmd', -1) does not return the same thing with vim. I tried to use getcmdline() and as far as I tried, it worked for both vim and neovim. For your information.

Copy link

george-b commented Apr 25, 2020

Thanks for the report @zekzekus, I've updated the gist as getcmdline() better reflects the fact that CmdLineLeave actually fires just before leaving the command-line.

As a result of this in my personal config I've had to alter a "chained" mapping. Before I had the rather common.

nnoremap gb :ls<CR>:buffer<Space>

But with the update the autocmd now fires for this, whereas before it did not. As such I've since changed it to the following.

nnoremap :noautocmd ls<CR>:buffer<Space>

Note I've not opted to have my mapping just execute :ls and rely on this gist to reply with the pre-populated command-line of :buffer. This may be something to bare in mind.

Copy link

josefson commented May 25, 2020

Tried using it as opposite to romain's CCR because it allowed me to nnoremap ,c :changes<CR>. Whereas with romain's i didn't know how to do that.
However, it collided with other stuff that used CmdLineLeave such as the builtin method motions for python filetypes for instance.
So if in visual mode i try to any method motion [m [M ]m ]M, it will jump to that motion but also it will stop visual selection in its tracks by ':' in command-line-mode.

Copy link

george-b commented May 25, 2020

This should already be fixed in the latest revision.

I suspect you have an older copy where get() was still returning its default of 0 in the failed case, rather than the empty string as it does now. The former results in the the first comparison against previous_cmd evaluating to true. This is because in Vimscript when comparing a number to a string the string is converted to the value 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment