0

I am trying to write a function which I bind to "n" and "N" to highlight the current search pattern. That part works.

I would like to detect when the cursor wraps to the first match in the buffer (when 'search hit BOTTOM' is shown), and use a different highlight then.

But I fail getting the line where the search pattern first appears.

I know hot to get a list of lines with a global and p flag but am not sure if and how I should trim it.

g/pattern/p

I can also use search() with n flag (not to move the cursor), but I am only able to get the previous match with it.

So I tried to hack my way around the problem by setting the cursor position to the top of the file, then using search() to get the first line including the pattern, then restoring the cursor position. It seems to get the next search despite moving the cursor.

That's what it looks like:

function! HLCurrent() abort
    if exists("currmatch")
        call matchdelete(currmatch)
    endif

    let patt = '\c\%#'.@/                                  "set pattern
    let currline = line('.')                               "save current line
    let currcol = col('.')                                 "save current column
    call cursor(1, 1)                                      "move to top of file
    let firstmatchline = search(patt)                      "get first line with pattern
    call cursor(currline, currcol)                         "restore cursor


    if firstmatchline == getline('.')                      "always true
        let currmatch = matchadd('Todo', match, 101)
    else                                                   "never in else
        let currmatch = matchadd('IncSearch', match, 101)
    endif
    redraw
endfunction
nnoremap <silent> n n:call HLCurrent()<cr>
nnoremap <silent> N N:call HLCurrent()<cr>

TL;DR

So the question is, how can I get the line of the first occurrence of a pattern properly?

3
  • 1
    Rather than trying to find the first match in the file, how about just checking whether the cursor moves up or down (by checking line() before and after? If the cursor moves up then you’ve wrapped around.
    – Rich
    May 1, 2020 at 20:57
  • 1
    You should give a look to the W flag of search, it allows you to forbid the wrap around
    – Zorzi
    May 1, 2020 at 21:00
  • Thanks for your comments! I guess both could do the trick, but I chose @Zorzi's solution.
    – Biggybi
    May 1, 2020 at 21:21

1 Answer 1

2

From my point of view, the easiest way to know if your cursor is at the first occurrence of the word is to search backwards with the W flag:

  {flags} is a String, which can contain these character flags:

                      [...]

  'W'     don't Wrap around the end of the file

If there is no match found, then it's the 1st one:

function! HLCurrent() abort
    if exists("currmatch")
        call matchdelete(currmatch)
    endif

    let prevOccurence = search(@/, 'bWn')

    if prevOccurence == 0
        " First occurence
        let currmatch = matchadd('Todo', match, 101)
    else
        " Not first occurence
        let currmatch = matchadd('IncSearch', match, 101)
    endif

    redraw
endfunction
nnoremap <silent> n n:call HLCurrent()<cr>
nnoremap <silent> N N:call HLCurrent()<cr>
1
  • 1
    It works like a charm, thank you!
    – Biggybi
    May 1, 2020 at 21:21

Your Answer

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

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