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; } }