mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-204702 Support after-line-end inlays in editor
temporary revert changes - they are causing tests failures
This commit is contained in:
@@ -32,7 +32,7 @@ public interface Inlay<T extends EditorCustomElementRenderer> extends Disposable
|
||||
* Defines relative position of inlay element with respect to the containing text.
|
||||
*/
|
||||
@NotNull
|
||||
Placement getPlacement();
|
||||
VerticalAlignment getVerticalAlignment();
|
||||
|
||||
/**
|
||||
* Tells whether this element is valid. Inlay becomes invalid on explicit disposal,
|
||||
@@ -103,7 +103,7 @@ public interface Inlay<T extends EditorCustomElementRenderer> extends Disposable
|
||||
void repaint();
|
||||
|
||||
/**
|
||||
* @see #getPlacement()
|
||||
* @see #getVerticalAlignment()
|
||||
*/
|
||||
enum Placement { INLINE, ABOVE_LINE, BELOW_LINE, AFTER_LINE_END }
|
||||
enum VerticalAlignment { INLINE, ABOVE_LINE, BELOW_LINE }
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides an ability to introduce custom visual elements into editor's representation.
|
||||
* Such elements are not reflected in document contents. Elements are 'anchored' to a certain document offset at creation,
|
||||
* this offset behaves similar to a zero-range {@link RangeMarker} with respect to document changes.
|
||||
* Such elements are not reflected in document contents.
|
||||
* <p>
|
||||
* WARNING! This is an experimental API, it can change at any time.
|
||||
* @see Editor#getInlayModel()
|
||||
@@ -30,24 +29,21 @@ public interface InlayModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Introduces an inline visual element at a given offset, its width and appearance is defined by the provided renderer.
|
||||
*
|
||||
* Introduces an inline visual element at a given offset, its width and appearance is defined by the provided renderer. With respect to
|
||||
* document changes, created element behaves in a similar way to a zero-range {@link RangeMarker}. This method returns {@code null}
|
||||
* if requested element cannot be created, e.g. if corresponding functionality is not supported by current editor instance.
|
||||
*
|
||||
* @param relatesToPrecedingText whether element is associated with preceding or following text
|
||||
* (see {@link Inlay#isRelatedToPrecedingText()})
|
||||
* @return {@code null} if requested element cannot be created, e.g. if corresponding functionality
|
||||
* is not supported by current editor instance.
|
||||
*/
|
||||
@Nullable
|
||||
<T extends EditorCustomElementRenderer> Inlay<T> addInlineElement(int offset, boolean relatesToPrecedingText, @NotNull T renderer);
|
||||
|
||||
/**
|
||||
* Introduces a 'block' visual element at a given offset, its size and appearance is defined by the provided renderer. This element
|
||||
* will be displayed between lines of text.
|
||||
*
|
||||
* @param relatesToPrecedingText whether element is associated with preceding or following text
|
||||
* (see {@link Inlay#isRelatedToPrecedingText()})
|
||||
* @return {@code null} if requested element cannot be created, e.g. if corresponding functionality
|
||||
* is not supported by current editor instance.
|
||||
* will be displayed between lines of text. With respect to document changes, created element behaves in a similar way to a zero-range
|
||||
* {@link RangeMarker}. This method returns {@code null} if requested element cannot be created, e.g. if corresponding functionality
|
||||
* is not supported by current editor instance.
|
||||
*/
|
||||
@Nullable
|
||||
<T extends EditorCustomElementRenderer> Inlay<T> addBlockElement(int offset,
|
||||
@@ -56,18 +52,6 @@ public interface InlayModel {
|
||||
int priority,
|
||||
@NotNull T renderer);
|
||||
|
||||
|
||||
/**
|
||||
* Introduces a visual element, which will be displayed after the end of corresponding logical line.
|
||||
*
|
||||
* @param relatesToPrecedingText whether element is associated with preceding or following text
|
||||
* (see {@link Inlay#isRelatedToPrecedingText()})
|
||||
* @return {@code null} if requested element cannot be created, e.g. if corresponding functionality
|
||||
* is not supported by current editor instance.
|
||||
*/
|
||||
@Nullable
|
||||
<T extends EditorCustomElementRenderer> Inlay<T> addAfterLineEndElement(int offset, boolean relatesToPrecedingText, @NotNull T renderer);
|
||||
|
||||
/**
|
||||
* Returns a list of inline elements for a given offset range (both limits are inclusive). Returned list is sorted by offset.
|
||||
* Both visible and invisible (due to folding) elements are returned.
|
||||
@@ -152,34 +136,6 @@ public interface InlayModel {
|
||||
@Nullable
|
||||
Inlay getElementAt(@NotNull Point point);
|
||||
|
||||
/**
|
||||
* Returns a list of after-line-end elements for a given offset range (both limits are inclusive).
|
||||
* Returned list is sorted by offset. Both visible and invisible (due to folding) elements are returned.
|
||||
*
|
||||
* @see #addAfterLineEndElement(int, boolean, EditorCustomElementRenderer)
|
||||
*/
|
||||
@NotNull
|
||||
List<Inlay> getAfterLineEndElementsInRange(int startOffset, int endOffset);
|
||||
|
||||
/**
|
||||
* Same as {@link #getAfterLineEndElementsInRange(int, int)}, but returned list contains only inlays with renderer of given type.
|
||||
*/
|
||||
@NotNull
|
||||
default <T> List<Inlay<? extends T>> getAfterLineEndElementsInRange(int startOffset, int endOffset, Class<T> type) {
|
||||
//noinspection unchecked
|
||||
return (List)ContainerUtil.filter(getAfterLineEndElementsInRange(startOffset, endOffset),
|
||||
inlay -> type.isInstance(inlay.getRenderer()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns after-line-end elements for a given logical line, in creation order (this is the order they are displayed in).
|
||||
* Elements are returned regardless of whether they are currently visible.
|
||||
*
|
||||
* @see #addAfterLineEndElement(int, boolean, EditorCustomElementRenderer)
|
||||
*/
|
||||
@NotNull
|
||||
List<Inlay> getAfterLineEndElementsForLogicalLine(int logicalLine);
|
||||
|
||||
/**
|
||||
* When text is inserted at inline element's offset, resulting element's position is determined by its
|
||||
* {@link Inlay#isRelatedToPrecedingText()} property. But to enable natural editing experience around inline elements (so that typed text
|
||||
|
||||
-23
@@ -37,15 +37,6 @@ class InlayModelWindow implements InlayModel {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends EditorCustomElementRenderer> Inlay<T> addAfterLineEndElement(int offset,
|
||||
boolean relatesToPrecedingText,
|
||||
@NotNull T renderer) {
|
||||
logUnsupported();
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Inlay> getInlineElementsInRange(int startOffset, int endOffset) {
|
||||
@@ -87,20 +78,6 @@ class InlayModelWindow implements InlayModel {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Inlay> getAfterLineEndElementsInRange(int startOffset, int endOffset) {
|
||||
logUnsupported();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Inlay> getAfterLineEndElementsForLogicalLine(int logicalLine) {
|
||||
logUnsupported();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConsiderCaretPositionOnDocumentUpdates(boolean enabled) {
|
||||
logUnsupported();
|
||||
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.editor.impl;
|
||||
|
||||
import com.intellij.openapi.editor.EditorCustomElementRenderer;
|
||||
import com.intellij.openapi.editor.Inlay;
|
||||
import com.intellij.openapi.editor.VisualPosition;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
class AfterLineEndInlayImpl<R extends EditorCustomElementRenderer> extends InlayImpl<R, AfterLineEndInlayImpl> {
|
||||
private static int ourGlobalCounter = 0;
|
||||
final int myOrder;
|
||||
|
||||
AfterLineEndInlayImpl(@NotNull EditorImpl editor, int offset, boolean relatesToPrecedingText, @NotNull R renderer) {
|
||||
super(editor, offset, relatesToPrecedingText, renderer);
|
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
myOrder = ourGlobalCounter++;
|
||||
}
|
||||
|
||||
@Override
|
||||
RangeMarkerTree<AfterLineEndInlayImpl> getTree() {
|
||||
return myEditor.getInlayModel().myAfterLineEndElementsTree;
|
||||
}
|
||||
|
||||
@Override
|
||||
void doUpdateSize() {
|
||||
myWidthInPixels = myRenderer.calcWidthInPixels(this);
|
||||
if (myWidthInPixels <= 0) {
|
||||
throw new IllegalArgumentException("Positive width should be defined for an after-line-end element");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Point getPosition() {
|
||||
VisualPosition pos = getVisualPosition();
|
||||
return myEditor.visualPositionToXY(pos);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Rectangle getBounds() {
|
||||
int targetOffset = DocumentUtil.getLineEndOffset(getOffset(), myEditor.getDocument());
|
||||
if (myEditor.getFoldingModel().isOffsetCollapsed(targetOffset)) return null;
|
||||
Point pos = getPosition();
|
||||
return new Rectangle(pos.x, pos.y, getWidthInPixels(), getHeightInPixels());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Placement getPlacement() {
|
||||
return Placement.AFTER_LINE_END;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public VisualPosition getVisualPosition() {
|
||||
int offset = getOffset();
|
||||
int logicalLine = myEditor.getDocument().getLineNumber(offset);
|
||||
int lineEndOffset = myEditor.getDocument().getLineEndOffset(logicalLine);
|
||||
VisualPosition position = myEditor.offsetToVisualPosition(lineEndOffset, true, true);
|
||||
if (myEditor.getFoldingModel().isOffsetCollapsed(lineEndOffset)) return position;
|
||||
List<Inlay> inlays = myEditor.getInlayModel().getAfterLineEndElementsForLogicalLine(logicalLine);
|
||||
int order = inlays.indexOf(this);
|
||||
return new VisualPosition(position.line, position.column + 1 + order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeightInPixels() {
|
||||
return myEditor.getLineHeight();
|
||||
}
|
||||
}
|
||||
@@ -75,8 +75,8 @@ class BlockInlayImpl<R extends EditorCustomElementRenderer> extends InlayImpl<R,
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Placement getPlacement() {
|
||||
return myShowAbove ? Placement.ABOVE_LINE : Placement.BELOW_LINE;
|
||||
public VerticalAlignment getVerticalAlignment() {
|
||||
return myShowAbove ? VerticalAlignment.ABOVE_LINE : VerticalAlignment.BELOW_LINE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -47,7 +47,6 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
|
||||
private volatile CaretImpl myPrimaryCaret;
|
||||
private CaretImpl myCurrentCaret; // active caret in the context of 'runForEachCaret' call
|
||||
private boolean myPerformCaretMergingAfterCurrentOperation;
|
||||
private boolean myVisualPositionUpdateScheduled;
|
||||
|
||||
int myDocumentUpdateCounter;
|
||||
|
||||
@@ -80,7 +79,6 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
|
||||
myDocumentUpdateCounter++;
|
||||
if (!myEditor.getDocument().isInBulkUpdate()) {
|
||||
doWithCaretMerging(() -> {}); // do caret merging if it's not scheduled for later
|
||||
if (myVisualPositionUpdateScheduled) updateVisualPosition();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +90,6 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
|
||||
}
|
||||
}
|
||||
myIsInUpdate = true;
|
||||
myVisualPositionUpdateScheduled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -594,34 +591,28 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
|
||||
@Override
|
||||
public void onAdded(@NotNull Inlay inlay) {
|
||||
if (myEditor.getDocument().isInBulkUpdate()) return;
|
||||
Inlay.Placement placement = inlay.getPlacement();
|
||||
if (placement == Inlay.Placement.INLINE) {
|
||||
if (inlay.getVerticalAlignment() == Inlay.VerticalAlignment.INLINE) {
|
||||
int offset = inlay.getOffset();
|
||||
for (CaretImpl caret : myCarets) {
|
||||
caret.onInlayAdded(offset);
|
||||
}
|
||||
}
|
||||
else if (placement != Inlay.Placement.AFTER_LINE_END || hasCaretInVirtualSpace()) {
|
||||
else {
|
||||
updateVisualPosition();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(@NotNull Inlay inlay) {
|
||||
if (myEditor.getDocument().isInBulkUpdate()) return;
|
||||
Inlay.Placement placement = inlay.getPlacement();
|
||||
if (myEditor.getDocument().isInEventsHandling()) {
|
||||
if (placement == Inlay.Placement.AFTER_LINE_END) myVisualPositionUpdateScheduled = true;
|
||||
return;
|
||||
}
|
||||
if (placement == Inlay.Placement.INLINE) {
|
||||
if (myEditor.getDocument().isInEventsHandling() || myEditor.getDocument().isInBulkUpdate()) return;
|
||||
if (inlay.getVerticalAlignment() == Inlay.VerticalAlignment.INLINE) {
|
||||
doWithCaretMerging(() -> {
|
||||
for (CaretImpl caret : myCarets) {
|
||||
caret.onInlayRemoved(inlay.getOffset(), ((InlineInlayImpl)inlay).getOrder());
|
||||
caret.onInlayRemoved(inlay.getOffset(), ((InlayImpl)inlay).getOrder());
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (placement != Inlay.Placement.AFTER_LINE_END || hasCaretInVirtualSpace()) {
|
||||
else {
|
||||
updateVisualPosition();
|
||||
}
|
||||
}
|
||||
@@ -629,13 +620,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
|
||||
@Override
|
||||
public void onUpdated(@NotNull Inlay inlay) {
|
||||
if (myEditor.getDocument().isInBulkUpdate()) return;
|
||||
if (inlay.getPlacement() != Inlay.Placement.AFTER_LINE_END || hasCaretInVirtualSpace()) {
|
||||
updateVisualPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasCaretInVirtualSpace() {
|
||||
return myEditor.getSettings().isVirtualSpace() && ContainerUtil.exists(myCarets, CaretImpl::isInVirtualSpace);
|
||||
updateVisualPosition();
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.intellij.diagnostic.Dumpable;
|
||||
import com.intellij.ide.*;
|
||||
import com.intellij.ide.dnd.DnDManager;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.internal.performance.LatenciometerKt;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
|
||||
@@ -627,14 +628,9 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
if (myDocument.isInEventsHandling() || myDocument.isInBulkUpdate()) return;
|
||||
validateSize();
|
||||
int offset = inlay.getOffset();
|
||||
Inlay.Placement placement = inlay.getPlacement();
|
||||
if (placement == Inlay.Placement.INLINE) {
|
||||
if (inlay.getVerticalAlignment() == Inlay.VerticalAlignment.INLINE) {
|
||||
repaint(offset, offset, false);
|
||||
}
|
||||
else if (placement == Inlay.Placement.AFTER_LINE_END) {
|
||||
int lineEndOffset = DocumentUtil.getLineEndOffset(offset, myDocument);
|
||||
repaint(lineEndOffset, lineEndOffset, false);
|
||||
}
|
||||
else {
|
||||
int visualLine = offsetToVisualLine(offset);
|
||||
int y = visualLineToY(visualLine) - EditorUtil.getTotalInlaysHeight(myInlayModel.getBlockElementsForVisualLine(visualLine, true));
|
||||
@@ -2073,7 +2069,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
|
||||
+ ", caret model: " + getCaretModel().dumpState()
|
||||
+ ", soft wraps data: " + getSoftWrapModel().dumpState()
|
||||
+ "\n\nfolding data: " + getFoldingModel().dumpState()
|
||||
+ "\ninlay model: " + getInlayModel().dumpState()
|
||||
+ (myDocument instanceof DocumentImpl ? "\n\ndocument info: " + ((DocumentImpl)myDocument).dumpState() : "")
|
||||
+ "\nfont preferences: " + myScheme.getFontPreferences()
|
||||
+ "\npure painting mode: " + myPurePaintingMode
|
||||
|
||||
@@ -101,6 +101,24 @@ public class FoldingModelImpl extends InlayModel.SimpleAdapter
|
||||
return region instanceof FoldRegionImpl && ((FoldRegionImpl)region).hasDocumentRegionChanged();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
FoldRegion getFirstRegion(@NotNull FoldingGroup group, @NotNull FoldRegion child) {
|
||||
final List<FoldRegion> regions = getGroupedRegions(group);
|
||||
if (regions.isEmpty()) {
|
||||
final boolean inAll = Arrays.asList(getAllFoldRegions()).contains(child);
|
||||
throw new AssertionError("Folding group without children; the known child is in all: " + inAll);
|
||||
}
|
||||
|
||||
FoldRegion main = regions.get(0);
|
||||
for (int i = 1; i < regions.size(); i++) {
|
||||
FoldRegion region = regions.get(i);
|
||||
if (main.getStartOffset() > region.getStartOffset()) {
|
||||
main = region;
|
||||
}
|
||||
}
|
||||
return main;
|
||||
}
|
||||
|
||||
public int getEndOffset(@NotNull FoldingGroup group) {
|
||||
final List<FoldRegion> regions = getGroupedRegions(group);
|
||||
int endOffset = 0;
|
||||
@@ -548,8 +566,7 @@ public class FoldingModelImpl extends InlayModel.SimpleAdapter
|
||||
|
||||
@Override
|
||||
public void onUpdated(@NotNull Inlay inlay) {
|
||||
Inlay.Placement placement = inlay.getPlacement();
|
||||
if (placement == Inlay.Placement.ABOVE_LINE || placement == Inlay.Placement.BELOW_LINE) myFoldTree.clearCachedInlayValues();
|
||||
if (inlay.getVerticalAlignment() != Inlay.VerticalAlignment.INLINE) myFoldTree.clearCachedInlayValues();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -10,9 +10,11 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
abstract class InlayImpl<R extends EditorCustomElementRenderer, T extends InlayImpl> extends RangeMarkerWithGetterImpl implements Inlay<R> {
|
||||
static final Key<Integer> OFFSET_BEFORE_DISPOSAL = Key.create("inlay.offset.before.disposal");
|
||||
private static final Key<Integer> ORDER_BEFORE_DISPOSAL = Key.create("inlay.order.before.disposal");
|
||||
|
||||
@NotNull
|
||||
final EditorImpl myEditor;
|
||||
@@ -76,10 +78,13 @@ abstract class InlayImpl<R extends EditorCustomElementRenderer, T extends InlayI
|
||||
public void dispose() {
|
||||
if (isValid()) {
|
||||
int offset = getOffset(); // We want listeners notified after disposal, but want inlay offset to be available at that time
|
||||
InlayModelImpl inlayModel = myEditor.getInlayModel();
|
||||
List<Inlay> inlays = inlayModel.getInlineElementsInRange(offset, offset);
|
||||
putUserData(ORDER_BEFORE_DISPOSAL, inlays.indexOf(this));
|
||||
putUserData(OFFSET_BEFORE_DISPOSAL, offset);
|
||||
//noinspection unchecked
|
||||
getTree().removeInterval((T)this);
|
||||
myEditor.getInlayModel().notifyRemoved(this);
|
||||
inlayModel.notifyRemoved(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,4 +119,9 @@ abstract class InlayImpl<R extends EditorCustomElementRenderer, T extends InlayI
|
||||
public int getWidthInPixels() {
|
||||
return myWidthInPixels;
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
Integer value = getUserData(ORDER_BEFORE_DISPOSAL);
|
||||
return value == null ? -1 : value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.editor.impl;
|
||||
|
||||
import com.intellij.diagnostic.Dumpable;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.editor.ex.PrioritizedInternalDocumentListener;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
@@ -20,20 +18,21 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class InlayModelImpl implements InlayModel, Disposable, Dumpable {
|
||||
public class InlayModelImpl implements InlayModel, Disposable {
|
||||
private static final Logger LOG = Logger.getInstance(InlayModelImpl.class);
|
||||
private static final Comparator<Inlay> INLINE_ELEMENTS_COMPARATOR = Comparator.comparingInt((Inlay i) -> i.getOffset())
|
||||
private static final Comparator<Inlay> INLINE_ELEMENTS_COMPARATOR = Comparator.comparingInt((Inlay inlay) -> inlay.getOffset())
|
||||
.thenComparing(i -> i.isRelatedToPrecedingText());
|
||||
private static final Comparator<BlockInlayImpl> BLOCK_ELEMENTS_PRIORITY_COMPARATOR = Comparator.comparingInt(i -> -i.myPriority);
|
||||
private static final Comparator<BlockInlayImpl> BLOCK_ELEMENTS_COMPARATOR = Comparator.comparing((BlockInlayImpl i) -> i.getPlacement())
|
||||
.thenComparing(i -> i.getPlacement() == Inlay.Placement.ABOVE_LINE ? i.myPriority : -i.myPriority);
|
||||
private static final Comparator<AfterLineEndInlayImpl> AFTER_LINE_END_ELEMENTS_OFFSET_COMPARATOR =
|
||||
Comparator.comparingInt((AfterLineEndInlayImpl i) -> i.getOffset()).thenComparingInt(i -> i.myOrder);
|
||||
private static final Comparator<AfterLineEndInlayImpl> AFTER_LINE_END_ELEMENTS_COMPARATOR = Comparator.comparingInt(i -> i.myOrder);
|
||||
private static final Comparator<BlockInlayImpl> BLOCK_ELEMENTS_PRIORITY_COMPARATOR =
|
||||
Comparator.comparingInt((BlockInlayImpl i) -> -i.myPriority);
|
||||
private static final Comparator<BlockInlayImpl> BLOCK_ELEMENTS_COMPARATOR =
|
||||
Comparator.comparing((BlockInlayImpl inlay) -> inlay.getVerticalAlignment())
|
||||
.thenComparing(i -> i.getVerticalAlignment() == Inlay.VerticalAlignment.ABOVE_LINE ? i.myPriority : -i.myPriority);
|
||||
private static final Processor<InlayImpl> UPDATE_SIZE_PROCESSOR = inlay -> {
|
||||
inlay.updateSize();
|
||||
return true;
|
||||
@@ -45,7 +44,6 @@ public class InlayModelImpl implements InlayModel, Disposable, Dumpable {
|
||||
final List<InlayImpl> myInlaysInvalidatedOnMove = new ArrayList<>();
|
||||
final RangeMarkerTree<InlineInlayImpl> myInlineElementsTree;
|
||||
final MarkerTreeWithPartialSums<BlockInlayImpl> myBlockElementsTree;
|
||||
final RangeMarkerTree<AfterLineEndInlayImpl> myAfterLineEndElementsTree;
|
||||
|
||||
boolean myMoveInProgress;
|
||||
boolean myPutMergedIntervalsAtBeginning;
|
||||
@@ -56,7 +54,6 @@ public class InlayModelImpl implements InlayModel, Disposable, Dumpable {
|
||||
myEditor = editor;
|
||||
myInlineElementsTree = new InlineElementsTree(editor.getDocument());
|
||||
myBlockElementsTree = new BlockElementsTree(editor.getDocument());
|
||||
myAfterLineEndElementsTree = new AfterLineEndElementTree(editor.getDocument());
|
||||
myEditor.getDocument().addDocumentListener(new PrioritizedInternalDocumentListener() {
|
||||
@Override
|
||||
public int getPriority() {
|
||||
@@ -143,19 +140,6 @@ public class InlayModelImpl implements InlayModel, Disposable, Dumpable {
|
||||
return inlay;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends EditorCustomElementRenderer> Inlay<T> addAfterLineEndElement(int offset,
|
||||
boolean relatesToPrecedingText,
|
||||
@NotNull T renderer) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
Document document = myEditor.getDocument();
|
||||
offset = Math.max(0, Math.min(document.getTextLength(), offset));
|
||||
AfterLineEndInlayImpl<T> inlay = new AfterLineEndInlayImpl<>(myEditor, offset, relatesToPrecedingText, renderer);
|
||||
notifyAdded(inlay);
|
||||
return inlay;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Inlay> getInlineElementsInRange(int startOffset, int endOffset) {
|
||||
@@ -298,10 +282,8 @@ public class InlayModelImpl implements InlayModel, Disposable, Dumpable {
|
||||
public Inlay getElementAt(@NotNull Point point) {
|
||||
boolean hasInlineElements = hasInlineElements();
|
||||
boolean hasBlockElements = hasBlockElements();
|
||||
boolean hasAfterLineEndElements = hasAfterLineEndElements();
|
||||
if (!hasInlineElements && !hasBlockElements && !hasAfterLineEndElements) return null;
|
||||
if (!hasInlineElements && !hasBlockElements) return null;
|
||||
|
||||
int offset = -1;
|
||||
VisualPosition visualPosition = myEditor.xyToVisualPosition(point);
|
||||
if (hasBlockElements) {
|
||||
int visualLine = visualPosition.line;
|
||||
@@ -332,84 +314,21 @@ public class InlayModelImpl implements InlayModel, Disposable, Dumpable {
|
||||
}
|
||||
}
|
||||
if (hasInlineElements) {
|
||||
offset = myEditor.logicalPositionToOffset(myEditor.visualToLogicalPosition(visualPosition));
|
||||
int offset = myEditor.logicalPositionToOffset(myEditor.visualToLogicalPosition(visualPosition));
|
||||
List<Inlay> inlays = getInlineElementsInRange(offset, offset);
|
||||
if (!inlays.isEmpty()) {
|
||||
VisualPosition startVisualPosition = myEditor.offsetToVisualPosition(offset);
|
||||
int x = myEditor.visualPositionToXY(startVisualPosition).x;
|
||||
Inlay inlay = findInlay(inlays, point, x);
|
||||
if (inlay != null) return inlay;
|
||||
}
|
||||
}
|
||||
if (hasAfterLineEndElements) {
|
||||
if (offset < 0) offset = myEditor.logicalPositionToOffset(myEditor.visualToLogicalPosition(visualPosition));
|
||||
int logicalLine = myEditor.getDocument().getLineNumber(offset);
|
||||
if (offset == myEditor.getDocument().getLineEndOffset(logicalLine) && !myEditor.getFoldingModel().isOffsetCollapsed(offset)) {
|
||||
List<Inlay> inlays = myEditor.getInlayModel().getAfterLineEndElementsForLogicalLine(logicalLine);
|
||||
if (!inlays.isEmpty()) {
|
||||
Rectangle bounds = inlays.get(0).getBounds();
|
||||
assert bounds != null;
|
||||
Inlay inlay = findInlay(inlays, point, bounds.x);
|
||||
if (inlay != null) return inlay;
|
||||
}
|
||||
if (inlays.isEmpty()) return null;
|
||||
|
||||
VisualPosition startVisualPosition = myEditor.offsetToVisualPosition(offset);
|
||||
int x = myEditor.visualPositionToXY(startVisualPosition).x;
|
||||
for (Inlay inlay : inlays) {
|
||||
int endX = x + inlay.getWidthInPixels();
|
||||
if (point.x >= x && point.x < endX) return inlay;
|
||||
x = endX;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Inlay findInlay(List<Inlay> inlays, @NotNull Point point, int startX) {
|
||||
for (Inlay inlay : inlays) {
|
||||
int endX = startX + inlay.getWidthInPixels();
|
||||
if (point.x >= startX && point.x < endX) return inlay;
|
||||
startX = endX;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Inlay> getAfterLineEndElementsInRange(int startOffset, int endOffset) {
|
||||
if (!hasAfterLineEndElements()) return Collections.emptyList();
|
||||
List<AfterLineEndInlayImpl> range =
|
||||
getElementsInRange(myAfterLineEndElementsTree, startOffset, endOffset, inlay -> true, AFTER_LINE_END_ELEMENTS_OFFSET_COMPARATOR);
|
||||
//noinspection unchecked
|
||||
return (List)range;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public <T> List<Inlay<? extends T>> getAfterLineEndElementsInRange(int startOffset, int endOffset, Class<T> type) {
|
||||
if (!hasAfterLineEndElements()) return Collections.emptyList();
|
||||
List<AfterLineEndInlayImpl> range =
|
||||
getElementsInRange(myAfterLineEndElementsTree, startOffset, endOffset, inlay -> type.isInstance(inlay.myRenderer),
|
||||
AFTER_LINE_END_ELEMENTS_OFFSET_COMPARATOR);
|
||||
//noinspection unchecked
|
||||
return (List)range;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Inlay> getAfterLineEndElementsForLogicalLine(int logicalLine) {
|
||||
DocumentEx document = myEditor.getDocument();
|
||||
if (!hasAfterLineEndElements() || logicalLine < 0 || logicalLine > 0 && logicalLine >= document.getLineCount()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<AfterLineEndInlayImpl> result = new ArrayList<>();
|
||||
int startOffset = document.getLineStartOffset(logicalLine);
|
||||
int endOffset = document.getLineEndOffset(logicalLine);
|
||||
myAfterLineEndElementsTree.processOverlappingWith(startOffset, endOffset, inlay -> {
|
||||
result.add(inlay);
|
||||
return true;
|
||||
});
|
||||
result.sort(AFTER_LINE_END_ELEMENTS_COMPARATOR);
|
||||
//noinspection unchecked
|
||||
return (List)result;
|
||||
}
|
||||
|
||||
public boolean hasAfterLineEndElements() {
|
||||
return myAfterLineEndElementsTree.size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConsiderCaretPositionOnDocumentUpdates(boolean enabled) {
|
||||
myConsiderCaretPositionOnDocumentUpdates = enabled;
|
||||
@@ -439,24 +358,6 @@ public class InlayModelImpl implements InlayModel, Disposable, Dumpable {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String dumpState() {
|
||||
return "Inline elements: " + dumpInlays(myInlineElementsTree)
|
||||
+ ", after-line-end elements: " + dumpInlays(myAfterLineEndElementsTree)
|
||||
+ ", block elements: " + dumpInlays(myBlockElementsTree);
|
||||
}
|
||||
|
||||
|
||||
private static String dumpInlays(RangeMarkerTree<? extends InlayImpl> tree) {
|
||||
StringJoiner joiner = new StringJoiner(",", "[", "]");
|
||||
tree.processAll(o -> {
|
||||
joiner.add(Integer.toString(o.getOffset()));
|
||||
return true;
|
||||
});
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
private class InlineElementsTree extends HardReferencingRangeMarkerTree<InlineInlayImpl> {
|
||||
InlineElementsTree(@NotNull Document document) {
|
||||
super(document);
|
||||
@@ -507,17 +408,4 @@ public class InlayModelImpl implements InlayModel, Disposable, Dumpable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AfterLineEndElementTree extends HardReferencingRangeMarkerTree<AfterLineEndInlayImpl> {
|
||||
AfterLineEndElementTree(@NotNull Document document) {
|
||||
super(document);
|
||||
}
|
||||
|
||||
@Override
|
||||
void fireBeforeRemoved(@NotNull AfterLineEndInlayImpl inlay, @NotNull @NonNls Object reason) {
|
||||
if (inlay.getUserData(InlayImpl.OFFSET_BEFORE_DISPOSAL) == null) {
|
||||
notifyRemoved(inlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.intellij.openapi.editor.EditorCustomElementRenderer;
|
||||
import com.intellij.openapi.editor.Inlay;
|
||||
import com.intellij.openapi.editor.VisualPosition;
|
||||
import com.intellij.openapi.editor.event.DocumentEvent;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -13,8 +12,6 @@ import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
class InlineInlayImpl<R extends EditorCustomElementRenderer> extends InlayImpl<R, InlineInlayImpl> {
|
||||
private static final Key<Integer> ORDER_BEFORE_DISPOSAL = Key.create("inlay.order.before.disposal");
|
||||
|
||||
InlineInlayImpl(@NotNull EditorImpl editor,
|
||||
int offset,
|
||||
boolean relatesToPrecedingText,
|
||||
@@ -51,16 +48,6 @@ class InlineInlayImpl<R extends EditorCustomElementRenderer> extends InlayImpl<R
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (isValid()) {
|
||||
int offset = getOffset();
|
||||
List<Inlay> inlays = myEditor.getInlayModel().getInlineElementsInRange(offset, offset);
|
||||
putUserData(ORDER_BEFORE_DISPOSAL, inlays.indexOf(this));
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
void doUpdateSize() {
|
||||
myWidthInPixels = myRenderer.calcWidthInPixels(this);
|
||||
@@ -71,8 +58,8 @@ class InlineInlayImpl<R extends EditorCustomElementRenderer> extends InlayImpl<R
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Placement getPlacement() {
|
||||
return Placement.INLINE;
|
||||
public VerticalAlignment getVerticalAlignment() {
|
||||
return VerticalAlignment.INLINE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -95,9 +82,4 @@ class InlineInlayImpl<R extends EditorCustomElementRenderer> extends InlayImpl<R
|
||||
public int getHeightInPixels() {
|
||||
return myEditor.getLineHeight();
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
Integer value = getUserData(ORDER_BEFORE_DISPOSAL);
|
||||
return value == null ? -1 : value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,6 @@ public class SoftWrapModelImpl extends InlayModel.SimpleAdapter
|
||||
private boolean myDirty;
|
||||
|
||||
private boolean myForceAdditionalColumns;
|
||||
private boolean myAfterLineEndInlayUpdated;
|
||||
|
||||
SoftWrapModelImpl(@NotNull EditorImpl editor) {
|
||||
myEditor = editor;
|
||||
@@ -398,7 +397,6 @@ public class SoftWrapModelImpl extends InlayModel.SimpleAdapter
|
||||
|
||||
@Override
|
||||
public void beforeDocumentChange(@NotNull DocumentEvent event) {
|
||||
myAfterLineEndInlayUpdated = false;
|
||||
if (myBulkUpdateInProgress) {
|
||||
return;
|
||||
}
|
||||
@@ -419,7 +417,7 @@ public class SoftWrapModelImpl extends InlayModel.SimpleAdapter
|
||||
if (!isSoftWrappingEnabled()) {
|
||||
return;
|
||||
}
|
||||
myApplianceManager.documentChanged(event, myAfterLineEndInlayUpdated);
|
||||
myApplianceManager.documentChanged(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -474,23 +472,14 @@ public class SoftWrapModelImpl extends InlayModel.SimpleAdapter
|
||||
|
||||
@Override
|
||||
public void onUpdated(@NotNull Inlay inlay) {
|
||||
if (myEditor.getDocument().isInBulkUpdate() ||
|
||||
inlay.getPlacement() != Inlay.Placement.INLINE && inlay.getPlacement() != Inlay.Placement.AFTER_LINE_END) return;
|
||||
if (myEditor.getDocument().isInEventsHandling() || myEditor.getDocument().isInBulkUpdate() ||
|
||||
inlay.getVerticalAlignment() != Inlay.VerticalAlignment.INLINE) return;
|
||||
if (!isSoftWrappingEnabled()) {
|
||||
myDirty = true;
|
||||
return;
|
||||
}
|
||||
if (!myDirty) {
|
||||
if (myEditor.getDocument().isInEventsHandling()) {
|
||||
if (inlay.getPlacement() == Inlay.Placement.AFTER_LINE_END) {
|
||||
myAfterLineEndInlayUpdated = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
int offset = inlay.getOffset();
|
||||
if (inlay.getPlacement() == Inlay.Placement.AFTER_LINE_END) {
|
||||
offset = DocumentUtil.getLineEndOffset(offset, myEditor.getDocument());
|
||||
}
|
||||
myApplianceManager.recalculate(Collections.singletonList(new TextRange(offset, offset)));
|
||||
}
|
||||
}
|
||||
|
||||
+21
-9
@@ -19,18 +19,21 @@ public class IncrementalCacheUpdateEvent {
|
||||
private final int myStartOffset;
|
||||
private final int myMandatoryEndOffset;
|
||||
private int myActualEndOffset = -1;
|
||||
|
||||
|
||||
private final int myLengthDiff;
|
||||
|
||||
|
||||
@NotNull
|
||||
private final LogicalPosition myStartLogicalPosition;
|
||||
private final int myOldEndLogicalLine;
|
||||
private int myNewEndLogicalLine = -1;
|
||||
|
||||
/**
|
||||
* Creates new {@code IncrementalCacheUpdateEvent} object on the basis on the given event object that describes
|
||||
* document change that caused cache update.
|
||||
* <p/>
|
||||
* This constructor is assumed to be used <b>before</b> the document change.
|
||||
*
|
||||
* This constructor is assumed to be used <b>before</b> the document change, {@link #updateAfterDocumentChange(Document)}
|
||||
* should be called <b>'after'</b> document change to complete object creation.
|
||||
*
|
||||
* @param event object that describes document change that caused cache update
|
||||
*/
|
||||
IncrementalCacheUpdateEvent(@NotNull DocumentEvent event, @NotNull EditorImpl editor) {
|
||||
@@ -43,12 +46,13 @@ public class IncrementalCacheUpdateEvent {
|
||||
*/
|
||||
IncrementalCacheUpdateEvent(int startOffset, int endOffset, @NotNull EditorImpl editor) {
|
||||
this(startOffset, endOffset, endOffset, editor);
|
||||
myNewEndLogicalLine = myOldEndLogicalLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@code IncrementalCacheUpdateEvent} object that is configured to perform whole reparse of the given
|
||||
* document.
|
||||
*
|
||||
*
|
||||
* @param document target document to reparse
|
||||
*/
|
||||
IncrementalCacheUpdateEvent(@NotNull Document document) {
|
||||
@@ -56,8 +60,9 @@ public class IncrementalCacheUpdateEvent {
|
||||
myMandatoryEndOffset = document.getTextLength();
|
||||
myLengthDiff = 0;
|
||||
myStartLogicalPosition = new LogicalPosition(0, 0);
|
||||
myOldEndLogicalLine = myNewEndLogicalLine = Math.max(0, document.getLineCount() - 1);
|
||||
}
|
||||
|
||||
|
||||
private IncrementalCacheUpdateEvent(int startOffset, int oldEndOffset, int newEndOffset, @NotNull EditorImpl editor) {
|
||||
VisualLineInfo info = getVisualLineInfo(editor, startOffset, false);
|
||||
if (info.startsWithSoftWrap) {
|
||||
@@ -67,6 +72,7 @@ public class IncrementalCacheUpdateEvent {
|
||||
myStartLogicalPosition = editor.offsetToLogicalPosition(myStartOffset);
|
||||
myMandatoryEndOffset = newEndOffset;
|
||||
myLengthDiff = newEndOffset - oldEndOffset;
|
||||
myOldEndLogicalLine = editor.getDocument().getLineNumber(oldEndOffset);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,11 +88,11 @@ public class IncrementalCacheUpdateEvent {
|
||||
int wrapIndex = softWrapModel.getSoftWrapIndex(offset);
|
||||
int prevSoftWrapIndex = wrapIndex < 0 ? - wrapIndex - 2 : wrapIndex - (beforeSoftWrap ? 1 : 0);
|
||||
SoftWrap prevSoftWrap = prevSoftWrapIndex < 0 ? null : softWrapModel.getRegisteredSoftWraps().get(prevSoftWrapIndex);
|
||||
|
||||
|
||||
int visualLineStartOffset = prevSoftWrap == null ? startOffset : Math.max(startOffset, prevSoftWrap.getStart());
|
||||
return new VisualLineInfo(visualLineStartOffset, prevSoftWrap != null && prevSoftWrap.getStart() == visualLineStartOffset);
|
||||
}
|
||||
|
||||
|
||||
private static class VisualLineInfo {
|
||||
private final int startOffset;
|
||||
private final boolean startsWithSoftWrap;
|
||||
@@ -97,6 +103,10 @@ public class IncrementalCacheUpdateEvent {
|
||||
}
|
||||
}
|
||||
|
||||
void updateAfterDocumentChange(@NotNull Document document) {
|
||||
myNewEndLogicalLine = document.getLineNumber(myMandatoryEndOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns offset, from which soft wrap recalculation should start
|
||||
*/
|
||||
@@ -144,6 +154,8 @@ public class IncrementalCacheUpdateEvent {
|
||||
", mandatoryEndOffset=" + myMandatoryEndOffset +
|
||||
", actualEndOffset=" + myActualEndOffset +
|
||||
", lengthDiff=" + myLengthDiff +
|
||||
", startLogicalPosition=" + myStartLogicalPosition;
|
||||
", startLogicalPosition=" + myStartLogicalPosition +
|
||||
", oldEndLogicalLine=" + myOldEndLogicalLine +
|
||||
", newEndLogicalLine=" + myNewEndLogicalLine;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-44
@@ -295,9 +295,7 @@ public class SoftWrapApplianceManager implements Dumpable {
|
||||
myContext.softWrapStartOffset++;
|
||||
}
|
||||
|
||||
myContext.inlineInlays = myEditor.getInlayModel().getInlineElementsInRange(start, endOffsetUpperEstimate);
|
||||
myContext.afterLineEndInlays = myEditor.getInlayModel().getAfterLineEndElementsInRange(DocumentUtil.getLineStartOffset(start, document),
|
||||
endOffsetUpperEstimate);
|
||||
myContext.inlays = myEditor.getInlayModel().getInlineElementsInRange(start, endOffsetUpperEstimate);
|
||||
|
||||
// Perform soft wraps calculation.
|
||||
while (!iterationState.atEnd()) {
|
||||
@@ -949,15 +947,10 @@ public class SoftWrapApplianceManager implements Dumpable {
|
||||
myDocumentChangedEvent = new IncrementalCacheUpdateEvent(event, myEditor);
|
||||
}
|
||||
|
||||
public void documentChanged(DocumentEvent event, boolean processAlsoLineEnd) {
|
||||
public void documentChanged(DocumentEvent event) {
|
||||
LOG.assertTrue(myDocumentChangedEvent != null);
|
||||
myDocumentChangedEvent.updateAfterDocumentChange(event.getDocument());
|
||||
recalculate(myDocumentChangedEvent);
|
||||
if (processAlsoLineEnd) {
|
||||
int lineEndOffset = DocumentUtil.getLineEndOffset(myDocumentChangedEvent.getMandatoryEndOffset(), event.getDocument());
|
||||
if (lineEndOffset > myDocumentChangedEvent.getActualEndOffset()) {
|
||||
recalculate(new IncrementalCacheUpdateEvent(lineEndOffset, lineEndOffset, myEditor));
|
||||
}
|
||||
}
|
||||
myDocumentChangedEvent = null;
|
||||
}
|
||||
|
||||
@@ -1212,10 +1205,8 @@ public class SoftWrapApplianceManager implements Dumpable {
|
||||
int fontType;
|
||||
boolean skipToLineEnd;
|
||||
|
||||
List<Inlay> inlineInlays;
|
||||
int inlineInlayIndex;
|
||||
List<Inlay> afterLineEndInlays;
|
||||
int afterLineEndInlayIndex;
|
||||
List<Inlay> inlays;
|
||||
int inlayIndex;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -1241,10 +1232,8 @@ public class SoftWrapApplianceManager implements Dumpable {
|
||||
skipToLineEnd = false;
|
||||
fontType2spaceWidth.reset();
|
||||
logicalLineData.reset();
|
||||
inlineInlays = null;
|
||||
inlineInlayIndex = 0;
|
||||
afterLineEndInlays = null;
|
||||
afterLineEndInlayIndex = 0;
|
||||
inlays = null;
|
||||
inlayIndex = 0;
|
||||
}
|
||||
|
||||
int getSpaceWidth() {
|
||||
@@ -1329,11 +1318,11 @@ public class SoftWrapApplianceManager implements Dumpable {
|
||||
}
|
||||
|
||||
private int getInlaysWidthForOffset(int offset) {
|
||||
while (inlineInlayIndex < inlineInlays.size() && inlineInlays.get(inlineInlayIndex).getOffset() < offset) inlineInlayIndex++;
|
||||
while (inlineInlayIndex > 0 && inlineInlays.get(inlineInlayIndex - 1).getOffset() >= offset) inlineInlayIndex--;
|
||||
while (inlayIndex < inlays.size() && inlays.get(inlayIndex).getOffset() < offset) inlayIndex++;
|
||||
while (inlayIndex > 0 && inlays.get(inlayIndex - 1).getOffset() >= offset) inlayIndex--;
|
||||
int width = 0;
|
||||
while (inlineInlayIndex < inlineInlays.size() && inlineInlays.get(inlineInlayIndex).getOffset() == offset) {
|
||||
width += inlineInlays.get(inlineInlayIndex++).getWidthInPixels();
|
||||
while (inlayIndex < inlays.size() && inlays.get(inlayIndex).getOffset() == offset) {
|
||||
width += inlays.get(inlayIndex++).getWidthInPixels();
|
||||
}
|
||||
return width;
|
||||
}
|
||||
@@ -1343,28 +1332,7 @@ public class SoftWrapApplianceManager implements Dumpable {
|
||||
return nextOffset < text.length() && text.charAt(nextOffset) != '\n' ||
|
||||
nextOffset > tokenEndOffset ||
|
||||
nextOffset == tokenEndOffset && nextIsFoldRegion
|
||||
? 0 : getInlaysWidthForOffset(nextOffset) + getAfterLineEndInlaysWidth(currentPosition.logicalLine);
|
||||
}
|
||||
|
||||
private int getAfterLineEndInlaysWidth(int logicalLine) {
|
||||
int startOffset = myEditor.getDocument().getLineStartOffset(logicalLine);
|
||||
int endOffset = myEditor.getDocument().getLineEndOffset(logicalLine);
|
||||
while (afterLineEndInlayIndex < afterLineEndInlays.size()
|
||||
&& afterLineEndInlays.get(afterLineEndInlayIndex).getOffset() < startOffset) {
|
||||
afterLineEndInlayIndex++;
|
||||
}
|
||||
while (afterLineEndInlayIndex > 0 && afterLineEndInlays.get(afterLineEndInlayIndex - 1).getOffset() >= startOffset) {
|
||||
afterLineEndInlayIndex--;
|
||||
}
|
||||
int width = 0;
|
||||
while (afterLineEndInlayIndex < afterLineEndInlays.size()) {
|
||||
Inlay inlay = afterLineEndInlays.get(afterLineEndInlayIndex);
|
||||
int offset = inlay.getOffset();
|
||||
if (offset < startOffset || offset > endOffset) break;
|
||||
width += inlay.getWidthInPixels();
|
||||
afterLineEndInlayIndex++;
|
||||
}
|
||||
return width;
|
||||
? 0 : getInlaysWidthForOffset(nextOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+27
-95
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
package com.intellij.openapi.editor.impl.view;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Attachment;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
@@ -26,6 +28,8 @@ import java.util.List;
|
||||
* @see VisualPosition
|
||||
*/
|
||||
class EditorCoordinateMapper {
|
||||
private static final Logger LOG = Logger.getInstance(EditorCoordinateMapper.class);
|
||||
|
||||
private final EditorView myView;
|
||||
private final Document myDocument;
|
||||
private final FoldingModelImpl myFoldingModel;
|
||||
@@ -93,28 +97,19 @@ class EditorCoordinateMapper {
|
||||
int column = pos.column;
|
||||
int logicalLineCount = myDocument.getLineCount();
|
||||
if (line >= logicalLineCount) {
|
||||
if (line == 0) {
|
||||
int resultColumn = logToVisWithInlays(0, column, pos.leansForward);
|
||||
if (resultColumn < 0) resultColumn = Integer.MAX_VALUE; // guarding against overflow
|
||||
return new VisualPosition(0, resultColumn, pos.leansForward);
|
||||
}
|
||||
else {
|
||||
return new VisualPosition(line - logicalLineCount + myView.getEditor().getVisibleLineCount(), column, pos.leansForward);
|
||||
}
|
||||
return new VisualPosition(line - logicalLineCount + myView.getEditor().getVisibleLineCount(), column, pos.leansForward);
|
||||
}
|
||||
int offset = logicalPositionToOffset(pos);
|
||||
int visualLine = offsetToVisualLine(offset, beforeSoftWrap);
|
||||
int maxVisualColumn = 0;
|
||||
int maxLogicalColumn = 0;
|
||||
int endLogicalLine = line;
|
||||
for (VisualLineFragmentsIterator.Fragment fragment : VisualLineFragmentsIterator.create(myView, offset, beforeSoftWrap)) {
|
||||
if (!pos.leansForward && offset == fragment.getVisualLineStartOffset()) {
|
||||
return new VisualPosition(visualLine, fragment.getStartVisualColumn());
|
||||
}
|
||||
endLogicalLine = fragment.getEndLogicalLine();
|
||||
maxVisualColumn = fragment.getEndVisualColumn();
|
||||
if (fragment.isCollapsedFoldRegion()) {
|
||||
int startLogicalLine = fragment.getStartLogicalLine();
|
||||
int endLogicalLine = fragment.getEndLogicalLine();
|
||||
int startLogicalColumn = fragment.getStartLogicalColumn();
|
||||
int endLogicalColumn = fragment.getEndLogicalColumn();
|
||||
if ((line > startLogicalLine || line == startLogicalLine && (column > startLogicalColumn ||
|
||||
@@ -123,7 +118,7 @@ class EditorCoordinateMapper {
|
||||
return new VisualPosition(visualLine, fragment.getStartVisualColumn(), true);
|
||||
}
|
||||
if (line == endLogicalLine && column == endLogicalColumn && !pos.leansForward) {
|
||||
return new VisualPosition(visualLine, maxVisualColumn);
|
||||
return new VisualPosition(visualLine, fragment.getEndVisualColumn());
|
||||
}
|
||||
maxLogicalColumn = startLogicalLine == endLogicalLine ? Math.max(maxLogicalColumn, endLogicalColumn) : endLogicalColumn;
|
||||
}
|
||||
@@ -138,47 +133,31 @@ class EditorCoordinateMapper {
|
||||
}
|
||||
maxLogicalColumn = Math.max(maxLogicalColumn, maxColumn);
|
||||
}
|
||||
maxVisualColumn = fragment.getEndVisualColumn();
|
||||
}
|
||||
int resultColumn = column - maxLogicalColumn + maxVisualColumn;
|
||||
if (resultColumn < 0) {
|
||||
if (maxVisualColumn > maxLogicalColumn) {
|
||||
resultColumn = Integer.MAX_VALUE; // guarding against overflow
|
||||
}
|
||||
else {
|
||||
LOG.error("Error converting " + pos + " to visual position",
|
||||
new Attachment("details.txt", String.format("offset: %d, visual line: %d, max logical column: %d, max visual column: %d",
|
||||
offset, visualLine, maxLogicalColumn, maxVisualColumn)),
|
||||
new Attachment("dump.txt", myView.getEditor().dumpState()));
|
||||
resultColumn = 0;
|
||||
}
|
||||
}
|
||||
int resultColumn = maxVisualColumn + logToVisWithInlays(endLogicalLine, column - maxLogicalColumn, pos.leansForward);
|
||||
if (resultColumn < 0) resultColumn = Integer.MAX_VALUE; // guarding against overflow
|
||||
return new VisualPosition(visualLine, resultColumn, pos.leansForward);
|
||||
}
|
||||
|
||||
private int logToVisWithInlays(int logLine, int remainingLogColumn, boolean leansForward) {
|
||||
if (remainingLogColumn > 1 || remainingLogColumn == 1 && leansForward) {
|
||||
remainingLogColumn += myView.getEditor().getInlayModel().getAfterLineEndElementsForLogicalLine(logLine).size();
|
||||
}
|
||||
return remainingLogColumn;
|
||||
}
|
||||
|
||||
private int visToLogWithInlays(int logLine, int remainingVisColumns, boolean[] leansForward) {
|
||||
if (remainingVisColumns == 0) return 0;
|
||||
int inlayCount = myView.getEditor().getInlayModel().getAfterLineEndElementsForLogicalLine(logLine).size();
|
||||
if (inlayCount == 0) return remainingVisColumns;
|
||||
if (remainingVisColumns < inlayCount + 1) {
|
||||
leansForward[0] = false;
|
||||
return 1;
|
||||
}
|
||||
if (remainingVisColumns == inlayCount + 1) {
|
||||
leansForward[0] = true;
|
||||
}
|
||||
return remainingVisColumns - inlayCount;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
LogicalPosition visualToLogicalPosition(@NotNull VisualPosition pos) {
|
||||
int line = pos.line;
|
||||
int column = pos.column;
|
||||
int visualLineCount = myView.getEditor().getVisibleLineCount();
|
||||
if (line >= visualLineCount) {
|
||||
if (line == 0) {
|
||||
boolean[] leansForward = new boolean[] {pos.leansRight};
|
||||
int resultColumn = visToLogWithInlays(0, column, leansForward);
|
||||
return new LogicalPosition(0, resultColumn, leansForward[0]);
|
||||
}
|
||||
else {
|
||||
return new LogicalPosition(line - visualLineCount + myDocument.getLineCount(), column, pos.leansRight);
|
||||
}
|
||||
return new LogicalPosition(line - visualLineCount + myDocument.getLineCount(), column, pos.leansRight);
|
||||
}
|
||||
int offset = visualLineToOffset(line);
|
||||
int logicalLine = myDocument.getLineNumber(offset);
|
||||
@@ -214,10 +193,11 @@ class EditorCoordinateMapper {
|
||||
maxOffset = Math.max(maxOffset, fragment.getMaxOffset());
|
||||
}
|
||||
if (myView.getEditor().getSoftWrapModel().getSoftWrap(maxOffset) == null) {
|
||||
boolean[] leansForward = new boolean[] {pos.leansRight};
|
||||
int resultColumn = maxLogicalColumn + visToLogWithInlays(logicalLine, column - maxVisualColumn, leansForward);
|
||||
if (resultColumn < 0) resultColumn = Integer.MAX_VALUE; // guarding against overflow
|
||||
return new LogicalPosition(logicalLine, resultColumn, leansForward[0]);
|
||||
int resultColumn = column - maxVisualColumn + maxLogicalColumn;
|
||||
if (resultColumn < 0 && maxLogicalColumn > maxVisualColumn) {
|
||||
resultColumn = Integer.MAX_VALUE; // guarding against overflow
|
||||
}
|
||||
return new LogicalPosition(logicalLine, resultColumn, true);
|
||||
}
|
||||
else {
|
||||
return offsetToLogicalPosition(maxOffset).leanForward(true);
|
||||
@@ -321,7 +301,6 @@ class EditorCoordinateMapper {
|
||||
int lastColumn = 0;
|
||||
float x = getStartX(visualLine);
|
||||
float px = (float)p.getX();
|
||||
int logicalLine = -1;
|
||||
if (visualLine < myView.getEditor().getVisibleLineCount()) {
|
||||
int visualLineStartOffset = visualLineToOffset(visualLine);
|
||||
int maxOffset = 0;
|
||||
@@ -346,7 +325,6 @@ class EditorCoordinateMapper {
|
||||
x = nextX;
|
||||
lastColumn = fragment.getEndVisualColumn();
|
||||
maxOffset = Math.max(maxOffset, fragment.getMaxOffset());
|
||||
logicalLine = fragment.getEndLogicalLine();
|
||||
}
|
||||
if (myView.getEditor().getSoftWrapModel().getSoftWrap(maxOffset) != null) {
|
||||
int markerWidth = myView.getEditor().getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
|
||||
@@ -356,34 +334,10 @@ class EditorCoordinateMapper {
|
||||
}
|
||||
px -= markerWidth;
|
||||
lastColumn++;
|
||||
logicalLine = -1;
|
||||
}
|
||||
else if (logicalLine == -1) {
|
||||
logicalLine = myDocument.getLineNumber(visualLineStartOffset);
|
||||
}
|
||||
}
|
||||
else if (visualLine == 0) {
|
||||
logicalLine = 0;
|
||||
}
|
||||
float plainSpaceWidth = myView.getPlainSpaceWidth();
|
||||
float remainingShift = px - x;
|
||||
if (remainingShift > plainSpaceWidth && logicalLine >= 0) {
|
||||
List<Inlay> inlays = myView.getEditor().getInlayModel().getAfterLineEndElementsForLogicalLine(logicalLine);
|
||||
int inlaysWidth = 0;
|
||||
int inlayCount = 0;
|
||||
for (Inlay inlay : inlays) {
|
||||
int width = inlay.getWidthInPixels();
|
||||
int newWidth = inlaysWidth + width;
|
||||
if (remainingShift <= plainSpaceWidth + newWidth) {
|
||||
boolean leftPart = remainingShift <= plainSpaceWidth + (inlaysWidth + newWidth) / 2;
|
||||
return new VisualPosition(visualLine, lastColumn + 1 + inlayCount + (leftPart ? 0 : 1), leftPart);
|
||||
}
|
||||
inlaysWidth = newWidth;
|
||||
inlayCount++;
|
||||
}
|
||||
remainingShift -= inlaysWidth;
|
||||
lastColumn += inlayCount;
|
||||
}
|
||||
int additionalColumns = remainingShift <= 0 ? 0 : Math.round(remainingShift / plainSpaceWidth);
|
||||
return new VisualPosition(visualLine, lastColumn + additionalColumns, remainingShift > additionalColumns * plainSpaceWidth);
|
||||
}
|
||||
@@ -395,7 +349,6 @@ class EditorCoordinateMapper {
|
||||
int y = visualLineToY(visualLine);
|
||||
float x = getStartX(visualLine);
|
||||
int lastColumn = 0;
|
||||
int logicalLine = -1;
|
||||
if (visualLine < myView.getEditor().getVisibleLineCount()) {
|
||||
int visualLineStartOffset = visualLineToOffset(visualLine);
|
||||
int maxOffset = 0;
|
||||
@@ -411,32 +364,11 @@ class EditorCoordinateMapper {
|
||||
x = fragment.getEndX();
|
||||
lastColumn = endColumn;
|
||||
maxOffset = Math.max(maxOffset, fragment.getMaxOffset());
|
||||
logicalLine = fragment.getEndLogicalLine();
|
||||
}
|
||||
if (column > lastColumn && myView.getEditor().getSoftWrapModel().getSoftWrap(maxOffset) != null) {
|
||||
column--;
|
||||
x += myView.getEditor().getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
|
||||
}
|
||||
else if (logicalLine == -1) {
|
||||
logicalLine = myDocument.getLineNumber(visualLineStartOffset);
|
||||
}
|
||||
}
|
||||
else if (visualLine == 0) {
|
||||
logicalLine = 0;
|
||||
}
|
||||
if (column > lastColumn + 1 && logicalLine >= 0) {
|
||||
List<Inlay> inlays = myView.getEditor().getInlayModel().getAfterLineEndElementsForLogicalLine(logicalLine);
|
||||
int inlaysWidth = 0;
|
||||
int inlayCount = 0;
|
||||
for (Inlay inlay : inlays) {
|
||||
inlayCount++;
|
||||
inlaysWidth += inlay.getWidthInPixels();
|
||||
if (column == lastColumn + 1 + inlayCount) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
x += inlaysWidth;
|
||||
column -= inlayCount;
|
||||
}
|
||||
float additionalShift = column <= lastColumn ? 0 : (column - lastColumn) * myView.getPlainSpaceWidth();
|
||||
return new Point2D.Double(x + additionalShift, y);
|
||||
|
||||
+3
-16
@@ -501,20 +501,7 @@ public class EditorPainter implements TextDrawingCallback {
|
||||
int offset = iterationState.getEndOffset();
|
||||
SoftWrapModelImpl softWrapModel = myEditor.getSoftWrapModel();
|
||||
if (softWrapModel.getSoftWrap(offset) == null) {
|
||||
int logicalLine = myDocument.getLineNumber(offset);
|
||||
List<Inlay> inlays = myEditor.getInlayModel().getAfterLineEndElementsForLogicalLine(logicalLine);
|
||||
if (!inlays.isEmpty()) {
|
||||
x += myView.getPlainSpaceWidth();
|
||||
int lineHeight = myView.getLineHeight();
|
||||
TextAttributes backgroundAttributes = iterationState.getPastLineEndBackgroundAttributes();
|
||||
for (Inlay inlay : inlays) {
|
||||
int width = inlay.getWidthInPixels();
|
||||
inlay.getRenderer().paint(inlay, g, new Rectangle((int) x, y - myView.getAscent(), width, lineHeight),
|
||||
backgroundAttributes);
|
||||
x += width;
|
||||
}
|
||||
}
|
||||
paintLineExtensions(g, visualLine, logicalLine, x, y, extensionData);
|
||||
paintLineExtensions(g, visualLine, offset, x, y, extensionData);
|
||||
}
|
||||
else if (paintSoftWraps) {
|
||||
softWrapModel.doPaint(g, SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED,
|
||||
@@ -684,7 +671,7 @@ public class EditorPainter implements TextDrawingCallback {
|
||||
}
|
||||
}
|
||||
|
||||
private void paintLineExtensions(Graphics2D g, int visualLine, int logicalLine, float x, int y,
|
||||
private void paintLineExtensions(Graphics2D g, int visualLine, int offset, float x, int y,
|
||||
TIntObjectHashMap<List<LineExtensionData>> extensionData) {
|
||||
List<LineExtensionData> data = extensionData.get(visualLine);
|
||||
if (data == null) return;
|
||||
@@ -695,7 +682,7 @@ public class EditorPainter implements TextDrawingCallback {
|
||||
int currentLineWidth = myCorrector.lineWidth(visualLine, x);
|
||||
EditorSizeManager sizeManager = myView.getSizeManager();
|
||||
if (currentLineWidth > sizeManager.getMaxLineWithExtensionWidth()) {
|
||||
sizeManager.setMaxLineWithExtensionWidth(logicalLine, currentLineWidth);
|
||||
sizeManager.setMaxLineWithExtensionWidth(myDocument.getLineNumber(offset), currentLineWidth);
|
||||
myEditor.getContentComponent().revalidate();
|
||||
}
|
||||
}
|
||||
|
||||
+3
-31
@@ -17,7 +17,6 @@ import com.intellij.openapi.editor.impl.softwrap.mapping.SoftWrapAwareDocumentPa
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
import gnu.trove.TIntArrayList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -64,7 +63,6 @@ class EditorSizeManager extends InlayModel.SimpleAdapter implements PrioritizedD
|
||||
private boolean myDirty; // true if we cannot calculate preferred size now because soft wrap model was invalidated after editor
|
||||
// became hidden. myLineWidths contents is irrelevant in such a state. Previously calculated preferred size
|
||||
// is kept until soft wraps will be recalculated and size calculations will become possible
|
||||
private boolean myAfterLineEndInlayUpdated;
|
||||
|
||||
private final List<TextRange> myDeferredRanges = new ArrayList<>();
|
||||
|
||||
@@ -97,7 +95,6 @@ class EditorSizeManager extends InlayModel.SimpleAdapter implements PrioritizedD
|
||||
|
||||
@Override
|
||||
public void beforeDocumentChange(@NotNull DocumentEvent event) {
|
||||
myAfterLineEndInlayUpdated = false;
|
||||
myDuringDocumentUpdate = true;
|
||||
if (myDocument.isInBulkUpdate()) return;
|
||||
myDocumentChangeStartOffset = event.getOffset();
|
||||
@@ -109,10 +106,6 @@ class EditorSizeManager extends InlayModel.SimpleAdapter implements PrioritizedD
|
||||
myDuringDocumentUpdate = false;
|
||||
if (myDocument.isInBulkUpdate()) return;
|
||||
doInvalidateRange(myDocumentChangeStartOffset, myDocumentChangeEndOffset);
|
||||
if (myAfterLineEndInlayUpdated) {
|
||||
int lineEndOffset = DocumentUtil.getLineEndOffset(myDocumentChangeEndOffset, myDocument);
|
||||
doInvalidateRange(lineEndOffset, lineEndOffset);
|
||||
}
|
||||
assertValidState();
|
||||
}
|
||||
|
||||
@@ -143,19 +136,8 @@ class EditorSizeManager extends InlayModel.SimpleAdapter implements PrioritizedD
|
||||
|
||||
@Override
|
||||
public void onUpdated(@NotNull Inlay inlay) {
|
||||
if (myDocument.isInBulkUpdate()
|
||||
|| inlay.getPlacement() != Inlay.Placement.INLINE && inlay.getPlacement() != Inlay.Placement.AFTER_LINE_END) return;
|
||||
if (myDuringDocumentUpdate) {
|
||||
if (inlay.getPlacement() == Inlay.Placement.AFTER_LINE_END) {
|
||||
myAfterLineEndInlayUpdated = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
int offset = inlay.getOffset();
|
||||
if (inlay.getPlacement() == Inlay.Placement.AFTER_LINE_END) {
|
||||
offset = DocumentUtil.getLineEndOffset(offset, myDocument);
|
||||
}
|
||||
doInvalidateRange(offset, offset);
|
||||
if (myDuringDocumentUpdate || myDocument.isInBulkUpdate() || inlay.getVerticalAlignment() != Inlay.VerticalAlignment.INLINE) return;
|
||||
doInvalidateRange(inlay.getOffset(), inlay.getOffset());
|
||||
}
|
||||
|
||||
private void onSoftWrapRecalculationEnd(IncrementalCacheUpdateEvent event) {
|
||||
@@ -342,8 +324,7 @@ class EditorSizeManager extends InlayModel.SimpleAdapter implements PrioritizedD
|
||||
FoldRegion[] topLevelRegions = myEditor.getFoldingModel().fetchTopLevel();
|
||||
if (quickEvaluationListener != null &&
|
||||
(topLevelRegions == null || topLevelRegions.length == 0) && myEditor.getSoftWrapModel().getRegisteredSoftWraps().isEmpty() &&
|
||||
!myView.getTextLayoutCache().hasCachedLayoutFor(visualLine)
|
||||
&& !myEditor.getInlayModel().hasInlineElements() && !myEditor.getInlayModel().hasAfterLineEndElements()) {
|
||||
!myView.getTextLayoutCache().hasCachedLayoutFor(visualLine) && !myEditor.getInlayModel().hasInlineElements()) {
|
||||
// fast path - speeds up editor opening
|
||||
quickEvaluationListener.run();
|
||||
return (int)(myView.getLogicalPositionCache().offsetToLogicalColumn(visualLine,
|
||||
@@ -362,15 +343,6 @@ class EditorSizeManager extends InlayModel.SimpleAdapter implements PrioritizedD
|
||||
if (myEditor.getSoftWrapModel().getSoftWrap(maxOffset) != null) {
|
||||
x += myEditor.getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED);
|
||||
}
|
||||
else {
|
||||
List<Inlay> inlays = myEditor.getInlayModel().getAfterLineEndElementsForLogicalLine(iterator.getEndLogicalLine());
|
||||
if (!inlays.isEmpty()) {
|
||||
x += myView.getPlainSpaceWidth();
|
||||
for (Inlay inlay : inlays) {
|
||||
x += inlay.getWidthInPixels();
|
||||
}
|
||||
}
|
||||
}
|
||||
return (int)x;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -164,7 +164,7 @@ public class VisualLinesIterator {
|
||||
int foldIndex = myLocation.foldRegion;
|
||||
while (foldIndex < myFoldRegions.length && myFoldRegions[foldIndex].getEndOffset() <= inlayOffset) foldIndex++;
|
||||
if (foldIndex < myFoldRegions.length && myFoldRegions[foldIndex].getStartOffset() <= inlayOffset) continue;
|
||||
(inlay.getPlacement() == Inlay.Placement.ABOVE_LINE ? myInlaysAbove : myInlaysBelow).add(inlay);
|
||||
(inlay.getVerticalAlignment() == Inlay.VerticalAlignment.ABOVE_LINE ? myInlaysAbove : myInlaysBelow).add(inlay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-20
@@ -32,14 +32,6 @@ public class TextComponentInlayModel implements InlayModel {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends EditorCustomElementRenderer> Inlay<T> addAfterLineEndElement(int offset,
|
||||
boolean relatesToPrecedingText,
|
||||
@NotNull T renderer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Inlay> getInlineElementsInRange(int startOffset, int endOffset) {
|
||||
@@ -75,18 +67,6 @@ public class TextComponentInlayModel implements InlayModel {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Inlay> getAfterLineEndElementsInRange(int startOffset, int endOffset) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Inlay> getAfterLineEndElementsForLogicalLine(int logicalLine) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConsiderCaretPositionOnDocumentUpdates(boolean enabled) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user