support incsearch
add incsearch support, for :M/ :S/ :G/ :V/ command, and :M? backward search series
limitations:
- require
exists('##CmdlineChanged') && exists('##CmdlineLeave'), to simulate incsearch- it seems possible by
cmapa to zto simulate incsearch, but that would cause much more trouble
- it seems possible by
- require
has('timers'), to prevent some buggy behavior when used in keymaps, such asnnoremap xxx :S/<c-r><c-w> - for
vim, added acmap <cr>due to lack ofneovim'sv:event['abort']ofCmdlineLeave, which may break user's custom keymap- if unable to detect the "abort" state, incsearch still work, but the original search pattern can't be restored if
:M/canceled by<esc>or<c-c>
- if unable to detect the "abort" state, incsearch still work, but the original search pattern can't be restored if
This is awesome. Thanks @ZSaberLv0 !
And thanks @othree as well of course :)
@ZSaberLv0 is this ready for review? I see you kept pushing new commits when you created the PR. So I am waiting.
it's ready for review, I have tested for these days, no further issue found for my case
Question:
I always prefer case-insensitive matching for / but the safer case-sensitive matching for :s (and :S). So what I've been doing for years is to add \c by default:
nnoremap / /\c
nnoremap ? ?\c
In the case of eregex, I now do the same with \c:
nnoremap <expr> / ":<C-U>".v:count1."M/\\c"
nnoremap <expr> ? ":<C-U>".v:count1."M?\\c"
The problem is that incsearch will highlight the entire file because the pattern already has \c and vim doesn't realize that this is equivalent to just empty string and thus shouldn't be highlighted. Is there a workaround to avoid the momentary whole-file highlighting?
I guess another solution for me would be if eregex could support separate eregex_force_case_in_search and eregex_force_case_in_substitute. Then I wouldn't need the \c. But I don't know if this would cause problems (e.g., if I reuse the search history)
Not a big deal, either way.
maybe we can add user defined pattern filter around here: incsearch.vim#L53
let Fn_filter = get(b:, 'Fn_eregex_incsearch_filter', get(g:, 'Fn_eregex_incsearch_filter', ''))
if !empty(Fn_filter) && Fn_filter(cmd['pattern'])
if exists('s:patternSaved')
let @/ = s:patternSaved
endif
if exists('s:stateSaved')
call winrestview(s:stateSaved)
endif
redraw!
return
endif
@ZSaberLv0 A user-defined filter would be great for me.
Great, it works fine for me now if I do /. But for some reason I can't get incsearch when I do ?.
This is my .vimrc right now:
" We want `:S` substitutions to be case-sensitive.
let g:eregex_force_case = 1
" Disable the default mappings because we have to do the mapping ourselves
let g:eregex_default_enable = 0
let g:eregex_forward_delim = '/'
let g:eregex_backward_delim = '?'
" Avoid total-file highlight because of the additional `\c`
let g:Fn_eregex_incsearch_filter = {x -> x == '\c'}
" Code from eregex.vim
let s:enable = 0
function! EregexToggle(...)
let silent = 0
if exists('a:1') && a:1
let silent = 1
endif
if s:enable == 0
exec 'nnoremap <expr> '.g:eregex_forward_delim.' ":<C-U>".v:count1."M/\\c"'
exec 'nnoremap <expr> '.g:eregex_backward_delim.' ":<C-U>".v:count1."M?\\c"'
if silent != 1
echo "eregex.vim key mapping enabled"
endif
else
exec 'nunmap '.g:eregex_forward_delim
exec 'nunmap '.g:eregex_backward_delim
if silent != 1
echo "eregex.vim key mapping disabled"
endif
endif
let s:enable = 1 - s:enable
endfun
call MapKey('<M-t>/', '<Cmd>call EregexToggle()<CR>')
" Start out enabled
call EregexToggle(v:true)
There might be another issue. I have:
set ignorecase smartcase
let g:eregex_force_case = 1
So if I type :%S/case then CASE should not be highlighted by incsearch, but it is highlighted.
Thanks a lot for the quick turnaround! Looks good so far.
I think it's a good time to review and merge :)
add support for custom cmdparser, a typical config for dkprice/vim-easygrep
function! Easygrep_incsearch(cmdline)
let cmd = substitute(a:cmdline, ' .*', '', '')
if cmd == 'Grep'
return {
\ 'method' : cmd,
\ 'delim' : '/',
\ 'modifiers' : '',
\ 'pattern' : substitute(a:cmdline, '^ *[^ ]\+ \+', '', ''),
\ }
elseif cmd == 'Replace'
let slashToken = nr2char(127)
let cmdline = substitute(a:cmdline, '^ *[^ ]\+ \+', '', '')
let cmdline = substitute(cmdline, '\\/', slashToken, 'g')
let items = split(cmdline, '/')
if empty(items)
return {}
endif
return {
\ 'method' : cmd,
\ 'delim' : '/',
\ 'modifiers' : '',
\ 'pattern' : substitute(items[0], slashToken, '\\/', 'g'),
\ }
else
return {}
endif
endfunction
let g:eregex_incsearch_custom_cmdparser = {
\ 'easygrep' : function('Easygrep_incsearch'),
\ }