1
>
/*---------------------------------------------------------------------------------------------
output.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { Event, Emitter } from '../../../../base/common/event.js';
7
>
import { Registry } from '../../../../platform/registry/common/platform.js';
8
>
import { URI } from '../../../../base/common/uri.js';
9
>
import { RawContextKey } from '../../../../platform/contextkey/common/contextkey.js';
10
>
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
11
>
import { LogLevel } from '../../../../platform/log/common/log.js';
12
>
import { Range } from '../../../../editor/common/core/range.js';
13
>
import { Disposable } from '../../../../base/common/lifecycle.js';
14
>
15
>
/**
16
>
* Mime type used by the output editor.
17
>
*/
18
>
export const OUTPUT_MIME = 'text/x-code-output';
19
>
20
>
/**
21
>
* Id used by the output editor.
22
>
*/
23
>
export const OUTPUT_MODE_ID = 'Log';
24
>
25
>
/**
26
>
* Mime type used by the log output editor.
27
>
*/
28
>
export const LOG_MIME = 'text/x-code-log-output';
29
>
30
>
/**
31
>
* Id used by the log output editor.
32
>
*/
33
>
export const LOG_MODE_ID = 'log';
34
>
35
>
/**
36
>
* Output view id
37
>
*/
38
>
export const OUTPUT_VIEW_ID = 'workbench.panel.output';
39
>
40
>
export const CONTEXT_IN_OUTPUT = new RawContextKey<boolean>('inOutput', false);
41
>
export const CONTEXT_ACTIVE_FILE_OUTPUT = new RawContextKey<boolean>('activeLogOutput', false);
42
>
export const CONTEXT_ACTIVE_LOG_FILE_OUTPUT = new RawContextKey<boolean>('activeLogOutput.isLog', false);
43
>
export const CONTEXT_ACTIVE_OUTPUT_LEVEL_SETTABLE = new RawContextKey<boolean>('activeLogOutput.levelSettable', false);
44
>
export const CONTEXT_ACTIVE_OUTPUT_LEVEL = new RawContextKey<string>('activeLogOutput.level', '');
45
>
export const CONTEXT_ACTIVE_OUTPUT_LEVEL_IS_DEFAULT = new RawContextKey<boolean>('activeLogOutput.levelIsDefault', false);
46
>
export const CONTEXT_OUTPUT_SCROLL_LOCK = new RawContextKey<boolean>(`outputView.scrollLock`, false);
47
>
export const ACTIVE_OUTPUT_CHANNEL_CONTEXT = new RawContextKey<string>('activeOutputChannel', '');
48
>
export const SHOW_TRACE_FILTER_CONTEXT = new RawContextKey<boolean>('output.filter.trace', true);
49
>
export const SHOW_DEBUG_FILTER_CONTEXT = new RawContextKey<boolean>('output.filter.debug', true);
50
>
export const SHOW_INFO_FILTER_CONTEXT = new RawContextKey<boolean>('output.filter.info', true);
51
>
export const SHOW_WARNING_FILTER_CONTEXT = new RawContextKey<boolean>('output.filter.warning', true);
52
>
export const SHOW_ERROR_FILTER_CONTEXT = new RawContextKey<boolean>('output.filter.error', true);
53
>
export const OUTPUT_FILTER_FOCUS_CONTEXT = new RawContextKey<boolean>('outputFilterFocus', false);
54
>
export const HIDE_CATEGORY_FILTER_CONTEXT = new RawContextKey<string>('output.filter.categories', '');
55
>
56
>
export interface IOutputViewFilters {
57
>
readonly onDidChange: Event<void>;
58
>
text: string;
59
>
readonly includePatterns: string[];
60
>
readonly excludePatterns: string[];
61
>
trace: boolean;
62
>
debug: boolean;
63
>
info: boolean;
64
>
warning: boolean;
65
>
error: boolean;
66
>
categories: string;
67
>
toggleCategory(category: string): void;
68
>
hasCategory(category: string): boolean;
69
>
}
70
>
71
>
export const IOutputService = createDecorator<IOutputService>('outputService');
72
>
73
>
/**
74
>
* The output service to manage output from the various processes running.
75
>
*/
76
>
export interface IOutputService {
77
>
readonly _serviceBrand: undefined;
78
>
79
>
/**
80
>
* Output view filters.
81
>
*/
82
>
readonly filters: IOutputViewFilters;
83
>
84
>
/**
85
>
* Given the channel id returns the output channel instance.
86
>
* Channel should be first registered via OutputChannelRegistry.
87
>
*/
88
>
getChannel(id: string): IOutputChannel | undefined;
89
>
90
>
/**
91
>
* Given the channel id returns the registered output channel descriptor.
92
>
*/
93
>
getChannelDescriptor(id: string): IOutputChannelDescriptor | undefined;
94
>
95
>
/**
96
>
* Returns an array of all known output channels descriptors.
97
>
*/
98
>
getChannelDescriptors(): IOutputChannelDescriptor[];
99
>
100
>
/**
101
>
* Returns the currently active channel.
102
>
* Only one channel can be active at a given moment.
103
>
*/
104
>
getActiveChannel(): IOutputChannel | undefined;
105
>
106
>
/**
107
>
* Show the channel with the passed id.
108
>
*/
109
>
showChannel(id: string, preserveFocus?: boolean): Promise<void>;
110
>
111
>
/**
112
>
* Allows to register on active output channel change.
113
>
*/
114
>
readonly onActiveOutputChannel: Event<string>;
115
>
116
>
/**
117
>
* Register a compound log channel with the given channels.
118
>
*/
119
>
registerCompoundLogChannel(channels: IOutputChannelDescriptor[]): string;
120
>
121
>
/**
122
>
* Save the logs to a file.
123
>
*/
124
>
saveOutputAs(outputPath?: URI, ...channels: IOutputChannelDescriptor[]): Promise<void>;
125
>
126
>
/**
127
>
* Checks if the log level can be set for the given channel.
128
>
* @param channel
129
>
*/
130
>
canSetLogLevel(channel: IOutputChannelDescriptor): boolean;
131
>
132
>
/**
133
>
* Returns the log level for the given channel.
134
>
* @param channel
135
>
*/
136
>
getLogLevel(channel: IOutputChannelDescriptor): LogLevel | undefined;
137
>
138
>
/**
139
>
* Sets the log level for the given channel.
140
>
* @param channel
141
>
* @param logLevel
142
>
*/
143
>
setLogLevel(channel: IOutputChannelDescriptor, logLevel: LogLevel): void;
144
>
}
145
>
146
>
export enum OutputChannelUpdateMode {
147
>
Append = 1,
148
>
Replace,
149
>
Clear
150
>
}
151
>
152
>
export interface ILogEntry {
153
>
readonly range: Range;
154
>
readonly timestamp: number;
155
>
readonly timestampRange: Range;
156
>
readonly logLevel: LogLevel;
157
>
readonly logLevelRange: Range;
158
>
readonly category: string | undefined;
159
>
}
160
>
161
>
export interface IOutputChannel {
162
>
163
>
/**
164
>
* Identifier of the output channel.
165
>
*/
166
>
readonly id: string;
167
>
168
>
/**
169
>
* Label of the output channel to be displayed to the user.
170
>
*/
171
>
readonly label: string;
172
>
173
>
/**
174
>
* URI of the output channel.
175
>
*/
176
>
readonly uri: URI;
177
>
178
>
/**
179
>
* Log entries of the output channel.
180
>
*/
181
>
getLogEntries(): readonly ILogEntry[];
182
>
183
>
/**
184
>
* Appends output to the channel.
185
>
*/
186
>
append(output: string): void;
187
>
188
>
/**
189
>
* Clears all received output for this channel.
190
>
*/
191
>
clear(): void;
192
>
193
>
/**
194
>
* Replaces the content of the channel with given output
195
>
*/
196
>
replace(output: string): void;
197
>
198
>
/**
199
>
* Update the channel.
200
>
*/
201
>
update(mode: OutputChannelUpdateMode.Append): void;
202
>
update(mode: OutputChannelUpdateMode, till: number): void;
203
>
204
>
/**
205
>
* Disposes the output channel.
206
>
*/
207
>
dispose(): void;
208
>
}
209
>
210
>
export const Extensions = {
211
>
OutputChannels: 'workbench.contributions.outputChannels'
212
>
};
213
>
214
>
export interface IOutputChannelDescriptor {
215
>
id: string;
216
>
label: string;
217
>
log: boolean;
218
>
languageId?: string;
219
>
source?: IOutputContentSource | ReadonlyArray<IOutputContentSource>;
220
>
extensionId?: string;
221
>
user?: boolean;
222
>
}
223
>
224
>
export interface ISingleSourceOutputChannelDescriptor extends IOutputChannelDescriptor {
225
>
source: IOutputContentSource;
226
>
}
227
>
228
>
export interface IMultiSourceOutputChannelDescriptor extends IOutputChannelDescriptor {
229
>
source: ReadonlyArray<IOutputContentSource>;
230
>
}
231
>
232
>
export function isSingleSourceOutputChannelDescriptor(descriptor: IOutputChannelDescriptor): descriptor is ISingleSourceOutputChannelDescriptor {
233
return !!descriptor.source && !Array.isArray(descriptor.source);
234
}
236
>
export function isMultiSourceOutputChannelDescriptor(descriptor: IOutputChannelDescriptor): descriptor is IMultiSourceOutputChannelDescriptor {
237
return Array.isArray(descriptor.source);
238
}
240
>
export interface IOutputContentSource {
241
>
readonly name?: string;
242
>
readonly resource: URI;
243
>
}
244
>
245
>
export interface IOutputChannelRegistry {
246
>
247
>
readonly onDidRegisterChannel: Event<string>;
248
>
readonly onDidRemoveChannel: Event<IOutputChannelDescriptor>;
249
>
readonly onDidUpdateChannelSources: Event<IMultiSourceOutputChannelDescriptor>;
250
>
251
>
/**
252
>
* Make an output channel known to the output world.
253
>
*/
254
>
registerChannel(descriptor: IOutputChannelDescriptor): void;
255
>
256
>
/**
257
>
* Update the files for the given output channel.
258
>
*/
259
>
updateChannelSources(id: string, sources: IOutputContentSource[]): void;
260
>
261
>
/**
262
>
* Returns the list of channels known to the output world.
263
>
*/
264
>
getChannels(): IOutputChannelDescriptor[];
265
>
266
>
/**
267
>
* Returns the channel with the passed id.
268
>
*/
269
>
getChannel(id: string): IOutputChannelDescriptor | undefined;
270
>
271
>
/**
272
>
* Remove the output channel with the passed id.
273
>
*/
274
>
removeChannel(id: string): void;
275
>
}
276
>
277
>
class OutputChannelRegistry extends Disposable implements IOutputChannelRegistry {
278
>
private channels = new Map<string, IOutputChannelDescriptor>();
279
>
280
>
private readonly _onDidRegisterChannel = this._register(new Emitter<string>());
281
>
readonly onDidRegisterChannel = this._onDidRegisterChannel.event;
282
>
283
>
private readonly _onDidRemoveChannel = this._register(new Emitter<IOutputChannelDescriptor>());
284
>
readonly onDidRemoveChannel = this._onDidRemoveChannel.event;
285
>
286
>
private readonly _onDidUpdateChannelFiles = this._register(new Emitter<IMultiSourceOutputChannelDescriptor>());
287
>
readonly onDidUpdateChannelSources = this._onDidUpdateChannelFiles.event;
288
>
289
>
public registerChannel(descriptor: IOutputChannelDescriptor): void {
290
if (!this.channels.has(descriptor.id)) {
291
this.channels.set(descriptor.id, descriptor);