/*
* Copyright 2011-present Greg Shrago
*
* 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.grammar.livePreview;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory;
import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.containers.ContainerUtil;
import org.intellij.grammar.psi.BnfExpression;
import org.intellij.grammar.psi.BnfFile;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Set;
/**
* @author gregsh
*/
public class GrammarAtCaretPassFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory {
public static final Key<Boolean> GRAMMAR_AT_CARET_KEY = Key.create("GRAMMAR_AT_CARET_KEY");
public GrammarAtCaretPassFactory(Project project, TextEditorHighlightingPassRegistrar highlightingPassRegistrar) {
super(project);
highlightingPassRegistrar.registerTextEditorHighlightingPass(this, null, new int[]{Pass.UPDATE_ALL}, false, -1);
}
@Override
public TextEditorHighlightingPass createHighlightingPass(@NotNull final PsiFile file, @NotNull final Editor editor) {
if (ApplicationManager.getApplication().isHeadlessEnvironment()) return null;
if (editor.isOneLineMode()) return null;
if (!(file instanceof BnfFile)) return null;
final VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null || !FileEditorManager.getInstance(myProject).isFileOpen(virtualFile)) return null;
return new TextEditorHighlightingPass(file.getProject(), editor.getDocument(), false) {
List<HighlightInfo> infos = ContainerUtil.newArrayList();
@Override
public void doCollectInformation(@NotNull ProgressIndicator progress) {
infos.clear();
LivePreviewLanguage previewLanguage = LivePreviewLanguage.findInstance(file);
if (previewLanguage == null) return;
List<Editor> previewEditors = previewLanguage.getPreviewEditors(myProject);
for (Editor e : previewEditors) {
if (Boolean.TRUE.equals(GRAMMAR_AT_CARET_KEY.get(e))) {
collectHighlighters(myProject, previewEditors.get(0), previewLanguage, infos);
}
}
}
@Override
public void doApplyInformationToEditor() {
Document document = editor.getDocument();
UpdateHighlightersUtil.setHighlightersToEditor(myProject, document, 0, file.getTextLength(), infos, getColorsScheme(), getId());
}
};
}
private static void collectHighlighters(@NotNull final Project project,
@NotNull Editor editor,
@NotNull LivePreviewLanguage livePreviewLanguage,
@NotNull List<HighlightInfo> result) {
final Set<TextRange> trueRanges = ContainerUtil.newHashSet();
final Set<TextRange> falseRanges = ContainerUtil.newHashSet();
final Set<BnfExpression> visited = ContainerUtil.newHashSet();
LivePreviewHelper.collectExpressionsAtOffset(project, editor, livePreviewLanguage, (bnfExpression, result1) -> {
for (PsiElement parent = bnfExpression.getParent();
parent instanceof BnfExpression && visited.add((BnfExpression)parent); ) {
parent = parent.getParent();
}
if (visited.add(bnfExpression)) {
(result1 ? trueRanges : falseRanges).add(bnfExpression.getTextRange());
}
return true;
});
createHighlights(trueRanges, falseRanges, result);
}
private static void createHighlights(Set<TextRange> trueRanges,
Set<TextRange> falseRanges,
List<HighlightInfo> result) {
EditorColorsManager manager = EditorColorsManager.getInstance();
TextAttributes trueAttrs = manager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
TextAttributes falseAttrs = manager.getGlobalScheme().getAttributes(EditorColors.WRITE_SEARCH_RESULT_ATTRIBUTES);
for (TextRange range : trueRanges) {
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.INFORMATION)
.range(range)
.textAttributes(trueAttrs)
.createUnconditionally();
result.add(info);
}
for (TextRange range : falseRanges) {
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.INFORMATION)
.range(range)
.textAttributes(falseAttrs)
.createUnconditionally();
result.add(info);
}
}
}