6
6
*/
7
7
8
8
import 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' ;
10
10
import { DEFAULT_ANSI_COLORS } from 'browser/services/ThemeService' ;
11
11
import { IAttributeData , IColor } from 'common/Types' ;
12
12
@@ -21,24 +21,24 @@ abstract class BaseSerializeHandler {
21
21
) {
22
22
}
23
23
24
- public serialize ( range : IBufferRange ) : string {
24
+ public serialize ( range : IBufferRange , excludeFinalCursorPosition ?: boolean ) : string {
25
25
// we need two of them to flip between old and new cell
26
26
const cell1 = this . _buffer . getNullCell ( ) ;
27
27
const cell2 = this . _buffer . getNullCell ( ) ;
28
28
let oldCell = cell1 ;
29
29
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 ;
34
34
35
35
this . _beforeSerialize ( endRow - startRow , startRow , endRow ) ;
36
36
37
37
for ( let row = startRow ; row <= endRow ; row ++ ) {
38
38
const line = this . _buffer . getLine ( row ) ;
39
39
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 ;
42
42
for ( let col = startLineColumn ; col < endLineColumn ; col ++ ) {
43
43
const c = line . getCell ( col , oldCell === cell1 ? cell2 : cell1 ) ;
44
44
if ( ! c ) {
@@ -54,14 +54,14 @@ abstract class BaseSerializeHandler {
54
54
55
55
this . _afterSerialize ( ) ;
56
56
57
- return this . _serializeString ( ) ;
57
+ return this . _serializeString ( excludeFinalCursorPosition ) ;
58
58
}
59
59
60
60
protected _nextCell ( cell : IBufferCell , oldCell : IBufferCell , row : number , col : number ) : void { }
61
61
protected _rowEnd ( row : number , isLastRow : boolean ) : void { }
62
62
protected _beforeSerialize ( rows : number , startRow : number , endRow : number ) : void { }
63
63
protected _afterSerialize ( ) : void { }
64
- protected _serializeString ( ) : string { return '' ; }
64
+ protected _serializeString ( excludeFinalCursorPosition ?: boolean ) : string { return '' ; }
65
65
}
66
66
67
67
function equalFg ( cell1 : IBufferCell | IAttributeData , cell2 : IBufferCell ) : boolean {
@@ -353,7 +353,7 @@ class StringSerializeHandler extends BaseSerializeHandler {
353
353
}
354
354
}
355
355
356
- protected _serializeString ( ) : string {
356
+ protected _serializeString ( excludeFinalCursorPosition : boolean ) : string {
357
357
let rowEnd = this . _allRows . length ;
358
358
359
359
// the fixup is only required for data without scrollback
@@ -374,29 +374,31 @@ class StringSerializeHandler extends BaseSerializeHandler {
374
374
}
375
375
376
376
// 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 ;
379
380
380
- const cursorMoved = ( realCursorRow !== this . _lastCursorRow || realCursorCol !== this . _lastCursorCol ) ;
381
+ const cursorMoved = ( realCursorRow !== this . _lastCursorRow || realCursorCol !== this . _lastCursorCol ) ;
381
382
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
+ } ;
396
397
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
+ }
400
402
}
401
403
402
404
// 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 {
419
421
this . _terminal = terminal ;
420
422
}
421
423
422
- private _serializeBuffer ( terminal : Terminal , buffer : IBuffer , scrollback ?: number ) : string {
424
+ private _serializeBufferByScrollback ( terminal : Terminal , buffer : IBuffer , scrollback ?: number ) : string {
423
425
const maxRows = buffer . length ;
424
- const handler = new StringSerializeHandler ( buffer , terminal ) ;
425
426
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 ) ;
426
435
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 ) ;
430
439
}
431
440
432
441
private _serializeBufferAsHTML ( terminal : Terminal , options : Partial < IHTMLSerializeOptions > ) : string {
@@ -438,16 +447,16 @@ export class SerializeAddon implements ITerminalAddon , ISerializeApi {
438
447
const scrollback = options . scrollback ;
439
448
const correctRows = ( scrollback === undefined ) ? maxRows : constrain ( scrollback + terminal . rows , 0 , maxRows ) ;
440
449
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 }
443
452
} ) ;
444
453
}
445
454
446
455
const selection = this . _terminal ?. getSelectionPosition ( ) ;
447
456
if ( selection !== undefined ) {
448
457
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 }
451
460
} ) ;
452
461
}
453
462
@@ -490,12 +499,14 @@ export class SerializeAddon implements ITerminalAddon , ISerializeApi {
490
499
}
491
500
492
501
// 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 ) ;
494
505
495
506
// Alternate buffer
496
507
if ( ! options ?. excludeAltBuffer ) {
497
508
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 ) ;
499
510
content += `\u001b[?1049h\u001b[H${ alternativeScreenContent } ` ;
500
511
}
501
512
}
@@ -519,19 +530,6 @@ export class SerializeAddon implements ITerminalAddon , ISerializeApi {
519
530
public dispose ( ) : void { }
520
531
}
521
532
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
-
535
533
export class HTMLSerializeHandler extends BaseSerializeHandler {
536
534
private _currentRow : string = '' ;
537
535
0 commit comments