Merge remote-tracking branch 'mb/antlr4-support' into languages.antlr
diff --git a/java/languages.antlr/licenseinfo.xml b/java/languages.antlr/licenseinfo.xml
index a3acf1b..b2f810e 100644
--- a/java/languages.antlr/licenseinfo.xml
+++ b/java/languages.antlr/licenseinfo.xml
@@ -27,6 +27,10 @@
         <file>src/org/antlr/parser/antlr4/LexerAdaptor.java</file>
         <license ref="BSD-antlr4-grammar" />
     </fileset>
+    <fileset>
+        <file>src/org/netbeans/modules/languages/antlr/resources/antlr.png</file>
+        <license ref="BSD-antlr-icons" />
+    </fileset>
     <!--fileset>
         <file>src/org/antlr/parser/antlr4/ANTLRv4Lexer.java</file>
         <file>src/org/antlr/parser/antlr4/ANTLRv4Parser.java</file>
diff --git a/java/languages.antlr/nbproject/project.xml b/java/languages.antlr/nbproject/project.xml
index 77d4c82..7de043e 100644
--- a/java/languages.antlr/nbproject/project.xml
+++ b/java/languages.antlr/nbproject/project.xml
@@ -96,6 +96,15 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.netbeans.modules.editor.settings</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.75</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.netbeans.modules.lexer</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
diff --git a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrCompletionProvider.java b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrCompletionProvider.java
new file mode 100644
index 0000000..d640ddc
--- /dev/null
+++ b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrCompletionProvider.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.languages.antlr;
+
+import java.util.Collections;
+import java.util.prefs.Preferences;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import org.netbeans.api.editor.mimelookup.MimeLookup;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.editor.settings.SimpleValueNames;
+import org.netbeans.api.lexer.Token;
+import org.netbeans.api.lexer.TokenHierarchy;
+import org.netbeans.api.lexer.TokenSequence;
+import org.netbeans.modules.csl.spi.ParserResult;
+import org.netbeans.modules.parsing.api.ParserManager;
+import org.netbeans.modules.parsing.api.ResultIterator;
+import org.netbeans.modules.parsing.api.Source;
+import org.netbeans.modules.parsing.api.UserTask;
+import org.netbeans.modules.parsing.spi.ParseException;
+import org.netbeans.spi.editor.completion.CompletionItem;
+import org.netbeans.spi.editor.completion.CompletionProvider;
+import org.netbeans.spi.editor.completion.CompletionResultSet;
+import org.netbeans.spi.editor.completion.CompletionTask;
+import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery;
+import org.netbeans.spi.editor.completion.support.AsyncCompletionTask;
+import org.netbeans.spi.editor.completion.support.CompletionUtilities;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Laszlo Kishalmi
+ */
+@MimeRegistration(mimeType = AntlrTokenId.MIME_TYPE, service = CompletionProvider.class)
+public class AntlrCompletionProvider implements CompletionProvider {
+
+    @Override
+    public CompletionTask createTask(int queryType, JTextComponent component) {
+        return new AsyncCompletionTask(new AntlrCompletionQuery(), component);
+    }
+
+    @Override
+    public int getAutoQueryTypes(JTextComponent component, String typedText) {
+        return 0;
+    }
+
+    private static boolean isCaseSensitive() {
+        Preferences prefs = MimeLookup.getLookup(MimePath.EMPTY).lookup(Preferences.class);
+        return prefs.getBoolean(SimpleValueNames.COMPLETION_CASE_SENSITIVE, false);
+    }
+
+    private class AntlrCompletionQuery extends AsyncCompletionQuery {
+
+        //TODO: This is a Lexer based pretty dumb implementation. Only offer
+        //      prefix if the cursor is at the end of a start of token/lexer rule.
+        //      Shall be replaced with a better approach.
+        private String getPrefix(ParserResult info, int caretOffset, boolean upToOffset) {
+            String ret = null;
+            TokenHierarchy<?> tokenHierarchy = info.getSnapshot().getTokenHierarchy();
+            TokenSequence<?> ts = tokenHierarchy.tokenSequence();
+            ts.move(caretOffset);
+            if (ts.movePrevious()) {
+                int len = caretOffset - ts.offset();
+                Token<?> token = ts.token();
+                if (token.id() == AntlrTokenId.RULE || token.id() == AntlrTokenId.TOKEN) {
+                    ret = String.valueOf(token.text());
+                    ret = upToOffset ? ret.substring(0, len) : ret;
+                }
+            }
+            return ret;
+        }
+
+        @Override
+        protected void query(CompletionResultSet resultSet, Document doc, int caretOffset) {
+            try {
+                Source source = Source.create(doc);
+                if (source != null) {
+                    UserTask task = new UserTask() {
+                        @Override
+                        public void run(ResultIterator resultIterator) throws Exception {
+                            AntlrParserResult result = (AntlrParserResult) resultIterator.getParserResult(caretOffset);
+                            boolean isCaseSensitive = isCaseSensitive();
+                            String prefix = getPrefix(result, caretOffset, true);
+                            if (prefix != null) {
+                                String mprefix = isCaseSensitive ? prefix : prefix.toUpperCase();
+
+                                for (String ref : result.references.keySet()) {
+                                    String mref = isCaseSensitive ? ref : ref.toUpperCase();
+                                    boolean match = mref.startsWith(mprefix);
+                                    if (match) {
+                                        String insert = ref.substring(prefix.length());
+                                        if (insert.length() > 0) {
+                                            CompletionItem item = CompletionUtilities.newCompletionItemBuilder(insert)
+                                                    .leftHtmlText(ref)
+                                                    .sortText(ref)
+                                                    .build();
+                                            resultSet.addItem(item);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    };
+                    ParserManager.parse(Collections.singleton(source), task);
+                }
+            } catch (ParseException ex) {
+                Exceptions.printStackTrace(ex);
+            } finally {
+                resultSet.finish();
+            }
+        }
+    }
+}
diff --git a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrDataObject.java b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrDataObject.java
deleted file mode 100644
index 42b559b..0000000
--- a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrDataObject.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.netbeans.modules.languages.antlr;
-
-import org.netbeans.core.spi.multiview.MultiViewElement;
-import org.netbeans.core.spi.multiview.text.MultiViewEditorElement;
-import org.openide.awt.ActionID;
-import org.openide.awt.ActionReference;
-import org.openide.awt.ActionReferences;
-import org.openide.filesystems.FileObject;
-import org.openide.filesystems.MIMEResolver;
-import org.openide.loaders.DataNode;
-import org.openide.loaders.DataObject;
-import org.openide.loaders.DataObjectExistsException;
-import org.openide.loaders.MultiDataObject;
-import org.openide.loaders.MultiFileLoader;
-import org.openide.nodes.Children;
-import org.openide.nodes.Node;
-import org.openide.util.Lookup;
-import org.openide.util.NbBundle;
-import org.openide.windows.TopComponent;
-
-/**
- *
- * @author lkishalmi
- */
-@NbBundle.Messages(
-        "ANTLRResolver=ANTLR4 Grammar"
-)
-@MIMEResolver.ExtensionRegistration(displayName = "#ANTLRResolver",
-    extension = "g4",
-    mimeType = AntlrTokenId.MIME_TYPE,
-    position = 285
-)
-
-@ActionReferences({
-    @ActionReference(
-            path = "Loaders/text/x-antlr4/Actions",
-            id = @ActionID(category = "System", id = "org.openide.actions.OpenAction"),
-            position = 100,
-            separatorAfter = 300
-    ),
-    @ActionReference(
-            path = "Loaders/text/x-antlr4/Actions",
-            id = @ActionID(category = "Edit", id = "org.openide.actions.CutAction"),
-            position = 400
-    ),
-    @ActionReference(
-            path = "Loaders/text/x-antlr4/Actions",
-            id = @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"),
-            position = 500,
-            separatorAfter = 600
-    ),
-    @ActionReference(
-            path = "Loaders/text/x-antlr4/Actions",
-            id = @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"),
-            position = 700
-    ),
-    @ActionReference(
-            path = "Loaders/text/x-antlr4/Actions",
-            id = @ActionID(category = "System", id = "org.openide.actions.RenameAction"),
-            position = 800,
-            separatorAfter = 900
-    ),
-    @ActionReference(
-            path = "Loaders/text/x-antlr4/Actions",
-            id = @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"),
-            position = 1000,
-            separatorAfter = 1100
-    ),
-    @ActionReference(
-            path = "Loaders/text/x-antlr4/Actions",
-            id = @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"),
-            position = 1200,
-            separatorAfter = 1300
-    ),
-    @ActionReference(
-            path = "Loaders/text/x-antlr4/Actions",
-            id = @ActionID(category = "System", id = "org.openide.actions.ToolsAction"),
-            position = 1400
-    ),
-    @ActionReference(
-            path = "Loaders/text/x-antlr4/Actions",
-            id = @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"),
-            position = 1500
-    )
-})
-
-@DataObject.Registration(
-        mimeType = AntlrTokenId.MIME_TYPE,
-        displayName = "#ANTLRResolver",
-        position = 304
-)
-public class AntlrDataObject extends MultiDataObject {
-
-    public AntlrDataObject(FileObject fo, MultiFileLoader loader) throws DataObjectExistsException {
-        super(fo, loader);
-        registerEditor(AntlrTokenId.MIME_TYPE, true);
-    }
-
-    @Override
-    protected Node createNodeDelegate() {
-        return new DataNode(this, Children.LEAF, getLookup());
-    }
-
-    @Override
-    protected int associateLookup() {
-        return 1;
-    }
-
-    @NbBundle.Messages("Source=&Source")
-    @MultiViewElement.Registration(
-            displayName = "#Source",
-            persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
-            mimeType = AntlrTokenId.MIME_TYPE,
-            preferredID = "neon.source",
-            position = 1
-    )
-    public static MultiViewEditorElement createMultiViewEditorElement(Lookup context) {
-        return new MultiViewEditorElement(context);
-    }
-
-}
diff --git a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrLanguage.java b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrLanguage.java
index 5c7256e..c264d1f 100644
--- a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrLanguage.java
+++ b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrLanguage.java
@@ -19,18 +19,94 @@
 package org.netbeans.modules.languages.antlr;
 
 import org.netbeans.api.lexer.Language;
+import org.netbeans.core.spi.multiview.MultiViewElement;
+import org.netbeans.core.spi.multiview.text.MultiViewEditorElement;
 import org.netbeans.modules.csl.api.DeclarationFinder;
 import org.netbeans.modules.csl.api.OccurrencesFinder;
 import org.netbeans.modules.csl.api.StructureScanner;
 import org.netbeans.modules.csl.spi.DefaultLanguageConfig;
 import org.netbeans.modules.csl.spi.LanguageRegistration;
 import org.netbeans.modules.parsing.spi.Parser;
+import org.openide.awt.ActionID;
+import org.openide.awt.ActionReference;
+import org.openide.awt.ActionReferences;
+import org.openide.filesystems.MIMEResolver;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle;
+import org.openide.windows.TopComponent;
 
 /**
  *
  * @author lkishalmi
  */
-@LanguageRegistration(mimeType = AntlrTokenId.MIME_TYPE)
+@NbBundle.Messages(
+        "ANTLRResolver=ANTLR4 Grammar"
+)
+@MIMEResolver.ExtensionRegistration(displayName = "#ANTLRResolver",
+    extension = "g4",
+    mimeType = AntlrTokenId.MIME_TYPE,
+    position = 285
+)
+
+@ActionReferences({
+    @ActionReference(
+            path = "Loaders/text/x-antlr4/Actions",
+            id = @ActionID(category = "System", id = "org.openide.actions.OpenAction"),
+            position = 100,
+            separatorAfter = 200
+    ),
+    @ActionReference(
+            path = "Loaders/text/x-antlr4/Actions",
+            id = @ActionID(category = "Edit", id = "org.openide.actions.CutAction"),
+            position = 300
+    ),
+    @ActionReference(
+            path = "Loaders/text/x-antlr4/Actions",
+            id = @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"),
+            position = 400
+    ),
+    @ActionReference(
+            path = "Loaders/text/x-antlr4/Actions",
+            id = @ActionID(category = "Edit", id = "org.openide.actions.PasteAction"),
+            position = 500,
+            separatorAfter = 600
+    ),
+    @ActionReference(
+            path = "Loaders/text/x-antlr4/Actions",
+            id = @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"),
+            position = 700
+    ),
+    @ActionReference(
+            path = "Loaders/text/x-antlr4/Actions",
+            id = @ActionID(category = "System", id = "org.openide.actions.RenameAction"),
+            position = 800,
+            separatorAfter = 900
+    ),
+    @ActionReference(
+            path = "Loaders/text/x-antlr4/Actions",
+            id = @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"),
+            position = 1000,
+            separatorAfter = 1100
+    ),
+    @ActionReference(
+            path = "Loaders/text/x-antlr4/Actions",
+            id = @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"),
+            position = 1200,
+            separatorAfter = 1300
+    ),
+    @ActionReference(
+            path = "Loaders/text/x-antlr4/Actions",
+            id = @ActionID(category = "System", id = "org.openide.actions.ToolsAction"),
+            position = 1400
+    ),
+    @ActionReference(
+            path = "Loaders/text/x-antlr4/Actions",
+            id = @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"),
+            position = 1500
+    )
+})
+
+@LanguageRegistration(mimeType = AntlrTokenId.MIME_TYPE, useMultiview = true)
 public class AntlrLanguage extends DefaultLanguageConfig{
 
     @Override
@@ -83,5 +159,16 @@
         return "g4";
     }
 
+    @NbBundle.Messages("Source=&Source")
+    @MultiViewElement.Registration(
+            displayName = "#Source",
+            persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED,
+            mimeType = AntlrTokenId.MIME_TYPE,
+            preferredID = "neon.source",
+            position = 1
+    )
+    public static MultiViewEditorElement createMultiViewEditorElement(Lookup context) {
+        return new MultiViewEditorElement(context);
+    }
 
 }
diff --git a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrLexer.java b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrLexer.java
index 6c2f8ee..a87c761 100644
--- a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrLexer.java
+++ b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrLexer.java
@@ -52,98 +52,97 @@
 
     @Override
     public Token<AntlrTokenId> nextToken() {
-        try {
-            org.antlr.v4.runtime.Token nextToken;
-            if (preFetchedToken != null) {
-                nextToken = preFetchedToken;
-                lexer.getInputStream().seek(preFetchedToken.getStopIndex() + 1);
-                preFetchedToken = null;
-            } else {
-                nextToken = lexer.nextToken();
-            }
-            if (nextToken.getType() == EOF) {
-                return null;
-            }
-            switch (nextToken.getType()) {
-                case TOKEN_REF:
-                    return token(TOKEN);
-                case RULE_REF:
-                    return token(RULE);
+        org.antlr.v4.runtime.Token nextToken;
+        if (preFetchedToken != null) {
+            nextToken = preFetchedToken;
+            lexer.getInputStream().seek(preFetchedToken.getStopIndex() + 1);
+            preFetchedToken = null;
+        } else {
+            nextToken = lexer.nextToken();
+        }
+        if (nextToken.getType() == EOF) {
+            return null;
+        }
+        switch (nextToken.getType()) {
+            case TOKEN_REF:
+                return token(TOKEN);
+            case RULE_REF:
+                return token(RULE);
 
-                case DOC_COMMENT:
-                case BLOCK_COMMENT:
-                case LINE_COMMENT:
-                    return token(AntlrTokenId.COMMENT);
+            case DOC_COMMENT:
+            case BLOCK_COMMENT:
+            case LINE_COMMENT:
+                return token(AntlrTokenId.COMMENT);
 
-                case INT:
-                    return token(NUMBER);
+            case INT:
+                return token(NUMBER);
 
-                case STRING_LITERAL:
-                case UNTERMINATED_STRING_LITERAL:
-                    return token(STRING);
+            case LEXER_CHAR_SET:
+            case STRING_LITERAL:
+            case UNTERMINATED_STRING_LITERAL:
+                return token(STRING);
 
-                case OPTIONS:
-                case TOKENS:
-                case CHANNELS:
-                case IMPORT:
-                case FRAGMENT:
-                case LEXER:
-                case PARSER:
-                case GRAMMAR:
-                case PROTECTED:
-                case PUBLIC:
-                case PRIVATE:
-                case RETURNS:
-                case LOCALS:
-                case THROWS:
-                case CATCH:
-                case FINALLY:
-                case MODE:
-                    return token(KEYWORD);
+            case OPTIONS:
+            case TOKENS:
+            case CHANNELS:
+            case IMPORT:
+            case FRAGMENT:
+            case LEXER:
+            case PARSER:
+            case GRAMMAR:
+            case PROTECTED:
+            case PUBLIC:
+            case PRIVATE:
+            case RETURNS:
+            case LOCALS:
+            case THROWS:
+            case CATCH:
+            case FINALLY:
+            case MODE:
+                return token(KEYWORD);
 
-                case COLON:
-                case COLONCOLON:
-                case COMMA:
-                case SEMI:
-                case LPAREN:
-                case RPAREN:
-                case LBRACE:
-                case RBRACE:
-                case RARROW:
-                case LT:
-                case GT:
-                case ASSIGN:
-                case QUESTION:
-                case STAR:
-                case PLUS_ASSIGN:
-                case PLUS:
-                case OR:
-                case DOLLAR:
-                case RANGE:
-                case DOT:
-                case AT:
-                case POUND:
-                case NOT:
-                case BEGIN_ACTION:
-                case END_ACTION:
-                    return token(PUNCTUATION);
+            case COLON:
+            case COLONCOLON:
+            case LT:
+            case GT:
+            case BEGIN_ACTION:
+            case END_ACTION:
+            case AT:
+            case PLUS_ASSIGN:
+            case POUND:
+            case LBRACE:
+            case RBRACE:
+            case RARROW:
+            case ASSIGN:
+            case COMMA:
+            case SEMI:
+                return token(PUNCTUATION);
 
-                case WS:
-                    return token(WHITESPACE);
+            case LPAREN:
+            case RPAREN:
+            case QUESTION:
+            case STAR:
+            case PLUS:
+            case OR:
+            case DOLLAR:
+            case RANGE:
+            case DOT:
+            case NOT:
+                return token(REGEXP_CHARS);
 
-                case ACTION_CONTENT:
+            case WS:
+                return token(WHITESPACE);
+
+            case ACTION_CONTENT:
+                preFetchedToken = lexer.nextToken();
+                while (preFetchedToken.getType() == ACTION_CONTENT) {
                     preFetchedToken = lexer.nextToken();
-                    while (preFetchedToken.getType() == ACTION_CONTENT) {
-                        preFetchedToken = lexer.nextToken();
-                    }
-                    lexer.getInputStream().seek(preFetchedToken.getStartIndex());
-                    return token(ACTION);
-                
-                default:
-                    return token(ERROR);
-            }
-        } catch (IndexOutOfBoundsException ex) {
-            return token(ERROR);
+                }
+                lexer.getInputStream().seek(preFetchedToken.getStartIndex());
+                return token(ACTION);
+
+            default:
+                return token(ERROR);
         }
     }
 
diff --git a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrTokenId.java b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrTokenId.java
index 8eb63a4..cb5f5b2 100644
--- a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrTokenId.java
+++ b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/AntlrTokenId.java
@@ -47,6 +47,7 @@
     KEYWORD("keyword"),
     NUMBER("number"),
     PUNCTUATION("punctuation"),
+    REGEXP_CHARS("regexp-chars"),
     RULE("rule"),
     STRING("string"),
     TOKEN("token"),
diff --git a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/Bundle.properties b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/Bundle.properties
index 423ea4b..9d857db 100644
--- a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/Bundle.properties
+++ b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/Bundle.properties
@@ -28,6 +28,7 @@
 keyword=Keyword
 number=Number
 punctuation=Punctuations
+regexp-chars=Regular Expression Special Characters
 rule=Parser Rule
 string=String
 token=Lexer Token
diff --git a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/FlatLafDark-FontAndColors.xml b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/FlatLafDark-FontAndColors.xml
new file mode 100644
index 0000000..1e971ab
--- /dev/null
+++ b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/FlatLafDark-FontAndColors.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<!DOCTYPE fontscolors PUBLIC "-//NetBeans//DTD Editor Fonts and Colors settings 1.1//EN" "http://www.netbeans.org/dtds/EditorFontsColors-1_1.dtd">
+<fontscolors>
+    <fontcolor name="action" default="keyword"/>
+    <fontcolor name="comment" default="comment"/>
+    <fontcolor name="error" default="error"/>
+    <fontcolor name="number" default="number"/>
+    <fontcolor name="keyword" default="keyword"/>
+    <fontcolor name="number" default="number"/>
+    <fontcolor name="punctuation" default="operator"/>
+    <fontcolor name="regexp-chars" foreColor="33ffcc">
+        <font style="bold"/>
+    </fontcolor>
+    <fontcolor name="rule" foreColor="b2b200">
+        <font style="bold"/>
+    </fontcolor>
+    <fontcolor name="string" default="string">
+        <font style="bold"/>
+    </fontcolor>
+    <fontcolor name="token" foreColor="e500e5">
+        <font style="bold" />
+    </fontcolor>
+    <fontcolor name="whitespace" default="whitespace"/>
+</fontscolors>
diff --git a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/FontAndColors.xml b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/FontAndColors.xml
index c9e4564..666fdd2 100644
--- a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/FontAndColors.xml
+++ b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/FontAndColors.xml
@@ -25,15 +25,19 @@
     <fontcolor name="comment" default="comment"/>
     <fontcolor name="error" default="error"/>
     <fontcolor name="number" default="number"/>
-    <fontcolor name="keyword" default="keyword">
-        <font style="bold" />
-    </fontcolor>
+    <fontcolor name="keyword" default="keyword"/>
     <fontcolor name="number" default="number"/>
-    <fontcolor name="punctuation" default="operator" bgColor="ffe3f2e1">
+    <fontcolor name="punctuation" default="operator"/>
+    <fontcolor name="regexp-chars" foreColor="bf4040">
+        <font style="bold"/>
     </fontcolor>
-    <fontcolor name="rule" default="identifier"/>
-    <fontcolor name="string" default="string"/>
-    <fontcolor name="token" default="identfier">
+    <fontcolor name="rule" foreColor="47478e">
+        <font style="bold"/>
+    </fontcolor>
+    <fontcolor name="string" default="string">
+        <font style="bold"/>
+    </fontcolor>
+    <fontcolor name="token" foreColor="660e7a">
         <font style="bold" />
     </fontcolor>
     <fontcolor name="whitespace" default="whitespace"/>
diff --git a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/layer.xml b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/layer.xml
index b05cd6b..a691529 100644
--- a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/layer.xml
+++ b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/layer.xml
@@ -26,6 +26,13 @@
             <folder name="x-antlr4">
                 <attr name="displayName" bundlevalue="org.netbeans.modules.languages.antlr.Bundle#Editors/text/x-antlr4"/>
                 <folder name="FontsColors">
+                    <folder name="FlatLafDark">
+                        <folder name="Defaults">
+                            <file name="FontAndColors.xml" url="FlatLafDark-FontAndColors.xml">
+                                <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.languages.antlr.Bundle"/>
+                            </file>
+                        </folder>
+                    </folder>
                     <folder name="NetBeans">
                         <folder name="Defaults">
                             <file name="FontAndColors.xml" url="FontAndColors.xml">
@@ -37,6 +44,16 @@
             </folder>
         </folder>
     </folder>
+    <folder name="Loaders">
+        <folder name="text">
+            <folder name="x-antlr3">
+                <attr name="iconBase" stringvalue="org/netbeans/modules/languages/antlr/resources/antlr.png"/>
+            </folder>
+            <folder name="x-antlr4">
+                <attr name="iconBase" stringvalue="org/netbeans/modules/languages/antlr/resources/antlr.png"/>
+            </folder>
+        </folder>
+    </folder>
     <folder name="OptionsDialog">
         <folder name="PreviewExamples">
             <folder name="text">
diff --git a/java/languages.antlr/src/org/netbeans/modules/languages/antlr/resources/antlr.png b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/resources/antlr.png
new file mode 100644
index 0000000..cea8293
--- /dev/null
+++ b/java/languages.antlr/src/org/netbeans/modules/languages/antlr/resources/antlr.png
Binary files differ
diff --git a/nbbuild/licenses/BSD-antlr-icons b/nbbuild/licenses/BSD-antlr-icons
new file mode 100644
index 0000000..4b754bb
--- /dev/null
+++ b/nbbuild/licenses/BSD-antlr-icons
@@ -0,0 +1,31 @@
+Use of Antlr Icon(s) are originated from ANTLR Intelli-J Plugin from:
+https://github.com/antlr/intellij-plugin-v4 repository which at the time of
+writing is governed by the terms of the license below:
+
+Copyright (c) 2013, Terence Parr
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+  Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+  Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+
+  Neither the name of the {organization} nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.