Search code examples
functionvimregistry

Turn vimscript key mapping into function


I am trying to make a function in vimscript that will activate on every cursor movement in visual mode, i.e. it will automatically highlight all the matches of the current visual selection.

The mapping from https://vi.stackexchange.com/questions/20077/automatically-highlight-all-occurrences-of-the-selected-text-in-visual-mode:

xnoremap <silent> <cr> "*y:silent! let searchTerm = '\V'.substitute(escape(@*, '\/'), "\n", '\\n', "g") <bar> let @/ = searchTerm <bar> echo '/'.@/ <bar> call histadd("search", searchTerm) <bar> set hls<cr>

works perfectly for me but I am failing to implement it into function. This is what I tried:

function! HighlightVisual(mode)
    if mode()=~#"^[vV\<C-v>]"
        call feedkeys('"*y')
        let searchTerm = '\V'.substitute(escape(@*, '\/'), "\n", '\\n', "g")
        let @/ = searchTerm
        echo '/'.@/
        call histadd("search", searchTerm)
        set hls
    endif
endfunction

autocmd CursorMoved * call HighlightVisual(mode())

However, it is not working. What am I doing wrong? I think the function is terminated each time a call is invoked but have no idea how to workaround that.


Solution

  • I have made it work. Firstly, I found from https://vi.stackexchange.com/questions/28404/vim-does-not-call-functions-correctly-when-wrapped-in-another-function that "Vim doesn't like updating Screen too often" so redraw was necessary after set hls. And secondly, y was forcing normal mode and gv was moving cursor triggering the autocmd CursorMoved inside the function thus making an infinite loop. I made a workaround by set eventignore=CursorMoved and resetting it back at the end of function. I am saving selected word to register h (as in highlight) but you can choose any by changing "hy and @h. Moreover, I added highlight toggle when not needed. So, if somebody wants to use the feature of automatically highlighting visual matches, here is the code:

    function! HighlightVisual(mode)
        if mode()=~#"^[vV\<C-v>]"
            set eventignore=CursorMoved
            normal "hy
            normal gv
            let searchTerm = '\V'.substitute(escape(@h, '\/'), "\n", '\\n', "g")
            let @/ = searchTerm
            call histadd("search", searchTerm)
            set hls
            redraw
            set eventignore=""
        endif
    endfunction
    
    autocmd CursorMoved * :call HighlightVisual(mode())
    vnoremap <silent> <ESC> :<C-u>set nohlsearch<CR>
    

    ; just copy-paste it in your .vimrc/init.vim. Big thanks to trusktr as I used his answer in https://vi.stackexchange.com/questions/20077/automatically-highlight-all-occurrences-of-the-selected-text-in-visual-mode to build my function I wanted for sooo long. Happy coding!