blob: 6020f31da2e8f5f1f7dc089f3b4ca24c3cfcbd12 [file] [log] [blame]
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
*
* 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.google.idea.blaze.base.lang.projectview.completion;
import static com.intellij.patterns.PlatformPatterns.psiElement;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
import com.google.idea.blaze.base.projectview.section.ListSectionParser;
import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
import com.google.idea.blaze.base.projectview.section.SectionParser;
import com.google.idea.blaze.base.projectview.section.sections.Sections;
import com.intellij.codeInsight.completion.AutoCompletionContext;
import com.intellij.codeInsight.completion.AutoCompletionDecision;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionProvider;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.ProcessingContext;
import java.util.List;
import javax.annotation.Nullable;
/** Completes project view section names. */
public class ProjectViewKeywordCompletionContributor extends CompletionContributor {
@Override
public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
// auto-insert the obvious only case; else show other cases.
final LookupElement[] items = context.getItems();
if (items.length == 1) {
return AutoCompletionDecision.insertItem(items[0]);
}
return AutoCompletionDecision.SHOW_LOOKUP;
}
public ProjectViewKeywordCompletionContributor() {
extend(
CompletionType.BASIC,
psiElement()
.withLanguage(ProjectViewLanguage.INSTANCE)
.withElementType(ProjectViewTokenType.IDENTIFIERS)
.andOr(psiElement().afterLeaf("\n"), psiElement().afterLeaf(psiElement().isNull())),
new CompletionProvider<CompletionParameters>() {
@Override
protected void addCompletions(
CompletionParameters parameters,
ProcessingContext context,
CompletionResultSet result) {
result.addAllElements(keywordLookups);
}
});
}
private static final List<LookupElement> keywordLookups = getLookups();
private static List<LookupElement> getLookups() {
ImmutableList.Builder<LookupElement> list = ImmutableList.builder();
for (SectionParser parser : Sections.getUndeprecatedParsers()) {
if (handledSectionType(parser)) {
list.add(forSectionParser(parser));
}
}
return list.build();
}
@VisibleForTesting
public static boolean handledSectionType(SectionParser parser) {
return parser instanceof ListSectionParser || parser instanceof ScalarSectionParser;
}
private static LookupElement forSectionParser(SectionParser parser) {
return LookupElementBuilder.create(parser.getName()).withInsertHandler(insertDivider(parser));
}
private static InsertHandler<LookupElement> insertDivider(SectionParser parser) {
return (context, item) -> {
Editor editor = context.getEditor();
Document document = editor.getDocument();
context.commitDocument();
String nextTokenText = findNextTokenText(context);
if (nextTokenText == null || nextTokenText.equals("\n")) {
document.insertString(context.getTailOffset(), getDivider(parser));
editor.getCaretModel().moveToOffset(context.getTailOffset());
}
};
}
private static String getDivider(SectionParser parser) {
if (parser instanceof ListSectionParser) {
return ":\n ";
}
char div = ((ScalarSectionParser) parser).getDivider();
return div == ' ' ? String.valueOf(div) : (div + " ");
}
@Nullable
private static String findNextTokenText(final InsertionContext context) {
final PsiFile file = context.getFile();
PsiElement element = file.findElementAt(context.getTailOffset());
while (element != null && element.getTextLength() == 0) {
ASTNode next = element.getNode().getTreeNext();
element = next != null ? next.getPsi() : null;
}
return element != null ? element.getText() : null;
}
}