66 */
77
88import type { IBuffer , IBufferCell , IBufferRange , ITerminalAddon , Terminal } from '@xterm/xterm' ;
9- import type { SerializeAddon as ISerializeApi } from '@xterm/addon-serialize' ;
9+ import type { IHTMLSerializeOptions , SerializeAddon as ISerializeApi , ISerializeOptions , ISerializeRange } from '@xterm/addon-serialize' ;
1010import { DEFAULT_ANSI_COLORS } from 'browser/services/ThemeService' ;
1111import { IAttributeData , IColor } from 'common/Types' ;
1212
@@ -21,24 +21,24 @@ abstract class BaseSerializeHandler {
2121 ) {
2222 }
2323
24- public serialize ( range : IBufferRange ) : string {
24+ public serialize ( range : IBufferRange , excludeFinalCursorPosition ?: boolean ) : string {
2525 // we need two of them to flip between old and new cell
2626 const cell1 = this . _buffer . getNullCell ( ) ;
2727 const cell2 = this . _buffer . getNullCell ( ) ;
2828 let oldCell = cell1 ;
2929
30- const startRow = range . start . x ;
31- const endRow = range . end . x ;
32- const startColumn = range . start . y ;
33- const endColumn = range . end . y ;
30+ const startRow = range . start . y ;
31+ const endRow = range . end . y ;
32+ const startColumn = range . start . x ;
33+ const endColumn = range . end . x ;
3434
3535 this . _beforeSerialize ( endRow - startRow , startRow , endRow ) ;
3636
3737 for ( let row = startRow ; row <= endRow ; row ++ ) {
3838 const line = this . _buffer . getLine ( row ) ;
3939 if ( line ) {
40- const startLineColumn = row !== range . start . x ? 0 : startColumn ;
41- const endLineColumn = row !== range . end . x ? line . length : endColumn ;
40+ const startLineColumn = row === range . start . y ? startColumn : 0 ;
41+ const endLineColumn = row === range . end . y ? endColumn : line . length ;
4242 for ( let col = startLineColumn ; col < endLineColumn ; col ++ ) {
4343 const c = line . getCell ( col , oldCell === cell1 ? cell2 : cell1 ) ;
4444 if ( ! c ) {
@@ -54,14 +54,14 @@ abstract class BaseSerializeHandler {
5454
5555 this . _afterSerialize ( ) ;
5656
57- return this . _serializeString ( ) ;
57+ return this . _serializeString ( excludeFinalCursorPosition ) ;
5858 }
5959
6060 protected _nextCell ( cell : IBufferCell , oldCell : IBufferCell , row : number , col : number ) : void { }
6161 protected _rowEnd ( row : number , isLastRow : boolean ) : void { }
6262 protected _beforeSerialize ( rows : number , startRow : number , endRow : number ) : void { }
6363 protected _afterSerialize ( ) : void { }
64- protected _serializeString ( ) : string { return '' ; }
64+ protected _serializeString ( excludeFinalCursorPosition ?: boolean ) : string { return '' ; }
6565}
6666
6767function equalFg ( cell1 : IBufferCell | IAttributeData , cell2 : IBufferCell ) : boolean {
@@ -353,7 +353,7 @@ class StringSerializeHandler extends BaseSerializeHandler {
353353 }
354354 }
355355
356- protected _serializeString ( ) : string {
356+ protected _serializeString ( excludeFinalCursorPosition : boolean ) : string {
357357 let rowEnd = this . _allRows . length ;
358358
359359 // the fixup is only required for data without scrollback
@@ -374,29 +374,31 @@ class StringSerializeHandler extends BaseSerializeHandler {
374374 }
375375
376376 // restore the cursor
377- const realCursorRow = this . _buffer . baseY + this . _buffer . cursorY ;
378- const realCursorCol = this . _buffer . cursorX ;
377+ if ( ! excludeFinalCursorPosition ) {
378+ const realCursorRow = this . _buffer . baseY + this . _buffer . cursorY ;
379+ const realCursorCol = this . _buffer . cursorX ;
379380
380- const cursorMoved = ( realCursorRow !== this . _lastCursorRow || realCursorCol !== this . _lastCursorCol ) ;
381+ const cursorMoved = ( realCursorRow !== this . _lastCursorRow || realCursorCol !== this . _lastCursorCol ) ;
381382
382- const moveRight = ( offset : number ) : void => {
383- if ( offset > 0 ) {
384- content += `\u001b[${ offset } C` ;
385- } else if ( offset < 0 ) {
386- content += `\u001b[${ - offset } D` ;
387- }
388- } ;
389- const moveDown = ( offset : number ) : void => {
390- if ( offset > 0 ) {
391- content += `\u001b[${ offset } B` ;
392- } else if ( offset < 0 ) {
393- content += `\u001b[${ - offset } A` ;
394- }
395- } ;
383+ const moveRight = ( offset : number ) : void => {
384+ if ( offset > 0 ) {
385+ content += `\u001b[${ offset } C` ;
386+ } else if ( offset < 0 ) {
387+ content += `\u001b[${ - offset } D` ;
388+ }
389+ } ;
390+ const moveDown = ( offset : number ) : void => {
391+ if ( offset > 0 ) {
392+ content += `\u001b[${ offset } B` ;
393+ } else if ( offset < 0 ) {
394+ content += `\u001b[${ - offset } A` ;
395+ }
396+ } ;
396397
397- if ( cursorMoved ) {
398- moveDown ( realCursorRow - this . _lastCursorRow ) ;
399- moveRight ( realCursorCol - this . _lastCursorCol ) ;
398+ if ( cursorMoved ) {
399+ moveDown ( realCursorRow - this . _lastCursorRow ) ;
400+ moveRight ( realCursorCol - this . _lastCursorCol ) ;
401+ }
400402 }
401403
402404 // Restore the cursor's current style, see https://github.com/xtermjs/xterm.js/issues/3677
@@ -419,14 +421,21 @@ export class SerializeAddon implements ITerminalAddon , ISerializeApi {
419421 this . _terminal = terminal ;
420422 }
421423
422- private _serializeBuffer ( terminal : Terminal , buffer : IBuffer , scrollback ?: number ) : string {
424+ private _serializeBufferByScrollback ( terminal : Terminal , buffer : IBuffer , scrollback ?: number ) : string {
423425 const maxRows = buffer . length ;
424- const handler = new StringSerializeHandler ( buffer , terminal ) ;
425426 const correctRows = ( scrollback === undefined ) ? maxRows : constrain ( scrollback + terminal . rows , 0 , maxRows ) ;
427+ return this . _serializeBufferByRange ( terminal , buffer , {
428+ start : maxRows - correctRows ,
429+ end : maxRows - 1
430+ } , false ) ;
431+ }
432+
433+ private _serializeBufferByRange ( terminal : Terminal , buffer : IBuffer , range : ISerializeRange , excludeFinalCursorPosition : boolean ) : string {
434+ const handler = new StringSerializeHandler ( buffer , terminal ) ;
426435 return handler . serialize ( {
427- start : { x : maxRows - correctRows , y : 0 } ,
428- end : { x : maxRows - 1 , y : terminal . cols }
429- } ) ;
436+ start : { x : 0 , y : typeof range . start === 'number' ? range . start : range . start . line } ,
437+ end : { x : terminal . cols , y : typeof range . end === 'number' ? range . end : range . end . line }
438+ } , excludeFinalCursorPosition ) ;
430439 }
431440
432441 private _serializeBufferAsHTML ( terminal : Terminal , options : Partial < IHTMLSerializeOptions > ) : string {
@@ -438,16 +447,16 @@ export class SerializeAddon implements ITerminalAddon , ISerializeApi {
438447 const scrollback = options . scrollback ;
439448 const correctRows = ( scrollback === undefined ) ? maxRows : constrain ( scrollback + terminal . rows , 0 , maxRows ) ;
440449 return handler . serialize ( {
441- start : { x : maxRows - correctRows , y : 0 } ,
442- end : { x : maxRows - 1 , y : terminal . cols }
450+ start : { x : 0 , y : maxRows - correctRows } ,
451+ end : { x : terminal . cols , y : maxRows - 1 }
443452 } ) ;
444453 }
445454
446455 const selection = this . _terminal ?. getSelectionPosition ( ) ;
447456 if ( selection !== undefined ) {
448457 return handler . serialize ( {
449- start : { x : selection . start . y , y : selection . start . x } ,
450- end : { x : selection . end . y , y : selection . end . x }
458+ start : { x : selection . start . x , y : selection . start . y } ,
459+ end : { x : selection . end . x , y : selection . end . y }
451460 } ) ;
452461 }
453462
@@ -490,12 +499,14 @@ export class SerializeAddon implements ITerminalAddon , ISerializeApi {
490499 }
491500
492501 // Normal buffer
493- let content = this . _serializeBuffer ( this . _terminal , this . _terminal . buffer . normal , options ?. scrollback ) ;
502+ let content = options ?. range
503+ ? this . _serializeBufferByRange ( this . _terminal , this . _terminal . buffer . normal , options . range , true )
504+ : this . _serializeBufferByScrollback ( this . _terminal , this . _terminal . buffer . normal , options ?. scrollback ) ;
494505
495506 // Alternate buffer
496507 if ( ! options ?. excludeAltBuffer ) {
497508 if ( this . _terminal . buffer . active . type === 'alternate' ) {
498- const alternativeScreenContent = this . _serializeBuffer ( this . _terminal , this . _terminal . buffer . alternate , undefined ) ;
509+ const alternativeScreenContent = this . _serializeBufferByScrollback ( this . _terminal , this . _terminal . buffer . alternate , undefined ) ;
499510 content += `\u001b[?1049h\u001b[H${ alternativeScreenContent } ` ;
500511 }
501512 }
@@ -519,19 +530,6 @@ export class SerializeAddon implements ITerminalAddon , ISerializeApi {
519530 public dispose ( ) : void { }
520531}
521532
522-
523- interface ISerializeOptions {
524- scrollback ?: number ;
525- excludeModes ?: boolean ;
526- excludeAltBuffer ?: boolean ;
527- }
528-
529- interface IHTMLSerializeOptions {
530- scrollback : number ;
531- onlySelection : boolean ;
532- includeGlobalBackground : boolean ;
533- }
534-
535533export class HTMLSerializeHandler extends BaseSerializeHandler {
536534 private _currentRow : string = '' ;
537535
0 commit comments