/* * Copyright 2014 TWO SIGMA OPEN SOURCE, LLC * * Licensed 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 com.twosigma.beaker.groovy.autocomplete; import com.twosigma.beaker.autocomplete.AutocompleteCandidate; import com.twosigma.beaker.autocomplete.AutocompleteRegistry; import com.twosigma.beaker.autocomplete.AutocompleteResult; import com.twosigma.beaker.autocomplete.ClassUtils; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTreeWalker; import java.util.ArrayList; import java.util.List; public class GroovyAutocomplete { AutocompleteRegistry registry; private GroovyClasspathScanner cps; private List<String> imports; public GroovyAutocomplete(GroovyClasspathScanner _cps) { this(_cps,GroovyCompletionTypes.NUM_TYPES); } public GroovyAutocomplete(GroovyClasspathScanner _cps, int num) { registry = new AutocompleteRegistry(num); setup(registry); cps = _cps; for ( String pkg : cps.getPackages()) { String[] pkgv = pkg.split("\\."); AutocompleteCandidate c = new AutocompleteCandidate(GroovyCompletionTypes.PACKAGE_NAME, pkgv); registry.addCandidate(c); List<String> cls = cps.getClasses(pkg); if(cls!=null && !cls.isEmpty()) { c = new AutocompleteCandidate(GroovyCompletionTypes.FQ_TYPE, pkgv); AutocompleteCandidate l = c; while(l.hasChildren()) { l = l.getChildrens().get(0); } for ( String cl : cls) { l.addChildren(new AutocompleteCandidate(GroovyCompletionTypes.FQ_TYPE, cl)); } registry.addCandidate(c); } } imports = new ArrayList<String>(); } /* * These are meant to be extended by personalized plugin versions. */ protected void moreSetup(AutocompleteRegistry r) { } protected void moreSetup(ClassUtils cu) { cu.defineVariable("beaker", "com.twosigma.beaker.NamespaceClient"); } public void addImport(String imp) { imports.add(imp); } private void setup(AutocompleteRegistry r) { AutocompleteCandidate c; c = new AutocompleteCandidate(GroovyCompletionTypes.INITIAL, "package"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "import"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "class"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "enum"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "interface"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "def"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "assert"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "if"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "switch"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "while"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "for"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "try"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "extends"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TOPLEVEL, "implements"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.CLASSLEVEL, "extends"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.CLASSLEVEL, "implements"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.STDFUNCS, "any"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.STDFUNCS, "collect"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.STDFUNCS, "each"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.STDFUNCS, "eachWithIndex"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.STDFUNCS, "every"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.STDFUNCS, "find"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.STDFUNCS, "findAll"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.STDFUNCS, "findIndexOf"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "int"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "float"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "char"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "byte"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "void"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "boolean"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "short"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "long"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "double"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Boolean"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Byte"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Character"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Double"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Float"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Integer"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Long"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Math"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Number"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Object"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Package"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Process"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "ProcessBuilder"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Runtime"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "RuntimePermission"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "SecurityManager"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Short"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "StackTraceElement"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "StrictMath"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "String"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "StringBuffer"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "StringBuilder"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "System"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Thread"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "ThreadGroup"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Throwable"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "Void"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.TYPE, "NamespaceClient"); r.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NEW, "new"); r.addCandidate(c); } private void setup(ClassUtils cu, AutocompleteRegistry registry2) { cu.defineClassShortName("Boolean", "java.lang.Boolean"); cu.defineClassShortName("Byte", "java.lang.Byte"); cu.defineClassShortName("Character", "java.lang.Character"); cu.defineClassShortName("Double", "java.lang.Double"); cu.defineClassShortName("Exception", "java.lang.Exception"); cu.defineClassShortName("Float", "java.lang.Float"); cu.defineClassShortName("Integer", "java.lang.Integer"); cu.defineClassShortName("Long", "java.lang.Long"); cu.defineClassShortName("Math", "java.lang.Math"); cu.defineClassShortName("Number", "java.lang.Number"); cu.defineClassShortName("Object", "java.lang.Object"); cu.defineClassShortName("Package", "java.lang.Package"); cu.defineClassShortName("Process", "java.lang.Process"); cu.defineClassShortName("ProcessBuilder", "java.lang.ProcessBuilder"); cu.defineClassShortName("Runtime", "java.lang.Runtime"); cu.defineClassShortName("RuntimePermission", "java.lang.RuntimePermission"); cu.defineClassShortName("SecurityManager", "java.lang.SecurityManager"); cu.defineClassShortName("Short", "java.lang.Short"); cu.defineClassShortName("StackTraceElement", "java.lang.StackTraceElement"); cu.defineClassShortName("StrictMath", "java.lang.StrictMath"); cu.defineClassShortName("String", "java.lang.String"); cu.defineClassShortName("StringBuffer", "java.lang.StringBuffer"); cu.defineClassShortName("StringBuilder", "java.lang.StringBuilder"); cu.defineClassShortName("System", "java.lang.System"); cu.defineClassShortName("Thread","java.lang.Thread"); cu.defineClassShortName("ThreadGroup", "java.lang.ThreadGroup"); cu.defineClassShortName("Throwable", "java.lang.Throwable"); cu.defineClassShortName("Void", "java.lang.Void"); cu.defineClassShortName("NamespaceClient", "com.twosigma.beaker.NamespaceClient"); AutocompleteCandidate c; c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Boolean"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Byte"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Character"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Double"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Exception"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Float"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Integer"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Long"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Number"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Object"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Package"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Process"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "ProcessBuilder"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Runtime"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "RuntimePermission"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "SecurityManager"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Short"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "StackTraceElement"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "StrictMath"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "String"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "StringBuffer"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "StringBuilder"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "System"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Thread"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "ThreadGroup"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Throwable"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "Void"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "NamespaceClient"); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.NAME, "beaker"); registry.addCandidate(c); } private void addDefaultImports(ClassUtils cu) { for(String imp : imports) { // this imports using '*' if(imp.endsWith(".*")) { String st = imp.substring(0, imp.length()-2); String [] txtv = st.split("\\."); AutocompleteCandidate c = new AutocompleteCandidate(GroovyCompletionTypes.PACKAGE_NAME, txtv); registry.addCandidate(c); List<String> cls = cps.getClasses(st); if(cls!=null) { c = new AutocompleteCandidate(GroovyCompletionTypes.FQ_TYPE, txtv); AutocompleteCandidate l = c.findLeaf(); for ( String s : cls) { l.addChildren(new AutocompleteCandidate(GroovyCompletionTypes.CUSTOM_TYPE, s)); registry.addCandidate(new AutocompleteCandidate(GroovyCompletionTypes.CUSTOM_TYPE, s)); cu.defineClassShortName(s, st+"."+s); } registry.addCandidate(c); } } else { String [] txtv = imp.split("\\."); AutocompleteCandidate c = new AutocompleteCandidate(GroovyCompletionTypes.PACKAGE_NAME, txtv, txtv.length-1); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.FQ_TYPE, txtv); registry.addCandidate(c); c = new AutocompleteCandidate(GroovyCompletionTypes.CUSTOM_TYPE, txtv[txtv.length-1]); registry.addCandidate(c); cu.defineClassShortName(txtv[txtv.length-1], imp); } } } protected ClassUtils createClassUtils(ClassLoader l) { return new GroovyClassUtils(cps, l); } public AutocompleteResult doAutocomplete(String txt, int cur, ClassLoader l) { ClassUtils cu = createClassUtils(l); setup(cu, registry); registry.clearForType(GroovyCompletionTypes.CUSTOM_TYPE); registry.clearForType(GroovyCompletionTypes.FIELD); registry.clearForType(GroovyCompletionTypes.NAME); addDefaultImports(cu); moreSetup(cu); moreSetup(registry); Lexer lexer = new GroovyLexer(new ANTLRInputStream(txt)); lexer.removeErrorListeners(); CommonTokenStream tokens = new CommonTokenStream(lexer); // Create a parser that reads from the scanner GroovyParser parser = new GroovyParser(tokens); parser.removeErrorListeners(); // start parsing at the compilationUnit rule ParserRuleContext t = parser.compilationUnit(); ParseTreeWalker walker = new ParseTreeWalker(); List<AutocompleteCandidate> q = new ArrayList<AutocompleteCandidate>(); GroovyImportDeclarationCompletion extractor = new GroovyImportDeclarationCompletion(txt,cur,registry,cps,cu); GroovyNameBuilder extractor2 = new GroovyNameBuilder(registry,cu ); GroovyNodeCompletion extractor3 = new GroovyNodeCompletion(txt,cur, registry, cu); walker.walk(extractor, t); if(extractor.getQuery()!=null) q.addAll(extractor.getQuery()); walker.walk(extractor2, t); walker.walk(extractor3, t); if(extractor3.getQuery()!=null) q.addAll(extractor3.getQuery()); List<String> ret = registry.searchCandidates(q); if(ret.isEmpty()) { q.clear(); for (int i=cur-1; i>=0; i--) { if(i<txt.length() && Character.isWhitespace(txt.charAt(i))) { String tx = txt.substring(i+1, cur).trim(); if(!txt.isEmpty()) { if(tx.contains(".")) { q.add(cu.expandExpression(tx, registry, cu.DO_ALL)); } else { q.add(new AutocompleteCandidate(GroovyCompletionTypes.NAME, tx)); } ret = registry.searchCandidates(q); } break; } } } if(txt.charAt(cur-1)=='.') { for(int i=0; i<ret.size(); i++) { String s = ret.get(i); if(s.startsWith(".")) ret.set(i, s.substring(1)); } } // this shows the GUI if(GroovyCompletionTypes.debug) t.inspect(parser); return new AutocompleteResult(ret, getStartIndex(extractor,extractor2,extractor3)); } private int getStartIndex(GroovyImportDeclarationCompletion extractor, GroovyNameBuilder extractor2, GroovyNodeCompletion extractor3) { if (extractor.getQuery()!=null){ return extractor.getStartIndex(); } if (extractor2.getQuery()!=null){ return extractor2.getStartIndex(); } if (extractor3.getQuery()!=null){ return extractor3.getStartIndex(); } return 0; } }