netbeans icon indicating copy to clipboard operation
netbeans copied to clipboard

Add generics angle brackets (<>) highlighting for Java

Open PavelTurk opened this issue 2 years ago • 14 comments

Description

When we work with round brackets in java we can see the start and end bracket via highlighting. For example:

Screenshot from 2021-05-27 10-33-18

I suggest to add the same functionality for angle bracket of generics, because rather often a structure can be complex and it is not seen where the bracket starts and where it ends.

For example,

Map<Class<? extends AbstractStudent>, Map<CourseTime, List<? extends AbstractCourse>>> coursesByStudentTypeAndTime;

The issue was also opened in old jira: https://issues.apache.org/jira/browse/NETBEANS-5716

Use case/motivation

No response

Related issues

No response

Are you willing to submit a pull request?

No

Code of Conduct

Yes

PavelTurk avatar Nov 28 '22 19:11 PavelTurk

@neilcsmith-net Maybe it is necessary to increase the priority of this issue? This is real a very basic feature and it is still absent.

PavelTurk avatar Jan 30 '23 14:01 PavelTurk

Not sure why you're tagging me specifically, but let's add it to the contribute page and labels.

neilcsmith-net avatar Jan 30 '23 15:01 neilcsmith-net

I would like to contribute to this issue.

TheMarvelFan avatar Sep 08 '23 13:09 TheMarvelFan

Hi I have opened a pull request referencing this issue, but I require some guidance. Can someone please review and help me with it?

TheMarvelFan avatar Oct 09 '23 15:10 TheMarvelFan

I had a look at the PR and I think all changes outside JavaBracesMatcher.java should not be there. of course you can try to change the lexing strategy for the java language in NetBeans, but that will be an uphill battle. I suggest to modify the braces matcher to deal with situations where characters do not map to a single token.

The java lexer can generate these tokens, that could match your case:

  • JavaTokenId.LT
  • JavaTokenId.LTLT
  • JavaTokenId.LTLTEQ
  • JavaTokenId.GT
  • JavaTokenId.GTEQ
  • JavaTokenId.GTGT
  • JavaTokenId.GTGTEQ
  • JavaTokenId.GTGTGT
  • JavaTokenId.GTGTGTEQ

For example this code:


import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;


public class testLexer<V> {
    public static <K,V2> void add(K k, V2 v) {}

    public static void main(String[] argv) {
        Map<String,Map<UUID,List<Map<Integer,Number>>>> m = new HashMap<>();
    }
}

is lexed to this token stream:

IMPORT          "import", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "java", la=1
DOT             ".", la=1
IDENTIFIER      "util", la=1
DOT             ".", la=1
IDENTIFIER      "HashMap", la=1
SEMICOLON       ";"
WHITESPACE      "\n", la=1
IMPORT          "import", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "java", la=1
DOT             ".", la=1
IDENTIFIER      "util", la=1
DOT             ".", la=1
IDENTIFIER      "List", la=1
SEMICOLON       ";"
WHITESPACE      "\n", la=1
IMPORT          "import", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "java", la=1
DOT             ".", la=1
IDENTIFIER      "util", la=1
DOT             ".", la=1
IDENTIFIER      "Map", la=1
SEMICOLON       ";"
WHITESPACE      "\n", la=1
IMPORT          "import", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "java", la=1
DOT             ".", la=1
IDENTIFIER      "util", la=1
DOT             ".", la=1
IDENTIFIER      "UUID", la=1
SEMICOLON       ";"
WHITESPACE      "\n\n\n", la=1
PUBLIC          "public", la=1
WHITESPACE      " ", la=1
CLASS           "class", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "testLexer", la=1
LT              "<", la=1
IDENTIFIER      "V", la=1
GT              ">", la=1
WHITESPACE      " ", la=1
LBRACE          "{"
WHITESPACE      "\n    ", la=1
PUBLIC          "public", la=1
WHITESPACE      " ", la=1
STATIC          "static", la=1
WHITESPACE      " ", la=1
LT              "<", la=1
IDENTIFIER      "K", la=1
COMMA           ","
IDENTIFIER      "V2", la=1
GT              ">", la=1
WHITESPACE      " ", la=1
VOID            "void", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "add", la=1
LPAREN          "("
IDENTIFIER      "K", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "k", la=1
COMMA           ","
WHITESPACE      " ", la=1
IDENTIFIER      "V2", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "v", la=1
RPAREN          ")"
WHITESPACE      " ", la=1
LBRACE          "{"
RBRACE          "}"
WHITESPACE      "\n\n    ", la=1
PUBLIC          "public", la=1
WHITESPACE      " ", la=1
STATIC          "static", la=1
WHITESPACE      " ", la=1
VOID            "void", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "main", la=1
LPAREN          "("
IDENTIFIER      "String", la=1
LBRACKET        "["
RBRACKET        "]"
WHITESPACE      " ", la=1
IDENTIFIER      "argv", la=1
RPAREN          ")"
WHITESPACE      " ", la=1
LBRACE          "{"
WHITESPACE      "\n        ", la=1
IDENTIFIER      "Map", la=1
LT              "<", la=1
IDENTIFIER      "String", la=1
COMMA           ","
IDENTIFIER      "Map", la=1
LT              "<", la=1
IDENTIFIER      "UUID", la=1
COMMA           ","
IDENTIFIER      "List", la=1
LT              "<", la=1
IDENTIFIER      "Map", la=1
LT              "<", la=1
IDENTIFIER      "Integer", la=1
COMMA           ","
IDENTIFIER      "Number", la=1
GTGTGT          ">>>", la=1
GT              ">", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "m", la=1
WHITESPACE      " ", la=1
EQ              "=", la=1
WHITESPACE      " ", la=1
NEW             "new", la=1
WHITESPACE      " ", la=1
IDENTIFIER      "HashMap", la=1
LT              "<", la=1
GT              ">", la=1
LPAREN          "("
RPAREN          ")"
SEMICOLON       ";"
WHITESPACE      "\n    ", la=1
RBRACE          "}"
WHITESPACE      "\n", la=1
RBRACE          "}"
----- EOF -----

The dump was generated by saving the java file to java/java.lexer/test/unit/data/testfiles/testLexer.java, adding

    public void test2() throws Exception {
        LexerTestUtilities.checkTokenDump(this, "testfiles/testLexer.java",
                JavaTokenId.language());
    }

to JavaTokenDumpTest and running that test.

In the sample you find both GT and GTGTGT. I don't know why it was done this way, but I would start with the assumption, that they author made a sane decision there.

matthiasblaesing avatar Oct 15 '23 13:10 matthiasblaesing

@matthiasblaesing Thanks for the advice.

I suggest to modify the braces matcher to deal with situations where characters do not map to a single token.

Can you please elaborate how it will be possible to do this? Also, before adding support for highlighting characters that map to multiple tokens, I feel like I should make single character with single token work first, which I have not been able to do so far. The pair of single open and closing angle brackets should be highlighted, but they are not.

TheMarvelFan avatar Oct 23 '23 11:10 TheMarvelFan

Not sure what you are seeing as a problem, but that case seems trivial:

--- a/java/java.editor/src/org/netbeans/modules/editor/java/JavaBracesMatcher.java
+++ b/java/java.editor/src/org/netbeans/modules/editor/java/JavaBracesMatcher.java
@@ -50,11 +50,12 @@
  */
 public final class JavaBracesMatcher implements BracesMatcher, BracesMatcherFactory, BracesMatcher.ContextLocator {
 
-    private static final char [] PAIRS = new char [] { '(', ')', '[', ']', '{', '}' }; //NOI18N
+    private static final char [] PAIRS = new char [] { '(', ')', '[', ']', '{', '}', '<', '>' }; //NOI18N
     private static final JavaTokenId [] PAIR_TOKEN_IDS = new JavaTokenId [] { 
         JavaTokenId.LPAREN, JavaTokenId.RPAREN, 
         JavaTokenId.LBRACKET, JavaTokenId.RBRACKET, 
-        JavaTokenId.LBRACE, JavaTokenId.RBRACE
+        JavaTokenId.LBRACE, JavaTokenId.RBRACE,
+        JavaTokenId.LT, JavaTokenId.GT
     };
     
     private final MatcherContext context;

results in (this is NetBeans colorscheme, matching braces are highlighted in yellow):

Match from left:

image

Match from right:

image

Jumping between the matching braces also worked.

Edit: This also works for simple type arguments:

image

matthiasblaesing avatar Oct 23 '23 17:10 matthiasblaesing

Hi @matthiasblaesing, I just checked the latest netbeans source code and it looks like the changes you suggested here have already been incorporated. But upon running ant build on the latest cloned branch (I did not make any changes in it), I am still getting the same error as before, i.e., the red highlight on only one bracket rather than the yellow one on both (the color scheme is the same as before, i.e., yellow for matching braces).

TheMarvelFan avatar Nov 17 '23 14:11 TheMarvelFan

Nothing I suggested was worth a direct integration and it was not done. I suspect, that you are looking at an old checkout and did not switch to the current master.

Please show the output of git log -n 1 and git status.

matthiasblaesing avatar Nov 18 '23 11:11 matthiasblaesing

Output of git log: Screenshot 2023-11-18 181045

Output of git status: Screenshot 2023-11-18 181118

You are right the changes were not directly integrated. I reset the local branch hard to upstream and I thought all of my previous changes to it would be wiped, as I did not want to clone the repository again for starting fresh. But that is not the case, apparently.

It was a false alarm. Apologies for any inconvenience this may have caused.

TheMarvelFan avatar Nov 18 '23 12:11 TheMarvelFan

@TheMarvelFan Could you say if you are working on this issue? As I understand @matthiasblaesing has shown what it is necessary to do.

PavelTurk avatar Jan 24 '24 15:01 PavelTurk

Hi @PavelTurk , Yes I am working on this issue and I will soon be adding the finishing commit to the PR.

TheMarvelFan avatar Jan 25 '24 07:01 TheMarvelFan

Nothing I suggested was worth a direct integration and it was not done. I suspect, that you are looking at an old checkout and did not switch to the current master.

@matthiasblaesing Could you explain why the code you showed can't be added to master? According to your example everything works. What else should be done?

PavelTurk avatar Apr 28 '24 07:04 PavelTurk

@PavelTurk no - not everything works:

image

The highlighting is broken.

matthiasblaesing avatar Apr 28 '24 14:04 matthiasblaesing