2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.jetbrains.plugins.groovy.lang.completion;
20 import com.intellij.codeInsight.TailType;
21 import com.intellij.codeInsight.completion.CompletionData;
22 import com.intellij.codeInsight.completion.CompletionVariant;
23 import com.intellij.codeInsight.lookup.LookupElement;
24 import com.intellij.codeInsight.lookup.LookupItem;
25 import com.intellij.codeInsight.lookup.LookupElementDecorator;
26 import com.intellij.openapi.diagnostic.Logger;
27 import com.intellij.psi.PsiElement;
28 import com.intellij.psi.PsiFile;
29 import com.intellij.psi.PsiReference;
30 import com.intellij.psi.filters.*;
31 import com.intellij.psi.filters.position.LeftNeighbour;
32 import com.intellij.psi.filters.position.ParentElementFilter;
33 import com.intellij.psi.impl.source.tree.LeafPsiElement;
34 import gnu.trove.THashSet;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.plugins.groovy.lang.completion.filters.classdef.ExtendsFilter;
37 import org.jetbrains.plugins.groovy.lang.completion.filters.classdef.ImplementsFilter;
38 import org.jetbrains.plugins.groovy.lang.completion.filters.control.BranchFilter;
39 import org.jetbrains.plugins.groovy.lang.completion.filters.control.ControlStructureFilter;
40 import org.jetbrains.plugins.groovy.lang.completion.filters.control.additional.CaseDefaultFilter;
41 import org.jetbrains.plugins.groovy.lang.completion.filters.control.additional.CatchFinallyFilter;
42 import org.jetbrains.plugins.groovy.lang.completion.filters.control.additional.ElseFilter;
43 import org.jetbrains.plugins.groovy.lang.completion.filters.exprs.InstanceOfFilter;
44 import org.jetbrains.plugins.groovy.lang.completion.filters.exprs.SimpleExpressionFilter;
45 import org.jetbrains.plugins.groovy.lang.completion.filters.modifiers.*;
46 import org.jetbrains.plugins.groovy.lang.completion.filters.toplevel.AnnotationFilter;
47 import org.jetbrains.plugins.groovy.lang.completion.filters.toplevel.ClassInterfaceEnumFilter;
48 import org.jetbrains.plugins.groovy.lang.completion.filters.toplevel.ImportFilter;
49 import org.jetbrains.plugins.groovy.lang.completion.filters.toplevel.PackageFilter;
50 import org.jetbrains.plugins.groovy.lang.completion.filters.types.BuiltInTypeAsArgumentFilter;
51 import org.jetbrains.plugins.groovy.lang.completion.filters.types.BuiltInTypeFilter;
52 import org.jetbrains.plugins.groovy.lang.completion.getters.SuggestedVariableNamesGetter;
53 import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
60 public class GroovyCompletionData extends CompletionData {
61 private final static Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionData");
62 public static final String[] BUILT_IN_TYPES = {"boolean", "byte", "char", "short", "int", "float", "long", "double", "void"};
63 public static final String[] MODIFIERS = new String[]{"private", "public", "protected", "transient", "abstract", "native", "volatile", "strictfp"};
65 public GroovyCompletionData() {
66 registerAllCompletions();
70 * Registers completions on top level of Groovy script file
72 private void registerAllCompletions() {
73 registerPackageCompletion();
74 registerImportCompletion();
76 registerClassInterfaceEnumAnnotationCompletion();
77 registerControlCompletion();
78 registerSimpleExprsCompletion();
79 registerBuiltInTypeCompletion();
80 registerBuiltInTypesAsArgumentCompletion();
81 registerInstanceofCompletion();
82 registerThrowsCompletion();
83 registerBranchCompletion();
84 registerModifierCompletion();
85 registerSynchronizedCompletion();
86 registerFinalCompletion();
88 registerSuggestVariableNameCompletion();
91 private void registerSuggestVariableNameCompletion() {
92 CompletionVariant variant = new CompletionVariant(new ParentElementFilter(new ClassFilter(GrVariable.class)));
93 variant.includeScopeClass(LeafPsiElement.class);
94 variant.addCompletion(new SuggestedVariableNamesGetter(), TailType.NONE);
95 registerVariant(variant);
99 private void registerPackageCompletion() {
100 registerStandardCompletion(new PackageFilter(), "package");
103 private void registerClassInterfaceEnumAnnotationCompletion() {
104 registerStandardCompletion(new ClassInterfaceEnumFilter(), "class", "interface", "enum");
105 registerStandardCompletion(new AnnotationFilter(), "interface");
106 registerStandardCompletion(new ExtendsFilter(), "extends");
107 registerStandardCompletion(new ImplementsFilter(), "implements");
110 private void registerControlCompletion() {
111 String[] controlKeywords = {"try", "while", "with", "switch", "for", "return", "throw", "assert", "synchronized",};
113 registerStandardCompletion(new ControlStructureFilter(), controlKeywords);
114 registerStandardCompletion(new CaseDefaultFilter(), "case", "default");
115 registerStandardCompletion(new CatchFinallyFilter(), "catch", "finally");
116 registerStandardCompletion(new ElseFilter(), "else");
121 private void registerBuiltInTypeCompletion() {
122 registerStandardCompletion(new AndFilter(new BuiltInTypeFilter(), new NotFilter(new ThrowsFilter())), BUILT_IN_TYPES);
125 private void registerBuiltInTypesAsArgumentCompletion() {
126 AndFilter filter = new AndFilter(new BuiltInTypeAsArgumentFilter(), new NotFilter(new ThrowsFilter()));
127 LeftNeighbour afterDotFilter = new LeftNeighbour(new TextFilter("."));
128 CompletionVariant variant = new CompletionVariant(new AndFilter(new NotFilter(afterDotFilter), filter));
129 variant.includeScopeClass(LeafPsiElement.class);
130 for (String completion : BUILT_IN_TYPES) {
131 variant.addCompletion(completion, TailType.SPACE);
133 registerVariant(variant);
136 private void registerSimpleExprsCompletion() {
137 String[] exprs = {"true", "false", "null", "super", "new", "this"};
138 registerStandardCompletion(new SimpleExpressionFilter(), exprs);
141 private void registerThrowsCompletion() {
142 registerStandardCompletion(new ThrowsFilter(), "throws");
145 private void registerFinalCompletion() {
146 registerStandardCompletion(new AndFilter(new FinalFilter(), new NotFilter(new ThrowsFilter())), "final");
149 private void registerSynchronizedCompletion() {
150 registerStandardCompletion(new SynchronizedFilter(), "synchronized");
153 private void registerImportCompletion() {
154 registerStandardCompletion(new ImportFilter(), "import");
157 private void registerInstanceofCompletion() {
158 registerStandardCompletion(new InstanceOfFilter(), "instanceof");
161 private void registerBranchCompletion() {
162 registerStandardCompletion(new BranchFilter(), "break", "continue");
165 private void registerModifierCompletion() {
166 registerStandardCompletion(new ModifiersFilter(), MODIFIERS);
167 registerStandardCompletion(new LeftNeighbour(new PreviousModifierFilter()), "private", "public", "protected", "transient", "abstract",
168 "native", "volatile", "strictfp", "synchronized", "static");
169 registerStandardCompletion(new StaticFilter(), "static");
174 public void completeReference(final PsiReference reference,
175 final Set<LookupElement> set,
176 @NotNull final PsiElement position,
179 super.completeReference(reference, set, position, file, offset);
180 Set<LookupElement> result = new THashSet<LookupElement>();
181 for (final LookupElement element : set) {
182 result.add(LookupElementDecorator.withInsertHandler(element, new GroovyInsertHandlerAdapter()));
190 * Template to add all standard keywords completions
192 * @param filter - Semantic filter for given keywords
193 * @param keywords - Keywords to be completed
195 private void registerStandardCompletion(ElementFilter filter, String... keywords) {
196 LeftNeighbour afterDotFilter = new LeftNeighbour(new TextFilter("."));
197 CompletionVariant variant = new CompletionVariant(new AndFilter(new NotFilter(afterDotFilter), filter));
198 variant.setItemProperty(LookupItem.HIGHLIGHTED_ATTR, "");
199 variant.includeScopeClass(LeafPsiElement.class);
200 variant.setInsertHandler(new GroovyInsertHandlerAdapter());
201 addCompletions(variant, keywords);
202 registerVariant(variant);
206 public String findPrefix(PsiElement insertedElement, int offset) {
207 if (insertedElement == null) return "";
208 final String text = insertedElement.getText();
209 final int offsetInElement = offset - insertedElement.getTextRange().getStartOffset();
210 int start = offsetInElement - 1;
212 final char c = text.charAt(start);
213 if (!Character.isJavaIdentifierPart(c) && c != '\'') break;
217 return text.substring(start + 1, offsetInElement).trim();
221 * Adds all completion variants in sequence
223 * @param comps Given completions
224 * @param variant Variant for completions
226 private void addCompletions(CompletionVariant variant, String... comps) {
227 for (String completion : comps) {
228 variant.addCompletion(completion, TailType.SPACE);