Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Vim autoreply

A modified version of George's gist which I recommend checking out.

A modified version of Romain's gist which I recomend checking out.

Instead we pull the last line from the command history with ~~~histget()~~~ getcmdline() and take the first expansion of what looks to be the first command* with getcompletion(). This gives us the proper command name which we can match against literally.

Also rather than always having to return a carriage return and whatever else in an expression I've opted to use an autocmd.

This also fixes what could be considered a minor bug at the time of writting in the original the dlist and ilist mapping. The pattern may have spaces so rather than increment the cursor backwards move it to the start then increment it forwards to the correct destination.

* This of course doesn't work with things like :g/foo/# and to make that work would require a lot more logic. Instead I take the easy way out and just do nnoremap <key> :global //#<Left><Left> instead.

Just throwing this up so I can play around with further modifications.

" taken from
" modified in

if !exists('##CmdlineLeave')

let s:has_replied = v:false

function s:feedkeys(str) abort
  call feedkeys(a:str, 'n')

function! AutoReply(cmdline) abort
  let previous = split(a:cmdline)

  if empty(previous)
    return s:has_replied

  let previous_cmd = getcompletion(previous[0], 'command')
  if &ignorecase
    " call filter(previous_cmd, { _, v -> v =~# previous[0] })
    call filter(previous_cmd, "v:val =~# previous[0]")
  let previous_cmd  = get(previous_cmd, 0, '')
  let previous_args = previous[1:]

  if empty(previous_cmd)
    return s:has_replied

  if s:has_replied
    let s:has_replied = v:false
    return s:has_replied

  let s:has_replied = v:true

  if previous_cmd ==# 'global'
    call s:feedkeys(':')
  elseif previous_cmd ==# 'undolist'
    call s:feedkeys(':undo' . ' ')
  elseif previous_cmd ==# 'oldfiles'
    call s:feedkeys(':edit #<')
  elseif previous_cmd ==# 'marks'
    call s:feedkeys(':normal! `')

  elseif previous_cmd ==# 'changes'
    call s:feedkeys(':normal! g;')
    call s:feedkeys("\<S-Left>")
  elseif previous_cmd ==# 'jumps'
    call s:feedkeys(':normal!' . ' ')
    call s:feedkeys("\<C-O>\<S-Left>")
  elseif previous_cmd ==# 'registers'
    call s:feedkeys(':normal! "p')
    call s:feedkeys("\<Left>")
  elseif previous_cmd ==# 'tags'
    call s:feedkeys(':pop')
    call s:feedkeys("\<Home>")

  elseif index(['ls', 'files', 'buffers'], previous_cmd) != -1
    call s:feedkeys(':buffer' . ' ')
  elseif index(['clist', 'llist'], previous_cmd) != -1
    call s:feedkeys(':' . repeat(previous_cmd[0], 2) . ' ')
  elseif index(['dlist', 'ilist'], previous_cmd) != -1
    call s:feedkeys(':' . previous_cmd[0] . 'jump' . ' ' . join(previous_args))
    call s:feedkeys("\<Home>\<S-Right>\<Space>")

    let s:has_replied = v:false

  return s:has_replied

augroup AutoReply
  autocmd CmdlineLeave : call AutoReply(getcmdline())
augroup END

This comment has been minimized.

Copy link
Owner Author

@benknoble benknoble commented Jan 5, 2020

The cancellable stuff (g:has_replied &co.) doesn't play super well with romainl/vim-cool, but only when using :global, and I can't figure out what's causing it.


This comment has been minimized.

Copy link

@zekzekus zekzekus commented Apr 24, 2020

It seems neovim implemented this CmdlineLeave differently because histget('cmd', -1) does not return 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.

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