@@ -33,6 +33,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
3333 private _charAtlasDisposable = this . _register ( new MutableDisposable ( ) ) ;
3434 private _charAtlas : ITextureAtlas | undefined ;
3535 private _devicePixelRatio : number ;
36+ private _deviceMaxTextureSize : number ;
3637 private _observerDisposable = this . _register ( new MutableDisposable ( ) ) ;
3738
3839 private _model : RenderModel = new RenderModel ( ) ;
@@ -102,6 +103,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
102103 throw new Error ( 'WebGL2 not supported ' + this . _gl ) ;
103104 }
104105
106+ this . _deviceMaxTextureSize = this . _gl . getParameter ( this . _gl . MAX_TEXTURE_SIZE ) ;
107+
105108 this . _register ( addDisposableListener ( this . _canvas , 'webglcontextlost' , ( e ) => {
106109 console . log ( 'webglcontextlost event received' ) ;
107110 // Prevent the default behavior in order to enable WebGL context restoration.
@@ -272,7 +275,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
272275 this . dimensions . device . cell . height ,
273276 this . dimensions . device . char . width ,
274277 this . dimensions . device . char . height ,
275- this . _coreBrowserService . dpr
278+ this . _coreBrowserService . dpr ,
279+ this . _deviceMaxTextureSize
276280 ) ;
277281 if ( this . _charAtlas !== atlas ) {
278282 this . _onChangeTextureAtlas . fire ( atlas . pages [ 0 ] . canvas ) ;
@@ -354,7 +358,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
354358 }
355359
356360 private _updateCursorBlink ( ) : void {
357- if ( this . _terminal . options . cursorBlink ) {
361+ if ( this . _coreService . decPrivateModes . cursorBlink ?? this . _terminal . options . cursorBlink ) {
358362 this . _cursorBlinkStateManager . value = new CursorBlinkStateManager ( ( ) => {
359363 this . _requestRedrawCursor ( ) ;
360364 } , this . _coreBrowserService ) ;
@@ -377,8 +381,11 @@ export class WebglRenderer extends Disposable implements IRenderer {
377381 let line : IBufferLine ;
378382 let joinedRanges : [ number , number ] [ ] ;
379383 let isJoined : boolean ;
384+ let skipJoinedCheckUntilX : number = 0 ;
385+ let isValidJoinRange : boolean = true ;
380386 let lastCharX : number ;
381387 let range : [ number , number ] ;
388+ let isCursorRow : boolean ;
382389 let chars : string ;
383390 let code : number ;
384391 let width : number ;
@@ -387,6 +394,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
387394 let j : number ;
388395 start = clamp ( start , terminal . rows - 1 , 0 ) ;
389396 end = clamp ( end , terminal . rows - 1 , 0 ) ;
397+ const cursorStyle = this . _coreService . decPrivateModes . cursorStyle ?? terminal . options . cursorStyle ?? 'block' ;
390398
391399 const cursorY = this . _terminal . buffer . active . baseY + this . _terminal . buffer . active . cursorY ;
392400 const viewportRelativeCursorY = cursorY - terminal . buffer . ydisp ;
@@ -404,6 +412,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
404412 row = y + terminal . buffer . ydisp ;
405413 line = terminal . buffer . lines . get ( row ) ! ;
406414 this . _model . lineLengths [ y ] = 0 ;
415+ isCursorRow = cursorY === row ;
416+ skipJoinedCheckUntilX = 0 ;
407417 joinedRanges = this . _characterJoinerService . getJoinedCharacters ( row ) ;
408418 for ( x = 0 ; x < terminal . cols ; x ++ ) {
409419 lastBg = this . _cellColorResolver . result . bg ;
@@ -415,25 +425,43 @@ export class WebglRenderer extends Disposable implements IRenderer {
415425
416426 // If true, indicates that the current character(s) to draw were joined.
417427 isJoined = false ;
428+
429+ // Indicates whether this cell is part of a joined range that should be ignored as it cannot
430+ // be rendered entirely, like the selection state differs across the range.
431+ isValidJoinRange = ( x >= skipJoinedCheckUntilX ) ;
432+
418433 lastCharX = x ;
419434
420435 // Process any joined character ranges as needed. Because of how the
421436 // ranges are produced, we know that they are valid for the characters
422437 // and attributes of our input.
423- if ( joinedRanges . length > 0 && x === joinedRanges [ 0 ] [ 0 ] ) {
424- isJoined = true ;
438+ if ( joinedRanges . length > 0 && x === joinedRanges [ 0 ] [ 0 ] && isValidJoinRange ) {
425439 range = joinedRanges . shift ( ) ! ;
426440
427- // We already know the exact start and end column of the joined range,
428- // so we get the string and width representing it directly.
429- cell = new JoinedCellData (
430- cell ,
431- line ! . translateToString ( true , range [ 0 ] , range [ 1 ] ) ,
432- range [ 1 ] - range [ 0 ]
433- ) ;
434-
435- // Skip over the cells occupied by this range in the loop
436- lastCharX = range [ 1 ] - 1 ;
441+ // If the ligature's selection state is not consistent, don't join it. This helps the
442+ // selection render correctly regardless whether they should be joined.
443+ const firstSelectionState = this . _model . selection . isCellSelected ( this . _terminal , range [ 0 ] , row ) ;
444+ for ( i = range [ 0 ] + 1 ; i < range [ 1 ] ; i ++ ) {
445+ isValidJoinRange &&= ( firstSelectionState === this . _model . selection . isCellSelected ( this . _terminal , i , row ) ) ;
446+ }
447+ // Similarly, if the cursor is in the ligature, don't join it.
448+ isValidJoinRange &&= ! isCursorRow || cursorX < range [ 0 ] || cursorX >= range [ 1 ] ;
449+ if ( ! isValidJoinRange ) {
450+ skipJoinedCheckUntilX = range [ 1 ] ;
451+ } else {
452+ isJoined = true ;
453+
454+ // We already know the exact start and end column of the joined range,
455+ // so we get the string and width representing it directly.
456+ cell = new JoinedCellData (
457+ cell ,
458+ line ! . translateToString ( true , range [ 0 ] , range [ 1 ] ) ,
459+ range [ 1 ] - range [ 0 ]
460+ ) ;
461+
462+ // Skip over the cells occupied by this range in the loop
463+ lastCharX = range [ 1 ] - 1 ;
464+ }
437465 }
438466
439467 chars = cell . getChars ( ) ;
@@ -450,18 +478,18 @@ export class WebglRenderer extends Disposable implements IRenderer {
450478 x : cursorX ,
451479 y : viewportRelativeCursorY ,
452480 width : cell . getWidth ( ) ,
453- style : this . _coreBrowserService . isFocused ?
454- ( terminal . options . cursorStyle || 'block' ) : terminal . options . cursorInactiveStyle ,
481+ style : this . _coreBrowserService . isFocused ? cursorStyle : terminal . options . cursorInactiveStyle ,
455482 cursorWidth : terminal . options . cursorWidth ,
456483 dpr : this . _devicePixelRatio
457484 } ;
458485 lastCursorX = cursorX + cell . getWidth ( ) - 1 ;
459486 }
460487 if ( x >= cursorX && x <= lastCursorX &&
461488 ( ( this . _coreBrowserService . isFocused &&
462- ( terminal . options . cursorStyle || 'block' ) === 'block' ) ||
489+ cursorStyle === 'block' ) ||
463490 ( this . _coreBrowserService . isFocused === false &&
464- terminal . options . cursorInactiveStyle === 'block' ) ) ) {
491+ terminal . options . cursorInactiveStyle === 'block' ) )
492+ ) {
465493 this . _cellColorResolver . result . fg =
466494 Attributes . CM_RGB | ( this . _themeService . colors . cursorAccent . rgba >> 8 & Attributes . RGB_MASK ) ;
467495 this . _cellColorResolver . result . bg =
0 commit comments