diff --git a/jme3-glsl-highlighter/nbproject/project.xml b/jme3-glsl-highlighter/nbproject/project.xml
index 6cee79cf8..52b8cf079 100644
--- a/jme3-glsl-highlighter/nbproject/project.xml
+++ b/jme3-glsl-highlighter/nbproject/project.xml
@@ -50,6 +50,15 @@
1.39.1.55
+
+ org.netbeans.modules.editor.completion
+
+
+
+ 1
+ 1.71.0.2
+
+
org.netbeans.modules.editor.indent
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/GlslCompletionProvider.java b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/GlslCompletionProvider.java
new file mode 100644
index 000000000..128e73a7d
--- /dev/null
+++ b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/GlslCompletionProvider.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2003-2024 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 OWNER 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.
+ */
+package com.jme3.gde.glsl.highlighter.editor;
+
+import com.jme3.gde.glsl.highlighter.editor.completion.FunctionCompletionItem;
+import com.jme3.gde.glsl.highlighter.editor.completion.KeywordCompletionItem;
+import com.jme3.gde.glsl.highlighter.editor.completion.TypeCompletionItem;
+import com.jme3.gde.glsl.highlighter.editor.completion.VariableCompletionItem;
+import com.jme3.gde.glsl.highlighter.lexer.GlslKeywordLibrary;
+import java.util.List;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.StyledDocument;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+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.openide.util.Exceptions;
+
+@MimeRegistration(mimeType = "text/x-glsl", service = CompletionProvider.class)
+public class GlslCompletionProvider implements CompletionProvider {
+
+ @Override
+ public CompletionTask createTask(int queryType, JTextComponent component) {
+ if (queryType != CompletionProvider.COMPLETION_QUERY_TYPE) {
+ return null;
+ }
+
+ return new AsyncCompletionTask(new AsyncCompletionQuery() {
+ @Override
+ protected void query(CompletionResultSet completionResultSet,
+ Document document, int caretOffset) {
+
+ String filter = "";
+ int startOffset = caretOffset - 1;
+
+ try {
+ final StyledDocument bDoc = (StyledDocument) document;
+ final int lineStartOffset = getRowFirstNonWhite(bDoc, caretOffset);
+ final char[] line = bDoc.getText(lineStartOffset, caretOffset - lineStartOffset).toCharArray();
+ final int whiteOffset = indexOfWhite(line);
+ filter = new String(line, whiteOffset + 1, line.length - whiteOffset - 1);
+ if (whiteOffset > 0) {
+ startOffset = lineStartOffset + whiteOffset + 1;
+ } else {
+ startOffset = lineStartOffset;
+ }
+ } catch (BadLocationException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+
+ setCompletionItems(filter, completionResultSet, startOffset, caretOffset);
+
+ completionResultSet.finish();
+ }
+
+ private void setCompletionItems(String filter, CompletionResultSet completionResultSet, int startOffset, int caretOffset) {
+ List keywords = GlslKeywordLibrary.lookupAll(filter);
+ completionResultSet.addAllItems(keywords.stream().map((keyword) -> createCompletionItem(keyword, startOffset, caretOffset)).toList());
+ }
+
+ private CompletionItem createCompletionItem(GlslKeywordLibrary.Keyword keyword, int dotOffset, int caretOffset) {
+ return switch (keyword.keywordType()) {
+ case KEYWORD ->
+ new KeywordCompletionItem(keyword.keyword(), dotOffset, caretOffset);
+ case BUILTIN_FUNCTION ->
+ new FunctionCompletionItem(keyword.keyword(), dotOffset, caretOffset);
+ case BUILTIN_VARIABLE ->
+ new VariableCompletionItem(keyword.keyword(), dotOffset, caretOffset);
+ case BASIC_TYPE ->
+ new TypeCompletionItem(keyword.keyword(), dotOffset, caretOffset);
+ case UNFINISHED ->
+ throw new AssertionError("Keyword type invalid");
+ default ->
+ throw new AssertionError("Keyword type not implemented");
+ };
+ }
+ }, component);
+ }
+
+ private static int getRowFirstNonWhite(StyledDocument doc, int offset)
+ throws BadLocationException {
+ Element lineElement = doc.getParagraphElement(offset);
+ int start = lineElement.getStartOffset();
+ while (start + 1 < lineElement.getEndOffset()) {
+ try {
+ if (doc.getText(start, 1).charAt(0) != ' ') {
+ break;
+ }
+ } catch (BadLocationException ex) {
+ throw (BadLocationException) new BadLocationException(
+ "calling getText(" + start + ", " + (start + 1)
+ + ") on doc of length: " + doc.getLength(), start
+ ).initCause(ex);
+ }
+ start++;
+ }
+ return start;
+ }
+
+ private static int indexOfWhite(char[] line) {
+ int i = line.length;
+ while (--i > -1) {
+ final char c = line[i];
+ if (Character.isWhitespace(c)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public int getAutoQueryTypes(JTextComponent jtc, String string) {
+ return 0;
+ }
+}
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/DefaultCompletionItem.java b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/DefaultCompletionItem.java
new file mode 100644
index 000000000..67347cb3f
--- /dev/null
+++ b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/DefaultCompletionItem.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2003-2024 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 OWNER 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.
+ */
+package com.jme3.gde.glsl.highlighter.editor.completion;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.event.KeyEvent;
+import javax.swing.ImageIcon;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.StyledDocument;
+import org.netbeans.api.editor.completion.Completion;
+import org.netbeans.spi.editor.completion.CompletionItem;
+import org.netbeans.spi.editor.completion.CompletionTask;
+import org.netbeans.spi.editor.completion.support.CompletionUtilities;
+import org.openide.util.Exceptions;
+
+public abstract class DefaultCompletionItem implements CompletionItem {
+
+ private final String keyword;
+ private final int caretOffset;
+ private final int dotOffset;
+
+ public DefaultCompletionItem(String keyword, int dotOffset, int caretOffset) {
+ this.keyword = keyword;
+ this.dotOffset = dotOffset;
+ this.caretOffset = caretOffset;
+ }
+
+ @Override
+ public void defaultAction(JTextComponent component) {
+ try {
+ StyledDocument doc = (StyledDocument) component.getDocument();
+ //Here we remove the characters starting at the start offset
+ //and ending at the point where the caret is currently found:
+ doc.remove(dotOffset, caretOffset - dotOffset);
+ doc.insertString(dotOffset, keyword, null);
+ Completion.get().hideAll();
+ } catch (BadLocationException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+
+ @Override
+ public void processKeyEvent(KeyEvent ke) {
+
+ }
+
+ @Override
+ public int getPreferredWidth(Graphics graphics, Font font) {
+ return CompletionUtilities.getPreferredWidth(keyword, null, graphics, font);
+ }
+
+ @Override
+ public void render(Graphics graphics, Font font, Color defaultColor,
+ Color backgroundColor, int width, int height, boolean selected) {
+ CompletionUtilities.renderHtml(getIcon(), keyword, null, graphics, font,
+ (selected ? Color.white : null), width, height, selected);
+ }
+
+ @Override
+ public CompletionTask createDocumentationTask() {
+ return null;
+ }
+
+ @Override
+ public CompletionTask createToolTipTask() {
+ return null;
+ }
+
+ @Override
+ public boolean instantSubstitution(JTextComponent jtc) {
+ return false;
+ }
+
+ @Override
+ public int getSortPriority() {
+ return 0;
+ }
+
+ @Override
+ public CharSequence getSortText() {
+ return keyword;
+ }
+
+ @Override
+ public CharSequence getInsertPrefix() {
+ return keyword;
+ }
+
+ protected abstract ImageIcon getIcon();
+
+}
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/FunctionCompletionItem.java b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/FunctionCompletionItem.java
new file mode 100644
index 000000000..6a672e49b
--- /dev/null
+++ b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/FunctionCompletionItem.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2003-2024 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 OWNER 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.
+ */
+package com.jme3.gde.glsl.highlighter.editor.completion;
+
+import javax.swing.ImageIcon;
+import org.openide.util.ImageUtilities;
+
+public class FunctionCompletionItem extends DefaultCompletionItem {
+
+ private static final ImageIcon fieldIcon
+ = new ImageIcon(ImageUtilities.loadImage("com/jme3/gde/glsl/highlighter/editor/completion/method_16.png"));
+
+ public FunctionCompletionItem(String keyword, int dotOffset, int caretOffset) {
+ super(keyword, dotOffset, caretOffset);
+ }
+
+ @Override
+ protected ImageIcon getIcon() {
+ return fieldIcon;
+ }
+}
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/KeywordCompletionItem.java b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/KeywordCompletionItem.java
new file mode 100644
index 000000000..324b0c658
--- /dev/null
+++ b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/KeywordCompletionItem.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2003-2024 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 OWNER 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.
+ */
+package com.jme3.gde.glsl.highlighter.editor.completion;
+
+import javax.swing.ImageIcon;
+import org.openide.util.ImageUtilities;
+
+public class KeywordCompletionItem extends DefaultCompletionItem {
+
+ private static final ImageIcon fieldIcon
+ = new ImageIcon(ImageUtilities.loadImage("com/jme3/gde/glsl/highlighter/editor/completion/method_static_protected_16.png"));
+
+ public KeywordCompletionItem(String keyword, int dotOffset, int caretOffset) {
+ super(keyword, dotOffset, caretOffset);
+ }
+
+ @Override
+ protected ImageIcon getIcon() {
+ return fieldIcon;
+ }
+}
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/TypeCompletionItem.java b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/TypeCompletionItem.java
new file mode 100644
index 000000000..f5f1fe658
--- /dev/null
+++ b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/TypeCompletionItem.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2003-2024 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 OWNER 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.
+ */
+package com.jme3.gde.glsl.highlighter.editor.completion;
+
+import javax.swing.ImageIcon;
+import org.openide.util.ImageUtilities;
+
+public class TypeCompletionItem extends DefaultCompletionItem {
+
+ private static final ImageIcon fieldIcon
+ = new ImageIcon(ImageUtilities.loadImage("com/jme3/gde/glsl/highlighter/editor/completion/class_16.png"));
+
+ public TypeCompletionItem(String keyword, int dotOffset, int caretOffset) {
+ super(keyword, dotOffset, caretOffset);
+ }
+
+ @Override
+ protected ImageIcon getIcon() {
+ return fieldIcon;
+ }
+}
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/VariableCompletionItem.java b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/VariableCompletionItem.java
new file mode 100644
index 000000000..f6408e2b3
--- /dev/null
+++ b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/VariableCompletionItem.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2003-2024 jMonkeyEngine
+ * 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 'jMonkeyEngine' 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 OWNER 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.
+ */
+package com.jme3.gde.glsl.highlighter.editor.completion;
+
+import javax.swing.ImageIcon;
+import org.openide.util.ImageUtilities;
+
+public class VariableCompletionItem extends DefaultCompletionItem {
+
+ private static final ImageIcon fieldIcon
+ = new ImageIcon(ImageUtilities.loadImage("com/jme3/gde/glsl/highlighter/editor/completion/field_16.png"));
+
+ public VariableCompletionItem(String keyword, int dotOffset, int caretOffset) {
+ super(keyword, dotOffset, caretOffset);
+ }
+
+ @Override
+ protected ImageIcon getIcon() {
+ return fieldIcon;
+ }
+}
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/class_16.png b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/class_16.png
new file mode 100644
index 000000000..220e6f385
Binary files /dev/null and b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/class_16.png differ
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/field_16.png b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/field_16.png
new file mode 100644
index 000000000..06a86fb1d
Binary files /dev/null and b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/field_16.png differ
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/method_16.png b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/method_16.png
new file mode 100644
index 000000000..7be8a378a
Binary files /dev/null and b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/method_16.png differ
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/method_static_protected_16.png b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/method_static_protected_16.png
new file mode 100644
index 000000000..e5f9c9bf8
Binary files /dev/null and b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/method_static_protected_16.png differ
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/lexer/GlslKeywordLibrary.java b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/lexer/GlslKeywordLibrary.java
index 2692dca85..bb72ee24f 100644
--- a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/lexer/GlslKeywordLibrary.java
+++ b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/lexer/GlslKeywordLibrary.java
@@ -32,6 +32,8 @@
package com.jme3.gde.glsl.highlighter.lexer;
import com.jme3.gde.glsl.highlighter.util.Trie;
+import java.util.ArrayList;
+import java.util.List;
/**
* Brace, yourselves, this file contains every word that means something in
@@ -39,11 +41,15 @@
*
* @author grizeldi
*/
-final class GlslKeywordLibrary {
+public final class GlslKeywordLibrary {
public enum KeywordType {
KEYWORD, BUILTIN_FUNCTION, BUILTIN_VARIABLE, BASIC_TYPE, UNFINISHED;
}
+
+ public record Keyword(String keyword, KeywordType keywordType) {
+
+ }
private static final Trie keywords = new Trie();
private static final Trie builtinFunctions = new Trie();
@@ -468,6 +474,13 @@ public enum KeywordType {
builtinFunctions.insert("groupMemoryBarrier");
}
+ /**
+ * Finds if given string is either a partial match, full match or nothing at
+ * all
+ *
+ * @param s string to search for
+ * @return returns the status of the string
+ */
public static KeywordType lookup(String s) {
KeywordType returnType = null;
returnType = lookup(s, returnType, KeywordType.BASIC_TYPE, basicTypes);
@@ -484,6 +497,23 @@ public static KeywordType lookup(String s) {
return returnType;
}
+ /**
+ * Gets all the possible matches for given string (auto-complete)
+ *
+ * @param s string to search for
+ * @return all the matches for given string
+ */
+ public static List lookupAll(String s) {
+ List matches = new ArrayList<>();
+
+ matches.addAll(basicTypes.searchAll(s).stream().map((keyword) -> new Keyword(keyword, KeywordType.BASIC_TYPE)).toList());
+ matches.addAll(builtinVariables.searchAll(s).stream().map((keyword) -> new Keyword(keyword, KeywordType.BUILTIN_VARIABLE)).toList());
+ matches.addAll(builtinFunctions.searchAll(s).stream().map((keyword) -> new Keyword(keyword, KeywordType.BUILTIN_FUNCTION)).toList());
+ matches.addAll(keywords.searchAll(s).stream().map((keyword) -> new Keyword(keyword, KeywordType.KEYWORD)).toList());
+
+ return matches;
+ }
+
private static KeywordType lookup(String s, KeywordType currentType, KeywordType matchType, Trie searchTrie) {
Trie.MatchType match = searchTrie.search(s);
if (match == Trie.MatchType.FULL_MATCH) {
diff --git a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/util/Trie.java b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/util/Trie.java
index cb771bccc..61f1c55de 100644
--- a/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/util/Trie.java
+++ b/jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/util/Trie.java
@@ -31,7 +31,12 @@
*/
package com.jme3.gde.glsl.highlighter.util;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -47,6 +52,10 @@ private static class TrieNode {
boolean isEndOfWord = false;
}
+ private record Pair(TrieNode node, StringBuilder prefix) {
+
+ }
+
public enum MatchType {
NO_MATCH,
PARTIAL_MATCH,
@@ -70,6 +79,18 @@ public void insert(String word) {
current.isEndOfWord = true;
}
+ private TrieNode findNode(String word) {
+ TrieNode current = root;
+ for (char ch : word.toCharArray()) {
+ if (!current.children.containsKey(ch)) {
+ return null;
+ }
+ current = current.children.get(ch);
+ }
+
+ return current;
+ }
+
/**
* Searches for the string
*
@@ -77,15 +98,50 @@ public void insert(String word) {
* @return match type
*/
public MatchType search(String word) {
- TrieNode current = root;
- for (char ch : word.toCharArray()) {
- if (!current.children.containsKey(ch)) {
- return MatchType.NO_MATCH;
+ TrieNode node = findNode(word);
+ if (node == null) {
+ return MatchType.NO_MATCH;
+ }
+
+ return node.isEndOfWord ? MatchType.FULL_MATCH : MatchType.PARTIAL_MATCH;
+ }
+
+ /**
+ * Searches for the string and gives out all the possible matches
+ *
+ * @param word word to search for
+ */
+ public List searchAll(String word) {
+ TrieNode node = findNode(word);
+ if (node == null) {
+ return Collections.emptyList();
+ }
+
+ return collectAllWords(node, word);
+ }
+
+ private static List collectAllWords(TrieNode startNode, String prefix) {
+ List results = new ArrayList<>();
+ Deque stack = new ArrayDeque<>();
+ stack.push(new Pair(startNode, new StringBuilder(prefix)));
+
+ while (!stack.isEmpty()) {
+ Pair pair = stack.pop();
+ TrieNode node = pair.node;
+ StringBuilder currentPrefix = pair.prefix;
+
+ if (node.isEndOfWord) {
+ results.add(currentPrefix.toString());
+ }
+
+ for (Map.Entry entry : node.children.entrySet()) {
+ char nextChar = entry.getKey();
+ TrieNode childNode = entry.getValue();
+ stack.push(new Pair(childNode, new StringBuilder(currentPrefix).append(nextChar)));
}
- current = current.children.get(ch);
}
- return current.isEndOfWord ? MatchType.FULL_MATCH : MatchType.PARTIAL_MATCH;
+ return results;
}
}