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