Skip to content

Commit 0521378

Browse files
committed
Fix ligature selection in DOM renderer
Part of #5231
1 parent ad08a2e commit 0521378

1 file changed

Lines changed: 29 additions & 15 deletions

File tree

src/browser/renderer/dom/DomRendererRowFactory.ts

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export class DomRendererRowFactory {
9191
let oldSpacing = 0;
9292
let oldIsInSelection: boolean = false;
9393
let spacing = 0;
94+
let skipJoinedCheckUntilX = 0;
9495
const classes: string[] = [];
9596

9697
const hasHover = linkStart !== -1 && linkEnd !== -1;
@@ -106,29 +107,41 @@ export class DomRendererRowFactory {
106107

107108
// If true, indicates that the current character(s) to draw were joined.
108109
let isJoined = false;
110+
111+
// Indicates whether this cell is part of a joined range that should be ignored as it cannot
112+
// be rendered entirely, like the selection state differs across the range.
113+
let isValidJoinRange = (x >= skipJoinedCheckUntilX);
114+
109115
let lastCharX = x;
110116

111117
// Process any joined character ranges as needed. Because of how the
112118
// ranges are produced, we know that they are valid for the characters
113119
// and attributes of our input.
114120
let cell = this._workCell;
115-
if (joinedRanges.length > 0 && x === joinedRanges[0][0]) {
116-
isJoined = true;
121+
if (joinedRanges.length > 0 && x === joinedRanges[0][0] && isValidJoinRange) {
117122
const range = joinedRanges.shift()!;
123+
// If the ligature's selection state is not consistent, don't join it. This helps the
124+
// selection render correctly regardless whether they should be joined.
125+
if (this._isCellInSelection(range[0], row) !== this._isCellInSelection(range[1], row)) {
126+
isValidJoinRange = false;
127+
skipJoinedCheckUntilX = range[1];
128+
} else {
129+
isJoined = true;
130+
131+
// We already know the exact start and end column of the joined range,
132+
// so we get the string and width representing it directly
133+
cell = new JoinedCellData(
134+
this._workCell,
135+
lineData.translateToString(true, range[0], range[1]),
136+
range[1] - range[0]
137+
);
118138

119-
// We already know the exact start and end column of the joined range,
120-
// so we get the string and width representing it directly
121-
cell = new JoinedCellData(
122-
this._workCell,
123-
lineData.translateToString(true, range[0], range[1]),
124-
range[1] - range[0]
125-
);
126-
127-
// Skip over the cells occupied by this range in the loop
128-
lastCharX = range[1] - 1;
139+
// Skip over the cells occupied by this range in the loop
140+
lastCharX = range[1] - 1;
129141

130-
// Recalculate width
131-
width = cell.getWidth();
142+
// Recalculate width
143+
width = cell.getWidth();
144+
}
132145
}
133146

134147
const isInSelection = this._isCellInSelection(x, row);
@@ -178,6 +191,7 @@ export class DomRendererRowFactory {
178191
&& !isCursorCell
179192
&& !isJoined
180193
&& !isDecorated
194+
&& isValidJoinRange
181195
) {
182196
// no span alterations, thus only account chars skipping all code below
183197
if (cell.isInvisible()) {
@@ -435,7 +449,7 @@ export class DomRendererRowFactory {
435449
}
436450

437451
// exclude conditions for cell merging - never merge these
438-
if (!isCursorCell && !isJoined && !isDecorated) {
452+
if (!isCursorCell && !isJoined && !isDecorated && isValidJoinRange) {
439453
cellAmount++;
440454
} else {
441455
charElement.textContent = text;

0 commit comments

Comments
 (0)