@@ -84,13 +84,15 @@ export class DomRendererRowFactory {
84
84
let charElement : HTMLSpanElement | undefined ;
85
85
let cellAmount = 0 ;
86
86
let text = '' ;
87
+ let i = 0 ;
87
88
let oldBg = 0 ;
88
89
let oldFg = 0 ;
89
90
let oldExt = 0 ;
90
91
let oldLinkHover : number | boolean = false ;
91
92
let oldSpacing = 0 ;
92
93
let oldIsInSelection : boolean = false ;
93
94
let spacing = 0 ;
95
+ let skipJoinedCheckUntilX = 0 ;
94
96
const classes : string [ ] = [ ] ;
95
97
96
98
const hasHover = linkStart !== - 1 && linkEnd !== - 1 ;
@@ -106,29 +108,44 @@ export class DomRendererRowFactory {
106
108
107
109
// If true, indicates that the current character(s) to draw were joined.
108
110
let isJoined = false ;
111
+
112
+ // Indicates whether this cell is part of a joined range that should be ignored as it cannot
113
+ // be rendered entirely, like the selection state differs across the range.
114
+ let isValidJoinRange = ( x >= skipJoinedCheckUntilX ) ;
115
+
109
116
let lastCharX = x ;
110
117
111
118
// Process any joined character ranges as needed. Because of how the
112
119
// ranges are produced, we know that they are valid for the characters
113
120
// and attributes of our input.
114
121
let cell = this . _workCell ;
115
- if ( joinedRanges . length > 0 && x === joinedRanges [ 0 ] [ 0 ] ) {
116
- isJoined = true ;
122
+ if ( joinedRanges . length > 0 && x === joinedRanges [ 0 ] [ 0 ] && isValidJoinRange ) {
117
123
const range = joinedRanges . shift ( ) ! ;
124
+ // If the ligature's selection state is not consistent, don't join it. This helps the
125
+ // selection render correctly regardless whether they should be joined.
126
+ const firstSelectionState = this . _isCellInSelection ( range [ 0 ] , row ) ;
127
+ for ( i = range [ 0 ] + 1 ; i < range [ 1 ] ; i ++ ) {
128
+ isValidJoinRange &&= ( firstSelectionState === this . _isCellInSelection ( i , row ) ) ;
129
+ }
130
+ if ( ! isValidJoinRange ) {
131
+ skipJoinedCheckUntilX = range [ 1 ] ;
132
+ } else {
133
+ isJoined = true ;
134
+
135
+ // We already know the exact start and end column of the joined range,
136
+ // so we get the string and width representing it directly
137
+ cell = new JoinedCellData (
138
+ this . _workCell ,
139
+ lineData . translateToString ( true , range [ 0 ] , range [ 1 ] ) ,
140
+ range [ 1 ] - range [ 0 ]
141
+ ) ;
118
142
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 ;
143
+ // Skip over the cells occupied by this range in the loop
144
+ lastCharX = range [ 1 ] - 1 ;
129
145
130
- // Recalculate width
131
- width = cell . getWidth ( ) ;
146
+ // Recalculate width
147
+ width = cell . getWidth ( ) ;
148
+ }
132
149
}
133
150
134
151
const isInSelection = this . _isCellInSelection ( x , row ) ;
@@ -178,6 +195,7 @@ export class DomRendererRowFactory {
178
195
&& ! isCursorCell
179
196
&& ! isJoined
180
197
&& ! isDecorated
198
+ && isValidJoinRange
181
199
) {
182
200
// no span alterations, thus only account chars skipping all code below
183
201
if ( cell . isInvisible ( ) ) {
@@ -435,7 +453,7 @@ export class DomRendererRowFactory {
435
453
}
436
454
437
455
// exclude conditions for cell merging - never merge these
438
- if ( ! isCursorCell && ! isJoined && ! isDecorated ) {
456
+ if ( ! isCursorCell && ! isJoined && ! isDecorated && isValidJoinRange ) {
439
457
cellAmount ++ ;
440
458
} else {
441
459
charElement . textContent = text ;
0 commit comments