5

Is is possible to search for a regexp in only the current line.

Here is an example line:

This is some text that I have written. Can you find this word?
                                                    ^

This line contains many t's. I would like to search forward for this so the cursor ends up at the caret (the ^ character).

The problem with using / is that if the pattern does not match in the line the cursor will jump to another part of the buffer. I do not want that behavior. I want the search to stop if there is no match in the line.

I can of course search forward using ft and press ; repeatedly but if I were to record macro that would make the macro inconsistent when executed at different locations.

The most obvious solution would be :./this but that did not work for me (it finds matches at other lines in the buffer). So it appears to me that Vim is lacking this feature.

Do you know of a way to do what I am describing?

5 Answers 5

6

You can do:

:call search('find', '', line('.'))

... where 'find'is the pattern. The cursor will be moved to the start of the match.

Sample interactive mapping (not perfect):

:nnoremap <leader>/ :call search(input("Pattern: "), '', line('.'))<cr>

Also: with several plugins that enhance Vim grammar (operator-search, textobj-line (*)), you can do:

:map g/ <Plug>(operator-search)

and then:

g/il

... i.e. "go search for pattern (g/) in this line (il)". But also:

g/is

(search in this sentence).

Or, visually select a range, move cursor to the end, hit g/ to search inside the visual selection. Press n for next match, etc.

(*) Note that these plugins depend on their generic counterparts, Kana's textobj-user and operator-user.

4

You can use \%l to mach a specific line, but that means you would have to constantly change your pattern. e.g. /\%42lfoo. With a quick mapping you can start your search with the line number injected into your search:

nnoremap <key> /\%<c-r>=line('.')<cr>l

As @Yegappan Lakshmanan noted, you can use \%.l on newer version of Vim:

nnoremap <key> /\%.l

For more help see:

:h /\%l 
3
  • Your first example doesn't seem to match foo at the start of the line, or the word foobar, which is sort of what I would expect? In fact, it only seems to match the last occurrence of the match on the current line (rather than all matches on the current line)... I don't know of a better way to do this, though... Commented Aug 17, 2015 at 11:46
  • It will match at the start of the line. The problem is multiple matches. That is where things go wrong, so very wrong. To be perfectly honest I think regex has too much going on. It would not be difficult to use the /\%l method if a simple mapping, e.g. nnoremap <key> /\%<c-r>=line('.')<cr>l Commented Aug 17, 2015 at 12:08
  • 2
    The newer versions of Vim support the \%.l atom which matches the current line. So if you include this atom, then Vim will only match the pattern within the current line. For more information, refer to vimhelp.org/pattern.txt.html#E951. Commented Jul 21, 2022 at 14:24
2

How about using :s/this//cI? Substitutes this on the current line by it's own occurrence (an empty replacement string just uses the match), case sensitive (that's the I). Using c for confirmation, so the cursor actually jumps to the match, you'd have to press q afterwards to stop the substitute-command. It has the additional advantage that if you have several matches on a line, you just press y until you are where you want to be.

0

Using the search() tip from VanLaser I created these functions:

" Repeat in the opposite direction if `reverse` is true
function! RepeatLineSearch(reverse)
    if a:reverse == s:search_backward
        call search(s:search_pattern, '', line('.'), '')
    else
        call search(s:search_pattern, 'b', line('.'), '')
    endif
endfunction

" Search backward if `backward` is true
function! LineSearch(pattern, backward)
    let s:search_pattern = a:pattern
    let s:search_backward = a:backward
    call RepeatLineSearch(0)
endfunction

I then put these mappings in my .vimrc:

" Search forward/backward for a pattern in current line
noremap <silent> <leader>f :call LineSearch(input('--> '), 0)<cr>
noremap <silent> <leader>F :call LineSearch(input('<-- '), 1)<cr>
noremap <silent> <leader>; :call RepeatLineSearch(0)<cr>
noremap <silent> <leader>, :call RepeatLineSearch(1)<cr>

This allows me to search for a new pattern using \f and \F and repeat the last pattern using \; and \, where \, repeats the pattern in the opposite direction.

Feel free to copy this code directly into your .vimrc or modify it to fit your needs.

0

There's another solution that requires less typing/config than the existing answers on this page.

Start by typing a normal search (but don't press Enter)

/this

Then append \|$ and press Enter to perform the search:

/this\|$

\| means "or", and $ is the end of the line, so this will find the next occurrence on the line or stop at the end of the line if there is none.

I'm unclear what your actual use case is, so I'm not sure whether this behaviour will work for you, but if you're using it in a macro, you could tack on a normal-mode lh to abort the macro before performing your edits if no match is found.

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.