eregex.vim icon indicating copy to clipboard operation
eregex.vim copied to clipboard

support incsearch

Open ZSaberLv0 opened this issue 3 years ago • 12 comments

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 cmap a to z to simulate incsearch, but that would cause much more trouble
  • require has('timers'), to prevent some buggy behavior when used in keymaps, such as nnoremap xxx :S/<c-r><c-w>
  • for vim, added a cmap <cr> due to lack of neovim's v:event['abort'] of CmdlineLeave, 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>

ZSaberLv0 avatar Oct 30 '22 05:10 ZSaberLv0

This is awesome. Thanks @ZSaberLv0 !

huyz avatar Nov 09 '22 07:11 huyz

And thanks @othree as well of course :)

huyz avatar Nov 09 '22 07:11 huyz

@ZSaberLv0 is this ready for review? I see you kept pushing new commits when you created the PR. So I am waiting.

othree avatar Nov 09 '22 08:11 othree

it's ready for review, I have tested for these days, no further issue found for my case

ZSaberLv0 avatar Nov 09 '22 09:11 ZSaberLv0

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.

huyz avatar Nov 09 '22 09:11 huyz

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 avatar Nov 09 '22 09:11 ZSaberLv0

@ZSaberLv0 A user-defined filter would be great for me.

huyz avatar Nov 09 '22 18:11 huyz

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)

huyz avatar Nov 10 '22 06:11 huyz

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.

huyz avatar Nov 10 '22 07:11 huyz

Thanks a lot for the quick turnaround! Looks good so far.

huyz avatar Nov 10 '22 10:11 huyz

I think it's a good time to review and merge :)

huyz avatar Nov 27 '22 17:11 huyz

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'),
           \ }

ZSaberLv0 avatar Nov 29 '22 03:11 ZSaberLv0