@finos/legend-application 10.2.12 → 10.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -191,6 +191,9 @@ export class XTerm extends Terminal {
191
191
  overviewRulerWidth: 14, // 14px
192
192
  scrollback: 10000, // buffer a substantial content length
193
193
  convertEol: true, // treat \n as new line
194
+
195
+ // this is needed so we can control the cursor programmatically using escape sequences
196
+ scrollOnUserInput: false,
194
197
  });
195
198
 
196
199
  this.resizer = new XTermFitAddon();
@@ -319,12 +322,18 @@ export class XTerm extends Terminal {
319
322
  return;
320
323
  }
321
324
  this.isRunningCommand = true;
322
- matchingCommand.handler(args, command, text).finally(() => {
323
- this.isRunningCommand = false;
324
- if (!this.isFlushed) {
325
- this.abort();
326
- }
327
- });
325
+ matchingCommand
326
+ .handler(
327
+ args.map((arg) => arg.trim()),
328
+ command,
329
+ text,
330
+ )
331
+ .finally(() => {
332
+ this.isRunningCommand = false;
333
+ if (!this.isFlushed) {
334
+ this.abort();
335
+ }
336
+ });
328
337
  }
329
338
  } else if (
330
339
  isMatchingKeyCombination(domEvent, 'Control+KeyC') ||
@@ -336,44 +345,38 @@ export class XTerm extends Terminal {
336
345
  // Alt: jump word only, Ctrl: jump to end
337
346
  // this would apply for Delete, ArrowLeft, ArrowRight
338
347
  this.deleteFromCommand(
339
- domEvent.altKey
340
- ? this.computeCursorJumpMovement(true, true)
341
- : domEvent.ctrlKey
342
- ? this.computeCursorJumpMovement(true, false)
348
+ domEvent.altKey || domEvent.ctrlKey
349
+ ? this.computeCursorJumpMovement(true)
343
350
  : -1,
344
351
  );
345
352
  } else if (domEvent.code === 'Delete') {
346
353
  this.deleteFromCommand(
347
- domEvent.altKey
348
- ? this.computeCursorJumpMovement(false, true)
349
- : domEvent.ctrlKey
350
- ? this.computeCursorJumpMovement(false, false)
354
+ domEvent.altKey || domEvent.ctrlKey
355
+ ? this.computeCursorJumpMovement(false)
351
356
  : 1,
352
357
  );
353
358
  } else if (domEvent.code === 'ArrowLeft') {
354
- this.instance.write(
355
- this.generateMoveCursorANSISeq(
356
- domEvent.altKey
357
- ? this.computeCursorJumpMovement(true, true)
358
- : domEvent.ctrlKey
359
- ? this.computeCursorJumpMovement(true, false)
360
- : -1,
361
- ),
359
+ const movement = this.computeCursorMovement(
360
+ domEvent.altKey || domEvent.ctrlKey
361
+ ? this.computeCursorJumpMovement(true)
362
+ : -1,
362
363
  );
364
+ // console.log('left', movement);
365
+ this.instance.scrollLines(movement.scroll);
366
+ this.instance.write(movement.seq);
363
367
  } else if (domEvent.code === 'ArrowRight') {
364
- this.instance.write(
365
- this.generateMoveCursorANSISeq(
366
- domEvent.altKey
367
- ? this.computeCursorJumpMovement(false, true)
368
- : domEvent.ctrlKey
369
- ? this.computeCursorJumpMovement(false, false)
370
- : 1,
371
- ),
368
+ const movement = this.computeCursorMovement(
369
+ domEvent.altKey || domEvent.ctrlKey
370
+ ? this.computeCursorJumpMovement(false)
371
+ : 1,
372
372
  );
373
+ // console.log('right', movement);
374
+ this.instance.scrollLines(movement.scroll);
375
+ this.instance.write(movement.seq);
373
376
  } else if (
374
377
  // use key here so we absolute do not allow any characters other than these
375
378
  // being added to the input command
376
- key.match(/^[A-Za-z0-9!@#$%^&*()-_=+"':;,.<>/?[\]{}|\\~` \\t]$/)
379
+ key.match(/^[A-Za-z0-9!@#$%^&*()\-_=+"':;,.<>/?[\]{}|\\~` ]$/)
377
380
  ) {
378
381
  // commonly supported keys
379
382
  this.writeToCommand(key);
@@ -392,10 +395,7 @@ export class XTerm extends Terminal {
392
395
  this.writeToCommand(
393
396
  val
394
397
  // remove all unsupported characters, including newline
395
- .replaceAll(
396
- /[^A-Za-z0-9!@#$%^&*()-_=+"':;,.<>/?[\]{}|\\~` \\t]/g,
397
- '',
398
- )
398
+ .replaceAll(/[^A-Za-z0-9!@#$%^&*()\-_=+"':;,.<>/?[\]{}|\\~` ]/g, '')
399
399
  .trimEnd(),
400
400
  );
401
401
  }
@@ -458,43 +458,38 @@ export class XTerm extends Terminal {
458
458
  };
459
459
  }
460
460
 
461
- private computeCursorJumpMovement(
462
- back: boolean,
463
- jumpWordOnly: boolean,
464
- ): number {
461
+ private computeCursorJumpMovement(back: boolean): number {
465
462
  const range = this.getCommandRange();
466
463
 
467
464
  let distance: number | undefined = undefined;
468
465
  let foundWord = false;
469
466
 
470
467
  // scan for the boundary of the closest word to the cursor position
471
- if (jumpWordOnly) {
472
- if (back) {
473
- for (let i = range.cursorIdx - 1; i > -1; --i) {
474
- const char = this.command.charAt(i);
475
- if (char.match(/\w/)) {
476
- if (!foundWord) {
477
- foundWord = true;
478
- }
479
- } else {
480
- if (foundWord) {
481
- distance = range.cursorIdx - i - 1;
482
- break;
483
- }
468
+ if (back) {
469
+ for (let i = range.cursorIdx - 1; i > -1; --i) {
470
+ const char = this.command.charAt(i);
471
+ if (char.match(/\w/)) {
472
+ if (!foundWord) {
473
+ foundWord = true;
474
+ }
475
+ } else {
476
+ if (foundWord) {
477
+ distance = range.cursorIdx - i - 1;
478
+ break;
484
479
  }
485
480
  }
486
- } else {
487
- for (let i = range.cursorIdx + 1; i < this.command.length; ++i) {
488
- const char = this.command.charAt(i);
489
- if (char.match(/\w/)) {
490
- if (!foundWord) {
491
- foundWord = true;
492
- }
493
- } else {
494
- if (foundWord) {
495
- distance = i - range.cursorIdx - 1;
496
- break;
497
- }
481
+ }
482
+ } else {
483
+ for (let i = range.cursorIdx + 1; i < this.command.length; ++i) {
484
+ const char = this.command.charAt(i);
485
+ if (char.match(/\w/)) {
486
+ if (!foundWord) {
487
+ foundWord = true;
488
+ }
489
+ } else {
490
+ if (foundWord) {
491
+ distance = i - range.cursorIdx - 1;
492
+ break;
498
493
  }
499
494
  }
500
495
  }
@@ -513,11 +508,15 @@ export class XTerm extends Terminal {
513
508
  *
514
509
  * @param val a number (negative means cursor move leftwards)
515
510
  * @param limit whether to limit the movement of the cursor by the command range
516
- * @returns ANSI escape sequence for new cursor position
511
+ * @returns cursor movement information including the ANSI escape sequence for new cursor position and scroll distance
517
512
  */
518
- private generateMoveCursorANSISeq(val: number, limit = true): string {
513
+ private computeCursorMovement(
514
+ val: number,
515
+ limit = true,
516
+ ): { seq: string; scroll: number } {
519
517
  const buffer = this.instance.buffer.active;
520
518
  const cols = this.instance.cols;
519
+ const rows = this.instance.rows;
521
520
  const range = this.getCommandRange();
522
521
 
523
522
  const maxDistance = limit
@@ -529,25 +528,44 @@ export class XTerm extends Terminal {
529
528
 
530
529
  let newCursorX = buffer.cursorX;
531
530
  let newCursorY = buffer.cursorY;
531
+ let abs_cursorY = buffer.baseY + buffer.cursorY;
532
532
 
533
533
  if (val < 0) {
534
534
  // move leftwards
535
535
  newCursorX = (cols + ((buffer.cursorX - distance) % cols)) % cols;
536
536
  newCursorY =
537
- buffer.baseY +
538
537
  buffer.cursorY -
539
538
  (distance > buffer.cursorX ? Math.ceil(distance / cols) : 0);
539
+ abs_cursorY = newCursorY + buffer.baseY;
540
+ newCursorY = Math.max(newCursorY, -1);
540
541
  } else if (val > 0) {
541
542
  // move rightwards
542
543
  newCursorX = (buffer.cursorX + distance) % cols;
543
544
  newCursorY =
544
- buffer.baseY +
545
545
  buffer.cursorY +
546
546
  (buffer.cursorX + distance >= cols
547
547
  ? Math.floor((buffer.cursorX + distance) / cols)
548
548
  : 0);
549
+ abs_cursorY = newCursorY + buffer.baseY;
550
+ newCursorY = Math.min(newCursorY, rows - 1);
549
551
  }
550
- return ANSI_moveCursor(newCursorY + 1, newCursorX + 1);
552
+
553
+ const scroll =
554
+ abs_cursorY > buffer.viewportY + rows
555
+ ? abs_cursorY - (buffer.viewportY + rows)
556
+ : abs_cursorY < buffer.viewportY
557
+ ? abs_cursorY - buffer.viewportY
558
+ : 0;
559
+
560
+ return {
561
+ // NOTE: currently, there is a design limitation with programmatically set the cursor using escape sequence
562
+ // by design, the scrollback (everything above the viewport/ybase) is readonly, and most terminals work like this.
563
+ // So for very long command that causes an overflow, one cannot set the cursor position pass the `baseY`
564
+ // this will affect both navigation and delete/backspace behavior
565
+ // See https://github.com/xtermjs/xterm.js/issues/4405
566
+ seq: ANSI_moveCursor(newCursorY + 1, newCursorX + 1),
567
+ scroll,
568
+ };
551
569
  }
552
570
 
553
571
  /**
@@ -557,12 +575,14 @@ export class XTerm extends Terminal {
557
575
  const range = this.getCommandRange();
558
576
  const left = this.command.slice(0, range.cursorIdx);
559
577
  const right = this.command.slice(range.cursorIdx);
578
+ const movement = this.computeCursorMovement(val.length, false);
560
579
 
580
+ this.instance.scrollLines(movement.scroll);
561
581
  this.instance.write(
562
582
  val +
563
583
  right +
564
584
  // update the cursor
565
- this.generateMoveCursorANSISeq(val.length, false),
585
+ movement.seq,
566
586
  );
567
587
  this.setCommand(left + val + right);
568
588
  }
@@ -572,7 +592,10 @@ export class XTerm extends Terminal {
572
592
  * NOTE: negative number means backward deleting (i.e. backspace)
573
593
  */
574
594
  private deleteFromCommand(val: number): void {
595
+ // console.log(val);
596
+
575
597
  const range = this.getCommandRange();
598
+
576
599
  const maxDistance =
577
600
  val < 0 ? range.cursorIdx : this.command.length - range.cursorIdx;
578
601
  const distance = Math.min(Math.abs(val), maxDistance);
@@ -597,6 +620,9 @@ export class XTerm extends Terminal {
597
620
  cursorMovement = 0;
598
621
  }
599
622
 
623
+ const movement = this.computeCursorMovement(cursorMovement);
624
+
625
+ this.instance.scrollLines(movement.scroll);
600
626
  this.instance.write(
601
627
  // reset cursor to start of command, basically here, we're rewriting the entire command
602
628
  ANSI_moveCursor(range.startY + 1, range.startX + 1) +
@@ -605,7 +631,7 @@ export class XTerm extends Terminal {
605
631
  // fill space to erase cells rendered from previous command
606
632
  ' '.repeat(distance) +
607
633
  // move the cursor as well
608
- this.generateMoveCursorANSISeq(cursorMovement),
634
+ movement.seq,
609
635
  );
610
636
  this.setCommand(left + right);
611
637
  }
@@ -796,7 +822,7 @@ export class XTerm extends Terminal {
796
822
  output(val: string, opts?: TerminalWriteOption): void {
797
823
  this.resetANSIStyling();
798
824
 
799
- if (!opts?.clear && opts?.systemCommand) {
825
+ if ((!opts?.clear || this.preserveLog) && opts?.systemCommand) {
800
826
  this.newSystemCommand(opts.systemCommand);
801
827
  }
802
828