@theia/output 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 (44) hide show
  1. package/README.md +33 -33
  2. package/lib/browser/output-channel.d.ts +125 -125
  3. package/lib/browser/output-channel.js +334 -334
  4. package/lib/browser/output-commands.d.ts +17 -17
  5. package/lib/browser/output-commands.js +84 -84
  6. package/lib/browser/output-context-menu.d.ts +11 -11
  7. package/lib/browser/output-context-menu.js +42 -42
  8. package/lib/browser/output-contribution.d.ts +29 -29
  9. package/lib/browser/output-contribution.js +284 -284
  10. package/lib/browser/output-editor-factory.d.ts +12 -12
  11. package/lib/browser/output-editor-factory.d.ts.map +1 -1
  12. package/lib/browser/output-editor-factory.js +79 -84
  13. package/lib/browser/output-editor-factory.js.map +1 -1
  14. package/lib/browser/output-editor-model-factory.d.ts +15 -15
  15. package/lib/browser/output-editor-model-factory.js +61 -61
  16. package/lib/browser/output-frontend-module.d.ts +3 -3
  17. package/lib/browser/output-frontend-module.js +50 -50
  18. package/lib/browser/output-preferences.d.ts +11 -11
  19. package/lib/browser/output-preferences.js +46 -46
  20. package/lib/browser/output-resource.d.ts +18 -18
  21. package/lib/browser/output-resource.js +54 -54
  22. package/lib/browser/output-toolbar-contribution.d.ts +21 -21
  23. package/lib/browser/output-toolbar-contribution.js +125 -125
  24. package/lib/browser/output-widget.d.ts +48 -48
  25. package/lib/browser/output-widget.js +248 -248
  26. package/lib/common/output-uri.d.ts +7 -7
  27. package/lib/common/output-uri.js +47 -47
  28. package/lib/common/output-uri.spec.d.ts +1 -1
  29. package/lib/common/output-uri.spec.js +50 -50
  30. package/package.json +7 -7
  31. package/src/browser/output-channel.ts +366 -366
  32. package/src/browser/output-commands.ts +100 -100
  33. package/src/browser/output-context-menu.ts +34 -34
  34. package/src/browser/output-contribution.ts +274 -274
  35. package/src/browser/output-editor-factory.ts +68 -74
  36. package/src/browser/output-editor-model-factory.ts +54 -54
  37. package/src/browser/output-frontend-module.ts +53 -53
  38. package/src/browser/output-preferences.ts +58 -58
  39. package/src/browser/output-resource.ts +65 -65
  40. package/src/browser/output-toolbar-contribution.tsx +116 -116
  41. package/src/browser/output-widget.ts +256 -256
  42. package/src/browser/style/output.css +31 -31
  43. package/src/common/output-uri.spec.ts +53 -53
  44. package/src/common/output-uri.ts +47 -47
@@ -1,335 +1,335 @@
1
- "use strict";
2
- // *****************************************************************************
3
- // Copyright (C) 2018 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
- Object.defineProperty(exports, "__esModule", { value: true });
27
- exports.OutputChannel = exports.OutputChannelSeverity = exports.OutputChannelManager = void 0;
28
- const PQueue = require("p-queue");
29
- const inversify_1 = require("@theia/core/shared/inversify");
30
- const promise_util_1 = require("@theia/core/lib/common/promise-util");
31
- const core_1 = require("@theia/core");
32
- const monaco_text_model_service_1 = require("@theia/monaco/lib/browser/monaco-text-model-service");
33
- const output_uri_1 = require("../common/output-uri");
34
- const output_resource_1 = require("../browser/output-resource");
35
- const output_preferences_1 = require("./output-preferences");
36
- const monaco = require("@theia/monaco-editor-core");
37
- let OutputChannelManager = class OutputChannelManager {
38
- constructor() {
39
- this.channels = new Map();
40
- this.resources = new Map();
41
- this.channelAddedEmitter = new core_1.Emitter();
42
- this.channelDeletedEmitter = new core_1.Emitter();
43
- this.channelWasShownEmitter = new core_1.Emitter();
44
- this.channelWasHiddenEmitter = new core_1.Emitter();
45
- this.selectedChannelChangedEmitter = new core_1.Emitter();
46
- this.onChannelAdded = this.channelAddedEmitter.event;
47
- this.onChannelDeleted = this.channelDeletedEmitter.event;
48
- this.onChannelWasShown = this.channelWasShownEmitter.event;
49
- this.onChannelWasHidden = this.channelWasHiddenEmitter.event;
50
- this.onSelectedChannelChanged = this.selectedChannelChangedEmitter.event;
51
- this.toDispose = new core_1.DisposableCollection();
52
- this.toDisposeOnChannelDeletion = new Map();
53
- }
54
- getChannel(name) {
55
- const existing = this.channels.get(name);
56
- if (existing) {
57
- return existing;
58
- }
59
- // We have to register the resource first, because `textModelService#createModelReference` will require it
60
- // right after creating the monaco.editor.ITextModel.
61
- // All `append` and `appendLine` will be deferred until the underlying text-model instantiation.
62
- let resource = this.resources.get(name);
63
- if (!resource) {
64
- const uri = output_uri_1.OutputUri.create(name);
65
- const editorModelRef = new promise_util_1.Deferred();
66
- resource = this.createResource({ uri, editorModelRef });
67
- this.resources.set(name, resource);
68
- this.textModelService.createModelReference(uri).then(ref => editorModelRef.resolve(ref));
69
- }
70
- const channel = this.createChannel(resource);
71
- this.channels.set(name, channel);
72
- this.toDisposeOnChannelDeletion.set(name, this.registerListeners(channel));
73
- this.channelAddedEmitter.fire(channel);
74
- if (!this.selectedChannel) {
75
- this.selectedChannel = channel;
76
- }
77
- return channel;
78
- }
79
- registerListeners(channel) {
80
- const { name } = channel;
81
- return new core_1.DisposableCollection(channel, channel.onVisibilityChange(({ isVisible, preserveFocus }) => {
82
- if (isVisible) {
83
- this.selectedChannel = channel;
84
- this.channelWasShownEmitter.fire({ name, preserveFocus });
85
- }
86
- else {
87
- if (channel === this.selectedChannel) {
88
- this.selectedChannel = this.getVisibleChannels()[0];
89
- }
90
- this.channelWasHiddenEmitter.fire({ name });
91
- }
92
- }), channel.onDisposed(() => this.deleteChannel(name)), core_1.Disposable.create(() => {
93
- const resource = this.resources.get(name);
94
- if (resource) {
95
- resource.dispose();
96
- this.resources.delete(name);
97
- }
98
- else {
99
- console.warn(`Could not dispose. No resource was for output channel: '${name}'.`);
100
- }
101
- }), core_1.Disposable.create(() => {
102
- const toDispose = this.channels.get(name);
103
- if (!toDispose) {
104
- console.warn(`Could not dispose. No channel exist with name: '${name}'.`);
105
- return;
106
- }
107
- this.channels.delete(name);
108
- toDispose.dispose();
109
- this.channelDeletedEmitter.fire({ name });
110
- if (this.selectedChannel && this.selectedChannel.name === name) {
111
- this.selectedChannel = this.getVisibleChannels()[0];
112
- }
113
- }));
114
- }
115
- deleteChannel(name) {
116
- const toDispose = this.toDisposeOnChannelDeletion.get(name);
117
- if (toDispose) {
118
- toDispose.dispose();
119
- }
120
- }
121
- getChannels() {
122
- return Array.from(this.channels.values()).sort(this.channelComparator);
123
- }
124
- getVisibleChannels() {
125
- return this.getChannels().filter(channel => channel.isVisible);
126
- }
127
- get channelComparator() {
128
- return (left, right) => {
129
- if (left.isVisible !== right.isVisible) {
130
- return left.isVisible ? -1 : 1;
131
- }
132
- return left.name.toLocaleLowerCase().localeCompare(right.name.toLocaleLowerCase());
133
- };
134
- }
135
- dispose() {
136
- this.toDispose.dispose();
137
- }
138
- get selectedChannel() {
139
- return this._selectedChannel;
140
- }
141
- set selectedChannel(channel) {
142
- this._selectedChannel = channel;
143
- if (this._selectedChannel) {
144
- this.selectedChannelChangedEmitter.fire({ name: this._selectedChannel.name });
145
- }
146
- else {
147
- this.selectedChannelChangedEmitter.fire(undefined);
148
- }
149
- }
150
- /**
151
- * Non-API: do not call directly.
152
- */
153
- async resolve(uri) {
154
- if (!output_uri_1.OutputUri.is(uri)) {
155
- throw new Error(`Expected '${output_uri_1.OutputUri.SCHEME}' URI scheme. Got: ${uri} instead.`);
156
- }
157
- const resource = this.resources.get(output_uri_1.OutputUri.channelName(uri));
158
- if (!resource) {
159
- throw new Error(`No output resource was registered with URI: ${uri.toString()}`);
160
- }
161
- return resource;
162
- }
163
- createResource({ uri, editorModelRef }) {
164
- return new output_resource_1.OutputResource(uri, editorModelRef);
165
- }
166
- createChannel(resource) {
167
- return new OutputChannel(resource, this.preferences);
168
- }
169
- };
170
- __decorate([
171
- (0, inversify_1.inject)(monaco_text_model_service_1.MonacoTextModelService),
172
- __metadata("design:type", monaco_text_model_service_1.MonacoTextModelService)
173
- ], OutputChannelManager.prototype, "textModelService", void 0);
174
- __decorate([
175
- (0, inversify_1.inject)(output_preferences_1.OutputPreferences),
176
- __metadata("design:type", Object)
177
- ], OutputChannelManager.prototype, "preferences", void 0);
178
- OutputChannelManager = __decorate([
179
- (0, inversify_1.injectable)()
180
- ], OutputChannelManager);
181
- exports.OutputChannelManager = OutputChannelManager;
182
- var OutputChannelSeverity;
183
- (function (OutputChannelSeverity) {
184
- OutputChannelSeverity[OutputChannelSeverity["Error"] = 1] = "Error";
185
- OutputChannelSeverity[OutputChannelSeverity["Warning"] = 2] = "Warning";
186
- OutputChannelSeverity[OutputChannelSeverity["Info"] = 3] = "Info";
187
- })(OutputChannelSeverity = exports.OutputChannelSeverity || (exports.OutputChannelSeverity = {}));
188
- class OutputChannel {
189
- constructor(resource, preferences) {
190
- this.resource = resource;
191
- this.preferences = preferences;
192
- this.contentChangeEmitter = new core_1.Emitter();
193
- this.visibilityChangeEmitter = new core_1.Emitter();
194
- this.disposedEmitter = new core_1.Emitter();
195
- this.textModifyQueue = new PQueue({ autoStart: true, concurrency: 1 });
196
- this.toDispose = new core_1.DisposableCollection(core_1.Disposable.create(() => this.textModifyQueue.clear()), this.contentChangeEmitter, this.visibilityChangeEmitter, this.disposedEmitter);
197
- this.disposed = false;
198
- this.visible = true;
199
- this.decorationIds = new Set();
200
- this.onVisibilityChange = this.visibilityChangeEmitter.event;
201
- this.onContentChange = this.contentChangeEmitter.event;
202
- this.onDisposed = this.disposedEmitter.event;
203
- this._maxLineNumber = this.preferences['output.maxChannelHistory'];
204
- this.toDispose.push(resource);
205
- this.toDispose.push(core_1.Disposable.create(() => this.decorationIds.clear()));
206
- this.toDispose.push(this.preferences.onPreferenceChanged(event => {
207
- if (event.preferenceName === 'output.maxChannelHistory') {
208
- const maxLineNumber = event.newValue;
209
- if (this.maxLineNumber !== maxLineNumber) {
210
- this.maxLineNumber = maxLineNumber;
211
- }
212
- }
213
- }));
214
- }
215
- get name() {
216
- return output_uri_1.OutputUri.channelName(this.uri);
217
- }
218
- get uri() {
219
- return this.resource.uri;
220
- }
221
- hide() {
222
- this.visible = false;
223
- this.visibilityChangeEmitter.fire({ isVisible: this.isVisible });
224
- }
225
- /**
226
- * If `preserveFocus` is `true`, the channel will not take focus. It is `false` by default.
227
- * - Calling `show` without args or with `preserveFocus: false` will reveal **and** activate the `Output` widget.
228
- * - Calling `show` with `preserveFocus: true` will reveal the `Output` widget but **won't** activate it.
229
- */
230
- show({ preserveFocus } = { preserveFocus: false }) {
231
- this.visible = true;
232
- this.visibilityChangeEmitter.fire({ isVisible: this.isVisible, preserveFocus });
233
- }
234
- /**
235
- * Note: if `false` it does not meant it is disposed or not available, it is only hidden from the UI.
236
- */
237
- get isVisible() {
238
- return this.visible;
239
- }
240
- clear() {
241
- this.textModifyQueue.add(async () => {
242
- const textModel = (await this.resource.editorModelRef.promise).object.textEditorModel;
243
- textModel.deltaDecorations(Array.from(this.decorationIds), []);
244
- this.decorationIds.clear();
245
- textModel.setValue('');
246
- this.contentChangeEmitter.fire();
247
- });
248
- }
249
- dispose() {
250
- if (this.disposed) {
251
- return;
252
- }
253
- this.disposed = true;
254
- this.toDispose.dispose();
255
- this.disposedEmitter.fire();
256
- }
257
- append(content, severity = OutputChannelSeverity.Info) {
258
- this.textModifyQueue.add(() => this.doAppend({ content, severity }));
259
- }
260
- appendLine(content, severity = OutputChannelSeverity.Info) {
261
- this.textModifyQueue.add(() => this.doAppend({ content, severity, appendEol: true }));
262
- }
263
- async doAppend({ content, severity, appendEol }) {
264
- const textModel = (await this.resource.editorModelRef.promise).object.textEditorModel;
265
- const lastLine = textModel.getLineCount();
266
- const lastLineMaxColumn = textModel.getLineMaxColumn(lastLine);
267
- const position = new monaco.Position(lastLine, lastLineMaxColumn);
268
- const range = new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column);
269
- const edits = [{
270
- range,
271
- text: !!appendEol ? `${content}${textModel.getEOL()}` : content,
272
- forceMoveMarkers: true
273
- }];
274
- // We do not use `pushEditOperations` as we do not need undo/redo support. VS Code uses `applyEdits` too.
275
- // https://github.com/microsoft/vscode/blob/dc348340fd1a6c583cb63a1e7e6b4fd657e01e01/src/vs/workbench/services/output/common/outputChannelModel.ts#L108-L115
276
- textModel.applyEdits(edits);
277
- if (severity !== OutputChannelSeverity.Info) {
278
- const inlineClassName = severity === OutputChannelSeverity.Error ? 'theia-output-error' : 'theia-output-warning';
279
- let endLineNumber = textModel.getLineCount();
280
- // If last line is empty (the first non-whitespace is 0), apply decorator to previous line's last non-whitespace instead
281
- // Note: if the user appends `inlineWarning `, the new decorator's range includes the trailing whitespace.
282
- if (!textModel.getLineFirstNonWhitespaceColumn(endLineNumber)) {
283
- endLineNumber--;
284
- }
285
- const endColumn = textModel.getLineLastNonWhitespaceColumn(endLineNumber);
286
- const newDecorations = [{
287
- range: new monaco.Range(range.startLineNumber, range.startColumn, endLineNumber, endColumn), options: {
288
- inlineClassName
289
- }
290
- }];
291
- for (const decorationId of textModel.deltaDecorations([], newDecorations)) {
292
- this.decorationIds.add(decorationId);
293
- }
294
- }
295
- this.ensureMaxChannelHistory(textModel);
296
- this.contentChangeEmitter.fire();
297
- }
298
- ensureMaxChannelHistory(textModel) {
299
- this.contentChangeEmitter.fire();
300
- const linesToRemove = textModel.getLineCount() - this.maxLineNumber - 1; // -1 as the last line is usually empty -> `appendLine`.
301
- if (linesToRemove > 0) {
302
- const endColumn = textModel.getLineMaxColumn(linesToRemove);
303
- // `endLineNumber` is `linesToRemove` + 1 as monaco is one based.
304
- const range = new monaco.Range(1, 1, linesToRemove, endColumn + 1);
305
- // eslint-disable-next-line no-null/no-null
306
- const text = null;
307
- const decorationsToRemove = textModel.getLinesDecorations(range.startLineNumber, range.endLineNumber)
308
- .filter(({ id }) => this.decorationIds.has(id)).map(({ id }) => id); // Do we need to filter here? Who else can put decorations to the output model?
309
- if (decorationsToRemove.length) {
310
- for (const newId of textModel.deltaDecorations(decorationsToRemove, [])) {
311
- this.decorationIds.add(newId);
312
- }
313
- for (const toRemoveId of decorationsToRemove) {
314
- this.decorationIds.delete(toRemoveId);
315
- }
316
- }
317
- textModel.applyEdits([
318
- {
319
- range: new monaco.Range(1, 1, linesToRemove + 1, textModel.getLineFirstNonWhitespaceColumn(linesToRemove + 1)),
320
- text,
321
- forceMoveMarkers: true
322
- }
323
- ]);
324
- }
325
- }
326
- get maxLineNumber() {
327
- return this._maxLineNumber;
328
- }
329
- set maxLineNumber(maxLineNumber) {
330
- this._maxLineNumber = maxLineNumber;
331
- this.append(''); // will trigger an `ensureMaxChannelHistory` call and will refresh the content.
332
- }
333
- }
334
- exports.OutputChannel = OutputChannel;
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2018 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
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.OutputChannel = exports.OutputChannelSeverity = exports.OutputChannelManager = void 0;
28
+ const PQueue = require("p-queue");
29
+ const inversify_1 = require("@theia/core/shared/inversify");
30
+ const promise_util_1 = require("@theia/core/lib/common/promise-util");
31
+ const core_1 = require("@theia/core");
32
+ const monaco_text_model_service_1 = require("@theia/monaco/lib/browser/monaco-text-model-service");
33
+ const output_uri_1 = require("../common/output-uri");
34
+ const output_resource_1 = require("../browser/output-resource");
35
+ const output_preferences_1 = require("./output-preferences");
36
+ const monaco = require("@theia/monaco-editor-core");
37
+ let OutputChannelManager = class OutputChannelManager {
38
+ constructor() {
39
+ this.channels = new Map();
40
+ this.resources = new Map();
41
+ this.channelAddedEmitter = new core_1.Emitter();
42
+ this.channelDeletedEmitter = new core_1.Emitter();
43
+ this.channelWasShownEmitter = new core_1.Emitter();
44
+ this.channelWasHiddenEmitter = new core_1.Emitter();
45
+ this.selectedChannelChangedEmitter = new core_1.Emitter();
46
+ this.onChannelAdded = this.channelAddedEmitter.event;
47
+ this.onChannelDeleted = this.channelDeletedEmitter.event;
48
+ this.onChannelWasShown = this.channelWasShownEmitter.event;
49
+ this.onChannelWasHidden = this.channelWasHiddenEmitter.event;
50
+ this.onSelectedChannelChanged = this.selectedChannelChangedEmitter.event;
51
+ this.toDispose = new core_1.DisposableCollection();
52
+ this.toDisposeOnChannelDeletion = new Map();
53
+ }
54
+ getChannel(name) {
55
+ const existing = this.channels.get(name);
56
+ if (existing) {
57
+ return existing;
58
+ }
59
+ // We have to register the resource first, because `textModelService#createModelReference` will require it
60
+ // right after creating the monaco.editor.ITextModel.
61
+ // All `append` and `appendLine` will be deferred until the underlying text-model instantiation.
62
+ let resource = this.resources.get(name);
63
+ if (!resource) {
64
+ const uri = output_uri_1.OutputUri.create(name);
65
+ const editorModelRef = new promise_util_1.Deferred();
66
+ resource = this.createResource({ uri, editorModelRef });
67
+ this.resources.set(name, resource);
68
+ this.textModelService.createModelReference(uri).then(ref => editorModelRef.resolve(ref));
69
+ }
70
+ const channel = this.createChannel(resource);
71
+ this.channels.set(name, channel);
72
+ this.toDisposeOnChannelDeletion.set(name, this.registerListeners(channel));
73
+ this.channelAddedEmitter.fire(channel);
74
+ if (!this.selectedChannel) {
75
+ this.selectedChannel = channel;
76
+ }
77
+ return channel;
78
+ }
79
+ registerListeners(channel) {
80
+ const { name } = channel;
81
+ return new core_1.DisposableCollection(channel, channel.onVisibilityChange(({ isVisible, preserveFocus }) => {
82
+ if (isVisible) {
83
+ this.selectedChannel = channel;
84
+ this.channelWasShownEmitter.fire({ name, preserveFocus });
85
+ }
86
+ else {
87
+ if (channel === this.selectedChannel) {
88
+ this.selectedChannel = this.getVisibleChannels()[0];
89
+ }
90
+ this.channelWasHiddenEmitter.fire({ name });
91
+ }
92
+ }), channel.onDisposed(() => this.deleteChannel(name)), core_1.Disposable.create(() => {
93
+ const resource = this.resources.get(name);
94
+ if (resource) {
95
+ resource.dispose();
96
+ this.resources.delete(name);
97
+ }
98
+ else {
99
+ console.warn(`Could not dispose. No resource was for output channel: '${name}'.`);
100
+ }
101
+ }), core_1.Disposable.create(() => {
102
+ const toDispose = this.channels.get(name);
103
+ if (!toDispose) {
104
+ console.warn(`Could not dispose. No channel exist with name: '${name}'.`);
105
+ return;
106
+ }
107
+ this.channels.delete(name);
108
+ toDispose.dispose();
109
+ this.channelDeletedEmitter.fire({ name });
110
+ if (this.selectedChannel && this.selectedChannel.name === name) {
111
+ this.selectedChannel = this.getVisibleChannels()[0];
112
+ }
113
+ }));
114
+ }
115
+ deleteChannel(name) {
116
+ const toDispose = this.toDisposeOnChannelDeletion.get(name);
117
+ if (toDispose) {
118
+ toDispose.dispose();
119
+ }
120
+ }
121
+ getChannels() {
122
+ return Array.from(this.channels.values()).sort(this.channelComparator);
123
+ }
124
+ getVisibleChannels() {
125
+ return this.getChannels().filter(channel => channel.isVisible);
126
+ }
127
+ get channelComparator() {
128
+ return (left, right) => {
129
+ if (left.isVisible !== right.isVisible) {
130
+ return left.isVisible ? -1 : 1;
131
+ }
132
+ return left.name.toLocaleLowerCase().localeCompare(right.name.toLocaleLowerCase());
133
+ };
134
+ }
135
+ dispose() {
136
+ this.toDispose.dispose();
137
+ }
138
+ get selectedChannel() {
139
+ return this._selectedChannel;
140
+ }
141
+ set selectedChannel(channel) {
142
+ this._selectedChannel = channel;
143
+ if (this._selectedChannel) {
144
+ this.selectedChannelChangedEmitter.fire({ name: this._selectedChannel.name });
145
+ }
146
+ else {
147
+ this.selectedChannelChangedEmitter.fire(undefined);
148
+ }
149
+ }
150
+ /**
151
+ * Non-API: do not call directly.
152
+ */
153
+ async resolve(uri) {
154
+ if (!output_uri_1.OutputUri.is(uri)) {
155
+ throw new Error(`Expected '${output_uri_1.OutputUri.SCHEME}' URI scheme. Got: ${uri} instead.`);
156
+ }
157
+ const resource = this.resources.get(output_uri_1.OutputUri.channelName(uri));
158
+ if (!resource) {
159
+ throw new Error(`No output resource was registered with URI: ${uri.toString()}`);
160
+ }
161
+ return resource;
162
+ }
163
+ createResource({ uri, editorModelRef }) {
164
+ return new output_resource_1.OutputResource(uri, editorModelRef);
165
+ }
166
+ createChannel(resource) {
167
+ return new OutputChannel(resource, this.preferences);
168
+ }
169
+ };
170
+ __decorate([
171
+ (0, inversify_1.inject)(monaco_text_model_service_1.MonacoTextModelService),
172
+ __metadata("design:type", monaco_text_model_service_1.MonacoTextModelService)
173
+ ], OutputChannelManager.prototype, "textModelService", void 0);
174
+ __decorate([
175
+ (0, inversify_1.inject)(output_preferences_1.OutputPreferences),
176
+ __metadata("design:type", Object)
177
+ ], OutputChannelManager.prototype, "preferences", void 0);
178
+ OutputChannelManager = __decorate([
179
+ (0, inversify_1.injectable)()
180
+ ], OutputChannelManager);
181
+ exports.OutputChannelManager = OutputChannelManager;
182
+ var OutputChannelSeverity;
183
+ (function (OutputChannelSeverity) {
184
+ OutputChannelSeverity[OutputChannelSeverity["Error"] = 1] = "Error";
185
+ OutputChannelSeverity[OutputChannelSeverity["Warning"] = 2] = "Warning";
186
+ OutputChannelSeverity[OutputChannelSeverity["Info"] = 3] = "Info";
187
+ })(OutputChannelSeverity = exports.OutputChannelSeverity || (exports.OutputChannelSeverity = {}));
188
+ class OutputChannel {
189
+ constructor(resource, preferences) {
190
+ this.resource = resource;
191
+ this.preferences = preferences;
192
+ this.contentChangeEmitter = new core_1.Emitter();
193
+ this.visibilityChangeEmitter = new core_1.Emitter();
194
+ this.disposedEmitter = new core_1.Emitter();
195
+ this.textModifyQueue = new PQueue({ autoStart: true, concurrency: 1 });
196
+ this.toDispose = new core_1.DisposableCollection(core_1.Disposable.create(() => this.textModifyQueue.clear()), this.contentChangeEmitter, this.visibilityChangeEmitter, this.disposedEmitter);
197
+ this.disposed = false;
198
+ this.visible = true;
199
+ this.decorationIds = new Set();
200
+ this.onVisibilityChange = this.visibilityChangeEmitter.event;
201
+ this.onContentChange = this.contentChangeEmitter.event;
202
+ this.onDisposed = this.disposedEmitter.event;
203
+ this._maxLineNumber = this.preferences['output.maxChannelHistory'];
204
+ this.toDispose.push(resource);
205
+ this.toDispose.push(core_1.Disposable.create(() => this.decorationIds.clear()));
206
+ this.toDispose.push(this.preferences.onPreferenceChanged(event => {
207
+ if (event.preferenceName === 'output.maxChannelHistory') {
208
+ const maxLineNumber = event.newValue;
209
+ if (this.maxLineNumber !== maxLineNumber) {
210
+ this.maxLineNumber = maxLineNumber;
211
+ }
212
+ }
213
+ }));
214
+ }
215
+ get name() {
216
+ return output_uri_1.OutputUri.channelName(this.uri);
217
+ }
218
+ get uri() {
219
+ return this.resource.uri;
220
+ }
221
+ hide() {
222
+ this.visible = false;
223
+ this.visibilityChangeEmitter.fire({ isVisible: this.isVisible });
224
+ }
225
+ /**
226
+ * If `preserveFocus` is `true`, the channel will not take focus. It is `false` by default.
227
+ * - Calling `show` without args or with `preserveFocus: false` will reveal **and** activate the `Output` widget.
228
+ * - Calling `show` with `preserveFocus: true` will reveal the `Output` widget but **won't** activate it.
229
+ */
230
+ show({ preserveFocus } = { preserveFocus: false }) {
231
+ this.visible = true;
232
+ this.visibilityChangeEmitter.fire({ isVisible: this.isVisible, preserveFocus });
233
+ }
234
+ /**
235
+ * Note: if `false` it does not meant it is disposed or not available, it is only hidden from the UI.
236
+ */
237
+ get isVisible() {
238
+ return this.visible;
239
+ }
240
+ clear() {
241
+ this.textModifyQueue.add(async () => {
242
+ const textModel = (await this.resource.editorModelRef.promise).object.textEditorModel;
243
+ textModel.deltaDecorations(Array.from(this.decorationIds), []);
244
+ this.decorationIds.clear();
245
+ textModel.setValue('');
246
+ this.contentChangeEmitter.fire();
247
+ });
248
+ }
249
+ dispose() {
250
+ if (this.disposed) {
251
+ return;
252
+ }
253
+ this.disposed = true;
254
+ this.toDispose.dispose();
255
+ this.disposedEmitter.fire();
256
+ }
257
+ append(content, severity = OutputChannelSeverity.Info) {
258
+ this.textModifyQueue.add(() => this.doAppend({ content, severity }));
259
+ }
260
+ appendLine(content, severity = OutputChannelSeverity.Info) {
261
+ this.textModifyQueue.add(() => this.doAppend({ content, severity, appendEol: true }));
262
+ }
263
+ async doAppend({ content, severity, appendEol }) {
264
+ const textModel = (await this.resource.editorModelRef.promise).object.textEditorModel;
265
+ const lastLine = textModel.getLineCount();
266
+ const lastLineMaxColumn = textModel.getLineMaxColumn(lastLine);
267
+ const position = new monaco.Position(lastLine, lastLineMaxColumn);
268
+ const range = new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column);
269
+ const edits = [{
270
+ range,
271
+ text: !!appendEol ? `${content}${textModel.getEOL()}` : content,
272
+ forceMoveMarkers: true
273
+ }];
274
+ // We do not use `pushEditOperations` as we do not need undo/redo support. VS Code uses `applyEdits` too.
275
+ // https://github.com/microsoft/vscode/blob/dc348340fd1a6c583cb63a1e7e6b4fd657e01e01/src/vs/workbench/services/output/common/outputChannelModel.ts#L108-L115
276
+ textModel.applyEdits(edits);
277
+ if (severity !== OutputChannelSeverity.Info) {
278
+ const inlineClassName = severity === OutputChannelSeverity.Error ? 'theia-output-error' : 'theia-output-warning';
279
+ let endLineNumber = textModel.getLineCount();
280
+ // If last line is empty (the first non-whitespace is 0), apply decorator to previous line's last non-whitespace instead
281
+ // Note: if the user appends `inlineWarning `, the new decorator's range includes the trailing whitespace.
282
+ if (!textModel.getLineFirstNonWhitespaceColumn(endLineNumber)) {
283
+ endLineNumber--;
284
+ }
285
+ const endColumn = textModel.getLineLastNonWhitespaceColumn(endLineNumber);
286
+ const newDecorations = [{
287
+ range: new monaco.Range(range.startLineNumber, range.startColumn, endLineNumber, endColumn), options: {
288
+ inlineClassName
289
+ }
290
+ }];
291
+ for (const decorationId of textModel.deltaDecorations([], newDecorations)) {
292
+ this.decorationIds.add(decorationId);
293
+ }
294
+ }
295
+ this.ensureMaxChannelHistory(textModel);
296
+ this.contentChangeEmitter.fire();
297
+ }
298
+ ensureMaxChannelHistory(textModel) {
299
+ this.contentChangeEmitter.fire();
300
+ const linesToRemove = textModel.getLineCount() - this.maxLineNumber - 1; // -1 as the last line is usually empty -> `appendLine`.
301
+ if (linesToRemove > 0) {
302
+ const endColumn = textModel.getLineMaxColumn(linesToRemove);
303
+ // `endLineNumber` is `linesToRemove` + 1 as monaco is one based.
304
+ const range = new monaco.Range(1, 1, linesToRemove, endColumn + 1);
305
+ // eslint-disable-next-line no-null/no-null
306
+ const text = null;
307
+ const decorationsToRemove = textModel.getLinesDecorations(range.startLineNumber, range.endLineNumber)
308
+ .filter(({ id }) => this.decorationIds.has(id)).map(({ id }) => id); // Do we need to filter here? Who else can put decorations to the output model?
309
+ if (decorationsToRemove.length) {
310
+ for (const newId of textModel.deltaDecorations(decorationsToRemove, [])) {
311
+ this.decorationIds.add(newId);
312
+ }
313
+ for (const toRemoveId of decorationsToRemove) {
314
+ this.decorationIds.delete(toRemoveId);
315
+ }
316
+ }
317
+ textModel.applyEdits([
318
+ {
319
+ range: new monaco.Range(1, 1, linesToRemove + 1, textModel.getLineFirstNonWhitespaceColumn(linesToRemove + 1)),
320
+ text,
321
+ forceMoveMarkers: true
322
+ }
323
+ ]);
324
+ }
325
+ }
326
+ get maxLineNumber() {
327
+ return this._maxLineNumber;
328
+ }
329
+ set maxLineNumber(maxLineNumber) {
330
+ this._maxLineNumber = maxLineNumber;
331
+ this.append(''); // will trigger an `ensureMaxChannelHistory` call and will refresh the content.
332
+ }
333
+ }
334
+ exports.OutputChannel = OutputChannel;
335
335
  //# sourceMappingURL=output-channel.js.map