From 1ecb5f53a739dd84c66b51e2be1ea7f440141db7 Mon Sep 17 00:00:00 2001 From: gjsjohnmurray Date: Mon, 17 Jan 2022 21:29:04 +0000 Subject: [PATCH] Add optional languageId to window.createOutputChannel API (#19561) --- .../api/browser/mainThreadOutputService.ts | 4 ++-- .../workbench/api/common/extHost.api.impl.ts | 7 +++++-- .../workbench/api/common/extHost.protocol.ts | 2 +- src/vs/workbench/api/common/extHostOutput.ts | 8 ++++---- .../contrib/output/browser/outputServices.ts | 4 ++-- .../output/common/outputChannelModel.ts | 13 +++++++----- .../common/outputChannelModelService.ts | 6 +++--- .../common/extensionsApiProposals.ts | 1 + .../services/output/common/output.ts | 1 + ...vscode.proposed.outputChannelLanguage.d.ts | 20 +++++++++++++++++++ 10 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 src/vscode-dts/vscode.proposed.outputChannelLanguage.d.ts diff --git a/src/vs/workbench/api/browser/mainThreadOutputService.ts b/src/vs/workbench/api/browser/mainThreadOutputService.ts index 5e29097d76e..42b714e7fdb 100644 --- a/src/vs/workbench/api/browser/mainThreadOutputService.ts +++ b/src/vs/workbench/api/browser/mainThreadOutputService.ts @@ -42,12 +42,12 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut setVisibleChannel(); } - public async $register(label: string, log: boolean, file: UriComponents, extensionId: string): Promise { + public async $register(label: string, log: boolean, file: UriComponents, languageId: string, extensionId: string): Promise { const idCounter = (MainThreadOutputService._extensionIdPool.get(extensionId) || 0) + 1; MainThreadOutputService._extensionIdPool.set(extensionId, idCounter); const id = `extension-output-${extensionId}-#${idCounter}`; - Registry.as(Extensions.OutputChannels).registerChannel({ id, label, file: URI.revive(file), log }); + Registry.as(Extensions.OutputChannels).registerChannel({ id, label, file: URI.revive(file), log, languageId }); this._register(toDisposable(() => this.$dispose(id))); return id; } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index dca91a00f0f..1200f97e0ce 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -648,8 +648,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I withProgress(options: vscode.ProgressOptions, task: (progress: vscode.Progress<{ message?: string; worked?: number }>, token: vscode.CancellationToken) => Thenable) { return extHostProgress.withProgress(extension, options, task); }, - createOutputChannel(name: string): vscode.OutputChannel { - return extHostOutputService.createOutputChannel(name, extension); + createOutputChannel(name: string, languageId?: string): vscode.OutputChannel { + if (languageId) { + checkProposedApiEnabled(extension, 'outputChannelLanguage'); + } + return extHostOutputService.createOutputChannel(name, languageId || '', extension); }, createWebviewPanel(viewType: string, title: string, showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean }, options?: vscode.WebviewPanelOptions & vscode.WebviewOptions): vscode.WebviewPanel { return extHostWebviewPanels.createWebviewPanel(extension, viewType, title, showOptions, options); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 61af6759cb5..3c3716ffd23 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -467,7 +467,7 @@ export interface MainThreadMessageServiceShape extends IDisposable { } export interface MainThreadOutputServiceShape extends IDisposable { - $register(label: string, log: boolean, file: UriComponents, extensionId: string): Promise; + $register(label: string, log: boolean, file: UriComponents, languageId: string, extensionId: string): Promise; $update(channelId: string, mode: OutputChannelUpdateMode.Append): Promise; $update(channelId: string, mode: OutputChannelUpdateMode, till: number): Promise; $reveal(channelId: string, preserveFocus: boolean): Promise; diff --git a/src/vs/workbench/api/common/extHostOutput.ts b/src/vs/workbench/api/common/extHostOutput.ts index 186031d7205..26df54d4607 100644 --- a/src/vs/workbench/api/common/extHostOutput.ts +++ b/src/vs/workbench/api/common/extHostOutput.ts @@ -117,12 +117,12 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { } } - createOutputChannel(name: string, extension: IExtensionDescription): vscode.OutputChannel { + createOutputChannel(name: string, languageId: string, extension: IExtensionDescription): vscode.OutputChannel { name = name.trim(); if (!name) { throw new Error('illegal argument `name`. must not be falsy'); } - const extHostOutputChannel = this.doCreateOutputChannel(name, extension); + const extHostOutputChannel = this.doCreateOutputChannel(name, languageId, extension); extHostOutputChannel.then(channel => { this.channels.set(channel.id, channel); channel.visible = channel.id === this.visibleChannelId; @@ -130,11 +130,11 @@ export class ExtHostOutputService implements ExtHostOutputServiceShape { return this.createExtHostOutputChannel(name, extHostOutputChannel); } - private async doCreateOutputChannel(name: string, extension: IExtensionDescription): Promise { + private async doCreateOutputChannel(name: string, languageId: string, extension: IExtensionDescription): Promise { const outputDir = await this.createOutputDirectory(); const file = this.extHostFileSystemInfo.extUri.joinPath(outputDir, `${this.namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}.log`); const logger = this.loggerService.createLogger(file, { always: true, donotRotate: true, donotUseFormatters: true }); - const id = await this.proxy.$register(name, false, file, extension.identifier.value); + const id = await this.proxy.$register(name, false, file, languageId, extension.identifier.value); return new ExtHostOutputChannel(id, name, logger, this.proxy); } diff --git a/src/vs/workbench/contrib/output/browser/outputServices.ts b/src/vs/workbench/contrib/output/browser/outputServices.ts index a8dc8204d1b..900f4b5d121 100644 --- a/src/vs/workbench/contrib/output/browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/browser/outputServices.ts @@ -39,7 +39,7 @@ class OutputChannel extends Disposable implements IOutputChannel { this.id = outputChannelDescriptor.id; this.label = outputChannelDescriptor.label; this.uri = URI.from({ scheme: OUTPUT_SCHEME, path: this.id }); - this.model = this._register(outputChannelModelService.createOutputChannelModel(this.id, this.uri, outputChannelDescriptor.log ? LOG_MIME : OUTPUT_MIME, outputChannelDescriptor.file)); + this.model = this._register(outputChannelModelService.createOutputChannelModel(this.id, this.uri, outputChannelDescriptor.log ? LOG_MIME : OUTPUT_MIME, outputChannelDescriptor.file, outputChannelDescriptor.languageId)); } append(output: string): void { @@ -216,7 +216,7 @@ export class LogContentProvider { const channelDisposables: IDisposable[] = []; const outputChannelDescriptor = this.outputService.getChannelDescriptors().filter(({ id }) => id === channelId)[0]; if (outputChannelDescriptor && outputChannelDescriptor.file) { - channelModel = this.outputChannelModelService.createOutputChannelModel(channelId, resource, outputChannelDescriptor.log ? LOG_MIME : OUTPUT_MIME, outputChannelDescriptor.file); + channelModel = this.outputChannelModelService.createOutputChannelModel(channelId, resource, outputChannelDescriptor.log ? LOG_MIME : OUTPUT_MIME, outputChannelDescriptor.file, outputChannelDescriptor.languageId); channelModel.onDispose(() => dispose(channelDisposables), channelDisposables); this.channelModels.set(channelId, channelModel); } diff --git a/src/vs/workbench/contrib/output/common/outputChannelModel.ts b/src/vs/workbench/contrib/output/common/outputChannelModel.ts index 0b51f32b176..73422d5851b 100644 --- a/src/vs/workbench/contrib/output/common/outputChannelModel.ts +++ b/src/vs/workbench/contrib/output/common/outputChannelModel.ts @@ -108,6 +108,7 @@ export class FileOutputChannelModel extends Disposable implements IOutputChannel private readonly modelUri: URI, private readonly mimeType: 'text/x-code-log-output' | 'text/x-code-output', private readonly file: URI, + private readonly languageId: string, @IFileService private readonly fileService: IFileService, @IModelService private readonly modelService: IModelService, @ILanguageService private readonly languageService: ILanguageService, @@ -163,7 +164,7 @@ export class FileOutputChannelModel extends Disposable implements IOutputChannel if (this.model) { this.model.setValue(content); } else { - this.model = this.modelService.createModel(content, this.languageService.createByMimeType(this.mimeType), this.modelUri); + this.model = this.modelService.createModel(content, this.languageId ? this.languageService.createById(this.languageId) : this.languageService.createByMimeType(this.mimeType), this.modelUri); this.fileHandler.watch(this.etag); const disposable = this.model.onWillDispose(() => { this.cancelModelUpdate(); @@ -326,6 +327,7 @@ class OutputChannelBackedByFile extends FileOutputChannelModel implements IOutpu modelUri: URI, mimeType: 'text/x-code-log-output' | 'text/x-code-output', file: URI, + languageId: string, @IFileService fileService: IFileService, @IModelService modelService: IModelService, @ILanguageService languageService: ILanguageService, @@ -333,7 +335,7 @@ class OutputChannelBackedByFile extends FileOutputChannelModel implements IOutpu @ILogService logService: ILogService, @IEditorWorkerService editorWorkerService: IEditorWorkerService ) { - super(modelUri, mimeType, file, fileService, modelService, languageService, logService, editorWorkerService); + super(modelUri, mimeType, file, languageId, fileService, modelService, languageService, logService, editorWorkerService); // Donot rotate to check for the file reset this.logger = loggerService.createLogger(file, { always: true, donotRotate: true, donotUseFormatters: true }); @@ -373,18 +375,19 @@ export class DelegatedOutputChannelModel extends Disposable implements IOutputCh modelUri: URI, mimeType: 'text/x-code-log-output' | 'text/x-code-output', outputDir: Promise, + languageId: string, @IInstantiationService private readonly instantiationService: IInstantiationService, @IFileService private readonly fileService: IFileService, ) { super(); - this.outputChannelModel = this.createOutputChannelModel(id, modelUri, mimeType, outputDir); + this.outputChannelModel = this.createOutputChannelModel(id, modelUri, mimeType, outputDir, languageId); } - private async createOutputChannelModel(id: string, modelUri: URI, mimeType: 'text/x-code-log-output' | 'text/x-code-output', outputDirPromise: Promise): Promise { + private async createOutputChannelModel(id: string, modelUri: URI, mimeType: 'text/x-code-log-output' | 'text/x-code-output', outputDirPromise: Promise, languageId: string): Promise { const outputDir = await outputDirPromise; const file = resources.joinPath(outputDir, `${id.replace(/[\\/:\*\?"<>\|]/g, '')}.log`); await this.fileService.createFile(file); - const outputChannelModel = this._register(this.instantiationService.createInstance(OutputChannelBackedByFile, id, modelUri, mimeType, file)); + const outputChannelModel = this._register(this.instantiationService.createInstance(OutputChannelBackedByFile, id, modelUri, mimeType, file, languageId)); this._register(outputChannelModel.onDispose(() => this._onDispose.fire())); return outputChannelModel; } diff --git a/src/vs/workbench/contrib/output/common/outputChannelModelService.ts b/src/vs/workbench/contrib/output/common/outputChannelModelService.ts index e003de09770..c52f15160d6 100644 --- a/src/vs/workbench/contrib/output/common/outputChannelModelService.ts +++ b/src/vs/workbench/contrib/output/common/outputChannelModelService.ts @@ -17,7 +17,7 @@ export const IOutputChannelModelService = createDecorator | null = null; diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index ca0a04329d4..b2cffdc6790 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -40,6 +40,7 @@ export const allApiProposals = Object.freeze({ notebookLiveShare: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookLiveShare.d.ts', notebookMessaging: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookMessaging.d.ts', notebookMime: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.notebookMime.d.ts', + outputChannelLanguage: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.outputChannelLanguage.d.ts', portsAttributes: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.portsAttributes.d.ts', quickPickSeparators: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickSeparators.d.ts', quickPickSortByLabel: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickSortByLabel.d.ts', diff --git a/src/vs/workbench/services/output/common/output.ts b/src/vs/workbench/services/output/common/output.ts index 1a0833dd8f1..7f0eab939b2 100644 --- a/src/vs/workbench/services/output/common/output.ts +++ b/src/vs/workbench/services/output/common/output.ts @@ -16,6 +16,7 @@ export interface IOutputChannelDescriptor { label: string; log: boolean; file?: URI; + languageId?: string; } export interface IFileOutputChannelDescriptor extends IOutputChannelDescriptor { diff --git a/src/vscode-dts/vscode.proposed.outputChannelLanguage.d.ts b/src/vscode-dts/vscode.proposed.outputChannelLanguage.d.ts new file mode 100644 index 00000000000..1e863abc4fa --- /dev/null +++ b/src/vscode-dts/vscode.proposed.outputChannelLanguage.d.ts @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// https://github.com/microsoft/vscode/issues/19561 + +declare module 'vscode' { + + export namespace window { + + /** + * Creates a new {@link OutputChannel output channel} with the given name. + * + * @param name Human-readable string which will be used to represent the channel in the UI. + * @param languageId The identifier of the language associated with the channel. + */ + export function createOutputChannel(name: string, languageId?: string): OutputChannel; + } +}