Skip to content

Instantly share code, notes, and snippets.

@benknoble
Forked from g0xA52A2A/Vim_autoreply.md
Last active November 23, 2022 17:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benknoble/d53208c6f1ad8f2130fd706c9cdbd006 to your computer and use it in GitHub Desktop.
Save benknoble/d53208c6f1ad8f2130fd706c9cdbd006 to your computer and use it in GitHub Desktop.
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 use fullcommand() to get the command name. 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 now works correctly with any :global command, but to have line numbers show up for jumping you still want to use the # command at the end.

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

" taken from https://gist.github.com/george-b/2f842efaf2141cb935a81f6174b6401f
" modified in https://gist.github.com/benknoble/d53208c6f1ad8f2130fd706c9cdbd006

if !exists('##CmdlineLeave')
  finish
endif

let s:has_replied = v:false

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

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

  if empty(previous)
    return s:has_replied
  endif

  let previous_cmd = fullcommand(a:cmdline)
  let previous_args = previous[1:]

  if empty(previous_cmd)
    return s:has_replied
  endif

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

  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>")

  else
    let s:has_replied = v:false
  endif

  return s:has_replied
endfunction

augroup AutoReply
  autocmd!
  autocmd CmdlineLeave : call AutoReply(getcmdline())
augroup end
@benknoble
Copy link
Author

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.

@zekzekus
Copy link

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.

@Konfekt
Copy link

Konfekt commented Nov 23, 2022

The abbreviations of the command names can be checked for by the %[...] expresion, such as:

  if previous_cmd =~# '\v/(#|nu%[mber])$'
    call s:feedkeys(':')
  elseif previous_cmd =~# '\v^\s*undol%[ist]'
    call s:feedkeys(':undo' . ' ')
  elseif previous_cmd =~# '\v^\s*ol%[dfiles]\s*$'
    call s:feedkeys(':edit #<')
  elseif previous_cmd =~# '\v^\s*marks\s*(\s\w+)?$'
    call s:feedkeys(':normal! `')

  elseif previous_cmd =~# '^\s*changes\s*$'
    call s:feedkeys(':normal! g;')
    call s:feedkeys("\<S-Left>")
  elseif previous_cmd =~# '\v^\s*ju%[mps]'
    call s:feedkeys(':normal!' . ' ')
    call s:feedkeys("\<C-O>\<S-Left>")
  elseif previous_cmd =~# '\v^\s*reg%[isters]'
    call s:feedkeys(':normal! "p')
    call s:feedkeys("\<Left>")

  elseif previous_cmd =~# '\v^\s*(ls|files|buffers)!?\s*(\s[+\-=auhx%#]+)?$'
    call s:feedkeys(':buffer' . ' ')
  elseif previous_cmd =~# '\v^\s*(cli|lli)%[st]!?\s*(\s\d+(,\s*\d+)?)?$'
    call s:feedkeys(':' . repeat(previous_cmd[0], 2) . ' ')
  elseif previous_cmd =~# '\v^\s*(dli%[st]|il%[ist])!?\s+\S'
    call s:feedkeys(':' . previous_cmd[0] . 'jump' . ' ' . join(previous_args))
    call s:feedkeys("\<Home>\<S-Right>\<Space>")

  else
    let s:has_replied = v:false
  endif

@benknoble
Copy link
Author

The abbreviations of the command names can be checked for by the %[...] expresion, such as:

  if previous_cmd =~# '\v/(#|nu%[mber])$'
    call s:feedkeys(':')
  elseif previous_cmd =~# '\v^\s*undol%[ist]'
    call s:feedkeys(':undo' . ' ')
  elseif previous_cmd =~# '\v^\s*ol%[dfiles]\s*$'
    call s:feedkeys(':edit #<')
  elseif previous_cmd =~# '\v^\s*marks\s*(\s\w+)?$'
    call s:feedkeys(':normal! `')

  elseif previous_cmd =~# '^\s*changes\s*$'
    call s:feedkeys(':normal! g;')
    call s:feedkeys("\<S-Left>")
  elseif previous_cmd =~# '\v^\s*ju%[mps]'
    call s:feedkeys(':normal!' . ' ')
    call s:feedkeys("\<C-O>\<S-Left>")
  elseif previous_cmd =~# '\v^\s*reg%[isters]'
    call s:feedkeys(':normal! "p')
    call s:feedkeys("\<Left>")

  elseif previous_cmd =~# '\v^\s*(ls|files|buffers)!?\s*(\s[+\-=auhx%#]+)?$'
    call s:feedkeys(':buffer' . ' ')
  elseif previous_cmd =~# '\v^\s*(cli|lli)%[st]!?\s*(\s\d+(,\s*\d+)?)?$'
    call s:feedkeys(':' . repeat(previous_cmd[0], 2) . ' ')
  elseif previous_cmd =~# '\v^\s*(dli%[st]|il%[ist])!?\s+\S'
    call s:feedkeys(':' . previous_cmd[0] . 'jump' . ' ' . join(previous_args))
    call s:feedkeys("\<Home>\<S-Right>\<Space>")

  else
    let s:has_replied = v:false
  endif

This is true, but I don’t think it’s necessary with fullcommand

@Konfekt
Copy link

Konfekt commented Nov 23, 2022

You seem right, thank you! I likely saw the Alias function in https://gist.github.com/g0xA52A2A/2f842efaf2141cb935a81f6174b6401f and presumed something similar was necessary here, but overlooked what fullcommand() achieves.

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