/* * Copyright 2015 The authors * 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.intellij.lang.ognl.completion; import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.completion.*; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.codeInsight.lookup.TailTypeDecorator; import com.intellij.lang.ognl.OgnlTypes; import com.intellij.lang.ognl.psi.*; import com.intellij.openapi.project.DumbAware; import com.intellij.patterns.PsiElementPattern; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.TokenSet; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; import static com.intellij.lang.ognl.psi.OgnlKeyword.*; import static com.intellij.patterns.PlatformPatterns.psiElement; /** * OGNL keyword completion. * * @author Yann Cébron */ public class OgnlKeywordCompletionContributor extends CompletionContributor implements DumbAware { private static final PsiElementPattern.Capture<PsiElement> FQN_TYPE_EXPRESSION = psiElement().inside(OgnlFqnTypeExpression.class); private static final PsiElementPattern.Capture<PsiElement> VARIABLE_EXPRESSION = psiElement().inside(OgnlVariableExpression.class); private static final PsiElementPattern.Capture<PsiElement> VARIABLE_ASSIGNMENT_EXPRESSION = psiElement().inside(OgnlVariableAssignmentExpression.class); private static final PsiElementPattern.Capture<PsiElement> AFTER_OPERATIONS = psiElement().afterLeaf(psiElement().withElementType(OgnlTokenGroups.OPERATIONS)); private static final PsiElementPattern.Capture<PsiElement> AFTER_NEW = psiElement().afterLeaf(psiElement().withElementType(OgnlTypes.NEW_KEYWORD)); private static final PsiElementPattern.Capture<PsiElement> AFTER_QUESTION = psiElement().afterLeaf(psiElement().withElementType(OgnlTypes.QUESTION)); private static final PsiElementPattern.Capture<PsiElement> AFTER_COLON = psiElement().afterLeaf(psiElement().withElementType(OgnlTypes.COLON)); private static final PsiElementPattern.Capture<PsiElement> AFTER_EXPRESSION = psiElement().afterLeaf(psiElement().inside(OgnlExpression.class)) .andNot(AFTER_OPERATIONS) .andNot(AFTER_QUESTION) .andNot(AFTER_COLON) .andNot(AFTER_NEW) .andNot(VARIABLE_EXPRESSION) .andNot(VARIABLE_ASSIGNMENT_EXPRESSION) .andNot(FQN_TYPE_EXPRESSION); private static final PsiElementPattern.Capture<PsiElement> AFTER_IDENTIFIER = psiElement().afterLeaf(psiElement().inside(OgnlReferenceExpression.class)); public OgnlKeywordCompletionContributor() { installBinaryOperations(); installSequence(); installIdentifier(); installBooleanNull(); installNew(); } private void installBinaryOperations() { extendKeywordCompletion(AFTER_EXPRESSION, SHL, SHR, USHR, AND, BAND, OR, BOR, XOR, EQ, NEQ, LT, LTE, GT, GTE); } private void installSequence() { extendKeywordCompletion(AFTER_EXPRESSION, NOT_IN, IN); } private void installIdentifier() { extendKeywordCompletion(AFTER_IDENTIFIER, INSTANCEOF); } private void installBooleanNull() { final TokenSet precedingOperators = TokenSet.create(OgnlTypes.EQUAL, OgnlTypes.EQ_KEYWORD, OgnlTypes.NOT_EQUAL, OgnlTypes.NEQ_KEYWORD, OgnlTypes.QUESTION, OgnlTypes.COLON, OgnlTypes.AND_KEYWORD, OgnlTypes.AND_AND, OgnlTypes.OR_KEYWORD, OgnlTypes.OR_OR, OgnlTypes.NEGATE, OgnlTypes.NOT_KEYWORD, OgnlTypes.EQ); extendKeywordCompletion(psiElement().afterLeaf(psiElement().inside(OgnlExpression.class) .withElementType(precedingOperators)), FALSE, TRUE, NULL); } // TODO simplify -> expression with no text private void installNew() { extendKeywordCompletion(psiElement().atStartOf(psiElement(OgnlExpression.class)) .andNot(AFTER_OPERATIONS) .andNot(AFTER_NEW), NEW); } private void extendKeywordCompletion(final PsiElementPattern.Capture<PsiElement> pattern, final String... keywords) { extend(CompletionType.BASIC, pattern, new CompletionProvider<CompletionParameters>() { @Override protected void addCompletions(@NotNull final CompletionParameters completionParameters, final ProcessingContext processingContext, @NotNull final CompletionResultSet completionResultSet) { for (final String keyword : keywords) { final LookupElementBuilder builder = LookupElementBuilder.create(keyword).bold(); completionResultSet.addElement(TailTypeDecorator.withTail(builder, TailType.SPACE)); } } }); } }