/*
* Copyright 2012-2015 Sergey Ignatov
*
* 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 org.intellij.erlang.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.patterns.PatternCondition;
import com.intellij.patterns.PsiElementPattern;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.ContainerUtil;
import org.intellij.erlang.ErlangFileType;
import org.intellij.erlang.ErlangTypes;
import org.intellij.erlang.psi.*;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import static com.intellij.patterns.PlatformPatterns.psiElement;
import static com.intellij.patterns.PlatformPatterns.virtualFile;
import static com.intellij.patterns.StandardPatterns.instanceOf;
public class ErlangAppCompletionContributor extends CompletionContributor {
// source: "FILE SYNTAX" section of http://www.erlang.org/doc/man/app.html
static final List<String> KEYWORDS =
ContainerUtil.immutableList("description", "id", "vsn", "modules", "maxP", "maxT", "registered", "applications",
"included_applications", "env", "mod", "start_phases", "runtime_dependencies");
private static final String APPLICATION_KEYWORD = "application";
@Override
public void beforeCompletion(@NotNull CompletionInitializationContext context) {
PsiFile file = context.getFile();
if (file.getFileType() != ErlangFileType.APP) return;
int startOffset = context.getStartOffset();
PsiElement elementAt = file.findElementAt(startOffset);
PsiElement parent = elementAt != null ? elementAt.getParent() : null;
if (parent instanceof ErlangTupleExpression) {
context.setDummyIdentifier(APPLICATION_KEYWORD);
}
}
public ErlangAppCompletionContributor() {
PsiElementPattern.Capture<PsiElement> psiElementInAppFile =
psiElement(ErlangTypes.ERL_ATOM_NAME).inFile(instanceOf(ErlangFile.class))
.inVirtualFile(virtualFile().ofType(ErlangFileType.APP));
//noinspection unchecked
PsiElementPattern.Capture<PsiElement> placeForAppKeyword = psiElementInAppFile
.withParents(ErlangAtom.class, ErlangQAtom.class, ErlangConfigExpression.class,
ErlangTupleExpression.class, ErlangFile.class).with(positionInTuple(0));
//noinspection unchecked
PsiElementPattern.Capture<PsiElement> placeForParameterKeywords = psiElementInAppFile
.withParents(ErlangAtom.class, ErlangQAtom.class, ErlangConfigExpression.class, ErlangTupleExpression.class,
ErlangListExpression.class, ErlangTupleExpression.class, ErlangFile.class).with(positionInTuple(0));
extend(CompletionType.BASIC, placeForAppKeyword, getProvider(ContainerUtil.list(APPLICATION_KEYWORD)));
extend(CompletionType.BASIC, placeForParameterKeywords, getProvider(KEYWORDS));
}
@NotNull
private static CompletionProvider<CompletionParameters> getProvider(@NotNull final List<String> keywords) {
return new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context,
@NotNull CompletionResultSet result) {
for (String keyword : keywords) {
result.addElement(PrioritizedLookupElement.withPriority(LookupElementBuilder.create(keyword),
ErlangCompletionContributor.KEYWORD_PRIORITY));
}
}
};
}
@NotNull
private static PatternCondition<PsiElement> positionInTuple(final int position) {
return new PatternCondition<PsiElement>("positionInTuple") {
@Override
public boolean accepts(@NotNull PsiElement element, ProcessingContext context) {
ErlangTupleExpression tuple = PsiTreeUtil.getParentOfType(element, ErlangTupleExpression.class);
ErlangExpression expression = PsiTreeUtil.getParentOfType(element, ErlangExpression.class);
List<ErlangExpression> expressions = tuple != null ? tuple.getExpressionList()
: ContainerUtil.<ErlangExpression>emptyList();
return expressions.size() > position && expressions.get(position) == expression;
}
};
}
}