@theia/terminal 1.45.1 → 1.46.0-next.137

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.
Files changed (61) hide show
  1. package/lib/browser/base/terminal-widget.d.ts +10 -0
  2. package/lib/browser/base/terminal-widget.d.ts.map +1 -1
  3. package/lib/browser/base/terminal-widget.js.map +1 -1
  4. package/lib/browser/index.js +2 -11
  5. package/lib/browser/index.js.map +1 -1
  6. package/lib/browser/search/terminal-search-widget.js +8 -16
  7. package/lib/browser/search/terminal-search-widget.js.map +1 -1
  8. package/lib/browser/terminal-copy-on-selection-handler.js +6 -14
  9. package/lib/browser/terminal-copy-on-selection-handler.js.map +1 -1
  10. package/lib/browser/terminal-file-link-provider.d.ts +10 -0
  11. package/lib/browser/terminal-file-link-provider.d.ts.map +1 -1
  12. package/lib/browser/terminal-file-link-provider.js +82 -23
  13. package/lib/browser/terminal-file-link-provider.js.map +1 -1
  14. package/lib/browser/terminal-frontend-contribution.d.ts +2 -0
  15. package/lib/browser/terminal-frontend-contribution.d.ts.map +1 -1
  16. package/lib/browser/terminal-frontend-contribution.js +72 -49
  17. package/lib/browser/terminal-frontend-contribution.js.map +1 -1
  18. package/lib/browser/terminal-frontend-module.d.ts.map +1 -1
  19. package/lib/browser/terminal-frontend-module.js +2 -0
  20. package/lib/browser/terminal-frontend-module.js.map +1 -1
  21. package/lib/browser/terminal-link-provider.js +19 -27
  22. package/lib/browser/terminal-link-provider.js.map +1 -1
  23. package/lib/browser/terminal-preferences.d.ts.map +1 -1
  24. package/lib/browser/terminal-preferences.js +2 -1
  25. package/lib/browser/terminal-preferences.js.map +1 -1
  26. package/lib/browser/terminal-profile-service.js +4 -12
  27. package/lib/browser/terminal-profile-service.js.map +1 -1
  28. package/lib/browser/terminal-quick-open-service.js +13 -21
  29. package/lib/browser/terminal-quick-open-service.js.map +1 -1
  30. package/lib/browser/terminal-theme-service.d.ts.map +1 -1
  31. package/lib/browser/terminal-theme-service.js +12 -16
  32. package/lib/browser/terminal-theme-service.js.map +1 -1
  33. package/lib/browser/terminal-url-link-provider.js +4 -12
  34. package/lib/browser/terminal-url-link-provider.js.map +1 -1
  35. package/lib/browser/terminal-widget-impl.d.ts +9 -12
  36. package/lib/browser/terminal-widget-impl.d.ts.map +1 -1
  37. package/lib/browser/terminal-widget-impl.js +111 -105
  38. package/lib/browser/terminal-widget-impl.js.map +1 -1
  39. package/lib/common/terminal-watcher.js +2 -7
  40. package/lib/common/terminal-watcher.js.map +1 -1
  41. package/lib/node/base-terminal-server.js +6 -17
  42. package/lib/node/base-terminal-server.js.map +1 -1
  43. package/lib/node/index.js +2 -11
  44. package/lib/node/index.js.map +1 -1
  45. package/lib/node/shell-process.js +10 -21
  46. package/lib/node/shell-process.js.map +1 -1
  47. package/lib/node/shell-terminal-server.js +9 -20
  48. package/lib/node/shell-terminal-server.js.map +1 -1
  49. package/lib/node/terminal-backend-contribution.js +6 -14
  50. package/lib/node/terminal-backend-contribution.js.map +1 -1
  51. package/lib/node/terminal-server.js +8 -19
  52. package/lib/node/terminal-server.js.map +1 -1
  53. package/package.json +14 -12
  54. package/src/browser/base/terminal-widget.ts +13 -0
  55. package/src/browser/terminal-file-link-provider.ts +66 -7
  56. package/src/browser/terminal-frontend-contribution.ts +38 -3
  57. package/src/browser/terminal-frontend-module.ts +3 -1
  58. package/src/browser/terminal-preferences.ts +2 -1
  59. package/src/browser/terminal-theme-service.ts +6 -2
  60. package/src/browser/terminal-widget-impl.ts +94 -62
  61. package/src/node/shell-process.ts +1 -1
@@ -14,7 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { Terminal, RendererType } from 'xterm';
17
+ import { Terminal } from 'xterm';
18
18
  import { FitAddon } from 'xterm-addon-fit';
19
19
  import { inject, injectable, named, postConstruct } from '@theia/core/shared/inversify';
20
20
  import { ContributionProvider, Disposable, Event, Emitter, ILogger, DisposableCollection, Channel, OS } from '@theia/core';
@@ -29,10 +29,11 @@ import { IBaseTerminalServer, TerminalProcessInfo, TerminalExitReason } from '..
29
29
  import { TerminalWatcher } from '../common/terminal-watcher';
30
30
  import {
31
31
  TerminalWidgetOptions, TerminalWidget, TerminalDimensions, TerminalExitStatus, TerminalLocationOptions,
32
- TerminalLocation
32
+ TerminalLocation,
33
+ TerminalBuffer
33
34
  } from './base/terminal-widget';
34
35
  import { Deferred } from '@theia/core/lib/common/promise-util';
35
- import { TerminalPreferences, TerminalRendererType, isTerminalRendererType, DEFAULT_TERMINAL_RENDERER_TYPE, CursorStyle } from './terminal-preferences';
36
+ import { TerminalPreferences } from './terminal-preferences';
36
37
  import URI from '@theia/core/lib/common/uri';
37
38
  import { TerminalService } from './base/terminal-service';
38
39
  import { TerminalSearchWidgetFactory, TerminalSearchWidget } from './search/terminal-search-widget';
@@ -60,6 +61,23 @@ export interface TerminalContribution {
60
61
  onCreate(term: TerminalWidgetImpl): void;
61
62
  }
62
63
 
64
+ class TerminalBufferImpl implements TerminalBuffer {
65
+ constructor(private readonly term: Terminal) {
66
+ }
67
+
68
+ get length(): number {
69
+ return this.term.buffer.active.length;
70
+ };
71
+ getLines(start: number, length: number): string[] {
72
+ const result: string[] = [];
73
+ for (let i = 0; i < length && this.length - 1 - i >= 0; i++) {
74
+ result.push(this.term.buffer.active.getLine(this.length - 1 - i)!.translateToString());
75
+ }
76
+ return result;
77
+ }
78
+
79
+ }
80
+
63
81
  @injectable()
64
82
  export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget, ExtractableWidget, EnhancedPreviewWidget {
65
83
  readonly isExtractable: boolean = true;
@@ -123,6 +141,9 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
123
141
  protected readonly onDataEmitter = new Emitter<string>();
124
142
  readonly onData: Event<string> = this.onDataEmitter.event;
125
143
 
144
+ protected readonly onOutputEmitter = new Emitter<string>();
145
+ readonly onOutput: Event<string> = this.onOutputEmitter.event;
146
+
126
147
  protected readonly onKeyEmitter = new Emitter<{ key: string, domEvent: KeyboardEvent }>();
127
148
  readonly onKey: Event<{ key: string, domEvent: KeyboardEvent }> = this.onKeyEmitter.event;
128
149
 
@@ -134,6 +155,11 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
134
155
 
135
156
  protected readonly toDisposeOnConnect = new DisposableCollection();
136
157
 
158
+ private _buffer: TerminalBuffer;
159
+ override get buffer(): TerminalBuffer {
160
+ return this._buffer;
161
+ }
162
+
137
163
  @postConstruct()
138
164
  protected init(): void {
139
165
  this.setTitle(this.options.title || TerminalWidgetImpl.LABEL);
@@ -161,7 +187,7 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
161
187
 
162
188
  this.term = new Terminal({
163
189
  cursorBlink: this.preferences['terminal.integrated.cursorBlinking'],
164
- cursorStyle: this.getCursorStyle(),
190
+ cursorStyle: this.preferences['terminal.integrated.cursorStyle'] === 'line' ? 'bar' : this.preferences['terminal.integrated.cursorStyle'],
165
191
  cursorWidth: this.preferences['terminal.integrated.cursorWidth'],
166
192
  fontFamily: this.preferences['terminal.integrated.fontFamily'],
167
193
  fontSize: this.preferences['terminal.integrated.fontSize'],
@@ -172,9 +198,9 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
172
198
  lineHeight: this.preferences['terminal.integrated.lineHeight'],
173
199
  scrollback: this.preferences['terminal.integrated.scrollback'],
174
200
  fastScrollSensitivity: this.preferences['terminal.integrated.fastScrollSensitivity'],
175
- rendererType: this.getTerminalRendererType(this.preferences['terminal.integrated.rendererType']),
176
201
  theme: this.themeService.theme
177
202
  });
203
+ this._buffer = new TerminalBufferImpl(this.term);
178
204
 
179
205
  this.fitAddon = new FitAddon();
180
206
  this.term.loadAddon(this.fitAddon);
@@ -182,34 +208,12 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
182
208
  this.initializeLinkHover();
183
209
 
184
210
  this.toDispose.push(this.preferences.onPreferenceChanged(change => {
185
- const lastSeparator = change.preferenceName.lastIndexOf('.');
186
- if (lastSeparator > 0) {
187
- let preferenceName = change.preferenceName.substring(lastSeparator + 1);
188
- let preferenceValue = change.newValue;
189
-
190
- if (preferenceName === 'rendererType') {
191
- const newRendererType = preferenceValue as string;
192
- if (newRendererType !== this.getTerminalRendererType(newRendererType)) {
193
- // Given terminal renderer type is not supported or invalid
194
- preferenceValue = DEFAULT_TERMINAL_RENDERER_TYPE;
195
- }
196
- } else if (preferenceName === 'cursorBlinking') {
197
- // Convert the terminal preference into a valid `xterm` option
198
- preferenceName = 'cursorBlink';
199
- } else if (preferenceName === 'cursorStyle') {
200
- preferenceValue = this.getCursorStyle();
201
- }
202
- try {
203
- this.term.setOption(preferenceName, preferenceValue);
204
- } catch (e) {
205
- console.debug(`xterm configuration: '${preferenceName}' with value '${preferenceValue}' is not valid.`);
206
- }
207
- this.needsResize = true;
208
- this.update();
209
- }
211
+ this.updateConfig();
212
+ this.needsResize = true;
213
+ this.update();
210
214
  }));
211
215
 
212
- this.toDispose.push(this.themeService.onDidChange(() => this.term.setOption('theme', this.themeService.theme)));
216
+ this.toDispose.push(this.themeService.onDidChange(() => this.term.options.theme = this.themeService.theme));
213
217
  this.attachCustomKeyEventHandler();
214
218
  const titleChangeListenerDispose = this.term.onTitleChange((title: string) => {
215
219
  if (this.options.useServerTitle) {
@@ -314,25 +318,38 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
314
318
  return this.terminalKind;
315
319
  }
316
320
 
317
- /**
318
- * Get the cursor style compatible with `xterm`.
319
- * @returns CursorStyle
320
- */
321
- private getCursorStyle(): CursorStyle {
322
- const value = this.preferences['terminal.integrated.cursorStyle'];
323
- return value === 'line' ? 'bar' : value;
321
+ updateConfig(): void {
322
+ this.setCursorBlink(this.preferences.get('terminal.integrated.cursorBlinking'));
323
+ this.setCursorStyle(this.preferences.get('terminal.integrated.cursorStyle'));
324
+ this.setCursorWidth(this.preferences.get('terminal.integrated.cursorWidth'));
325
+ this.term.options.fontFamily = this.preferences.get('terminal.integrated.fontFamily');
326
+ this.term.options.fontSize = this.preferences.get('terminal.integrated.fontSize');
327
+ this.term.options.fontWeight = this.preferences.get('terminal.integrated.fontWeight');
328
+ this.term.options.fontWeightBold = this.preferences.get('terminal.integrated.fontWeightBold');
329
+ this.term.options.drawBoldTextInBrightColors = this.preferences.get('terminal.integrated.drawBoldTextInBrightColors');
330
+ this.term.options.letterSpacing = this.preferences.get('terminal.integrated.letterSpacing');
331
+ this.term.options.lineHeight = this.preferences.get('terminal.integrated.lineHeight');
332
+ this.term.options.scrollback = this.preferences.get('terminal.integrated.scrollback');
333
+ this.term.options.fastScrollSensitivity = this.preferences.get('terminal.integrated.fastScrollSensitivity');
324
334
  }
325
335
 
326
- /**
327
- * Returns given renderer type if it is valid and supported or default renderer otherwise.
328
- *
329
- * @param terminalRendererType desired terminal renderer type
330
- */
331
- private getTerminalRendererType(terminalRendererType?: string | TerminalRendererType): RendererType {
332
- if (terminalRendererType && isTerminalRendererType(terminalRendererType)) {
333
- return terminalRendererType;
336
+ private setCursorBlink(blink: boolean): void {
337
+ if (this.term.options.cursorBlink !== blink) {
338
+ this.term.options.cursorBlink = blink;
339
+ this.term.refresh(0, this.term.rows - 1);
340
+ }
341
+ }
342
+
343
+ private setCursorStyle(style: 'block' | 'underline' | 'bar' | 'line'): void {
344
+ if (this.term.options.cursorStyle !== style) {
345
+ this.term.options.cursorStyle = (style === 'line') ? 'bar' : style;
346
+ }
347
+ }
348
+
349
+ private setCursorWidth(width: number): void {
350
+ if (this.term.options.cursorWidth !== width) {
351
+ this.term.options.cursorWidth = width;
334
352
  }
335
- return DEFAULT_TERMINAL_RENDERER_TYPE;
336
353
  }
337
354
 
338
355
  protected initializeLinkHover(): void {
@@ -611,8 +628,6 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
611
628
  if (this.needsResize) {
612
629
  this.resizeTerminal();
613
630
  this.needsResize = false;
614
-
615
- this.resizeTerminalProcess();
616
631
  }
617
632
  }
618
633
 
@@ -672,16 +687,34 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
672
687
  }
673
688
  this.term.open(this.node);
674
689
 
690
+ interface ViewportType {
691
+ register(d: Disposable): void;
692
+ _refreshAnimationFrame: number | null;
693
+ _coreBrowserService: {
694
+ window: Window;
695
+ }
696
+ }
697
+
698
+ // Workaround for https://github.com/xtermjs/xterm.js/issues/4775. Can be removed for releases > 5.3.0
699
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
700
+ const viewPort: ViewportType = (this.term as any)._core.viewport;
701
+ viewPort.register(Disposable.create(() => {
702
+ if (typeof viewPort._refreshAnimationFrame === 'number') {
703
+ viewPort._coreBrowserService.window.cancelAnimationFrame(viewPort._refreshAnimationFrame);
704
+ }
705
+ }));
706
+
675
707
  if (isFirefox) {
676
708
  // monkey patching intersection observer handling for secondary window support
677
709
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
678
710
  const renderService: any = (this.term as any)._core._renderService;
679
- const originalFunc: (entry: IntersectionObserverEntry) => void = renderService._onIntersectionChange.bind(renderService);
711
+
712
+ const originalFunc: (entry: IntersectionObserverEntry) => void = renderService._handleIntersectionChange.bind(renderService);
680
713
  const replacement = function (entry: IntersectionObserverEntry): void {
681
714
  if (entry.target.ownerDocument !== document) {
682
715
  // in Firefox, the intersection observer always reports the widget as non-intersecting if the dom element
683
716
  // is in a different document from when the IntersectionObserver started observing. Since we know
684
- // that the widget is always "visible" when in a secondary window, so we mark the entry as "intersecting"
717
+ // that the widget is always "visible" when in a secondary window, so we refresh the rows ourselves
685
718
  const patchedEvent: IntersectionObserverEntry = {
686
719
  ...entry,
687
720
  isIntersecting: true,
@@ -692,7 +725,7 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
692
725
  }
693
726
  };
694
727
 
695
- renderService._onIntersectionChange = replacement;
728
+ renderService._handleIntersectionChange = replacement.bind(renderService);
696
729
  }
697
730
 
698
731
  if (this.initialData) {
@@ -700,18 +733,12 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
700
733
  }
701
734
  this.termOpened = true;
702
735
  this.initialData = '';
703
-
704
- if (isFirefox) {
705
- // The software scrollbars don't work with xterm.js, so we disable the scrollbar if we are on firefox.
706
- if (this.term.element) {
707
- (this.term.element.children.item(0) as HTMLElement).style.overflow = 'hidden';
708
- }
709
- }
710
736
  }
711
737
 
712
738
  write(data: string): void {
713
739
  if (this.termOpened) {
714
740
  this.term.write(data);
741
+ this.onOutputEmitter.fire(data);
715
742
  } else {
716
743
  this.initialData += data;
717
744
  }
@@ -763,6 +790,7 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
763
790
 
764
791
  writeLine(text: string): void {
765
792
  this.term.writeln(text);
793
+ this.onOutputEmitter.fire(text + '\n');
766
794
  }
767
795
 
768
796
  get onTerminalDidClose(): Event<TerminalWidget> {
@@ -794,9 +822,13 @@ export class TerminalWidgetImpl extends TerminalWidget implements StatefulWidget
794
822
  return;
795
823
  }
796
824
  const geo = this.fitAddon.proposeDimensions();
797
- const cols = geo.cols;
798
- const rows = geo.rows - 1; // subtract one row for margin
799
- this.term.resize(cols, rows);
825
+ if (geo) {
826
+ const cols = geo.cols;
827
+ const rows = geo.rows - 1; // subtract one row for margin
828
+ this.term.resize(cols, rows);
829
+
830
+ this.resizeTerminalProcess();
831
+ }
800
832
  }
801
833
 
802
834
  protected resizeTerminalProcess(): void {
@@ -20,7 +20,7 @@ import { ILogger } from '@theia/core/lib/common/logger';
20
20
  import { TerminalProcess, TerminalProcessOptions, ProcessManager, MultiRingBuffer } from '@theia/process/lib/node';
21
21
  import { isWindows, isOSX } from '@theia/core/lib/common';
22
22
  import URI from '@theia/core/lib/common/uri';
23
- import { FileUri } from '@theia/core/lib/node/file-uri';
23
+ import { FileUri } from '@theia/core/lib/common/file-uri';
24
24
  import { EnvironmentUtils } from '@theia/core/lib/node/environment-utils';
25
25
  import { parseArgs } from '@theia/process/lib/node/utils';
26
26