skamsie
skamsie

Reputation: 2726

Vim: how to dynamically create regex pattern

I would like to concatenate a variable into a regex pattern. For example, considering this pattern for syntax that matches lines from 1 to 3.

syn match Title /\%>0l\%<4l.*/

I would like to be able to dynamically set the second integer in the pattern (the '4' in the above example to whatever the value of b:title_until is). I have tried with string concatenation but it does not work. The intention should be clear in the example below:

let b:title_until = 10

if exists("b:title_until")
  syn match Title "/\%>0l\%<" + b:title_until + "l.*/"
end
----------------------------------------------------------------------
> (NFA) Unknown operator '\%
> Invalid character after \%
> Invalid argument: Title "/\%>0l\%<" + b:title_until + "l.*/"

Upvotes: 2

Views: 295

Answers (1)

Ingo Karkat
Ingo Karkat

Reputation: 172608

General theory

Vimscript is evaluated exactly like the Ex commands typed in the : command-line. There were no variables in ex, so there's no way to specify them. When typing a command interactively, you'd probably use <C-R>= to insert variable contents:

:sleep <C-R>=timetowait<CR>m<CR>

... but in a script, :execute must be used. All the literal parts of the Ex command must be quoted (single or double quotes), and then concatenated with the variables:

execute 'sleep' timetowait . 'm'

Your problem

For a syntax script, you'd use execute. Additionally, please note that string concatenation in Vim is done with ., not with +. (Also note that I use single quotes to avoid escaping of the backslashes.)

execute 'syn match Title /\%>0l\%<' . b:title_until . 'l.*/'

Alternatively, you can use printf(); this is less cluttered when there are multiple variables. However, here you need to consider that % must be doubled:

execute printf('syn match Title /\%%>0l\%%<%sl.*/', b:title_until)

Final tips

The \%>0l is superfluous and can be omitted, as it will always match: there are no negative lines.

Upvotes: 5

Related Questions