[editor] IJPL-237520 paint selection correctly when soft wrap symbols are present

(cherry picked from commit 9736ba82194fc3b14a37c00402028dcc9c8096ea)

IJ-CR-194975

GitOrigin-RevId: 8bdc1980e0da580fa81d7a5a05ba8917a93f6001
This commit is contained in:
Stanislav Alekseev
2026-03-09 17:19:38 +00:00
committed by intellij-monorepo-bot
parent a5f97467ac
commit 744725eade
4 changed files with 15 additions and 25 deletions
@@ -523,7 +523,7 @@ public final class EditorPainter implements TextDrawingCallback {
if (visualLine == 0) xEnd -= myView.getPrefixTextWidthInPixels();
paintBackground(attributes, startX, y, xEnd);
if (shouldUseNewSelection()
&& it.isInSelection()
&& it.isInSelection(true)
&& myEditor.isRightAligned()) {
mySelectionLinePainter.paintSelection(new Rectangle2D.Float(
xEnd - selectionExtensionWidth, y,
@@ -542,7 +542,7 @@ public final class EditorPainter implements TextDrawingCallback {
}
@Override
public void paint(VisualLineFragmentsIterator.Fragment fragment, int start, int end,
public void paint(IterationState it, VisualLineFragmentsIterator.Fragment fragment, int start, int end,
TextAttributes attributes, float xStart, float xEnd, int y) {
if (dryRun) return;
FoldRegion foldRegion = fragment.getCurrentFoldRegion();
@@ -551,6 +551,11 @@ public final class EditorPainter implements TextDrawingCallback {
if (foldRegionInnerAttributes == null ||
!paintFoldingBackground(foldRegionInnerAttributes, xStart, y, xEnd - xStart, foldRegion)) {
paintBackground(attributes, xStart, y, xEnd - xStart);
if (it != null && it.isInSelection(false) && shouldUseNewSelection()) {
mySelectionLinePainter.paintSelection(new Rectangle2D.Float(
xStart, y, xEnd - xStart, myLineHeight
));
}
}
Inlay inlay = fragment.getCurrentInlay();
if (inlay != null) {
@@ -625,7 +630,7 @@ public final class EditorPainter implements TextDrawingCallback {
return;
}
paintBackground(backgroundAttributes.getBackgroundColor(), x, y, endX - x, myLineHeight);
if (it.isInSelection() && shouldUseNewSelection() && !myEditor.isRightAligned()) {
if (it.hasPastLineEndExtension() && shouldUseNewSelection() && !myEditor.isRightAligned()) {
mySelectionLinePainter.paintSelection(
new Rectangle2D.Float(x, y, selectionExtensionWidth, myLineHeight)
);
@@ -789,9 +794,6 @@ public final class EditorPainter implements TextDrawingCallback {
if (attributes == null) return;
paintBackground(attributes.getBackgroundColor(), x, y, width, height);
if (shouldUseNewSelection() && mySelectionLinePainter.isLineInSelection(x, y, width)) {
mySelectionLinePainter.paintSelection(new Rectangle2D.Float(x, y, width, height));
}
}
private void paintBackground(Color color, float x, int y, float width) {
@@ -1720,7 +1722,7 @@ public final class EditorPainter implements TextDrawingCallback {
TextAttributes attributes = it.getStartOffset() == start ? it.getBreakAttributes() : it.getMergedAttributes();
float xNew = fragment.getEndX();
if (xNew >= myClip.getMinX()) {
painter.paint(fragment, 0, 0, attributes, x, xNew, y);
painter.paint(it, fragment, 0, 0, attributes, x, xNew, y);
}
x = xNew;
}
@@ -1734,7 +1736,7 @@ public final class EditorPainter implements TextDrawingCallback {
int curEnd = fragment.isRtl() ? Math.max(it.getEndOffset(), end) : Math.min(it.getEndOffset(), end);
float xNew = fragment.offsetToX(x, start, curEnd);
if (xNew >= myClip.getMinX()) {
painter.paint(fragment,
painter.paint(it, fragment,
fragment.isRtl() ? fragmentStartOffset - start : start - fragmentStartOffset,
fragment.isRtl() ? fragmentStartOffset - curEnd : curEnd - fragmentStartOffset,
attributes, x, xNew, y);
@@ -1755,7 +1757,7 @@ public final class EditorPainter implements TextDrawingCallback {
else {
float xNew = fragment.getEndX();
if (xNew >= myClip.getMinX()) {
painter.paint(fragment, 0, fragment.getVisualLength(), getFoldRegionAttributes(foldRegion), x, xNew, y);
painter.paint(it, fragment, 0, fragment.getVisualLength(), getFoldRegionAttributes(foldRegion), x, xNew, y);
}
x = xNew;
prevEndOffset = -1;
@@ -296,8 +296,8 @@ public final class IterationState {
}
@ApiStatus.Internal
public boolean isInSelection() {
return myIsInSelection;
public boolean hasPastLineEndExtension() {
return isInSelection(hasSoftWrap());
}
@ApiStatus.Internal
@@ -405,7 +405,7 @@ public final class IterationState {
);
}
private boolean isInSelection(boolean atBreak) {
boolean isInSelection(boolean atBreak) {
return myCurrentSelectionIndex < myCaretData.selectionsSize() &&
(myReverseIteration ? lessThan(myStartOffset, myCaretData.selectionEnd(myCurrentSelectionIndex, true), !atBreak)
: lessThan(myCaretData.selectionStart(myCurrentSelectionIndex, false), myStartOffset, !atBreak));
@@ -527,7 +527,6 @@ public final class IterationState {
private void setAttributes(TextAttributes attributes, boolean atBreak, boolean beforeBreak) {
boolean isInSelection = isInSelection(atBreak);
myIsInSelection = isInSelection;
boolean isInCaretRow = isInCaretRow(
!myReverseIteration && (!atBreak || !beforeBreak),
myReverseIteration || (atBreak && beforeBreak)
@@ -16,6 +16,7 @@ interface LineFragmentPainter {
);
void paint(
IterationState iterationState,
VisualLineFragmentsIterator.Fragment fragment,
int start,
int end,
@@ -211,10 +211,6 @@ internal class SelectionLinePainter(
return editor.yToVisualLine(y - yShift)
}
private fun visualLineToY(visualLine: Int): Int {
return editor.visualLineToY(visualLine) + yShift
}
private fun customFoldRegionsFor(visualLine: Int): List<CustomFoldRegion> {
return customFoldRegions.filter { cfr ->
val startLine = editor.offsetToVisualLine(cfr.startOffset)
@@ -360,14 +356,6 @@ internal class SelectionLinePainter(
return customFoldRegionsFor(visualLine).isNotEmpty() || caretSelectionsForLine(visualLine).hasSelectionEnd(false, block.bottomRight.x)
}
fun isLineInSelection(x: Float, y: Int, width: Float): Boolean {
val line = yToVisualLine(y)
if (y != visualLineToY(line)) return false
val selection = caretSelectionsForLine(line).selectionContaining(x.toDouble()) ?: return false
return selection.contains((x + width).toDouble())
}
private fun paintRoundedBlock(block: SelectionRectangle, cornerTypes: Array<CornerType>) {
val (topLeftType, topRightType, bottomRightType, bottomLeftType) = cornerTypes