@@ -320,7 +320,37 @@ export class Buffer implements IBuffer {
320320 if ( toRemove . length > 0 ) {
321321 const newLayoutResult = reflowLargerCreateNewLayout ( this . lines , toRemove ) ;
322322 reflowLargerApplyNewLayout ( this . lines , newLayoutResult . layout ) ;
323+
324+ // For conpty, it has its own copy of the buffer _without scrollback_ internally. Its behavior
325+ // when reflowing larger is to insert empty lines at the bottom of the buffer as when lines
326+ // unwrap conpty's view cannot pull scrollback down, so it adds empty lines at the end.
327+ let removedInViewport = 0 ;
328+ const isWindowsMode = this . _optionsService . rawOptions . windowsMode || this . _optionsService . rawOptions . windowsPty . backend !== undefined || this . _optionsService . rawOptions . windowsPty . buildNumber !== undefined ;
329+ if ( isWindowsMode ) {
330+ for ( let i = ( toRemove . length / 2 ) - 1 ; i >= 0 ; i -- ) {
331+ if ( toRemove [ i * 2 + 0 ] > this . ybase + removedInViewport ) {
332+ removedInViewport += toRemove [ i * 2 + 1 ] ;
333+ }
334+ }
335+ }
336+
323337 this . _reflowLargerAdjustViewport ( newCols , newRows , newLayoutResult . countRemoved ) ;
338+
339+ // Apply empty lines for any removed in viewport for conpty.
340+ if ( isWindowsMode ) {
341+ if ( removedInViewport > 0 ) {
342+ for ( let i = 0 ; i < removedInViewport ; i ++ ) {
343+ // Just add the new missing rows on Windows as conpty reprints the screen with it's
344+ // view of the world. Once a line enters scrollback for conpty it remains there
345+ this . lines . push ( new BufferLine ( newCols , this . getNullCell ( DEFAULT_ATTR_DATA ) ) ) ;
346+ }
347+ if ( this . ybase === this . ydisp ) {
348+ this . ydisp += removedInViewport ;
349+ }
350+ this . ybase += removedInViewport ;
351+ this . y -= removedInViewport ;
352+ }
353+ }
324354 }
325355 }
326356
@@ -352,7 +382,7 @@ export class Buffer implements IBuffer {
352382 const nullCell = this . getNullCell ( DEFAULT_ATTR_DATA ) ;
353383 // Gather all BufferLines that need to be inserted into the Buffer here so that they can be
354384 // batched up and only committed once
355- const toInsert = [ ] ;
385+ const toInsert : { start : number , newLines : IBufferLine [ ] } [ ] = [ ] ;
356386 let countToInsert = 0 ;
357387 // Go backwards as many lines may be trimmed and this will avoid considering them
358388 for ( let y = this . lines . length - 1 ; y >= 0 ; y -- ) {
@@ -467,6 +497,20 @@ export class Buffer implements IBuffer {
467497 this . savedY = Math . min ( this . savedY + linesToAdd , this . ybase + newRows - 1 ) ;
468498 }
469499
500+ // For conpty, it has its own copy of the buffer _without scrollback_ internally. Its behavior
501+ // when reflowing smaller is to reflow all lines inside the viewport, and removing empty or
502+ // whitespace only lines from the bottom, until non-whitespace is hit in order to prevent
503+ // content from being pushed into the scrollback.
504+ let addedInViewport = 0 ;
505+ const isWindowsMode = this . _optionsService . rawOptions . windowsMode || this . _optionsService . rawOptions . windowsPty . backend !== undefined || this . _optionsService . rawOptions . windowsPty . buildNumber !== undefined ;
506+ if ( isWindowsMode ) {
507+ for ( let i = toInsert . length - 1 ; i >= 0 ; i -- ) {
508+ if ( toInsert [ i ] . start > this . ybase + addedInViewport ) {
509+ addedInViewport += toInsert [ i ] . newLines . length ;
510+ }
511+ }
512+ }
513+
470514 // Rearrange lines in the buffer if there are any insertions, this is done at the end rather
471515 // than earlier so that it's a single O(n) pass through the buffer, instead of O(n^2) from many
472516 // costly calls to CircularList.splice.
@@ -520,6 +564,35 @@ export class Buffer implements IBuffer {
520564 this . lines . onTrimEmitter . fire ( amountToTrim ) ;
521565 }
522566 }
567+
568+ // Apply empty lines to remove calculated earlier for conpty.
569+ if ( isWindowsMode ) {
570+ if ( addedInViewport > 0 ) {
571+ let emptyLinesAtBottom = 0 ;
572+ for ( let i = this . lines . length - 1 ; i >= this . ybase + this . y ; i -- ) {
573+ const line = this . lines . get ( i ) as BufferLine ;
574+ if ( line . isWrapped || line . getTrimmedLength ( ) > 0 ) {
575+ break ;
576+ }
577+ emptyLinesAtBottom ++ ;
578+ }
579+ const emptyLinesToRemove = Math . min ( addedInViewport , emptyLinesAtBottom ) ;
580+ if ( emptyLinesToRemove > 0 ) {
581+ for ( let i = 0 ; i < emptyLinesToRemove ; i ++ ) {
582+ this . lines . pop ( ) ;
583+ }
584+ if ( this . ybase === this . ydisp ) {
585+ this . ydisp -= emptyLinesToRemove ;
586+ }
587+ this . ybase -= emptyLinesToRemove ;
588+ this . y += emptyLinesToRemove ;
589+ this . lines . onDeleteEmitter . fire ( {
590+ index : this . lines . length - emptyLinesToRemove ,
591+ amount : emptyLinesToRemove
592+ } ) ;
593+ }
594+ }
595+ }
523596 }
524597
525598 /**
0 commit comments