Ver código fonte

Keyword competition for GLSL editor

Toni Helenius 7 meses atrás
pai
commit
789dab411b

+ 40 - 11
jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/GlslCompletionProvider.java

@@ -31,12 +31,19 @@
  */
 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;
@@ -58,27 +65,49 @@ public class GlslCompletionProvider implements CompletionProvider {
             protected void query(CompletionResultSet completionResultSet,
                     Document document, int caretOffset) {
 
-                String filter = getFilter(caretOffset, document);
+                String filter = "";
+                int startOffset = caretOffset - 1;
 
-                // TODO: get the posibilities
-                // TODO: filter out the special chars
-
-                completionResultSet.finish();
-            }
-
-            private String getFilter(int caretOffset, Document document) {
                 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);
-
-                    return new String(line, whiteOffset + 1, line.length - whiteOffset - 1);
+                    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);
                 }
 
-                return "";
+                setCompletionItems(filter, completionResultSet, startOffset, caretOffset);
+
+                completionResultSet.finish();
+            }
+
+            private void setCompletionItems(String filter, CompletionResultSet completionResultSet, int startOffset, int caretOffset) {
+                List<GlslKeywordLibrary.Keyword> 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);
     }

+ 123 - 0
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();
+
+}

+ 50 - 0
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;
+    }
+}

+ 50 - 0
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;
+    }
+}

+ 50 - 0
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;
+    }
+}

+ 50 - 0
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;
+    }
+}

BIN
jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/class_16.png


BIN
jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/field_16.png


BIN
jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/method_16.png


BIN
jme3-glsl-highlighter/src/com/jme3/gde/glsl/highlighter/editor/completion/method_static_protected_16.png


+ 31 - 1
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 @@ import com.jme3.gde.glsl.highlighter.util.Trie;
  *
  * @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 @@ final class GlslKeywordLibrary {
         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 @@ final class GlslKeywordLibrary {
         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<Keyword> lookupAll(String s) {
+        List<Keyword> 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) {

+ 62 - 6
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 @@ public class Trie {
         boolean isEndOfWord = false;
     }
 
+    private record Pair(TrieNode node, StringBuilder prefix) {
+
+    }
+
     public enum MatchType {
         NO_MATCH,
         PARTIAL_MATCH,
@@ -70,6 +79,18 @@ public class Trie {
         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 class Trie {
      * @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<String> searchAll(String word) {
+        TrieNode node = findNode(word);
+        if (node == null) {
+            return Collections.emptyList();
+        }
+
+        return collectAllWords(node, word);
+    }
+
+    private static List<String> collectAllWords(TrieNode startNode, String prefix) {
+        List<String> results = new ArrayList<>();
+        Deque<Pair> 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<Character, TrieNode> 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;
     }
 
 }