0

Follow here @muru point out how to highlight keyword in a function and function name but I want also highlight parameters, for example:

abc = myFunc(Green, Orange=Green, Green, abcd(Orange=Green), Green)
Green: it's highlighted green,
Orange: it's highlighted Orange.

Assume that we matched function name:

syn match pFun "XXXX" contains=pFun nextgroup=pVars 
syn region pVars start="(" end=")" contained contains=pKeyword,pParam transparent keepend
syn match pKeyword "\i*\ze\s*=[^=]" contained
syn match pParam "[^,]*" contained contais=XXXX
hi def link pKeyword something_green
hi def link pParam something_orange

As you can see problems, It overwirte pKeyword with pParam ([^,]* also match \i*\ze\s*=[^=])

My question is: How to write pParam correctly to exclude pKeyword that give correct highlight.

2

Lemme try to analyze the syntax a little bit...

  1. Everything inside ( and ) are pVars
  2. pKeyword are a sequence of identifiers followed by = but not ==
  3. pParam are identifiers that are not pKeyword nor a function call

So... lemme get the pVars: :syn match pVars /\v\(\zs.*\ze\)/ contains=pKeyword,pParam

I tested with :hi pVars ctermfg=1 so I can see if the syn ... is correct. With :syn region, the last Green isn't highlighted. I guess that is not good -- so I excluded the brackets using \zs and \ze instead of using :syn region (though we still got the inner brackets -- at least we saved the last Green).

By the way, as suggested by @Rastapopoulos using /\v\(\zs.*\ze\)/ directly we can see the highlighted region without bothering with :syn clear. After testing the /regex, we know the regex works and using :hi pVars ctermfg=1 helps us deal with contained and contains...

Next, the pKeyword: :syn match pKeyword /\i*\ze\s*=[^=]/ contained. Oh we see the keywords not highlighted anymore -- that means the regex is also working.

After that, the pParam: Let's start with :hi pParam ctermfg=4 so we can see which are captured just by look at the blue chars. :syn match pParam /\i*\(\i*(\)\@!/ contained We excluded functions calls by the logic of "a sequence of identifiers, which is not followed by a sequence of identifiers with an open bracket (".

Wait, this is also having the issue of overwriting the highlighting for keywords! pParam needs to also exclude pKeyword!

In that case, we make use of priorities! :help syn-priority

Let's reopen our vim to avoid the colors that we used to debug.

Rearranging gives:

:syn match pVars /\v\(\zs.*\ze\)/ contains=pKeyword,pParam
:syn match pParam /\i*\(\i*(\)\@!/ contained
:syn match pKeyword /\i*\ze\s*=[^=]/ contained

Then apply the colors. See if it works?

Preview

TL;DR:

Sample Text:

abc = myFunc(Green, Orange=abcd(Green, orange=ab(abc(e),g)), Green, abcd(Orange=Green), Green)
  1. (Optional) Start Vim with vim -Nu NONE to avoid plugins conflicting just in case. Do :hi pVars ctermfg=7 | hi pParam ctermfg=4 | hi pKeyword ctermfg=1 to see highlighting in action.

  2. Everything inside of () (excluding the outmost brackets) are pVars that contains pKeyword and pParam

    :syn match pVars /\v\(\zs.*\ze\)/ contains=pKeyword,pParam

  3. pParam is a sequence of identifiers, contained in pVars, not immediately followed by function names (Identifiers followed by an open bracket, i.e. \i*(, note that = is not identifier by default: :help /character-classes :help isident)

    :syn match pParam /\i*\(\i*(\)\@!/ contained

  4. pKeyword -- identifiers followed by a = but not ==, overriding pParam (as pParam also catches keyword -- we can negative lookahead if we want though)

    :syn match pKeyword /\i*\ze\s*=[^=]/ contained

  5. (Extra) If we want to highlight function names inside pVars, recall that in (2.) function names are identifiers followed by an open bracket:

    :syn match pFunc /\i*\ze(/ containedin=pVars contained and use :hi pFunc ctermfg=6 to check. However I haven't found a way to also highlight the outermost function call...

highlight inner function calls

  • I tried your syntax but it got cleared in my gvim8/windows, no clues. for id in synstack(line("."), col(".")) | echo synIDattr(id, "name") | endfor shows nothing. It should work as you did. I'll dig more when I have spare time. The question is: Does it work with nested function? Where to put match function name? I think your answer is closest. – Tuyen Pham Nov 17 '17 at 19:24
  • Edited my answer! Please see if 0-4 works for you -- sorry that I haven't found a nice way to also include the outermost function calls in 5. ;) – Sunny Pun Nov 18 '17 at 6:26
  • It works well. What if we have newlines between parameters? That would be outermost ) in seperated line, or maybe some inner ). – Tuyen Pham Nov 18 '17 at 16:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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