Vim - pattern to match only first character of literal string

Viewed 156

I am trying to write a pattern that would match only the first character (can be any character, whitespace as well) of a string interpreted literally.

So given this function, that uses "very no magic" to literally match a string given as argument and then highlight that string, how can I modify it, so it only highlights the first character?

function! MatchFirst(i)
  highlight Red ctermbg=red ctermfg=0 guibg=#ff0000 guifg=#000000
  call matchadd('Red', '\V' . escape(a:i, '\'))
endfunction

So for example calling MatchFirst('{^(sed') on the following text, would only highlight the { if { is followed by *(sed, but not in any other place. Currently it highlights the whole given string {^(sed.

Lorem ipsum do{^(lor sit amet, consectetur adipiscing elit, e{^(sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo con{^(sequat. Duis aute irure dolor in rep{^(rehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

LATER EDIT

To give a bit of context, the argument for the MatchFirst function is the text visually selected by the user, so it can literally be anything, it can be foobar, foo\ze\bar, &#@!^><..?/\\\, 国字字, etc.

1 Answers

The easiest way to select only part of a match in a Vim pattern is to use \ze to mark the end of the match. See :help /\ze for more details.

You can use \ze directly under "very nomagic" mode \V. You'll find this under :help /\V:

Use of \V means that after it, only a backslash and terminating character (usually / or ?) have special meaning: "very nomagic"

Since \ze already starts with a backslash, you don't need to modify it at all for it to work under \V.

In your example of {^(sed, you can use \V{\ze^(sed to match the first { but only when it's part of {^(sed.

Putting it all together in your function, you can use:

call matchadd('Red',
    \ '\V' .  escape(strcharpart(a:i, 0, 1), '\') .
    \ '\ze' . escape(strcharpart(a:i, 1), '\'))

NOTE: You might have a corner case where a:i is an empty string, you might want to do something different in that case.

Related