Fix ligature selection in DOM renderer

Part of #5231
This commit is contained in:
Daniel Imms
2025-01-06 10:50:13 -08:00
parent ad08a2e15b
commit 0521378e70
@@ -91,6 +91,7 @@ export class DomRendererRowFactory {
let oldSpacing = 0;
let oldIsInSelection: boolean = false;
let spacing = 0;
let skipJoinedCheckUntilX = 0;
const classes: string[] = [];
const hasHover = linkStart !== -1 && linkEnd !== -1;
@@ -106,29 +107,41 @@ export class DomRendererRowFactory {
// If true, indicates that the current character(s) to draw were joined.
let isJoined = false;
// Indicates whether this cell is part of a joined range that should be ignored as it cannot
// be rendered entirely, like the selection state differs across the range.
let isValidJoinRange = (x >= skipJoinedCheckUntilX);
let lastCharX = x;
// Process any joined character ranges as needed. Because of how the
// ranges are produced, we know that they are valid for the characters
// and attributes of our input.
let cell = this._workCell;
if (joinedRanges.length > 0 && x === joinedRanges[0][0]) {
isJoined = true;
if (joinedRanges.length > 0 && x === joinedRanges[0][0] && isValidJoinRange) {
const range = joinedRanges.shift()!;
// If the ligature's selection state is not consistent, don't join it. This helps the
// selection render correctly regardless whether they should be joined.
if (this._isCellInSelection(range[0], row) !== this._isCellInSelection(range[1], row)) {
isValidJoinRange = false;
skipJoinedCheckUntilX = range[1];
} else {
isJoined = true;
// We already know the exact start and end column of the joined range,
// so we get the string and width representing it directly
cell = new JoinedCellData(
this._workCell,
lineData.translateToString(true, range[0], range[1]),
range[1] - range[0]
);
// We already know the exact start and end column of the joined range,
// so we get the string and width representing it directly
cell = new JoinedCellData(
this._workCell,
lineData.translateToString(true, range[0], range[1]),
range[1] - range[0]
);
// Skip over the cells occupied by this range in the loop
lastCharX = range[1] - 1;
// Skip over the cells occupied by this range in the loop
lastCharX = range[1] - 1;
// Recalculate width
width = cell.getWidth();
// Recalculate width
width = cell.getWidth();
}
}
const isInSelection = this._isCellInSelection(x, row);
@@ -178,6 +191,7 @@ export class DomRendererRowFactory {
&& !isCursorCell
&& !isJoined
&& !isDecorated
&& isValidJoinRange
) {
// no span alterations, thus only account chars skipping all code below
if (cell.isInvisible()) {
@@ -435,7 +449,7 @@ export class DomRendererRowFactory {
}
// exclude conditions for cell merging - never merge these
if (!isCursorCell && !isJoined && !isDecorated) {
if (!isCursorCell && !isJoined && !isDecorated && isValidJoinRange) {
cellAmount++;
} else {
charElement.textContent = text;