From 31eb3745713e3650117baca2e6c0762a9a98fa0f Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Wed, 18 Jan 2012 23:53:58 +0300 Subject: [PATCH] generate highlighting markup --- plugins/devkit/resources/META-INF/plugin.xml | 5 + .../GenerateHighlightingMarkupAction.java | 145 ++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 plugins/devkit/src/actions/GenerateHighlightingMarkupAction.java diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index 8699948488a5..71d2881fedaf 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -112,6 +112,11 @@ + + + + diff --git a/plugins/devkit/src/actions/GenerateHighlightingMarkupAction.java b/plugins/devkit/src/actions/GenerateHighlightingMarkupAction.java new file mode 100644 index 000000000000..540e7ef751ad --- /dev/null +++ b/plugins/devkit/src/actions/GenerateHighlightingMarkupAction.java @@ -0,0 +1,145 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * 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.jetbrains.idea.devkit.actions; + +import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessorEx; +import com.intellij.openapi.command.UndoConfirmationPolicy; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.util.Processor; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.LinkedList; + +/** + * @author gregsh + */ +public class GenerateHighlightingMarkupAction extends AnAction { + @Override + public void update(AnActionEvent e) { + Editor editor = PlatformDataKeys.EDITOR.getData(e.getDataContext()); + PsiFile file = LangDataKeys.PSI_FILE.getData(e.getDataContext()); + e.getPresentation().setEnabled(editor != null && file != null); + } + + @Override + public void actionPerformed(AnActionEvent e) { + final Editor editor = PlatformDataKeys.EDITOR.getData(e.getDataContext()); + PsiFile file = LangDataKeys.PSI_FILE.getData(e.getDataContext()); + if (editor == null || file == null) return; + final Project project = file.getProject(); + CommandProcessorEx commandProcessorEx = (CommandProcessorEx)CommandProcessorEx.getInstance(); + Object commandToken = commandProcessorEx + .startCommand(project, e.getPresentation().getText(), e.getPresentation().getText(), UndoConfirmationPolicy.DEFAULT); + AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(getClass()); + try { + perform(project, editor.getDocument()); + } + finally { + token.finish(); + commandProcessorEx.finishCommand(project, commandToken, null); + } + } + + private static void perform(Project project, final Document document) { + final CharSequence sequence = document.getCharsSequence(); + final StringBuilder sb = new StringBuilder(); + final int[] offset = new int[] {0}; + final ArrayList infos = new ArrayList(); + DaemonCodeAnalyzerImpl.processHighlights( + document, project, HighlightSeverity.WARNING, 0, sequence.length(), + new Processor() { + @Override + public boolean process(HighlightInfo info) { + if (info.severity != HighlightSeverity.WARNING && info.severity != HighlightSeverity.ERROR) return true; + offset[0] = appendInfo(info, sb, sequence, offset[0], infos); + return true; + } + }); + offset[0] = appendInfo(null, sb, sequence, offset[0], infos); + sb.append(sequence.subSequence(offset[0], sequence.length())); + document.setText(sb); + } + + private static int appendInfo(@Nullable HighlightInfo info, StringBuilder sb, CharSequence sequence, int offset, ArrayList infos) { + if (info == null || !infos.isEmpty() && infos.get(infos.size() - 1).getEndOffset() < info.getStartOffset()) { + if (infos.size() == 1) { + HighlightInfo cur = infos.remove(0); + sb.append(sequence.subSequence(offset, cur.getStartOffset())); + sb.append(cur.severity == HighlightSeverity.WARNING ? "" : ""); + sb.append(sequence.subSequence(cur.getStartOffset(), cur.getEndOffset())); + sb.append(cur.severity == HighlightSeverity.WARNING ? "" : ""); + offset = cur.getEndOffset(); + } + else { + // process overlapped + LinkedList stack = new LinkedList(); + for (HighlightInfo cur : infos) { + offset = processStack(stack, sb, sequence, offset, cur.getStartOffset()); + sb.append(sequence.subSequence(offset, cur.getStartOffset())); + offset = cur.getStartOffset(); + sb.append(cur.severity == HighlightSeverity.WARNING ? "" : ""); + stack.addLast(cur); + } + offset = processStack(stack, sb, sequence, offset, sequence.length()); + infos.clear(); + } + } + if (info != null) { + boolean found = false; + for (HighlightInfo cur : infos) { + if (cur.getStartOffset() == info.getStartOffset() && cur.getEndOffset() == info.getEndOffset() && cur.severity == info.severity) { + found = true; + break; + } + } + if (!found) infos.add(info); + } + return offset; + } + + private static int processStack(LinkedList stack, + StringBuilder sb, + CharSequence sequence, + int offset, + final int endOffset) { + if (stack.isEmpty()) return offset; + for (HighlightInfo cur = stack.peekLast(); cur != null && cur.getEndOffset() <= endOffset; cur = stack.peekLast()) { + stack.removeLast(); + if (offset <= cur.getEndOffset()) { + sb.append(sequence.subSequence(offset, cur.getEndOffset())); + } + else { + //System.out.println("Incorrect overlapping infos: " + offset + " > " + cur.getEndOffset()); + } + offset = cur.getEndOffset(); + sb.append(cur.severity == HighlightSeverity.WARNING ? "" : ""); + } + return offset; + } +}