@theia/terminal 1.45.1 → 1.46.0-next.72

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 (126) hide show
  1. package/README.md +30 -30
  2. package/lib/browser/base/terminal-service.d.ts +34 -34
  3. package/lib/browser/base/terminal-service.js +7 -7
  4. package/lib/browser/base/terminal-widget.d.ts +192 -192
  5. package/lib/browser/base/terminal-widget.js +34 -34
  6. package/lib/browser/index.d.ts +1 -1
  7. package/lib/browser/index.js +28 -28
  8. package/lib/browser/search/terminal-search-container.d.ts +3 -3
  9. package/lib/browser/search/terminal-search-container.js +28 -28
  10. package/lib/browser/search/terminal-search-widget.d.ts +30 -30
  11. package/lib/browser/search/terminal-search-widget.js +147 -147
  12. package/lib/browser/shell-terminal-profile.d.ts +20 -20
  13. package/lib/browser/shell-terminal-profile.js +42 -42
  14. package/lib/browser/terminal-contribution.d.ts +3 -3
  15. package/lib/browser/terminal-contribution.js +20 -20
  16. package/lib/browser/terminal-copy-on-selection-handler.d.ts +10 -10
  17. package/lib/browser/terminal-copy-on-selection-handler.js +103 -103
  18. package/lib/browser/terminal-file-link-provider.d.ts +24 -24
  19. package/lib/browser/terminal-file-link-provider.js +200 -200
  20. package/lib/browser/terminal-frontend-contribution.d.ts +115 -115
  21. package/lib/browser/terminal-frontend-contribution.d.ts.map +1 -1
  22. package/lib/browser/terminal-frontend-contribution.js +1078 -1056
  23. package/lib/browser/terminal-frontend-contribution.js.map +1 -1
  24. package/lib/browser/terminal-frontend-module.d.ts +5 -5
  25. package/lib/browser/terminal-frontend-module.js +117 -117
  26. package/lib/browser/terminal-link-helpers.d.ts +27 -27
  27. package/lib/browser/terminal-link-helpers.js +155 -155
  28. package/lib/browser/terminal-link-provider.d.ts +51 -51
  29. package/lib/browser/terminal-link-provider.js +197 -197
  30. package/lib/browser/terminal-preferences.d.ts +61 -61
  31. package/lib/browser/terminal-preferences.d.ts.map +1 -1
  32. package/lib/browser/terminal-preferences.js +357 -356
  33. package/lib/browser/terminal-preferences.js.map +1 -1
  34. package/lib/browser/terminal-profile-service.d.ts +58 -58
  35. package/lib/browser/terminal-profile-service.js +158 -158
  36. package/lib/browser/terminal-quick-open-service.d.ts +36 -36
  37. package/lib/browser/terminal-quick-open-service.js +137 -137
  38. package/lib/browser/terminal-theme-service.d.ts +21 -21
  39. package/lib/browser/terminal-theme-service.d.ts.map +1 -1
  40. package/lib/browser/terminal-theme-service.js +222 -218
  41. package/lib/browser/terminal-theme-service.js.map +1 -1
  42. package/lib/browser/terminal-url-link-provider.d.ts +11 -11
  43. package/lib/browser/terminal-url-link-provider.js +76 -76
  44. package/lib/browser/terminal-widget-impl.d.ts +180 -187
  45. package/lib/browser/terminal-widget-impl.d.ts.map +1 -1
  46. package/lib/browser/terminal-widget-impl.js +857 -867
  47. package/lib/browser/terminal-widget-impl.js.map +1 -1
  48. package/lib/common/base-terminal-protocol.d.ts +55 -55
  49. package/lib/common/base-terminal-protocol.js +84 -84
  50. package/lib/common/shell-terminal-protocol.d.ts +66 -66
  51. package/lib/common/shell-terminal-protocol.js +35 -35
  52. package/lib/common/terminal-common-module.d.ts +7 -7
  53. package/lib/common/terminal-common-module.js +31 -31
  54. package/lib/common/terminal-protocol.d.ts +12 -12
  55. package/lib/common/terminal-protocol.js +21 -21
  56. package/lib/common/terminal-watcher.d.ts +13 -13
  57. package/lib/common/terminal-watcher.js +70 -70
  58. package/lib/node/base-terminal-server.d.ts +24 -24
  59. package/lib/node/base-terminal-server.js +168 -168
  60. package/lib/node/buffering-stream.d.ts +39 -39
  61. package/lib/node/buffering-stream.js +75 -75
  62. package/lib/node/buffering-stream.spec.d.ts +1 -1
  63. package/lib/node/buffering-stream.spec.js +43 -43
  64. package/lib/node/index.d.ts +1 -1
  65. package/lib/node/index.js +28 -28
  66. package/lib/node/shell-process.d.ts +27 -27
  67. package/lib/node/shell-process.js +107 -107
  68. package/lib/node/shell-process.js.map +1 -1
  69. package/lib/node/shell-terminal-server.d.ts +30 -30
  70. package/lib/node/shell-terminal-server.js +212 -212
  71. package/lib/node/shell-terminal-server.spec.d.ts +1 -1
  72. package/lib/node/shell-terminal-server.spec.js +35 -35
  73. package/lib/node/terminal-backend-contribution.d.ts +9 -9
  74. package/lib/node/terminal-backend-contribution.js +75 -75
  75. package/lib/node/terminal-backend-contribution.slow-spec.d.ts +1 -1
  76. package/lib/node/terminal-backend-contribution.slow-spec.js +54 -54
  77. package/lib/node/terminal-backend-module.d.ts +11 -11
  78. package/lib/node/terminal-backend-module.js +69 -69
  79. package/lib/node/terminal-server.d.ts +9 -9
  80. package/lib/node/terminal-server.js +64 -64
  81. package/lib/node/terminal-server.spec.d.ts +1 -1
  82. package/lib/node/terminal-server.spec.js +41 -41
  83. package/lib/node/test/terminal-test-container.d.ts +2 -2
  84. package/lib/node/test/terminal-test-container.js +40 -40
  85. package/lib/package.spec.js +25 -25
  86. package/package.json +12 -12
  87. package/src/browser/base/terminal-service.ts +60 -60
  88. package/src/browser/base/terminal-widget.ts +254 -254
  89. package/src/browser/index.ts +17 -17
  90. package/src/browser/search/terminal-search-container.ts +28 -28
  91. package/src/browser/search/terminal-search-widget.tsx +161 -161
  92. package/src/browser/shell-terminal-profile.ts +45 -45
  93. package/src/browser/style/terminal-search.css +99 -99
  94. package/src/browser/style/terminal.css +32 -32
  95. package/src/browser/terminal-contribution.ts +19 -19
  96. package/src/browser/terminal-copy-on-selection-handler.ts +92 -92
  97. package/src/browser/terminal-file-link-provider.ts +200 -200
  98. package/src/browser/terminal-frontend-contribution.ts +1120 -1098
  99. package/src/browser/terminal-frontend-module.ts +136 -136
  100. package/src/browser/terminal-link-helpers.ts +187 -187
  101. package/src/browser/terminal-link-provider.ts +203 -203
  102. package/src/browser/terminal-preferences.ts +428 -427
  103. package/src/browser/terminal-profile-service.ts +180 -180
  104. package/src/browser/terminal-quick-open-service.ts +132 -132
  105. package/src/browser/terminal-theme-service.ts +213 -209
  106. package/src/browser/terminal-url-link-provider.ts +66 -66
  107. package/src/browser/terminal-widget-impl.ts +939 -936
  108. package/src/common/base-terminal-protocol.ts +125 -125
  109. package/src/common/shell-terminal-protocol.ts +103 -103
  110. package/src/common/terminal-common-module.ts +30 -30
  111. package/src/common/terminal-protocol.ts +32 -32
  112. package/src/common/terminal-watcher.ts +69 -69
  113. package/src/node/base-terminal-server.ts +173 -173
  114. package/src/node/buffering-stream.spec.ts +46 -46
  115. package/src/node/buffering-stream.ts +95 -95
  116. package/src/node/index.ts +17 -17
  117. package/src/node/shell-process.ts +101 -101
  118. package/src/node/shell-terminal-server.spec.ts +40 -40
  119. package/src/node/shell-terminal-server.ts +221 -221
  120. package/src/node/terminal-backend-contribution.slow-spec.ts +63 -63
  121. package/src/node/terminal-backend-contribution.ts +60 -60
  122. package/src/node/terminal-backend-module.ts +82 -82
  123. package/src/node/terminal-server.spec.ts +47 -47
  124. package/src/node/terminal-server.ts +52 -52
  125. package/src/node/test/terminal-test-container.ts +39 -39
  126. package/src/package.spec.ts +28 -28
@@ -1,868 +1,858 @@
1
- "use strict";
2
- // *****************************************************************************
3
- // Copyright (C) 2017 TypeFox and others.
4
- //
5
- // This program and the accompanying materials are made available under the
6
- // terms of the Eclipse Public License v. 2.0 which is available at
7
- // http://www.eclipse.org/legal/epl-2.0.
8
- //
9
- // This Source Code may also be made available under the following Secondary
10
- // Licenses when the conditions for such availability set forth in the Eclipse
11
- // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
- // with the GNU Classpath Exception which is available at
13
- // https://www.gnu.org/software/classpath/license.html.
14
- //
15
- // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
- // *****************************************************************************
17
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
18
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21
- return c > 3 && r && Object.defineProperty(target, key, r), r;
22
- };
23
- var __metadata = (this && this.__metadata) || function (k, v) {
24
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
- };
26
- var TerminalWidgetImpl_1;
27
- Object.defineProperty(exports, "__esModule", { value: true });
28
- exports.TerminalWidgetImpl = exports.TerminalContribution = exports.TERMINAL_WIDGET_FACTORY_ID = void 0;
29
- const xterm_1 = require("xterm");
30
- const xterm_addon_fit_1 = require("xterm-addon-fit");
31
- const inversify_1 = require("@theia/core/shared/inversify");
32
- const core_1 = require("@theia/core");
33
- const browser_1 = require("@theia/core/lib/browser");
34
- const common_1 = require("@theia/core/lib/common");
35
- const browser_2 = require("@theia/workspace/lib/browser");
36
- const shell_terminal_protocol_1 = require("../common/shell-terminal-protocol");
37
- const terminal_protocol_1 = require("../common/terminal-protocol");
38
- const base_terminal_protocol_1 = require("../common/base-terminal-protocol");
39
- const terminal_watcher_1 = require("../common/terminal-watcher");
40
- const terminal_widget_1 = require("./base/terminal-widget");
41
- const promise_util_1 = require("@theia/core/lib/common/promise-util");
42
- const terminal_preferences_1 = require("./terminal-preferences");
43
- const uri_1 = require("@theia/core/lib/common/uri");
44
- const terminal_service_1 = require("./base/terminal-service");
45
- const terminal_search_widget_1 = require("./search/terminal-search-widget");
46
- const terminal_copy_on_selection_handler_1 = require("./terminal-copy-on-selection-handler");
47
- const terminal_theme_service_1 = require("./terminal-theme-service");
48
- const shell_command_builder_1 = require("@theia/process/lib/common/shell-command-builder");
49
- const keys_1 = require("@theia/core/lib/browser/keys");
50
- const nls_1 = require("@theia/core/lib/common/nls");
51
- const terminal_frontend_contribution_1 = require("./terminal-frontend-contribution");
52
- const debounce = require("p-debounce");
53
- const markdown_string_1 = require("@theia/core/lib/common/markdown-rendering/markdown-string");
54
- const markdown_renderer_1 = require("@theia/core/lib/browser/markdown-rendering/markdown-renderer");
55
- const service_connection_provider_1 = require("@theia/core/lib/browser/messaging/service-connection-provider");
56
- exports.TERMINAL_WIDGET_FACTORY_ID = 'terminal';
57
- exports.TerminalContribution = Symbol('TerminalContribution');
58
- let TerminalWidgetImpl = TerminalWidgetImpl_1 = class TerminalWidgetImpl extends terminal_widget_1.TerminalWidget {
59
- constructor() {
60
- super(...arguments);
61
- this.isExtractable = true;
62
- this.terminalKind = 'user';
63
- this._terminalId = -1;
64
- this.onTermDidClose = new core_1.Emitter();
65
- this.restored = false;
66
- this.closeOnDispose = true;
67
- this.isAttachedCloseListener = false;
68
- this.shown = false;
69
- this.lastCwd = new uri_1.default();
70
- this.onDidOpenEmitter = new core_1.Emitter();
71
- this.onDidOpen = this.onDidOpenEmitter.event;
72
- this.onDidOpenFailureEmitter = new core_1.Emitter();
73
- this.onDidOpenFailure = this.onDidOpenFailureEmitter.event;
74
- this.onSizeChangedEmitter = new core_1.Emitter();
75
- this.onSizeChanged = this.onSizeChangedEmitter.event;
76
- this.onDataEmitter = new core_1.Emitter();
77
- this.onData = this.onDataEmitter.event;
78
- this.onKeyEmitter = new core_1.Emitter();
79
- this.onKey = this.onKeyEmitter.event;
80
- this.onMouseEnterLinkHoverEmitter = new core_1.Emitter();
81
- this.onMouseEnterLinkHover = this.onMouseEnterLinkHoverEmitter.event;
82
- this.onMouseLeaveLinkHoverEmitter = new core_1.Emitter();
83
- this.onMouseLeaveLinkHover = this.onMouseLeaveLinkHoverEmitter.event;
84
- this.toDisposeOnConnect = new core_1.DisposableCollection();
85
- this.needsResize = true;
86
- // Device status code emitted by Xterm.js
87
- // Check: https://github.com/xtermjs/xterm.js/blob/release/3.14/src/InputHandler.ts#L1055-L1082
88
- this.deviceStatusCodes = new Set(['\u001B[>0;276;0c', '\u001B[>85;95;0c', '\u001B[>83;40003;0c', '\u001B[?1;2c', '\u001B[?6c']);
89
- this.termOpened = false;
90
- this.initialData = '';
91
- this.resizeTerminal = debounce(() => this.doResizeTerminal(), 50);
92
- }
93
- get markdownRenderer() {
94
- this._markdownRenderer || (this._markdownRenderer = this.markdownRendererFactory());
95
- return this._markdownRenderer;
96
- }
97
- init() {
98
- this.setTitle(this.options.title || TerminalWidgetImpl_1.LABEL);
99
- if (this.options.iconClass) {
100
- this.title.iconClass = this.options.iconClass;
101
- }
102
- else {
103
- this.title.iconClass = (0, browser_1.codicon)('terminal');
104
- }
105
- if (this.options.kind) {
106
- this.terminalKind = this.options.kind;
107
- }
108
- if (this.options.destroyTermOnClose === true) {
109
- this.toDispose.push(core_1.Disposable.create(() => this.term.dispose()));
110
- }
111
- this.location = this.options.location || terminal_widget_1.TerminalLocation.Panel;
112
- this.title.closable = true;
113
- this.addClass('terminal-container');
114
- this.term = new xterm_1.Terminal({
115
- cursorBlink: this.preferences['terminal.integrated.cursorBlinking'],
116
- cursorStyle: this.getCursorStyle(),
117
- cursorWidth: this.preferences['terminal.integrated.cursorWidth'],
118
- fontFamily: this.preferences['terminal.integrated.fontFamily'],
119
- fontSize: this.preferences['terminal.integrated.fontSize'],
120
- fontWeight: this.preferences['terminal.integrated.fontWeight'],
121
- fontWeightBold: this.preferences['terminal.integrated.fontWeightBold'],
122
- drawBoldTextInBrightColors: this.preferences['terminal.integrated.drawBoldTextInBrightColors'],
123
- letterSpacing: this.preferences['terminal.integrated.letterSpacing'],
124
- lineHeight: this.preferences['terminal.integrated.lineHeight'],
125
- scrollback: this.preferences['terminal.integrated.scrollback'],
126
- fastScrollSensitivity: this.preferences['terminal.integrated.fastScrollSensitivity'],
127
- rendererType: this.getTerminalRendererType(this.preferences['terminal.integrated.rendererType']),
128
- theme: this.themeService.theme
129
- });
130
- this.fitAddon = new xterm_addon_fit_1.FitAddon();
131
- this.term.loadAddon(this.fitAddon);
132
- this.initializeLinkHover();
133
- this.toDispose.push(this.preferences.onPreferenceChanged(change => {
134
- const lastSeparator = change.preferenceName.lastIndexOf('.');
135
- if (lastSeparator > 0) {
136
- let preferenceName = change.preferenceName.substring(lastSeparator + 1);
137
- let preferenceValue = change.newValue;
138
- if (preferenceName === 'rendererType') {
139
- const newRendererType = preferenceValue;
140
- if (newRendererType !== this.getTerminalRendererType(newRendererType)) {
141
- // Given terminal renderer type is not supported or invalid
142
- preferenceValue = terminal_preferences_1.DEFAULT_TERMINAL_RENDERER_TYPE;
143
- }
144
- }
145
- else if (preferenceName === 'cursorBlinking') {
146
- // Convert the terminal preference into a valid `xterm` option
147
- preferenceName = 'cursorBlink';
148
- }
149
- else if (preferenceName === 'cursorStyle') {
150
- preferenceValue = this.getCursorStyle();
151
- }
152
- try {
153
- this.term.setOption(preferenceName, preferenceValue);
154
- }
155
- catch (e) {
156
- console.debug(`xterm configuration: '${preferenceName}' with value '${preferenceValue}' is not valid.`);
157
- }
158
- this.needsResize = true;
159
- this.update();
160
- }
161
- }));
162
- this.toDispose.push(this.themeService.onDidChange(() => this.term.setOption('theme', this.themeService.theme)));
163
- this.attachCustomKeyEventHandler();
164
- const titleChangeListenerDispose = this.term.onTitleChange((title) => {
165
- if (this.options.useServerTitle) {
166
- this.title.label = title;
167
- }
168
- });
169
- this.toDispose.push(titleChangeListenerDispose);
170
- this.toDispose.push(this.terminalWatcher.onTerminalError(({ terminalId, error, attached }) => {
171
- if (terminalId === this.terminalId) {
172
- this.exitStatus = { code: undefined, reason: base_terminal_protocol_1.TerminalExitReason.Process };
173
- this.logger.error(`The terminal process terminated. Cause: ${error}`);
174
- if (!attached) {
175
- this.dispose();
176
- }
177
- }
178
- }));
179
- this.toDispose.push(this.terminalWatcher.onTerminalExit(({ terminalId, code, reason, attached }) => {
180
- if (terminalId === this.terminalId) {
181
- if (reason) {
182
- this.exitStatus = { code, reason };
183
- }
184
- else {
185
- this.exitStatus = { code, reason: base_terminal_protocol_1.TerminalExitReason.Process };
186
- }
187
- if (!attached) {
188
- this.dispose();
189
- }
190
- }
191
- }));
192
- this.toDispose.push(this.toDisposeOnConnect);
193
- this.toDispose.push(this.shellTerminalServer.onDidCloseConnection(() => {
194
- const disposable = this.shellTerminalServer.onDidOpenConnection(() => {
195
- disposable.dispose();
196
- this.reconnectTerminalProcess();
197
- });
198
- this.toDispose.push(disposable);
199
- }));
200
- this.toDispose.push(this.onTermDidClose);
201
- this.toDispose.push(this.onDidOpenEmitter);
202
- this.toDispose.push(this.onDidOpenFailureEmitter);
203
- this.toDispose.push(this.onSizeChangedEmitter);
204
- this.toDispose.push(this.onDataEmitter);
205
- this.toDispose.push(this.onKeyEmitter);
206
- const touchEndListener = (event) => {
207
- if (this.node.contains(event.target)) {
208
- this.lastTouchEnd = event;
209
- }
210
- };
211
- document.addEventListener('touchend', touchEndListener, { passive: true });
212
- this.onDispose(() => {
213
- document.removeEventListener('touchend', touchEndListener);
214
- });
215
- const mouseListener = (event) => {
216
- this.lastMousePosition = { x: event.x, y: event.y };
217
- };
218
- this.node.addEventListener('mousemove', mouseListener);
219
- this.onDispose(() => {
220
- this.node.removeEventListener('mousemove', mouseListener);
221
- });
222
- const contextMenuListener = (event) => {
223
- event.preventDefault();
224
- event.stopPropagation();
225
- this.contextMenuRenderer.render({ menuPath: terminal_frontend_contribution_1.TerminalMenus.TERMINAL_CONTEXT_MENU, anchor: event });
226
- };
227
- this.node.addEventListener('contextmenu', contextMenuListener);
228
- this.onDispose(() => this.node.removeEventListener('contextmenu', contextMenuListener));
229
- this.toDispose.push(this.term.onSelectionChange(() => {
230
- if (this.copyOnSelection) {
231
- this.copyOnSelectionHandler.copy(this.term.getSelection());
232
- }
233
- }));
234
- this.toDispose.push(this.term.onResize(data => {
235
- this.onSizeChangedEmitter.fire(data);
236
- }));
237
- this.toDispose.push(this.term.onData(data => {
238
- this.onDataEmitter.fire(data);
239
- }));
240
- this.toDispose.push(this.term.onBinary(data => {
241
- this.onDataEmitter.fire(data);
242
- }));
243
- this.toDispose.push(this.term.onKey(data => {
244
- this.onKeyEmitter.fire(data);
245
- }));
246
- for (const contribution of this.terminalContributionProvider.getContributions()) {
247
- contribution.onCreate(this);
248
- }
249
- this.searchBox = this.terminalSearchBoxFactory(this.term);
250
- this.toDispose.push(this.searchBox);
251
- }
252
- get kind() {
253
- return this.terminalKind;
254
- }
255
- /**
256
- * Get the cursor style compatible with `xterm`.
257
- * @returns CursorStyle
258
- */
259
- getCursorStyle() {
260
- const value = this.preferences['terminal.integrated.cursorStyle'];
261
- return value === 'line' ? 'bar' : value;
262
- }
263
- /**
264
- * Returns given renderer type if it is valid and supported or default renderer otherwise.
265
- *
266
- * @param terminalRendererType desired terminal renderer type
267
- */
268
- getTerminalRendererType(terminalRendererType) {
269
- if (terminalRendererType && (0, terminal_preferences_1.isTerminalRendererType)(terminalRendererType)) {
270
- return terminalRendererType;
271
- }
272
- return terminal_preferences_1.DEFAULT_TERMINAL_RENDERER_TYPE;
273
- }
274
- initializeLinkHover() {
275
- this.linkHover = document.createElement('div');
276
- this.linkHover.style.position = 'fixed';
277
- this.linkHover.style.color = 'var(--theia-editorHoverWidget-foreground)';
278
- this.linkHover.style.backgroundColor = 'var(--theia-editorHoverWidget-background)';
279
- this.linkHover.style.borderColor = 'var(--theia-editorHoverWidget-border)';
280
- this.linkHover.style.borderWidth = '0.5px';
281
- this.linkHover.style.borderStyle = 'solid';
282
- this.linkHover.style.padding = '5px';
283
- // Above the xterm.js canvas layers:
284
- // https://github.com/xtermjs/xterm.js/blob/ff790236c1b205469f17a21246141f512d844295/src/renderer/Renderer.ts#L41-L46
285
- this.linkHover.style.zIndex = '10';
286
- // Initially invisible:
287
- this.linkHover.style.display = 'none';
288
- this.linkHoverButton = document.createElement('a');
289
- this.linkHoverButton.textContent = this.linkHoverMessage();
290
- this.linkHoverButton.style.cursor = 'pointer';
291
- this.linkHover.appendChild(this.linkHoverButton);
292
- const cmdCtrl = common_1.isOSX ? 'cmd' : 'ctrl';
293
- const cmdHint = document.createTextNode(` (${nls_1.nls.localizeByDefault(`${cmdCtrl} + click`)})`);
294
- this.linkHover.appendChild(cmdHint);
295
- const onMouseEnter = (mouseEvent) => this.onMouseEnterLinkHoverEmitter.fire(mouseEvent);
296
- this.linkHover.addEventListener('mouseenter', onMouseEnter);
297
- this.toDispose.push(core_1.Disposable.create(() => this.linkHover.removeEventListener('mouseenter', onMouseEnter)));
298
- const onMouseLeave = (mouseEvent) => this.onMouseLeaveLinkHoverEmitter.fire(mouseEvent);
299
- this.linkHover.addEventListener('mouseleave', onMouseLeave);
300
- this.toDispose.push(core_1.Disposable.create(() => this.linkHover.removeEventListener('mouseleave', onMouseLeave)));
301
- this.node.appendChild(this.linkHover);
302
- }
303
- showLinkHover(invokeAction, x, y, message) {
304
- var _a, _b, _c, _d;
305
- const mouseY = (_b = (_a = this.lastMousePosition) === null || _a === void 0 ? void 0 : _a.y) !== null && _b !== void 0 ? _b : y;
306
- const mouseX = (_d = (_c = this.lastMousePosition) === null || _c === void 0 ? void 0 : _c.x) !== null && _d !== void 0 ? _d : x;
307
- this.linkHoverButton.textContent = this.linkHoverMessage(message);
308
- this.linkHoverButton.onclick = (mouseEvent) => invokeAction(mouseEvent);
309
- this.linkHover.style.display = 'inline';
310
- this.linkHover.style.top = `${mouseY - 30}px`;
311
- this.linkHover.style.left = `${mouseX - 60}px`;
312
- }
313
- linkHoverMessage(message) {
314
- return message !== null && message !== void 0 ? message : nls_1.nls.localizeByDefault('Follow link');
315
- }
316
- hideLinkHover() {
317
- this.linkHover.style.display = 'none';
318
- // eslint-disable-next-line no-null/no-null
319
- this.linkHoverButton.onclick = null;
320
- }
321
- getTerminal() {
322
- return this.term;
323
- }
324
- getSearchBox() {
325
- return this.searchBox;
326
- }
327
- onCloseRequest(msg) {
328
- this.exitStatus = { code: undefined, reason: base_terminal_protocol_1.TerminalExitReason.User };
329
- super.onCloseRequest(msg);
330
- }
331
- get dimensions() {
332
- return {
333
- cols: this.term.cols,
334
- rows: this.term.rows,
335
- };
336
- }
337
- get cwd() {
338
- if (!base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)) {
339
- return Promise.reject(new Error('terminal is not started'));
340
- }
341
- if (this.terminalService.getById(this.id)) {
342
- return this.shellTerminalServer.getCwdURI(this.terminalId)
343
- .then(cwdUrl => {
344
- this.lastCwd = new uri_1.default(cwdUrl);
345
- return this.lastCwd;
346
- }).catch(() => this.lastCwd);
347
- }
348
- return Promise.resolve(new uri_1.default());
349
- }
350
- get processId() {
351
- if (!base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)) {
352
- return Promise.reject(new Error('terminal is not started'));
353
- }
354
- return this.shellTerminalServer.getProcessId(this.terminalId);
355
- }
356
- get processInfo() {
357
- if (!base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)) {
358
- return Promise.reject(new Error('terminal is not started'));
359
- }
360
- return this.shellTerminalServer.getProcessInfo(this.terminalId);
361
- }
362
- get envVarCollectionDescriptionsByExtension() {
363
- if (!base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)) {
364
- return Promise.reject(new Error('terminal is not started'));
365
- }
366
- return this.shellTerminalServer.getEnvVarCollectionDescriptionsByExtension(this.terminalId);
367
- }
368
- get terminalId() {
369
- return this._terminalId;
370
- }
371
- get lastTouchEndEvent() {
372
- return this.lastTouchEnd;
373
- }
374
- get hiddenFromUser() {
375
- var _a;
376
- if (this.shown) {
377
- return false;
378
- }
379
- return (_a = this.options.hideFromUser) !== null && _a !== void 0 ? _a : false;
380
- }
381
- get transient() {
382
- // The terminal is transient if session persistence is disabled or it's explicitly marked as transient
383
- return !this.preferences['terminal.integrated.enablePersistentSessions'] || !!this.options.isTransient;
384
- }
385
- onDispose(onDispose) {
386
- this.toDispose.push(core_1.Disposable.create(onDispose));
387
- }
388
- clearOutput() {
389
- this.term.clear();
390
- }
391
- selectAll() {
392
- this.term.selectAll();
393
- }
394
- async hasChildProcesses() {
395
- return this.shellTerminalServer.hasChildProcesses(await this.processId);
396
- }
397
- storeState() {
398
- this.closeOnDispose = false;
399
- if (this.transient || this.options.isPseudoTerminal) {
400
- return {};
401
- }
402
- return { terminalId: this.terminalId, titleLabel: this.title.label };
403
- }
404
- restoreState(oldState) {
405
- // transient terminals and pseudo terminals are not restored
406
- if (this.transient || this.options.isPseudoTerminal) {
407
- this.dispose();
408
- return;
409
- }
410
- if (this.restored === false) {
411
- const state = oldState;
412
- /* This is a workaround to issue #879 */
413
- this.restored = true;
414
- this.title.label = state.titleLabel;
415
- this.start(state.terminalId);
416
- }
417
- }
418
- /**
419
- * Create a new shell terminal in the back-end and attach it to a
420
- * new terminal widget.
421
- * If id is provided attach to the terminal for this id.
422
- */
423
- async start(id) {
424
- this._terminalId = typeof id !== 'number' ? await this.createTerminal() : await this.attachTerminal(id);
425
- this.resizeTerminalProcess();
426
- this.connectTerminalProcess();
427
- if (base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)) {
428
- this.onDidOpenEmitter.fire(undefined);
429
- await this.shellTerminalServer.onAttachAttempted(this._terminalId);
430
- return this.terminalId;
431
- }
432
- this.onDidOpenFailureEmitter.fire(undefined);
433
- throw new Error('Failed to start terminal' + (id ? ` for id: ${id}.` : '.'));
434
- }
435
- async attachTerminal(id) {
436
- const terminalId = await this.shellTerminalServer.attach(id);
437
- if (base_terminal_protocol_1.IBaseTerminalServer.validateId(terminalId)) {
438
- // reset exit status if a new terminal process is attached
439
- this.exitStatus = undefined;
440
- return terminalId;
441
- }
442
- this.logger.warn(`Failed attaching to terminal id ${id}, the terminal is most likely gone. Starting up a new terminal instead.`);
443
- if (this.kind === 'user') {
444
- return this.createTerminal();
445
- }
446
- else {
447
- return -1;
448
- }
449
- }
450
- async createTerminal() {
451
- var _a, _b;
452
- let rootURI = (_a = this.options.cwd) === null || _a === void 0 ? void 0 : _a.toString();
453
- if (!rootURI) {
454
- const root = (await this.workspaceService.roots)[0];
455
- rootURI = (_b = root === null || root === void 0 ? void 0 : root.resource) === null || _b === void 0 ? void 0 : _b.toString();
456
- }
457
- const { cols, rows } = this.term;
458
- const terminalId = await this.shellTerminalServer.create({
459
- shell: this.options.shellPath || this.shellPreferences.shell[core_1.OS.backend.type()],
460
- args: this.options.shellArgs || this.shellPreferences.shellArgs[core_1.OS.backend.type()],
461
- env: this.options.env,
462
- strictEnv: this.options.strictEnv,
463
- isPseudo: this.options.isPseudoTerminal,
464
- rootURI,
465
- cols,
466
- rows
467
- });
468
- if (base_terminal_protocol_1.IBaseTerminalServer.validateId(terminalId)) {
469
- return terminalId;
470
- }
471
- throw new Error('Error creating terminal widget, see the backend error log for more information.');
472
- }
473
- processMessage(msg) {
474
- super.processMessage(msg);
475
- switch (msg.type) {
476
- case 'fit-request':
477
- this.onFitRequest(msg);
478
- break;
479
- default:
480
- break;
481
- }
482
- }
483
- onFitRequest(msg) {
484
- super.onFitRequest(msg);
485
- browser_1.MessageLoop.sendMessage(this, browser_1.Widget.ResizeMessage.UnknownSize);
486
- }
487
- onActivateRequest(msg) {
488
- super.onActivateRequest(msg);
489
- this.term.focus();
490
- }
491
- onAfterShow(msg) {
492
- super.onAfterShow(msg);
493
- this.update();
494
- this.shown = true;
495
- }
496
- onAfterAttach(msg) {
497
- browser_1.Widget.attach(this.searchBox, this.node);
498
- super.onAfterAttach(msg);
499
- this.update();
500
- }
501
- onBeforeDetach(msg) {
502
- browser_1.Widget.detach(this.searchBox);
503
- super.onBeforeDetach(msg);
504
- }
505
- onResize(msg) {
506
- super.onResize(msg);
507
- this.needsResize = true;
508
- this.update();
509
- }
510
- onUpdateRequest(msg) {
511
- super.onUpdateRequest(msg);
512
- if (!this.isVisible || !this.isAttached) {
513
- return;
514
- }
515
- this.open();
516
- if (this.needsResize) {
517
- this.resizeTerminal();
518
- this.needsResize = false;
519
- this.resizeTerminalProcess();
520
- }
521
- }
522
- connectTerminalProcess() {
523
- if (typeof this.terminalId !== 'number') {
524
- return;
525
- }
526
- if (this.options.isPseudoTerminal) {
527
- return;
528
- }
529
- this.toDisposeOnConnect.dispose();
530
- this.toDispose.push(this.toDisposeOnConnect);
531
- const waitForConnection = this.waitForConnection = new promise_util_1.Deferred();
532
- this.connectionProvider.listen(`${terminal_protocol_1.terminalsPath}/${this.terminalId}`, (path, connection) => {
533
- connection.onMessage(e => {
534
- this.write(e().readString());
535
- });
536
- // Excludes the device status code emitted by Xterm.js
537
- const sendData = (data) => {
538
- if (data && !this.deviceStatusCodes.has(data) && !this.disableEnterWhenAttachCloseListener()) {
539
- connection.getWriteBuffer().writeString(data).commit();
540
- }
541
- };
542
- const disposable = new core_1.DisposableCollection();
543
- disposable.push(this.term.onData(sendData));
544
- disposable.push(this.term.onBinary(sendData));
545
- connection.onClose(() => disposable.dispose());
546
- if (waitForConnection) {
547
- waitForConnection.resolve(connection);
548
- }
549
- }, false);
550
- }
551
- async reconnectTerminalProcess() {
552
- if (this.options.isPseudoTerminal) {
553
- return;
554
- }
555
- if (typeof this.terminalId === 'number') {
556
- await this.start(this.terminalId);
557
- }
558
- }
559
- open() {
560
- if (this.termOpened) {
561
- return;
562
- }
563
- this.term.open(this.node);
564
- if (browser_1.isFirefox) {
565
- // monkey patching intersection observer handling for secondary window support
566
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
567
- const renderService = this.term._core._renderService;
568
- const originalFunc = renderService._onIntersectionChange.bind(renderService);
569
- const replacement = function (entry) {
570
- if (entry.target.ownerDocument !== document) {
571
- // in Firefox, the intersection observer always reports the widget as non-intersecting if the dom element
572
- // is in a different document from when the IntersectionObserver started observing. Since we know
573
- // that the widget is always "visible" when in a secondary window, so we mark the entry as "intersecting"
574
- const patchedEvent = {
575
- ...entry,
576
- isIntersecting: true,
577
- };
578
- originalFunc(patchedEvent);
579
- }
580
- else {
581
- originalFunc(entry);
582
- }
583
- };
584
- renderService._onIntersectionChange = replacement;
585
- }
586
- if (this.initialData) {
587
- this.term.write(this.initialData);
588
- }
589
- this.termOpened = true;
590
- this.initialData = '';
591
- if (browser_1.isFirefox) {
592
- // The software scrollbars don't work with xterm.js, so we disable the scrollbar if we are on firefox.
593
- if (this.term.element) {
594
- this.term.element.children.item(0).style.overflow = 'hidden';
595
- }
596
- }
597
- }
598
- write(data) {
599
- if (this.termOpened) {
600
- this.term.write(data);
601
- }
602
- else {
603
- this.initialData += data;
604
- }
605
- }
606
- resize(cols, rows) {
607
- this.term.resize(cols, rows);
608
- }
609
- sendText(text) {
610
- if (this.waitForConnection) {
611
- this.waitForConnection.promise.then(connection => connection.getWriteBuffer().writeString(text).commit());
612
- }
613
- }
614
- async executeCommand(commandOptions) {
615
- this.sendText(this.shellCommandBuilder.buildCommand(await this.processInfo, commandOptions) + core_1.OS.backend.EOL);
616
- }
617
- scrollLineUp() {
618
- this.term.scrollLines(-1);
619
- }
620
- scrollLineDown() {
621
- this.term.scrollLines(1);
622
- }
623
- scrollToTop() {
624
- this.term.scrollToTop();
625
- }
626
- scrollToBottom() {
627
- this.term.scrollToBottom();
628
- }
629
- scrollPageUp() {
630
- this.term.scrollPages(-1);
631
- }
632
- scrollPageDown() {
633
- this.term.scrollPages(1);
634
- }
635
- resetTerminal() {
636
- this.term.reset();
637
- }
638
- writeLine(text) {
639
- this.term.writeln(text);
640
- }
641
- get onTerminalDidClose() {
642
- return this.onTermDidClose.event;
643
- }
644
- dispose() {
645
- if (this.closeOnDispose === true && typeof this.terminalId === 'number' && !this.exitStatus) {
646
- // Close the backend terminal only when explicitly closing the terminal
647
- // a refresh for example won't close it.
648
- this.shellTerminalServer.close(this.terminalId);
649
- // Exit status is set when terminal is closed by user or by process, so most likely an extension closed it.
650
- this.exitStatus = { code: undefined, reason: base_terminal_protocol_1.TerminalExitReason.Extension };
651
- }
652
- if (this.exitStatus) {
653
- this.onTermDidClose.fire(this);
654
- }
655
- if (this.enhancedPreviewNode) {
656
- // don't use preview node anymore. rendered markdown will be disposed on super call
657
- this.enhancedPreviewNode = undefined;
658
- }
659
- super.dispose();
660
- }
661
- doResizeTerminal() {
662
- if (this.isDisposed) {
663
- return;
664
- }
665
- const geo = this.fitAddon.proposeDimensions();
666
- const cols = geo.cols;
667
- const rows = geo.rows - 1; // subtract one row for margin
668
- this.term.resize(cols, rows);
669
- }
670
- resizeTerminalProcess() {
671
- if (this.options.isPseudoTerminal) {
672
- return;
673
- }
674
- if (!base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)
675
- || this.exitStatus
676
- || !this.terminalService.getById(this.id)) {
677
- return;
678
- }
679
- const { cols, rows } = this.term;
680
- this.shellTerminalServer.resize(this.terminalId, cols, rows);
681
- }
682
- get enableCopy() {
683
- return this.preferences['terminal.enableCopy'];
684
- }
685
- get enablePaste() {
686
- return this.preferences['terminal.enablePaste'];
687
- }
688
- get shellPreferences() {
689
- var _a, _b, _c;
690
- return {
691
- shell: {
692
- Windows: (_a = this.preferences['terminal.integrated.shell.windows']) !== null && _a !== void 0 ? _a : undefined,
693
- Linux: (_b = this.preferences['terminal.integrated.shell.linux']) !== null && _b !== void 0 ? _b : undefined,
694
- OSX: (_c = this.preferences['terminal.integrated.shell.osx']) !== null && _c !== void 0 ? _c : undefined,
695
- },
696
- shellArgs: {
697
- Windows: this.preferences['terminal.integrated.shellArgs.windows'],
698
- Linux: this.preferences['terminal.integrated.shellArgs.linux'],
699
- OSX: this.preferences['terminal.integrated.shellArgs.osx'],
700
- }
701
- };
702
- }
703
- customKeyHandler(event) {
704
- const keyBindings = browser_1.KeyCode.createKeyCode(event).toString();
705
- const ctrlCmdCopy = (common_1.isOSX && keyBindings === 'meta+c') || (!common_1.isOSX && keyBindings === 'ctrl+c');
706
- const ctrlCmdPaste = (common_1.isOSX && keyBindings === 'meta+v') || (!common_1.isOSX && keyBindings === 'ctrl+v');
707
- if (ctrlCmdCopy && this.enableCopy && this.term.hasSelection()) {
708
- return false;
709
- }
710
- if (ctrlCmdPaste && this.enablePaste) {
711
- return false;
712
- }
713
- return true;
714
- }
715
- get copyOnSelection() {
716
- return this.preferences['terminal.integrated.copyOnSelection'];
717
- }
718
- attachCustomKeyEventHandler() {
719
- this.term.attachCustomKeyEventHandler(e => this.customKeyHandler(e));
720
- }
721
- setTitle(title) {
722
- this.title.caption = title;
723
- this.title.label = title;
724
- }
725
- waitOnExit(waitOnExit) {
726
- if (waitOnExit) {
727
- if (typeof waitOnExit === 'string') {
728
- let message = waitOnExit;
729
- // Bold the message and add an extra new line to make it stand out from the rest of the output
730
- message = `\r\n\x1b[1m${message}\x1b[0m`;
731
- this.write(message);
732
- }
733
- this.attachPressEnterKeyToCloseListener(this.term);
734
- return;
735
- }
736
- this.dispose();
737
- }
738
- attachPressEnterKeyToCloseListener(term) {
739
- if (term.textarea) {
740
- this.isAttachedCloseListener = true;
741
- this.addKeyListener(term.textarea, keys_1.Key.ENTER, (event) => {
742
- this.dispose();
743
- this.isAttachedCloseListener = false;
744
- });
745
- }
746
- }
747
- disableEnterWhenAttachCloseListener() {
748
- return this.isAttachedCloseListener;
749
- }
750
- getEnhancedPreviewNode() {
751
- if (this.enhancedPreviewNode) {
752
- return this.enhancedPreviewNode;
753
- }
754
- this.enhancedPreviewNode = document.createElement('div');
755
- Promise.all([this.envVarCollectionDescriptionsByExtension, this.processId, this.processInfo])
756
- .then((values) => {
757
- const extensions = values[0];
758
- const processId = values[1];
759
- const processInfo = values[2];
760
- const markdown = new markdown_string_1.MarkdownStringImpl();
761
- markdown.appendMarkdown('Process ID: ' + processId + '\\\n');
762
- markdown.appendMarkdown('Command line: ' +
763
- processInfo.executable +
764
- ' ' +
765
- processInfo.arguments.join(' ') +
766
- '\n\n---\n\n');
767
- markdown.appendMarkdown('The following extensions have contributed to this terminal\'s environment:\n');
768
- extensions.forEach((arr, key) => {
769
- arr.forEach(value => {
770
- if (value === undefined) {
771
- markdown.appendMarkdown('* ' + key + '\n');
772
- }
773
- else if (typeof value === 'string') {
774
- markdown.appendMarkdown('* ' + key + ': ' + value + '\n');
775
- }
776
- else {
777
- markdown.appendMarkdown('* ' + key + ': ' + value.value + '\n');
778
- }
779
- });
780
- });
781
- const enhancedPreviewNode = this.enhancedPreviewNode;
782
- if (!this.isDisposed && enhancedPreviewNode) {
783
- const result = this.markdownRenderer.render(markdown);
784
- this.toDispose.push(result);
785
- enhancedPreviewNode.appendChild(result.element);
786
- }
787
- });
788
- return this.enhancedPreviewNode;
789
- }
790
- };
791
- TerminalWidgetImpl.LABEL = nls_1.nls.localizeByDefault('Terminal');
792
- __decorate([
793
- (0, inversify_1.inject)(browser_2.WorkspaceService),
794
- __metadata("design:type", browser_2.WorkspaceService)
795
- ], TerminalWidgetImpl.prototype, "workspaceService", void 0);
796
- __decorate([
797
- (0, inversify_1.inject)(service_connection_provider_1.RemoteConnectionProvider),
798
- __metadata("design:type", service_connection_provider_1.ServiceConnectionProvider)
799
- ], TerminalWidgetImpl.prototype, "connectionProvider", void 0);
800
- __decorate([
801
- (0, inversify_1.inject)(terminal_widget_1.TerminalWidgetOptions),
802
- __metadata("design:type", Object)
803
- ], TerminalWidgetImpl.prototype, "options", void 0);
804
- __decorate([
805
- (0, inversify_1.inject)(shell_terminal_protocol_1.ShellTerminalServerProxy),
806
- __metadata("design:type", Object)
807
- ], TerminalWidgetImpl.prototype, "shellTerminalServer", void 0);
808
- __decorate([
809
- (0, inversify_1.inject)(terminal_watcher_1.TerminalWatcher),
810
- __metadata("design:type", terminal_watcher_1.TerminalWatcher)
811
- ], TerminalWidgetImpl.prototype, "terminalWatcher", void 0);
812
- __decorate([
813
- (0, inversify_1.inject)(core_1.ILogger),
814
- (0, inversify_1.named)('terminal'),
815
- __metadata("design:type", Object)
816
- ], TerminalWidgetImpl.prototype, "logger", void 0);
817
- __decorate([
818
- (0, inversify_1.inject)('terminal-dom-id'),
819
- __metadata("design:type", String)
820
- ], TerminalWidgetImpl.prototype, "id", void 0);
821
- __decorate([
822
- (0, inversify_1.inject)(terminal_preferences_1.TerminalPreferences),
823
- __metadata("design:type", Object)
824
- ], TerminalWidgetImpl.prototype, "preferences", void 0);
825
- __decorate([
826
- (0, inversify_1.inject)(core_1.ContributionProvider),
827
- (0, inversify_1.named)(exports.TerminalContribution),
828
- __metadata("design:type", Object)
829
- ], TerminalWidgetImpl.prototype, "terminalContributionProvider", void 0);
830
- __decorate([
831
- (0, inversify_1.inject)(terminal_service_1.TerminalService),
832
- __metadata("design:type", Object)
833
- ], TerminalWidgetImpl.prototype, "terminalService", void 0);
834
- __decorate([
835
- (0, inversify_1.inject)(terminal_search_widget_1.TerminalSearchWidgetFactory),
836
- __metadata("design:type", Function)
837
- ], TerminalWidgetImpl.prototype, "terminalSearchBoxFactory", void 0);
838
- __decorate([
839
- (0, inversify_1.inject)(terminal_copy_on_selection_handler_1.TerminalCopyOnSelectionHandler),
840
- __metadata("design:type", terminal_copy_on_selection_handler_1.TerminalCopyOnSelectionHandler)
841
- ], TerminalWidgetImpl.prototype, "copyOnSelectionHandler", void 0);
842
- __decorate([
843
- (0, inversify_1.inject)(terminal_theme_service_1.TerminalThemeService),
844
- __metadata("design:type", terminal_theme_service_1.TerminalThemeService)
845
- ], TerminalWidgetImpl.prototype, "themeService", void 0);
846
- __decorate([
847
- (0, inversify_1.inject)(shell_command_builder_1.ShellCommandBuilder),
848
- __metadata("design:type", shell_command_builder_1.ShellCommandBuilder)
849
- ], TerminalWidgetImpl.prototype, "shellCommandBuilder", void 0);
850
- __decorate([
851
- (0, inversify_1.inject)(browser_1.ContextMenuRenderer),
852
- __metadata("design:type", browser_1.ContextMenuRenderer)
853
- ], TerminalWidgetImpl.prototype, "contextMenuRenderer", void 0);
854
- __decorate([
855
- (0, inversify_1.inject)(markdown_renderer_1.MarkdownRendererFactory),
856
- __metadata("design:type", Function)
857
- ], TerminalWidgetImpl.prototype, "markdownRendererFactory", void 0);
858
- __decorate([
859
- (0, inversify_1.postConstruct)(),
860
- __metadata("design:type", Function),
861
- __metadata("design:paramtypes", []),
862
- __metadata("design:returntype", void 0)
863
- ], TerminalWidgetImpl.prototype, "init", null);
864
- TerminalWidgetImpl = TerminalWidgetImpl_1 = __decorate([
865
- (0, inversify_1.injectable)()
866
- ], TerminalWidgetImpl);
867
- exports.TerminalWidgetImpl = TerminalWidgetImpl;
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2017 TypeFox and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
18
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
22
+ };
23
+ var __metadata = (this && this.__metadata) || function (k, v) {
24
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25
+ };
26
+ var TerminalWidgetImpl_1;
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.TerminalWidgetImpl = exports.TerminalContribution = exports.TERMINAL_WIDGET_FACTORY_ID = void 0;
29
+ const xterm_1 = require("xterm");
30
+ const xterm_addon_fit_1 = require("xterm-addon-fit");
31
+ const inversify_1 = require("@theia/core/shared/inversify");
32
+ const core_1 = require("@theia/core");
33
+ const browser_1 = require("@theia/core/lib/browser");
34
+ const common_1 = require("@theia/core/lib/common");
35
+ const browser_2 = require("@theia/workspace/lib/browser");
36
+ const shell_terminal_protocol_1 = require("../common/shell-terminal-protocol");
37
+ const terminal_protocol_1 = require("../common/terminal-protocol");
38
+ const base_terminal_protocol_1 = require("../common/base-terminal-protocol");
39
+ const terminal_watcher_1 = require("../common/terminal-watcher");
40
+ const terminal_widget_1 = require("./base/terminal-widget");
41
+ const promise_util_1 = require("@theia/core/lib/common/promise-util");
42
+ const terminal_preferences_1 = require("./terminal-preferences");
43
+ const uri_1 = require("@theia/core/lib/common/uri");
44
+ const terminal_service_1 = require("./base/terminal-service");
45
+ const terminal_search_widget_1 = require("./search/terminal-search-widget");
46
+ const terminal_copy_on_selection_handler_1 = require("./terminal-copy-on-selection-handler");
47
+ const terminal_theme_service_1 = require("./terminal-theme-service");
48
+ const shell_command_builder_1 = require("@theia/process/lib/common/shell-command-builder");
49
+ const keys_1 = require("@theia/core/lib/browser/keys");
50
+ const nls_1 = require("@theia/core/lib/common/nls");
51
+ const terminal_frontend_contribution_1 = require("./terminal-frontend-contribution");
52
+ const debounce = require("p-debounce");
53
+ const markdown_string_1 = require("@theia/core/lib/common/markdown-rendering/markdown-string");
54
+ const markdown_renderer_1 = require("@theia/core/lib/browser/markdown-rendering/markdown-renderer");
55
+ const service_connection_provider_1 = require("@theia/core/lib/browser/messaging/service-connection-provider");
56
+ exports.TERMINAL_WIDGET_FACTORY_ID = 'terminal';
57
+ exports.TerminalContribution = Symbol('TerminalContribution');
58
+ let TerminalWidgetImpl = TerminalWidgetImpl_1 = class TerminalWidgetImpl extends terminal_widget_1.TerminalWidget {
59
+ constructor() {
60
+ super(...arguments);
61
+ this.isExtractable = true;
62
+ this.terminalKind = 'user';
63
+ this._terminalId = -1;
64
+ this.onTermDidClose = new core_1.Emitter();
65
+ this.restored = false;
66
+ this.closeOnDispose = true;
67
+ this.isAttachedCloseListener = false;
68
+ this.shown = false;
69
+ this.lastCwd = new uri_1.default();
70
+ this.onDidOpenEmitter = new core_1.Emitter();
71
+ this.onDidOpen = this.onDidOpenEmitter.event;
72
+ this.onDidOpenFailureEmitter = new core_1.Emitter();
73
+ this.onDidOpenFailure = this.onDidOpenFailureEmitter.event;
74
+ this.onSizeChangedEmitter = new core_1.Emitter();
75
+ this.onSizeChanged = this.onSizeChangedEmitter.event;
76
+ this.onDataEmitter = new core_1.Emitter();
77
+ this.onData = this.onDataEmitter.event;
78
+ this.onKeyEmitter = new core_1.Emitter();
79
+ this.onKey = this.onKeyEmitter.event;
80
+ this.onMouseEnterLinkHoverEmitter = new core_1.Emitter();
81
+ this.onMouseEnterLinkHover = this.onMouseEnterLinkHoverEmitter.event;
82
+ this.onMouseLeaveLinkHoverEmitter = new core_1.Emitter();
83
+ this.onMouseLeaveLinkHover = this.onMouseLeaveLinkHoverEmitter.event;
84
+ this.toDisposeOnConnect = new core_1.DisposableCollection();
85
+ this.needsResize = true;
86
+ // Device status code emitted by Xterm.js
87
+ // Check: https://github.com/xtermjs/xterm.js/blob/release/3.14/src/InputHandler.ts#L1055-L1082
88
+ this.deviceStatusCodes = new Set(['\u001B[>0;276;0c', '\u001B[>85;95;0c', '\u001B[>83;40003;0c', '\u001B[?1;2c', '\u001B[?6c']);
89
+ this.termOpened = false;
90
+ this.initialData = '';
91
+ this.resizeTerminal = debounce(() => this.doResizeTerminal(), 50);
92
+ }
93
+ get markdownRenderer() {
94
+ this._markdownRenderer || (this._markdownRenderer = this.markdownRendererFactory());
95
+ return this._markdownRenderer;
96
+ }
97
+ init() {
98
+ this.setTitle(this.options.title || TerminalWidgetImpl_1.LABEL);
99
+ if (this.options.iconClass) {
100
+ this.title.iconClass = this.options.iconClass;
101
+ }
102
+ else {
103
+ this.title.iconClass = (0, browser_1.codicon)('terminal');
104
+ }
105
+ if (this.options.kind) {
106
+ this.terminalKind = this.options.kind;
107
+ }
108
+ if (this.options.destroyTermOnClose === true) {
109
+ this.toDispose.push(core_1.Disposable.create(() => this.term.dispose()));
110
+ }
111
+ this.location = this.options.location || terminal_widget_1.TerminalLocation.Panel;
112
+ this.title.closable = true;
113
+ this.addClass('terminal-container');
114
+ this.term = new xterm_1.Terminal({
115
+ cursorBlink: this.preferences['terminal.integrated.cursorBlinking'],
116
+ cursorStyle: this.preferences['terminal.integrated.cursorStyle'] === 'line' ? 'bar' : this.preferences['terminal.integrated.cursorStyle'],
117
+ cursorWidth: this.preferences['terminal.integrated.cursorWidth'],
118
+ fontFamily: this.preferences['terminal.integrated.fontFamily'],
119
+ fontSize: this.preferences['terminal.integrated.fontSize'],
120
+ fontWeight: this.preferences['terminal.integrated.fontWeight'],
121
+ fontWeightBold: this.preferences['terminal.integrated.fontWeightBold'],
122
+ drawBoldTextInBrightColors: this.preferences['terminal.integrated.drawBoldTextInBrightColors'],
123
+ letterSpacing: this.preferences['terminal.integrated.letterSpacing'],
124
+ lineHeight: this.preferences['terminal.integrated.lineHeight'],
125
+ scrollback: this.preferences['terminal.integrated.scrollback'],
126
+ fastScrollSensitivity: this.preferences['terminal.integrated.fastScrollSensitivity'],
127
+ theme: this.themeService.theme
128
+ });
129
+ this.fitAddon = new xterm_addon_fit_1.FitAddon();
130
+ this.term.loadAddon(this.fitAddon);
131
+ this.initializeLinkHover();
132
+ this.toDispose.push(this.preferences.onPreferenceChanged(change => {
133
+ this.updateConfig();
134
+ this.needsResize = true;
135
+ this.update();
136
+ }));
137
+ this.toDispose.push(this.themeService.onDidChange(() => this.term.options.theme = this.themeService.theme));
138
+ this.attachCustomKeyEventHandler();
139
+ const titleChangeListenerDispose = this.term.onTitleChange((title) => {
140
+ if (this.options.useServerTitle) {
141
+ this.title.label = title;
142
+ }
143
+ });
144
+ this.toDispose.push(titleChangeListenerDispose);
145
+ this.toDispose.push(this.terminalWatcher.onTerminalError(({ terminalId, error, attached }) => {
146
+ if (terminalId === this.terminalId) {
147
+ this.exitStatus = { code: undefined, reason: base_terminal_protocol_1.TerminalExitReason.Process };
148
+ this.logger.error(`The terminal process terminated. Cause: ${error}`);
149
+ if (!attached) {
150
+ this.dispose();
151
+ }
152
+ }
153
+ }));
154
+ this.toDispose.push(this.terminalWatcher.onTerminalExit(({ terminalId, code, reason, attached }) => {
155
+ if (terminalId === this.terminalId) {
156
+ if (reason) {
157
+ this.exitStatus = { code, reason };
158
+ }
159
+ else {
160
+ this.exitStatus = { code, reason: base_terminal_protocol_1.TerminalExitReason.Process };
161
+ }
162
+ if (!attached) {
163
+ this.dispose();
164
+ }
165
+ }
166
+ }));
167
+ this.toDispose.push(this.toDisposeOnConnect);
168
+ this.toDispose.push(this.shellTerminalServer.onDidCloseConnection(() => {
169
+ const disposable = this.shellTerminalServer.onDidOpenConnection(() => {
170
+ disposable.dispose();
171
+ this.reconnectTerminalProcess();
172
+ });
173
+ this.toDispose.push(disposable);
174
+ }));
175
+ this.toDispose.push(this.onTermDidClose);
176
+ this.toDispose.push(this.onDidOpenEmitter);
177
+ this.toDispose.push(this.onDidOpenFailureEmitter);
178
+ this.toDispose.push(this.onSizeChangedEmitter);
179
+ this.toDispose.push(this.onDataEmitter);
180
+ this.toDispose.push(this.onKeyEmitter);
181
+ const touchEndListener = (event) => {
182
+ if (this.node.contains(event.target)) {
183
+ this.lastTouchEnd = event;
184
+ }
185
+ };
186
+ document.addEventListener('touchend', touchEndListener, { passive: true });
187
+ this.onDispose(() => {
188
+ document.removeEventListener('touchend', touchEndListener);
189
+ });
190
+ const mouseListener = (event) => {
191
+ this.lastMousePosition = { x: event.x, y: event.y };
192
+ };
193
+ this.node.addEventListener('mousemove', mouseListener);
194
+ this.onDispose(() => {
195
+ this.node.removeEventListener('mousemove', mouseListener);
196
+ });
197
+ const contextMenuListener = (event) => {
198
+ event.preventDefault();
199
+ event.stopPropagation();
200
+ this.contextMenuRenderer.render({ menuPath: terminal_frontend_contribution_1.TerminalMenus.TERMINAL_CONTEXT_MENU, anchor: event });
201
+ };
202
+ this.node.addEventListener('contextmenu', contextMenuListener);
203
+ this.onDispose(() => this.node.removeEventListener('contextmenu', contextMenuListener));
204
+ this.toDispose.push(this.term.onSelectionChange(() => {
205
+ if (this.copyOnSelection) {
206
+ this.copyOnSelectionHandler.copy(this.term.getSelection());
207
+ }
208
+ }));
209
+ this.toDispose.push(this.term.onResize(data => {
210
+ this.onSizeChangedEmitter.fire(data);
211
+ }));
212
+ this.toDispose.push(this.term.onData(data => {
213
+ this.onDataEmitter.fire(data);
214
+ }));
215
+ this.toDispose.push(this.term.onBinary(data => {
216
+ this.onDataEmitter.fire(data);
217
+ }));
218
+ this.toDispose.push(this.term.onKey(data => {
219
+ this.onKeyEmitter.fire(data);
220
+ }));
221
+ for (const contribution of this.terminalContributionProvider.getContributions()) {
222
+ contribution.onCreate(this);
223
+ }
224
+ this.searchBox = this.terminalSearchBoxFactory(this.term);
225
+ this.toDispose.push(this.searchBox);
226
+ }
227
+ get kind() {
228
+ return this.terminalKind;
229
+ }
230
+ updateConfig() {
231
+ this.setCursorBlink(this.preferences.get('terminal.integrated.cursorBlinking'));
232
+ this.setCursorStyle(this.preferences.get('terminal.integrated.cursorStyle'));
233
+ this.setCursorWidth(this.preferences.get('terminal.integrated.cursorWidth'));
234
+ this.term.options.fontFamily = this.preferences.get('terminal.integrated.fontFamily');
235
+ this.term.options.fontSize = this.preferences.get('terminal.integrated.fontSize');
236
+ this.term.options.fontWeight = this.preferences.get('terminal.integrated.fontWeight');
237
+ this.term.options.fontWeightBold = this.preferences.get('terminal.integrated.fontWeightBold');
238
+ this.term.options.drawBoldTextInBrightColors = this.preferences.get('terminal.integrated.drawBoldTextInBrightColors');
239
+ this.term.options.letterSpacing = this.preferences.get('terminal.integrated.letterSpacing');
240
+ this.term.options.lineHeight = this.preferences.get('terminal.integrated.lineHeight');
241
+ this.term.options.scrollback = this.preferences.get('terminal.integrated.scrollback');
242
+ this.term.options.fastScrollSensitivity = this.preferences.get('terminal.integrated.fastScrollSensitivity');
243
+ }
244
+ setCursorBlink(blink) {
245
+ if (this.term.options.cursorBlink !== blink) {
246
+ this.term.options.cursorBlink = blink;
247
+ this.term.refresh(0, this.term.rows - 1);
248
+ }
249
+ }
250
+ setCursorStyle(style) {
251
+ if (this.term.options.cursorStyle !== style) {
252
+ this.term.options.cursorStyle = (style === 'line') ? 'bar' : style;
253
+ }
254
+ }
255
+ setCursorWidth(width) {
256
+ if (this.term.options.cursorWidth !== width) {
257
+ this.term.options.cursorWidth = width;
258
+ }
259
+ }
260
+ initializeLinkHover() {
261
+ this.linkHover = document.createElement('div');
262
+ this.linkHover.style.position = 'fixed';
263
+ this.linkHover.style.color = 'var(--theia-editorHoverWidget-foreground)';
264
+ this.linkHover.style.backgroundColor = 'var(--theia-editorHoverWidget-background)';
265
+ this.linkHover.style.borderColor = 'var(--theia-editorHoverWidget-border)';
266
+ this.linkHover.style.borderWidth = '0.5px';
267
+ this.linkHover.style.borderStyle = 'solid';
268
+ this.linkHover.style.padding = '5px';
269
+ // Above the xterm.js canvas layers:
270
+ // https://github.com/xtermjs/xterm.js/blob/ff790236c1b205469f17a21246141f512d844295/src/renderer/Renderer.ts#L41-L46
271
+ this.linkHover.style.zIndex = '10';
272
+ // Initially invisible:
273
+ this.linkHover.style.display = 'none';
274
+ this.linkHoverButton = document.createElement('a');
275
+ this.linkHoverButton.textContent = this.linkHoverMessage();
276
+ this.linkHoverButton.style.cursor = 'pointer';
277
+ this.linkHover.appendChild(this.linkHoverButton);
278
+ const cmdCtrl = common_1.isOSX ? 'cmd' : 'ctrl';
279
+ const cmdHint = document.createTextNode(` (${nls_1.nls.localizeByDefault(`${cmdCtrl} + click`)})`);
280
+ this.linkHover.appendChild(cmdHint);
281
+ const onMouseEnter = (mouseEvent) => this.onMouseEnterLinkHoverEmitter.fire(mouseEvent);
282
+ this.linkHover.addEventListener('mouseenter', onMouseEnter);
283
+ this.toDispose.push(core_1.Disposable.create(() => this.linkHover.removeEventListener('mouseenter', onMouseEnter)));
284
+ const onMouseLeave = (mouseEvent) => this.onMouseLeaveLinkHoverEmitter.fire(mouseEvent);
285
+ this.linkHover.addEventListener('mouseleave', onMouseLeave);
286
+ this.toDispose.push(core_1.Disposable.create(() => this.linkHover.removeEventListener('mouseleave', onMouseLeave)));
287
+ this.node.appendChild(this.linkHover);
288
+ }
289
+ showLinkHover(invokeAction, x, y, message) {
290
+ var _a, _b, _c, _d;
291
+ const mouseY = (_b = (_a = this.lastMousePosition) === null || _a === void 0 ? void 0 : _a.y) !== null && _b !== void 0 ? _b : y;
292
+ const mouseX = (_d = (_c = this.lastMousePosition) === null || _c === void 0 ? void 0 : _c.x) !== null && _d !== void 0 ? _d : x;
293
+ this.linkHoverButton.textContent = this.linkHoverMessage(message);
294
+ this.linkHoverButton.onclick = (mouseEvent) => invokeAction(mouseEvent);
295
+ this.linkHover.style.display = 'inline';
296
+ this.linkHover.style.top = `${mouseY - 30}px`;
297
+ this.linkHover.style.left = `${mouseX - 60}px`;
298
+ }
299
+ linkHoverMessage(message) {
300
+ return message !== null && message !== void 0 ? message : nls_1.nls.localizeByDefault('Follow link');
301
+ }
302
+ hideLinkHover() {
303
+ this.linkHover.style.display = 'none';
304
+ // eslint-disable-next-line no-null/no-null
305
+ this.linkHoverButton.onclick = null;
306
+ }
307
+ getTerminal() {
308
+ return this.term;
309
+ }
310
+ getSearchBox() {
311
+ return this.searchBox;
312
+ }
313
+ onCloseRequest(msg) {
314
+ this.exitStatus = { code: undefined, reason: base_terminal_protocol_1.TerminalExitReason.User };
315
+ super.onCloseRequest(msg);
316
+ }
317
+ get dimensions() {
318
+ return {
319
+ cols: this.term.cols,
320
+ rows: this.term.rows,
321
+ };
322
+ }
323
+ get cwd() {
324
+ if (!base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)) {
325
+ return Promise.reject(new Error('terminal is not started'));
326
+ }
327
+ if (this.terminalService.getById(this.id)) {
328
+ return this.shellTerminalServer.getCwdURI(this.terminalId)
329
+ .then(cwdUrl => {
330
+ this.lastCwd = new uri_1.default(cwdUrl);
331
+ return this.lastCwd;
332
+ }).catch(() => this.lastCwd);
333
+ }
334
+ return Promise.resolve(new uri_1.default());
335
+ }
336
+ get processId() {
337
+ if (!base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)) {
338
+ return Promise.reject(new Error('terminal is not started'));
339
+ }
340
+ return this.shellTerminalServer.getProcessId(this.terminalId);
341
+ }
342
+ get processInfo() {
343
+ if (!base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)) {
344
+ return Promise.reject(new Error('terminal is not started'));
345
+ }
346
+ return this.shellTerminalServer.getProcessInfo(this.terminalId);
347
+ }
348
+ get envVarCollectionDescriptionsByExtension() {
349
+ if (!base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)) {
350
+ return Promise.reject(new Error('terminal is not started'));
351
+ }
352
+ return this.shellTerminalServer.getEnvVarCollectionDescriptionsByExtension(this.terminalId);
353
+ }
354
+ get terminalId() {
355
+ return this._terminalId;
356
+ }
357
+ get lastTouchEndEvent() {
358
+ return this.lastTouchEnd;
359
+ }
360
+ get hiddenFromUser() {
361
+ var _a;
362
+ if (this.shown) {
363
+ return false;
364
+ }
365
+ return (_a = this.options.hideFromUser) !== null && _a !== void 0 ? _a : false;
366
+ }
367
+ get transient() {
368
+ // The terminal is transient if session persistence is disabled or it's explicitly marked as transient
369
+ return !this.preferences['terminal.integrated.enablePersistentSessions'] || !!this.options.isTransient;
370
+ }
371
+ onDispose(onDispose) {
372
+ this.toDispose.push(core_1.Disposable.create(onDispose));
373
+ }
374
+ clearOutput() {
375
+ this.term.clear();
376
+ }
377
+ selectAll() {
378
+ this.term.selectAll();
379
+ }
380
+ async hasChildProcesses() {
381
+ return this.shellTerminalServer.hasChildProcesses(await this.processId);
382
+ }
383
+ storeState() {
384
+ this.closeOnDispose = false;
385
+ if (this.transient || this.options.isPseudoTerminal) {
386
+ return {};
387
+ }
388
+ return { terminalId: this.terminalId, titleLabel: this.title.label };
389
+ }
390
+ restoreState(oldState) {
391
+ // transient terminals and pseudo terminals are not restored
392
+ if (this.transient || this.options.isPseudoTerminal) {
393
+ this.dispose();
394
+ return;
395
+ }
396
+ if (this.restored === false) {
397
+ const state = oldState;
398
+ /* This is a workaround to issue #879 */
399
+ this.restored = true;
400
+ this.title.label = state.titleLabel;
401
+ this.start(state.terminalId);
402
+ }
403
+ }
404
+ /**
405
+ * Create a new shell terminal in the back-end and attach it to a
406
+ * new terminal widget.
407
+ * If id is provided attach to the terminal for this id.
408
+ */
409
+ async start(id) {
410
+ this._terminalId = typeof id !== 'number' ? await this.createTerminal() : await this.attachTerminal(id);
411
+ this.resizeTerminalProcess();
412
+ this.connectTerminalProcess();
413
+ if (base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)) {
414
+ this.onDidOpenEmitter.fire(undefined);
415
+ await this.shellTerminalServer.onAttachAttempted(this._terminalId);
416
+ return this.terminalId;
417
+ }
418
+ this.onDidOpenFailureEmitter.fire(undefined);
419
+ throw new Error('Failed to start terminal' + (id ? ` for id: ${id}.` : '.'));
420
+ }
421
+ async attachTerminal(id) {
422
+ const terminalId = await this.shellTerminalServer.attach(id);
423
+ if (base_terminal_protocol_1.IBaseTerminalServer.validateId(terminalId)) {
424
+ // reset exit status if a new terminal process is attached
425
+ this.exitStatus = undefined;
426
+ return terminalId;
427
+ }
428
+ this.logger.warn(`Failed attaching to terminal id ${id}, the terminal is most likely gone. Starting up a new terminal instead.`);
429
+ if (this.kind === 'user') {
430
+ return this.createTerminal();
431
+ }
432
+ else {
433
+ return -1;
434
+ }
435
+ }
436
+ async createTerminal() {
437
+ var _a, _b;
438
+ let rootURI = (_a = this.options.cwd) === null || _a === void 0 ? void 0 : _a.toString();
439
+ if (!rootURI) {
440
+ const root = (await this.workspaceService.roots)[0];
441
+ rootURI = (_b = root === null || root === void 0 ? void 0 : root.resource) === null || _b === void 0 ? void 0 : _b.toString();
442
+ }
443
+ const { cols, rows } = this.term;
444
+ const terminalId = await this.shellTerminalServer.create({
445
+ shell: this.options.shellPath || this.shellPreferences.shell[core_1.OS.backend.type()],
446
+ args: this.options.shellArgs || this.shellPreferences.shellArgs[core_1.OS.backend.type()],
447
+ env: this.options.env,
448
+ strictEnv: this.options.strictEnv,
449
+ isPseudo: this.options.isPseudoTerminal,
450
+ rootURI,
451
+ cols,
452
+ rows
453
+ });
454
+ if (base_terminal_protocol_1.IBaseTerminalServer.validateId(terminalId)) {
455
+ return terminalId;
456
+ }
457
+ throw new Error('Error creating terminal widget, see the backend error log for more information.');
458
+ }
459
+ processMessage(msg) {
460
+ super.processMessage(msg);
461
+ switch (msg.type) {
462
+ case 'fit-request':
463
+ this.onFitRequest(msg);
464
+ break;
465
+ default:
466
+ break;
467
+ }
468
+ }
469
+ onFitRequest(msg) {
470
+ super.onFitRequest(msg);
471
+ browser_1.MessageLoop.sendMessage(this, browser_1.Widget.ResizeMessage.UnknownSize);
472
+ }
473
+ onActivateRequest(msg) {
474
+ super.onActivateRequest(msg);
475
+ this.term.focus();
476
+ }
477
+ onAfterShow(msg) {
478
+ super.onAfterShow(msg);
479
+ this.update();
480
+ this.shown = true;
481
+ }
482
+ onAfterAttach(msg) {
483
+ browser_1.Widget.attach(this.searchBox, this.node);
484
+ super.onAfterAttach(msg);
485
+ this.update();
486
+ }
487
+ onBeforeDetach(msg) {
488
+ browser_1.Widget.detach(this.searchBox);
489
+ super.onBeforeDetach(msg);
490
+ }
491
+ onResize(msg) {
492
+ super.onResize(msg);
493
+ this.needsResize = true;
494
+ this.update();
495
+ }
496
+ onUpdateRequest(msg) {
497
+ super.onUpdateRequest(msg);
498
+ if (!this.isVisible || !this.isAttached) {
499
+ return;
500
+ }
501
+ this.open();
502
+ if (this.needsResize) {
503
+ this.resizeTerminal();
504
+ this.needsResize = false;
505
+ }
506
+ }
507
+ connectTerminalProcess() {
508
+ if (typeof this.terminalId !== 'number') {
509
+ return;
510
+ }
511
+ if (this.options.isPseudoTerminal) {
512
+ return;
513
+ }
514
+ this.toDisposeOnConnect.dispose();
515
+ this.toDispose.push(this.toDisposeOnConnect);
516
+ const waitForConnection = this.waitForConnection = new promise_util_1.Deferred();
517
+ this.connectionProvider.listen(`${terminal_protocol_1.terminalsPath}/${this.terminalId}`, (path, connection) => {
518
+ connection.onMessage(e => {
519
+ this.write(e().readString());
520
+ });
521
+ // Excludes the device status code emitted by Xterm.js
522
+ const sendData = (data) => {
523
+ if (data && !this.deviceStatusCodes.has(data) && !this.disableEnterWhenAttachCloseListener()) {
524
+ connection.getWriteBuffer().writeString(data).commit();
525
+ }
526
+ };
527
+ const disposable = new core_1.DisposableCollection();
528
+ disposable.push(this.term.onData(sendData));
529
+ disposable.push(this.term.onBinary(sendData));
530
+ connection.onClose(() => disposable.dispose());
531
+ if (waitForConnection) {
532
+ waitForConnection.resolve(connection);
533
+ }
534
+ }, false);
535
+ }
536
+ async reconnectTerminalProcess() {
537
+ if (this.options.isPseudoTerminal) {
538
+ return;
539
+ }
540
+ if (typeof this.terminalId === 'number') {
541
+ await this.start(this.terminalId);
542
+ }
543
+ }
544
+ open() {
545
+ if (this.termOpened) {
546
+ return;
547
+ }
548
+ this.term.open(this.node);
549
+ // Workaround for https://github.com/xtermjs/xterm.js/issues/4775. Can be removed for releases > 5.3.0
550
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
551
+ const viewPort = this.term._core.viewport;
552
+ viewPort.register(core_1.Disposable.create(() => {
553
+ if (typeof viewPort._refreshAnimationFrame === 'number') {
554
+ viewPort._coreBrowserService.window.cancelAnimationFrame(viewPort._refreshAnimationFrame);
555
+ }
556
+ }));
557
+ if (browser_1.isFirefox) {
558
+ // monkey patching intersection observer handling for secondary window support
559
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
560
+ const renderService = this.term._core._renderService;
561
+ const originalFunc = renderService._handleIntersectionChange.bind(renderService);
562
+ const replacement = function (entry) {
563
+ if (entry.target.ownerDocument !== document) {
564
+ // in Firefox, the intersection observer always reports the widget as non-intersecting if the dom element
565
+ // is in a different document from when the IntersectionObserver started observing. Since we know
566
+ // that the widget is always "visible" when in a secondary window, so we refresh the rows ourselves
567
+ const patchedEvent = {
568
+ ...entry,
569
+ isIntersecting: true,
570
+ };
571
+ originalFunc(patchedEvent);
572
+ }
573
+ else {
574
+ originalFunc(entry);
575
+ }
576
+ };
577
+ renderService._handleIntersectionChange = replacement.bind(renderService);
578
+ }
579
+ if (this.initialData) {
580
+ this.term.write(this.initialData);
581
+ }
582
+ this.termOpened = true;
583
+ this.initialData = '';
584
+ }
585
+ write(data) {
586
+ if (this.termOpened) {
587
+ this.term.write(data);
588
+ }
589
+ else {
590
+ this.initialData += data;
591
+ }
592
+ }
593
+ resize(cols, rows) {
594
+ this.term.resize(cols, rows);
595
+ }
596
+ sendText(text) {
597
+ if (this.waitForConnection) {
598
+ this.waitForConnection.promise.then(connection => connection.getWriteBuffer().writeString(text).commit());
599
+ }
600
+ }
601
+ async executeCommand(commandOptions) {
602
+ this.sendText(this.shellCommandBuilder.buildCommand(await this.processInfo, commandOptions) + core_1.OS.backend.EOL);
603
+ }
604
+ scrollLineUp() {
605
+ this.term.scrollLines(-1);
606
+ }
607
+ scrollLineDown() {
608
+ this.term.scrollLines(1);
609
+ }
610
+ scrollToTop() {
611
+ this.term.scrollToTop();
612
+ }
613
+ scrollToBottom() {
614
+ this.term.scrollToBottom();
615
+ }
616
+ scrollPageUp() {
617
+ this.term.scrollPages(-1);
618
+ }
619
+ scrollPageDown() {
620
+ this.term.scrollPages(1);
621
+ }
622
+ resetTerminal() {
623
+ this.term.reset();
624
+ }
625
+ writeLine(text) {
626
+ this.term.writeln(text);
627
+ }
628
+ get onTerminalDidClose() {
629
+ return this.onTermDidClose.event;
630
+ }
631
+ dispose() {
632
+ if (this.closeOnDispose === true && typeof this.terminalId === 'number' && !this.exitStatus) {
633
+ // Close the backend terminal only when explicitly closing the terminal
634
+ // a refresh for example won't close it.
635
+ this.shellTerminalServer.close(this.terminalId);
636
+ // Exit status is set when terminal is closed by user or by process, so most likely an extension closed it.
637
+ this.exitStatus = { code: undefined, reason: base_terminal_protocol_1.TerminalExitReason.Extension };
638
+ }
639
+ if (this.exitStatus) {
640
+ this.onTermDidClose.fire(this);
641
+ }
642
+ if (this.enhancedPreviewNode) {
643
+ // don't use preview node anymore. rendered markdown will be disposed on super call
644
+ this.enhancedPreviewNode = undefined;
645
+ }
646
+ super.dispose();
647
+ }
648
+ doResizeTerminal() {
649
+ if (this.isDisposed) {
650
+ return;
651
+ }
652
+ const geo = this.fitAddon.proposeDimensions();
653
+ if (geo) {
654
+ const cols = geo.cols;
655
+ const rows = geo.rows - 1; // subtract one row for margin
656
+ this.term.resize(cols, rows);
657
+ this.resizeTerminalProcess();
658
+ }
659
+ }
660
+ resizeTerminalProcess() {
661
+ if (this.options.isPseudoTerminal) {
662
+ return;
663
+ }
664
+ if (!base_terminal_protocol_1.IBaseTerminalServer.validateId(this.terminalId)
665
+ || this.exitStatus
666
+ || !this.terminalService.getById(this.id)) {
667
+ return;
668
+ }
669
+ const { cols, rows } = this.term;
670
+ this.shellTerminalServer.resize(this.terminalId, cols, rows);
671
+ }
672
+ get enableCopy() {
673
+ return this.preferences['terminal.enableCopy'];
674
+ }
675
+ get enablePaste() {
676
+ return this.preferences['terminal.enablePaste'];
677
+ }
678
+ get shellPreferences() {
679
+ var _a, _b, _c;
680
+ return {
681
+ shell: {
682
+ Windows: (_a = this.preferences['terminal.integrated.shell.windows']) !== null && _a !== void 0 ? _a : undefined,
683
+ Linux: (_b = this.preferences['terminal.integrated.shell.linux']) !== null && _b !== void 0 ? _b : undefined,
684
+ OSX: (_c = this.preferences['terminal.integrated.shell.osx']) !== null && _c !== void 0 ? _c : undefined,
685
+ },
686
+ shellArgs: {
687
+ Windows: this.preferences['terminal.integrated.shellArgs.windows'],
688
+ Linux: this.preferences['terminal.integrated.shellArgs.linux'],
689
+ OSX: this.preferences['terminal.integrated.shellArgs.osx'],
690
+ }
691
+ };
692
+ }
693
+ customKeyHandler(event) {
694
+ const keyBindings = browser_1.KeyCode.createKeyCode(event).toString();
695
+ const ctrlCmdCopy = (common_1.isOSX && keyBindings === 'meta+c') || (!common_1.isOSX && keyBindings === 'ctrl+c');
696
+ const ctrlCmdPaste = (common_1.isOSX && keyBindings === 'meta+v') || (!common_1.isOSX && keyBindings === 'ctrl+v');
697
+ if (ctrlCmdCopy && this.enableCopy && this.term.hasSelection()) {
698
+ return false;
699
+ }
700
+ if (ctrlCmdPaste && this.enablePaste) {
701
+ return false;
702
+ }
703
+ return true;
704
+ }
705
+ get copyOnSelection() {
706
+ return this.preferences['terminal.integrated.copyOnSelection'];
707
+ }
708
+ attachCustomKeyEventHandler() {
709
+ this.term.attachCustomKeyEventHandler(e => this.customKeyHandler(e));
710
+ }
711
+ setTitle(title) {
712
+ this.title.caption = title;
713
+ this.title.label = title;
714
+ }
715
+ waitOnExit(waitOnExit) {
716
+ if (waitOnExit) {
717
+ if (typeof waitOnExit === 'string') {
718
+ let message = waitOnExit;
719
+ // Bold the message and add an extra new line to make it stand out from the rest of the output
720
+ message = `\r\n\x1b[1m${message}\x1b[0m`;
721
+ this.write(message);
722
+ }
723
+ this.attachPressEnterKeyToCloseListener(this.term);
724
+ return;
725
+ }
726
+ this.dispose();
727
+ }
728
+ attachPressEnterKeyToCloseListener(term) {
729
+ if (term.textarea) {
730
+ this.isAttachedCloseListener = true;
731
+ this.addKeyListener(term.textarea, keys_1.Key.ENTER, (event) => {
732
+ this.dispose();
733
+ this.isAttachedCloseListener = false;
734
+ });
735
+ }
736
+ }
737
+ disableEnterWhenAttachCloseListener() {
738
+ return this.isAttachedCloseListener;
739
+ }
740
+ getEnhancedPreviewNode() {
741
+ if (this.enhancedPreviewNode) {
742
+ return this.enhancedPreviewNode;
743
+ }
744
+ this.enhancedPreviewNode = document.createElement('div');
745
+ Promise.all([this.envVarCollectionDescriptionsByExtension, this.processId, this.processInfo])
746
+ .then((values) => {
747
+ const extensions = values[0];
748
+ const processId = values[1];
749
+ const processInfo = values[2];
750
+ const markdown = new markdown_string_1.MarkdownStringImpl();
751
+ markdown.appendMarkdown('Process ID: ' + processId + '\\\n');
752
+ markdown.appendMarkdown('Command line: ' +
753
+ processInfo.executable +
754
+ ' ' +
755
+ processInfo.arguments.join(' ') +
756
+ '\n\n---\n\n');
757
+ markdown.appendMarkdown('The following extensions have contributed to this terminal\'s environment:\n');
758
+ extensions.forEach((arr, key) => {
759
+ arr.forEach(value => {
760
+ if (value === undefined) {
761
+ markdown.appendMarkdown('* ' + key + '\n');
762
+ }
763
+ else if (typeof value === 'string') {
764
+ markdown.appendMarkdown('* ' + key + ': ' + value + '\n');
765
+ }
766
+ else {
767
+ markdown.appendMarkdown('* ' + key + ': ' + value.value + '\n');
768
+ }
769
+ });
770
+ });
771
+ const enhancedPreviewNode = this.enhancedPreviewNode;
772
+ if (!this.isDisposed && enhancedPreviewNode) {
773
+ const result = this.markdownRenderer.render(markdown);
774
+ this.toDispose.push(result);
775
+ enhancedPreviewNode.appendChild(result.element);
776
+ }
777
+ });
778
+ return this.enhancedPreviewNode;
779
+ }
780
+ };
781
+ TerminalWidgetImpl.LABEL = nls_1.nls.localizeByDefault('Terminal');
782
+ __decorate([
783
+ (0, inversify_1.inject)(browser_2.WorkspaceService),
784
+ __metadata("design:type", browser_2.WorkspaceService)
785
+ ], TerminalWidgetImpl.prototype, "workspaceService", void 0);
786
+ __decorate([
787
+ (0, inversify_1.inject)(service_connection_provider_1.RemoteConnectionProvider),
788
+ __metadata("design:type", service_connection_provider_1.ServiceConnectionProvider)
789
+ ], TerminalWidgetImpl.prototype, "connectionProvider", void 0);
790
+ __decorate([
791
+ (0, inversify_1.inject)(terminal_widget_1.TerminalWidgetOptions),
792
+ __metadata("design:type", Object)
793
+ ], TerminalWidgetImpl.prototype, "options", void 0);
794
+ __decorate([
795
+ (0, inversify_1.inject)(shell_terminal_protocol_1.ShellTerminalServerProxy),
796
+ __metadata("design:type", Object)
797
+ ], TerminalWidgetImpl.prototype, "shellTerminalServer", void 0);
798
+ __decorate([
799
+ (0, inversify_1.inject)(terminal_watcher_1.TerminalWatcher),
800
+ __metadata("design:type", terminal_watcher_1.TerminalWatcher)
801
+ ], TerminalWidgetImpl.prototype, "terminalWatcher", void 0);
802
+ __decorate([
803
+ (0, inversify_1.inject)(core_1.ILogger),
804
+ (0, inversify_1.named)('terminal'),
805
+ __metadata("design:type", Object)
806
+ ], TerminalWidgetImpl.prototype, "logger", void 0);
807
+ __decorate([
808
+ (0, inversify_1.inject)('terminal-dom-id'),
809
+ __metadata("design:type", String)
810
+ ], TerminalWidgetImpl.prototype, "id", void 0);
811
+ __decorate([
812
+ (0, inversify_1.inject)(terminal_preferences_1.TerminalPreferences),
813
+ __metadata("design:type", Object)
814
+ ], TerminalWidgetImpl.prototype, "preferences", void 0);
815
+ __decorate([
816
+ (0, inversify_1.inject)(core_1.ContributionProvider),
817
+ (0, inversify_1.named)(exports.TerminalContribution),
818
+ __metadata("design:type", Object)
819
+ ], TerminalWidgetImpl.prototype, "terminalContributionProvider", void 0);
820
+ __decorate([
821
+ (0, inversify_1.inject)(terminal_service_1.TerminalService),
822
+ __metadata("design:type", Object)
823
+ ], TerminalWidgetImpl.prototype, "terminalService", void 0);
824
+ __decorate([
825
+ (0, inversify_1.inject)(terminal_search_widget_1.TerminalSearchWidgetFactory),
826
+ __metadata("design:type", Function)
827
+ ], TerminalWidgetImpl.prototype, "terminalSearchBoxFactory", void 0);
828
+ __decorate([
829
+ (0, inversify_1.inject)(terminal_copy_on_selection_handler_1.TerminalCopyOnSelectionHandler),
830
+ __metadata("design:type", terminal_copy_on_selection_handler_1.TerminalCopyOnSelectionHandler)
831
+ ], TerminalWidgetImpl.prototype, "copyOnSelectionHandler", void 0);
832
+ __decorate([
833
+ (0, inversify_1.inject)(terminal_theme_service_1.TerminalThemeService),
834
+ __metadata("design:type", terminal_theme_service_1.TerminalThemeService)
835
+ ], TerminalWidgetImpl.prototype, "themeService", void 0);
836
+ __decorate([
837
+ (0, inversify_1.inject)(shell_command_builder_1.ShellCommandBuilder),
838
+ __metadata("design:type", shell_command_builder_1.ShellCommandBuilder)
839
+ ], TerminalWidgetImpl.prototype, "shellCommandBuilder", void 0);
840
+ __decorate([
841
+ (0, inversify_1.inject)(browser_1.ContextMenuRenderer),
842
+ __metadata("design:type", browser_1.ContextMenuRenderer)
843
+ ], TerminalWidgetImpl.prototype, "contextMenuRenderer", void 0);
844
+ __decorate([
845
+ (0, inversify_1.inject)(markdown_renderer_1.MarkdownRendererFactory),
846
+ __metadata("design:type", Function)
847
+ ], TerminalWidgetImpl.prototype, "markdownRendererFactory", void 0);
848
+ __decorate([
849
+ (0, inversify_1.postConstruct)(),
850
+ __metadata("design:type", Function),
851
+ __metadata("design:paramtypes", []),
852
+ __metadata("design:returntype", void 0)
853
+ ], TerminalWidgetImpl.prototype, "init", null);
854
+ TerminalWidgetImpl = TerminalWidgetImpl_1 = __decorate([
855
+ (0, inversify_1.injectable)()
856
+ ], TerminalWidgetImpl);
857
+ exports.TerminalWidgetImpl = TerminalWidgetImpl;
868
858
  //# sourceMappingURL=terminal-widget-impl.js.map