Skip to content

Instantly share code, notes, and snippets.

@g0xA52A2A
Last active January 5, 2021 13:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save g0xA52A2A/b8238d97ed3b6ab65ce8784de83307b0 to your computer and use it in GitHub Desktop.
Save g0xA52A2A/b8238d97ed3b6ab65ce8784de83307b0 to your computer and use it in GitHub Desktop.

Performs reverse incremental history search provided the current command-line is empty.

Started out by tweaking ctrlr.vim but ended up being a total re-write. Functionally it's largely the same, differs as follows.

  • History type is detected so works for all command-line types.
  • Mapping uses ternary operator to allow native <C-R> behaviour rather than having to re-implement it.
  • Matches characters using Vim's key notation rather than relying on a dictionary.
  • Gets matches using filter() rather than an explicit loop.
  • Is generally both more readable and concise.
function! CtrlR()
  let history     = execute('history' . ' ' . getcmdtype())
  let history     = split(history, '\n')[1:]                " Remove header
  let history[-1] = join(split(history[-1])[1:])            " Remove '>'
  let history     = map(history, "join(split(v:val)[1:])")  " Remove index
  let history     = reverse(history)

  let case =
    \ { "\<C-R>" : "let skips += 1"
    \ , "\<CR>"  : "redraw! | return match . '\<CR>'"
    \ , "\<Esc>" : "redraw! | return match"
    \ , "\<C-U>" : "silent! unlet matches search"
    \ , "\<C-W>" : "silent! unlet matches | let search = join(split(search        )[0:-2])"
    \ , "\<BS>"  : "silent! unlet matches | let search = join(split(search, '\\zs')[0:-2], '')"
    \ , }

  while 1
    if !exists('search') || empty(search)
      let search = ''
      let match  = ''
      let skips  = 0
      echo '(reverse-i-search)'
    else
      let matches = exists('matches') ? matches : copy(history)
      let matches = filter(matches, "v:val =~# search")
      let match   = get(matches, skips, '')
      echo '(reverse-i-search)' . ' ' . search . ' : ' . match
    endif

    let char    = getchar()
    let string  = nr2char(char)
    let command = get(case, string, get(case, char, ''))

    if !empty(command)
      execute command
    else
      let search .= string
    endif
  endwhile
endfunction

cnoremap <expr> <C-R> empty(getcmdline()) ? CtrlR() : "\<C-R>"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment