0

I wrote a vimscript function that prevents the cursor from changing its location on the screen when I press n:

function! s:my_n()
    let l:start=line("w0")
    let end = line("w$")
    let cursor = line(".")
    let from_top = cursor-l:start
    normal! n
    let new_start = line("w0")
    let new_end = line("w$")
    let new_cursor = line(".")
    let new_from_top = new_cursor-new_start
    if new_from_top>from_top
        for i in range(new_from_top-from_top)
            execute "normal! \<C-e>"
        endfor
    else
        for i in range(from_top-new_from_top)
            execute "normal! \<C-y>"
        endfor
    endif
endfunction
nnoremap n :call <SID>my_n()<CR>

Everything works fine, except for the messages:

I'd want the same as a normal n, namely:

  • When there is a match, get .. match x out of y
  • When there is no match, get E486 Pattern not found: ...

Instead, what I get is:

  • If I press n directly after the / command and when there is a match, I get :call <SNR>1_my_n() in the command line, but once I move away from matches and then press n again, I don't get anything at all anymore.

  • When there is no match, the command line grows in size and displays

    Error detected while processing function 1_contextn: line 6: E486: Pattern not found: asdfsdf Press ENTER or type command to continue

I tried a few things:

(A) Use silent normal! n

Nothing changes

(B) Use silent! normal! n

When there is no match, I don't get an error message anymore and instead get :call <SNR>1_my_n()

(C) Use map <silent> n and go back to normal! n

  • When there is a match, I get the proper message .. match x out of y, but once I leave the matches and then press n I don't get anything at all
  • Same behavior as in the original when there are no matches

(D) Use map <silent> n and silent normal! n

Exactly as (C)

(E) Use map <silent> n and silent! normal! n

  • When there is a match, same as in (C)
  • When there is no match, no message or error at all

Note: This question is basically the same as How to show "/foobar match 1 of " or "E486: Pattern not found: foobar" in commandline when calling `normal! n` in function but cleaned up, with the complete code, and with all my attempts. In comparison to that question, I am omitting here another complexity, namely that my full mapping is nnoremap n :call <SID>my_n()<CR><SID>my_other_function()<CR> and if the solution to my problem involves changing this mapping, it'd be also good to know how to control the output of the two function calls separately

2
  • confused, because printing "match x out of y" is not normal vim behavior
    – Mass
    Commented Jan 25, 2019 at 15:27
  • @Mass, I'm sorry, I guess that's a plug-in that I installed, I'll figure that out later and update the question
    – Bananach
    Commented Jan 25, 2019 at 19:35

1 Answer 1

0

You can add try...endtry block for your normal! n:

function! s:my_n()
    let l:start=line("w0")
    let end = line("w$")
    let cursor = line(".")
    let from_top = cursor-l:start
    try
        normal! n
    catch
        echohl ErrorMsg
        echo substitute(v:exception, '^Vim(.*):', '', '')
        echohl NONE
    endtry
    let new_start = line("w0")
    let new_end = line("w$")
    let new_cursor = line(".")
    let new_from_top = new_cursor-new_start
    if new_from_top>from_top
        for i in range(new_from_top-from_top)
            execute "normal! \<C-e>"
        endfor
    else
        for i in range(from_top-new_from_top)
            execute "normal! \<C-y>"
        endfor
    endif
endfunction
nnoremap n :call <SID>my_n()<CR>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.