mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
mergeable line marker infos
This commit is contained in:
@@ -25,6 +25,7 @@ import com.intellij.codeInsight.daemon.impl.LineMarkersPass;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -34,7 +35,7 @@ public class MethodSeparatorProvider extends FileSeparatorProvider {
|
||||
final List<LineMarkerInfo> result = new ArrayList<LineMarkerInfo>();
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
LineMarkersPass action = new LineMarkersPass(file.getProject(), file, document, 0, file.getTextLength(), true);
|
||||
LineMarkersPass action = new LineMarkersPass(file.getProject(), file, PsiUtilBase.findEditor(file), document, 0, file.getTextLength(), true);
|
||||
Collection<LineMarkerInfo> lineMarkerInfos = action.queryLineMarkers();
|
||||
for (LineMarkerInfo lineMarkerInfo : lineMarkerInfos) {
|
||||
if (lineMarkerInfo.separatorColor != null) {
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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 com.intellij.codeInsight.daemon;
|
||||
|
||||
import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.FunctionUtil;
|
||||
import com.intellij.util.NotNullFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public abstract class MergeableLineMarkerInfo<T extends PsiElement> extends LineMarkerInfo<T> {
|
||||
|
||||
public MergeableLineMarkerInfo(@NotNull T element,
|
||||
TextRange textRange,
|
||||
Icon icon,
|
||||
int updatePass,
|
||||
@Nullable Function<? super T, String> tooltipProvider,
|
||||
@Nullable GutterIconNavigationHandler<T> navHandler,
|
||||
GutterIconRenderer.Alignment alignment) {
|
||||
super(element, textRange, icon, updatePass, tooltipProvider, navHandler, alignment);
|
||||
}
|
||||
|
||||
public abstract boolean canMergeWith(MergeableLineMarkerInfo<?> info);
|
||||
|
||||
public abstract Icon getCommonIcon(List<MergeableLineMarkerInfo> infos);
|
||||
|
||||
public static List<LineMarkerInfo> merge(List<MergeableLineMarkerInfo> markers) {
|
||||
final List<LineMarkerInfo> result = new ArrayList<LineMarkerInfo>();
|
||||
final HashSet<LineMarkerInfo> processed = new HashSet<LineMarkerInfo>();
|
||||
for (MergeableLineMarkerInfo marker : markers) {
|
||||
if (processed.contains(marker)) continue;
|
||||
processed.add(marker);
|
||||
final List<MergeableLineMarkerInfo> toMerge = new ArrayList<MergeableLineMarkerInfo>();
|
||||
for (MergeableLineMarkerInfo current : markers) {
|
||||
if (!processed.contains(current) && marker.canMergeWith(current)) {
|
||||
toMerge.add(current);
|
||||
processed.add(current);
|
||||
}
|
||||
}
|
||||
if (toMerge.isEmpty()) {
|
||||
result.add(marker);
|
||||
} else {
|
||||
toMerge.add(marker);
|
||||
result.add(new MyLineMarkerInfo(toMerge));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class MyLineMarkerInfo extends LineMarkerInfo {
|
||||
public MyLineMarkerInfo(List<MergeableLineMarkerInfo> markers) {
|
||||
//noinspection unchecked,ConstantConditions
|
||||
super(markers.get(0).getElement(),
|
||||
getCommonTextRange(markers),
|
||||
markers.get(0).getCommonIcon(markers),
|
||||
4, //TODO move Pass to lang-api and make it enum
|
||||
FunctionUtil.<Object, String>nullConstant(),
|
||||
getCommonNavigationHandler(markers),
|
||||
GutterIconRenderer.Alignment.RIGHT);
|
||||
}
|
||||
|
||||
private static TextRange getCommonTextRange(List<MergeableLineMarkerInfo> markers) {
|
||||
int startOffset = Integer.MAX_VALUE;
|
||||
int endOffset = Integer.MIN_VALUE;
|
||||
for (MergeableLineMarkerInfo marker : markers) {
|
||||
startOffset = Math.min(startOffset, marker.startOffset);
|
||||
endOffset = Math.max(endOffset, marker.endOffset);
|
||||
}
|
||||
return TextRange.create(startOffset, endOffset);
|
||||
}
|
||||
|
||||
private static GutterIconNavigationHandler getCommonNavigationHandler(final List<MergeableLineMarkerInfo> markers) {
|
||||
return new GutterIconNavigationHandler() {
|
||||
@Override
|
||||
public void navigate(final MouseEvent e, PsiElement elt) {
|
||||
final List<LineMarkerInfo> infos = new ArrayList<LineMarkerInfo>(markers);
|
||||
Collections.sort(infos, new Comparator<LineMarkerInfo>() {
|
||||
@Override
|
||||
public int compare(LineMarkerInfo o1, LineMarkerInfo o2) {
|
||||
return o1.startOffset - o2.startOffset;
|
||||
}
|
||||
});
|
||||
final JBList list = new JBList(infos);
|
||||
list.setFixedCellHeight(20);
|
||||
list.installCellRenderer(new NotNullFunction<Object, JComponent>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public JComponent fun(Object dom) {
|
||||
if (dom instanceof LineMarkerInfo) {
|
||||
Icon icon = null;
|
||||
final GutterIconRenderer renderer = ((LineMarkerInfo)dom).createGutterRenderer();
|
||||
if (renderer != null) {
|
||||
icon = renderer.getIcon();
|
||||
}
|
||||
final PsiElement element = ((LineMarkerInfo)dom).getElement();
|
||||
assert element != null;
|
||||
final String text = StringUtil.first(element.getText(), 100, true).replace('\n', ' ');
|
||||
|
||||
return new JBLabel(text, icon, SwingConstants.LEFT);
|
||||
}
|
||||
|
||||
return new JBLabel();
|
||||
}
|
||||
});
|
||||
JBPopupFactory.getInstance().createListPopupBuilder(list)
|
||||
.setItemChoosenCallback(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final Object value = list.getSelectedValue();
|
||||
if (value instanceof LineMarkerInfo) {
|
||||
final GutterIconNavigationHandler handler = ((LineMarkerInfo)value).getNavigationHandler();
|
||||
if (handler != null) {
|
||||
//noinspection unchecked
|
||||
handler.navigate(e, ((LineMarkerInfo)value).getElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
}).createPopup().show(new RelativePoint(e));
|
||||
}
|
||||
};
|
||||
}
|
||||
//private static int getCommonStartOffset(List<MergeableLineMarkerInfo> markers) {
|
||||
// int startOffset = Integer.MAX_VALUE;
|
||||
// for (MergeableLineMarkerInfo marker : markers) {
|
||||
// startOffset = Math.min(startOffset, marker.startOffset);
|
||||
// }
|
||||
// return startOffset;
|
||||
//}
|
||||
//
|
||||
private static PsiElement getCommonElement(List<MergeableLineMarkerInfo> markers) {
|
||||
final List<PsiElement> elements = new ArrayList<PsiElement>();
|
||||
for (MergeableLineMarkerInfo marker : markers) {
|
||||
elements.add(marker.getElement());
|
||||
}
|
||||
final AccessToken token = ApplicationManager.getApplication().acquireReadActionLock();
|
||||
try {
|
||||
final PsiElement parent = PsiTreeUtil.findCommonParent(elements);
|
||||
return parent == null ? elements.get(0) : parent;
|
||||
}
|
||||
finally {
|
||||
token.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import com.intellij.codeHighlighting.Pass;
|
||||
import com.intellij.codeInsight.daemon.LineMarkerInfo;
|
||||
import com.intellij.codeInsight.daemon.LineMarkerProvider;
|
||||
import com.intellij.codeInsight.daemon.LineMarkerProviders;
|
||||
import com.intellij.codeInsight.daemon.MergeableLineMarkerInfo;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightLevelUtil;
|
||||
import com.intellij.injected.editor.DocumentWindow;
|
||||
import com.intellij.lang.Language;
|
||||
@@ -30,6 +31,8 @@ import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
@@ -49,6 +52,7 @@ import com.intellij.util.Function;
|
||||
import com.intellij.util.FunctionUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
@@ -58,17 +62,20 @@ public class LineMarkersPass extends ProgressableTextEditorHighlightingPass impl
|
||||
|
||||
private volatile Collection<LineMarkerInfo> myMarkers = Collections.emptyList();
|
||||
|
||||
@Nullable private final Editor myEditor;
|
||||
private final int myStartOffset;
|
||||
private final int myEndOffset;
|
||||
private final boolean myUpdateAll;
|
||||
|
||||
public LineMarkersPass(@NotNull Project project,
|
||||
@NotNull PsiFile file,
|
||||
@Nullable Editor editor,
|
||||
@NotNull Document document,
|
||||
int startOffset,
|
||||
int endOffset,
|
||||
boolean updateAll) {
|
||||
super(project, document, GeneralHighlightingPass.PRESENTABLE_NAME, file, false);
|
||||
myEditor = editor;
|
||||
myStartOffset = startOffset;
|
||||
myEndOffset = endOffset;
|
||||
myUpdateAll = updateAll;
|
||||
@@ -92,7 +99,17 @@ public class LineMarkersPass extends ProgressableTextEditorHighlightingPass impl
|
||||
PsiElement psiRoot = viewProvider.getPsi(language);
|
||||
if (!HighlightLevelUtil.shouldHighlight(psiRoot)) continue;
|
||||
//long time = System.currentTimeMillis();
|
||||
List<PsiElement> elements = CollectHighlightsUtil.getElementsInRange(psiRoot, myStartOffset, myEndOffset);
|
||||
int start = myStartOffset;
|
||||
int end = myEndOffset;
|
||||
//if (myEditor != null) {
|
||||
// final int startLine = myEditor.offsetToLogicalPosition(start).line;
|
||||
// final int endLine = myEditor.offsetToLogicalPosition(end).line;
|
||||
// if (startLine != endLine) {
|
||||
// start = myEditor.logicalPositionToOffset(myEditor.visualToLogicalPosition(new VisualPosition(startLine, 0)));
|
||||
// end = myEditor.logicalPositionToOffset(myEditor.visualToLogicalPosition(new VisualPosition(endLine + 1, 0))) - 1;
|
||||
// }
|
||||
//}
|
||||
List<PsiElement> elements = CollectHighlightsUtil.getElementsInRange(psiRoot, start, end);
|
||||
if (elements.isEmpty()) {
|
||||
elements = Collections.singletonList(psiRoot);
|
||||
}
|
||||
@@ -101,7 +118,40 @@ public class LineMarkersPass extends ProgressableTextEditorHighlightingPass impl
|
||||
collectLineMarkersForInjected(lineMarkers, elements, this, myFile, progress);
|
||||
}
|
||||
|
||||
myMarkers = lineMarkers;
|
||||
myMarkers = mergeLineMarkers(lineMarkers);
|
||||
}
|
||||
|
||||
private List<LineMarkerInfo> mergeLineMarkers(List<LineMarkerInfo> markers) {
|
||||
List<MergeableLineMarkerInfo> forMerge = new ArrayList<MergeableLineMarkerInfo>();
|
||||
final Iterator<LineMarkerInfo> iterator = markers.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final LineMarkerInfo marker = iterator.next();
|
||||
|
||||
if (marker instanceof MergeableLineMarkerInfo) {
|
||||
iterator.remove();
|
||||
forMerge.add((MergeableLineMarkerInfo)marker);
|
||||
}
|
||||
}
|
||||
|
||||
if (forMerge.isEmpty() || myEditor == null) return markers;
|
||||
|
||||
final List<LineMarkerInfo> result = new ArrayList<LineMarkerInfo>(markers);
|
||||
final HashMap<Integer, List<MergeableLineMarkerInfo>> map = new HashMap<Integer, List<MergeableLineMarkerInfo>>();
|
||||
for (MergeableLineMarkerInfo info : forMerge) {
|
||||
final LogicalPosition position = myEditor.offsetToLogicalPosition(info.startOffset);
|
||||
List<MergeableLineMarkerInfo> infos = map.get(position.line);
|
||||
if (infos == null) {
|
||||
infos = new ArrayList<MergeableLineMarkerInfo>();
|
||||
map.put(position.line, infos);
|
||||
}
|
||||
infos.add(info);
|
||||
}
|
||||
|
||||
for (List<MergeableLineMarkerInfo> infos : map.values()) {
|
||||
result.addAll(MergeableLineMarkerInfo.merge(infos));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<LineMarkerProvider> getMarkerProviders(Language language, Project project) {
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class LineMarkersPassFactory extends AbstractProjectComponent implements
|
||||
public TextEditorHighlightingPass createHighlightingPass(@NotNull PsiFile file, @NotNull final Editor editor) {
|
||||
TextRange textRange = calculateRangeToProcessForSyntaxPass(editor);
|
||||
if (textRange == null) return new ProgressableTextEditorHighlightingPass.EmptyPass(myProject, editor.getDocument());
|
||||
return new LineMarkersPass(myProject, file, editor.getDocument(), textRange.getStartOffset(), textRange.getEndOffset(), true);
|
||||
return new LineMarkersPass(myProject, file, editor, editor.getDocument(), textRange.getStartOffset(), textRange.getEndOffset(), true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+1
-1
@@ -50,6 +50,6 @@ public class VisibleLineMarkersPassFactory extends VisibleHighlightingPassFactor
|
||||
TextRange textRange = calculateRangeToProcess(editor);
|
||||
if (textRange == null) return null;
|
||||
|
||||
return new LineMarkersPass(file.getProject(), file, editor.getDocument(), textRange.getStartOffset(), textRange.getEndOffset(), false);
|
||||
return new LineMarkersPass(file.getProject(), file, editor, editor.getDocument(), textRange.getStartOffset(), textRange.getEndOffset(), false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user