3

I found this question on SO but it is not adequately answered there. I thought that re-posting it here would bring it to the attention of people with more specialized knowledge who can answer it adequately. The SO answer doesn't even come close and basically just writes it off as impossible. I posted the best answer I could, but my solution isn't ideal either.

How do I edit the java.vim syntax file to highlight only the identifier of a Java function?

Here is the best regex I came up with, but as you'll see, it has a side effect: it incorrectly highlights the closing parenthesis as an error (presumably because my regex makes it part of the highlighted region).

syn region javaFuncDef start=+^\s\+\(\(public\|protected\|private\|static\|abstract\|final\|native\|synchronized\)\s\+\)*\(\(void\|boolean\|char\|byte\|short\|int\|long\|float\|double\|\([A-Za-z_][A-Za-z0-9_$]*\.\)*[A-Z][A-Za-z0-9_$]*\)\(<[^>]*>\)\=\(\[\]\)*\s\+[a-z][A-Za-z0-9_$]*\|[A-Z][A-Za-z0-9_$]*\)\s*(+ end=+(+ contains=javaScopeDecl,javaType,javaStorageClass,javaComment,javaLineComment,@javaClasses

If I had a deeper knowledge of regex, or of Vim's syntax highlighting system, I might be able to fix it myself.

EDIT: I discovered a construct called a zero-width assertion with lookahead, which matches something but does not actually include it as part of the match. Trouble is, I still can't get it working.

In the example here it would be ?=( right at the end of the regex, to match but not include the opening parameter list parenthesis. I've tried different uses of it (in the region start field, the region end field, and also as a standalone match rule rather than a region rule), all to no avail.

  • 1
    I don't see why this should be impossible. By functions you mean methods, right? I think it should be something like syn match '^\(public\|...\)\? \(static\)\? \w\+ \zs[^(]+\ze It's optional public/static... space followed by optional static then by one or more letters (return type) space match one or more characters that isn't open parenthesis – user1685095 May 17 '17 at 18:02
  • Wow, i've tried to edit java file in vim. Syntax highlighting is awful. If you're interested I can try to create syntax file for java. – user1685095 May 17 '17 at 18:12
  • @user1685095 I constructed the regex as best I could from your hint and it did not highlight anything. Can you please post your regex in full as an answer? – Tim May 17 '17 at 19:56
  • Oh, sorry I've started to creating java syntax file and forgot about you. How do plan to override default syntax file? Put this in after/syntax or what? So that I could test it. – user1685095 May 17 '17 at 20:23
  • 1
    I think the \zs and \ze regex atoms might be relevant here, as it seems user1685095 already used in his suggested. These are described well in the user docs. – Karl Yngve Lervåg May 17 '17 at 20:31
1

I figured it out, mostly. Vim has a special version of the zero-width assertion. It doesn't recognize the standard regex ?= zero-width assertion. Thanks to Karl and user1685095 for pointing out the \ze specifier.

Actually you can use either \ze or \@= - though, as pointed out by user1685095, \ze is the more efficient of the two. \@= is a successor operation meaning the atom to which it should apply needs to come before it. \ze operates on the atom that follows it.

The following regex sort of works, and highlights the function identifier along with any non-primitive return type. This is still isn't exactly right, but it's close.

syn region javaFuncDef start=+^\s\+\(\(public\|protected\|private\|static\|abstract\|final\|native\|synchronized\)\s\+\)*\(\(void\|boolean\|char\|byte\|short\|int\|long\|float\|double\|\([A-Za-z_][A-Za-z0-9_$]*\.\)*[A-Z][A-Za-z0-9_$]*\)\(<[^>]*>\)\=\(\[\]\)*\s\+[a-z][A-Za-z0-9_$]*\|[A-Z][A-Za-z0-9_$]*\)\s*\ze(+ end=+\ze(+ contains=javaScopeDecl,javaType,javaStorageClass,javaComment,javaLineComment,@javaClasses

Replace this line in your syntax/java.vim file, or create a new java.vim in after/syntax and put it there. Either solution should work, but I have directly edited mine.

Ultimately I want it to include only the identifier and exclude the return type also. I had thought \zs would achieve this, but it doesn't appear to work as stated in the Vim doc. When placed in front of the constructor regex, everything else is highlighted correctly except for constructors. When placed just after the return type regex, so as to omit the return type but include the non-constructor identifier regex, constructors are correctly highlighted but nothing else is!

I thought there was hope when I read that it can be used multiple times. However, when placed in both spots, it completely disables the entire syntax rule. (I am guessing this is because with multiple \zs atoms, only the last matching instance is used. I haven't found a way to have it take the first instead, or an alternate specifier which does that.)

syn region javaFuncDef start=+^\s\+\(\(public\|protected\|private\|static\|abstract\|final\|native\|synchronized\)\s\+\)*\(\(void\|boolean\|char\|byte\|short\|int\|long\|float\|double\|\([A-Za-z_][A-Za-z0-9_$]*\.\)*[A-Z][A-Za-z0-9_$]*\)\(<[^>]*>\)\=\(\[\]\)*\s\+\zs[a-z][A-Za-z0-9_$]*\|\zs[A-Z][A-Za-z0-9_$]*\)\s*\ze(+ end=+\ze(+ contains=javaScopeDecl,javaType,javaStorageClass,javaComment,javaLineComment,@javaClasses
  • You can change (\@= into \ze(. It should be more efficient. – user1685095 May 17 '17 at 21:01
  • Thanks, I can confirm that works also. I'll edit it into my answer. – Tim May 17 '17 at 21:09

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.