From 979273be9647b532e03e4d10ecd4c7f5a92cf8c6 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 4 Mar 2019 15:02:11 +0100 Subject: [PATCH] Fix #69689 --- .../mainThreadOutputService.ts | 9 +- .../contrib/output/browser/logViewer.ts | 4 +- .../contrib/output/browser/outputActions.ts | 101 ++++++++++-------- .../contrib/output/browser/outputPanel.ts | 15 +-- .../workbench/contrib/output/common/output.ts | 8 +- .../electron-browser/output.contribution.ts | 7 +- .../output/electron-browser/outputServices.ts | 77 +++++++------ 7 files changed, 128 insertions(+), 93 deletions(-) diff --git a/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts b/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts index 7f9f642dafd..9665fd33072 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadOutputService.ts @@ -86,8 +86,11 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut public $close(channelId: string): Promise | undefined { const panel = this._panelService.getActivePanel(); - if (panel && panel.getId() === OUTPUT_PANEL_ID && channelId === this._outputService.getActiveChannel().id) { - this._partService.setPanelHidden(true); + if (panel && panel.getId() === OUTPUT_PANEL_ID) { + const activeChannel = this._outputService.getActiveChannel(); + if (activeChannel && channelId === activeChannel.id) { + this._partService.setPanelHidden(true); + } } return undefined; @@ -101,7 +104,7 @@ export class MainThreadOutputService extends Disposable implements MainThreadOut return undefined; } - private _getChannel(channelId: string): IOutputChannel { + private _getChannel(channelId: string): IOutputChannel | null { return this._outputService.getChannel(channelId); } } diff --git a/src/vs/workbench/contrib/output/browser/logViewer.ts b/src/vs/workbench/contrib/output/browser/logViewer.ts index a09231f1d15..b9819992434 100644 --- a/src/vs/workbench/contrib/output/browser/logViewer.ts +++ b/src/vs/workbench/contrib/output/browser/logViewer.ts @@ -17,7 +17,7 @@ import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorIn import { URI } from 'vs/base/common/uri'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IHashService } from 'vs/workbench/services/hash/common/hashService'; -import { LOG_SCHEME, IOutputChannelDescriptor } from 'vs/workbench/contrib/output/common/output'; +import { LOG_SCHEME, IFileOutputChannelDescriptor } from 'vs/workbench/contrib/output/common/output'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWindowService } from 'vs/platform/windows/common/windows'; @@ -26,7 +26,7 @@ export class LogViewerInput extends ResourceEditorInput { public static readonly ID = 'workbench.editorinputs.output'; - constructor(private outputChannelDescriptor: IOutputChannelDescriptor, + constructor(private outputChannelDescriptor: IFileOutputChannelDescriptor, @ITextModelService textModelResolverService: ITextModelService, @IHashService hashService: IHashService ) { diff --git a/src/vs/workbench/contrib/output/browser/outputActions.ts b/src/vs/workbench/contrib/output/browser/outputActions.ts index 934be8edfdd..28e23670269 100644 --- a/src/vs/workbench/contrib/output/browser/outputActions.ts +++ b/src/vs/workbench/contrib/output/browser/outputActions.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { IAction, Action } from 'vs/base/common/actions'; -import { IOutputService, OUTPUT_PANEL_ID, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannelDescriptor } from 'vs/workbench/contrib/output/common/output'; +import { IOutputService, OUTPUT_PANEL_ID, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannelDescriptor, IFileOutputChannelDescriptor } from 'vs/workbench/contrib/output/common/output'; import { SelectActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IPartService } from 'vs/workbench/services/part/common/partService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; @@ -50,9 +50,11 @@ export class ClearOutputAction extends Action { } public run(): Promise { - this.outputService.getActiveChannel().clear(); - aria.status(nls.localize('outputCleared', "Output was cleared")); - + const activeChannel = this.outputService.getActiveChannel(); + if (activeChannel) { + activeChannel.clear(); + aria.status(nls.localize('outputCleared', "Output was cleared")); + } return Promise.resolve(true); } } @@ -70,7 +72,12 @@ export class ToggleOrSetOutputScrollLockAction extends Action { constructor(id: string, label: string, @IOutputService private readonly outputService: IOutputService) { super(id, label, 'output-action output-scroll-unlock'); - this.toDispose.push(this.outputService.onActiveOutputChannel(channel => this.setClass(this.outputService.getActiveChannel().scrollLock))); + this.toDispose.push(this.outputService.onActiveOutputChannel(channel => { + const activeChannel = this.outputService.getActiveChannel(); + if (activeChannel) { + this.setClass(activeChannel.scrollLock); + } + })); } public run(newLockState?: boolean): Promise { @@ -113,7 +120,7 @@ export class SwitchOutputAction extends Action { this.class = 'output-action switch-to-output'; } - public run(channelId?: string): Promise { + public run(channelId: string): Promise { return this.outputService.showChannel(channelId); } } @@ -134,12 +141,12 @@ export class SwitchOutputActionItem extends SelectActionItem { super(null, action, [], 0, contextViewService, { ariaLabel: nls.localize('outputChannels', 'Output Channels.') }); let outputChannelRegistry = Registry.as(OutputExt.OutputChannels); - this.toDispose.push(outputChannelRegistry.onDidRegisterChannel(() => this.updateOtions(this.outputService.getActiveChannel().id))); - this.toDispose.push(outputChannelRegistry.onDidRemoveChannel(() => this.updateOtions(this.outputService.getActiveChannel().id))); - this.toDispose.push(this.outputService.onActiveOutputChannel(activeChannelId => this.updateOtions(activeChannelId))); + this.toDispose.push(outputChannelRegistry.onDidRegisterChannel(() => this.updateOtions())); + this.toDispose.push(outputChannelRegistry.onDidRemoveChannel(() => this.updateOtions())); + this.toDispose.push(this.outputService.onActiveOutputChannel(() => this.updateOtions())); this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService)); - this.updateOtions(this.outputService.getActiveChannel().id); + this.updateOtions(); } protected getActionContext(option: string, index: number): string { @@ -147,30 +154,34 @@ export class SwitchOutputActionItem extends SelectActionItem { return channel ? channel.id : option; } - private updateOtions(selectedChannel: string): void { - const groups = groupBy(this.outputService.getChannelDescriptors(), (c1: IOutputChannelDescriptor, c2: IOutputChannelDescriptor) => { - if (!c1.log && c2.log) { - return -1; - } - if (c1.log && !c2.log) { - return 1; - } - return 0; - }); - this.outputChannels = groups[0] || []; - this.logChannels = groups[1] || []; - const showSeparator = this.outputChannels.length && this.logChannels.length; - const separatorIndex = showSeparator ? this.outputChannels.length : -1; - const options: string[] = [...this.outputChannels.map(c => c.label), ...(showSeparator ? [SwitchOutputActionItem.SEPARATOR] : []), ...this.logChannels.map(c => nls.localize('logChannel', "Log ({0})", c.label))]; - let selected = 0; - if (selectedChannel) { - selected = this.outputChannels.map(c => c.id).indexOf(selectedChannel); - if (selected === -1) { - const logChannelIndex = this.logChannels.map(c => c.id).indexOf(selectedChannel); - selected = logChannelIndex !== -1 ? separatorIndex + 1 + logChannelIndex : 0; + private updateOtions(): void { + const activeChannel = this.outputService.getActiveChannel(); + if (activeChannel) { + const selectedChannel = activeChannel.id; + const groups = groupBy(this.outputService.getChannelDescriptors(), (c1: IOutputChannelDescriptor, c2: IOutputChannelDescriptor) => { + if (!c1.log && c2.log) { + return -1; + } + if (c1.log && !c2.log) { + return 1; + } + return 0; + }); + this.outputChannels = groups[0] || []; + this.logChannels = groups[1] || []; + const showSeparator = this.outputChannels.length && this.logChannels.length; + const separatorIndex = showSeparator ? this.outputChannels.length : -1; + const options: string[] = [...this.outputChannels.map(c => c.label), ...(showSeparator ? [SwitchOutputActionItem.SEPARATOR] : []), ...this.logChannels.map(c => nls.localize('logChannel', "Log ({0})", c.label))]; + let selected = 0; + if (selectedChannel) { + selected = this.outputChannels.map(c => c.id).indexOf(selectedChannel); + if (selected === -1) { + const logChannelIndex = this.logChannels.map(c => c.id).indexOf(selectedChannel); + selected = logChannelIndex !== -1 ? separatorIndex + 1 + logChannelIndex : 0; + } } + this.setOptions(options.map((label, index) => { text: label, isDisabled: (index === separatorIndex ? true : undefined) }), Math.max(0, selected)); } - this.setOptions(options.map((label, index) => { text: label, isDisabled: (index === separatorIndex ? true : undefined) }), Math.max(0, selected)); } } @@ -192,17 +203,23 @@ export class OpenLogOutputFile extends Action { } private update(): void { - const outputChannelDescriptor = this.getOutputChannelDescriptor(); - this.enabled = !!(outputChannelDescriptor && outputChannelDescriptor.file && outputChannelDescriptor.log); + this.enabled = !!this.getLogFileOutputChannelDescriptor(); } public run(): Promise { - return this.enabled ? this.editorService.openEditor(this.instantiationService.createInstance(LogViewerInput, this.getOutputChannelDescriptor())).then(() => null) : Promise.resolve(null); + const logFileOutputChannelDescriptor = this.getLogFileOutputChannelDescriptor(); + return logFileOutputChannelDescriptor ? this.editorService.openEditor(this.instantiationService.createInstance(LogViewerInput, logFileOutputChannelDescriptor)).then(() => null) : Promise.resolve(null); } - private getOutputChannelDescriptor(): IOutputChannelDescriptor { + private getLogFileOutputChannelDescriptor(): IFileOutputChannelDescriptor | null { const channel = this.outputService.getActiveChannel(); - return channel ? this.outputService.getChannelDescriptors().filter(c => c.id === channel.id)[0] : null; + if (channel) { + const descriptor = this.outputService.getChannelDescriptors().filter(c => c.id === channel.id)[0]; + if (descriptor && descriptor.file && descriptor.log) { + return descriptor; + } + } + return null; } } @@ -219,15 +236,15 @@ export class ShowLogsOutputChannelAction extends Action { } run(): Promise { - const entries: IQuickPickItem[] = this.outputService.getChannelDescriptors().filter(c => c.file && c.log) - .map(({ id, label }) => ({ id, label })); + const entries: { id: string, label: string }[] = this.outputService.getChannelDescriptors().filter(c => c.file && c.log) + .map(({ id, label }) => ({ id, label })); return this.quickInputService.pick(entries, { placeHolder: nls.localize('selectlog', "Select Log") }) .then(entry => { if (entry) { return this.outputService.showChannel(entry.id); } - return null; + return undefined; }); } } @@ -257,9 +274,9 @@ export class OpenOutputLogFileAction extends Action { return this.quickInputService.pick(entries, { placeHolder: nls.localize('selectlogFile', "Select Log file") }) .then(entry => { if (entry) { - return this.editorService.openEditor(this.instantiationService.createInstance(LogViewerInput, entry.channel)).then(() => null); + return this.editorService.openEditor(this.instantiationService.createInstance(LogViewerInput, entry.channel)).then(() => undefined); } - return null; + return undefined; }); } } \ No newline at end of file diff --git a/src/vs/workbench/contrib/output/browser/outputPanel.ts b/src/vs/workbench/contrib/output/browser/outputPanel.ts index d1e887071e8..944b643be3c 100644 --- a/src/vs/workbench/contrib/output/browser/outputPanel.ts +++ b/src/vs/workbench/contrib/output/browser/outputPanel.ts @@ -75,7 +75,7 @@ export class OutputPanel extends AbstractTextResourceEditor { return this.actions; } - public getActionItem(action: Action): IActionItem { + public getActionItem(action: Action): IActionItem | null { if (action.id === SwitchOutputAction.ID) { return this.instantiationService.createInstance(SwitchOutputActionItem, action); } @@ -154,11 +154,14 @@ export class OutputPanel extends AbstractTextResourceEditor { return; } - const newPositionLine = e.position.lineNumber; - const lastLine = codeEditor.getModel().getLineCount(); - const newLockState = lastLine !== newPositionLine; - const lockAction = this.actions.filter((action) => action.id === ToggleOrSetOutputScrollLockAction.ID)[0]; - lockAction.run(newLockState); + const model = codeEditor.getModel(); + if (model) { + const newPositionLine = e.position.lineNumber; + const lastLine = model.getLineCount(); + const newLockState = lastLine !== newPositionLine; + const lockAction = this.actions.filter((action) => action.id === ToggleOrSetOutputScrollLockAction.ID)[0]; + lockAction.run(newLockState); + } }); } diff --git a/src/vs/workbench/contrib/output/common/output.ts b/src/vs/workbench/contrib/output/common/output.ts index 6fee8571bbe..08e2a7a363e 100644 --- a/src/vs/workbench/contrib/output/common/output.ts +++ b/src/vs/workbench/contrib/output/common/output.ts @@ -68,7 +68,7 @@ export interface IOutputService { * Given the channel id returns the output channel instance. * Channel should be first registered via OutputChannelRegistry. */ - getChannel(id: string): IOutputChannel; + getChannel(id: string): IOutputChannel | null; /** * Returns an array of all known output channels descriptors. @@ -79,7 +79,7 @@ export interface IOutputService { * Returns the currently active channel. * Only one channel can be active at a given moment. */ - getActiveChannel(): IOutputChannel; + getActiveChannel(): IOutputChannel | null; /** * Show the channel with the passed id. @@ -137,6 +137,10 @@ export interface IOutputChannelDescriptor { file?: URI; } +export interface IFileOutputChannelDescriptor extends IOutputChannelDescriptor { + file: URI; +} + export interface IOutputChannelRegistry { readonly onDidRegisterChannel: Event; diff --git a/src/vs/workbench/contrib/output/electron-browser/output.contribution.ts b/src/vs/workbench/contrib/output/electron-browser/output.contribution.ts index e217ba7ab9e..65e36ae6aab 100644 --- a/src/vs/workbench/contrib/output/electron-browser/output.contribution.ts +++ b/src/vs/workbench/contrib/output/electron-browser/output.contribution.ts @@ -30,7 +30,6 @@ registerSingleton(IOutputService, OutputService); ModesRegistry.registerLanguage({ id: OUTPUT_MODE_ID, extensions: [], - aliases: [null], mimetypes: [OUTPUT_MIME] }); @@ -38,7 +37,6 @@ ModesRegistry.registerLanguage({ ModesRegistry.registerLanguage({ id: LOG_MODE_ID, extensions: [], - aliases: [null], mimetypes: [LOG_MIME] }); @@ -99,7 +97,10 @@ registerAction({ when: CONTEXT_IN_OUTPUT }, handler(accessor) { - accessor.get(IOutputService).getActiveChannel().clear(); + const activeChannel = accessor.get(IOutputService).getActiveChannel(); + if (activeChannel) { + activeChannel.clear(); + } } }); diff --git a/src/vs/workbench/contrib/output/electron-browser/outputServices.ts b/src/vs/workbench/contrib/output/electron-browser/outputServices.ts index 19a30ee0d38..897620d45f8 100644 --- a/src/vs/workbench/contrib/output/electron-browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/electron-browser/outputServices.ts @@ -14,7 +14,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { Registry } from 'vs/platform/registry/common/platform'; import { EditorOptions } from 'vs/workbench/common/editor'; -import { IOutputChannelDescriptor, IOutputChannel, IOutputService, Extensions, OUTPUT_PANEL_ID, IOutputChannelRegistry, OUTPUT_SCHEME, OUTPUT_MIME, LOG_SCHEME, LOG_MIME, CONTEXT_ACTIVE_LOG_OUTPUT, MAX_OUTPUT_LENGTH } from 'vs/workbench/contrib/output/common/output'; +import { IOutputChannelDescriptor, IOutputChannel, IOutputService, Extensions, OUTPUT_PANEL_ID, IOutputChannelRegistry, OUTPUT_SCHEME, OUTPUT_MIME, LOG_SCHEME, LOG_MIME, CONTEXT_ACTIVE_LOG_OUTPUT, MAX_OUTPUT_LENGTH, IFileOutputChannelDescriptor } from 'vs/workbench/contrib/output/common/output'; import { OutputPanel } from 'vs/workbench/contrib/output/browser/outputPanel'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -44,7 +44,7 @@ import { isNumber } from 'vs/base/common/types'; const OUTPUT_ACTIVE_CHANNEL_KEY = 'output.activechannel'; let watchingOutputDir = false; -let callbacks: ((eventType: string, fileName: string) => void)[] = []; +let callbacks: ((eventType: string, fileName?: string) => void)[] = []; function watchOutputDirectory(outputDir: string, logService: ILogService, onChange: (eventType: string, fileName: string) => void): IDisposable { callbacks.push(onChange); if (!watchingOutputDir) { @@ -65,7 +65,7 @@ function watchOutputDirectory(outputDir: string, logService: ILogService, onChan } interface OutputChannel extends IOutputChannel { - readonly file: URI; + readonly file: URI | null; readonly onDidAppendedContent: Event; readonly onDispose: Event; loadModel(): Promise; @@ -83,14 +83,14 @@ abstract class AbstractFileOutputChannel extends Disposable implements OutputCha private readonly mimeType: string; protected modelUpdater: RunOnceScheduler; - protected model: ITextModel; + protected model: ITextModel | null; readonly file: URI; protected startOffset: number = 0; protected endOffset: number = 0; constructor( - readonly outputChannelDescriptor: IOutputChannelDescriptor, + readonly outputChannelDescriptor: IFileOutputChannelDescriptor, private readonly modelUri: URI, protected fileService: IFileService, protected modelService: IModelService, @@ -154,7 +154,7 @@ abstract class AbstractFileOutputChannel extends Disposable implements OutputCha abstract append(message: string); protected onModelCreated(model: ITextModel) { } - protected onModelWillDispose(model: ITextModel) { } + protected onModelWillDispose(model: ITextModel | null) { } protected onUpdateModelCancelled() { } protected updateModel() { } @@ -176,15 +176,14 @@ class OutputChannelBackedByFile extends AbstractFileOutputChannel implements Out private readonly rotatingFilePath: string; constructor( - outputChannelDescriptor: IOutputChannelDescriptor, - outputDir: string, + outputChannelDescriptor: IFileOutputChannelDescriptor, modelUri: URI, @IFileService fileService: IFileService, @IModelService modelService: IModelService, @IModeService modeService: IModeService, @ILogService logService: ILogService ) { - super({ ...outputChannelDescriptor, file: URI.file(join(outputDir, `${outputChannelDescriptor.id}.log`)) }, modelUri, fileService, modelService, modeService); + super(outputChannelDescriptor, modelUri, fileService, modelService, modeService); // Use one rotating file to check for main file reset this.appender = new OutputAppender(this.id, this.file.fsPath); @@ -262,7 +261,7 @@ class OutputChannelBackedByFile extends AbstractFileOutputChannel implements Out } } - private onFileChangedInOutputDirector(eventType: string, fileName: string): void { + private onFileChangedInOutputDirector(eventType: string, fileName?: string): void { // Check if rotating file has changed. It changes only when the main file exceeds its limit. if (this.rotatingFilePath === fileName) { this.resettingDelayer.trigger(() => this.resetModel()); @@ -286,11 +285,11 @@ class FileOutputChannel extends AbstractFileOutputChannel implements OutputChann private readonly fileHandler: FileListener; private updateInProgress: boolean = false; - private etag: string = ''; - private loadModelPromise: Promise = Promise.resolve(undefined); + private etag: string | undefined = ''; + private loadModelPromise: Promise | null = null; constructor( - outputChannelDescriptor: IOutputChannelDescriptor, + outputChannelDescriptor: IFileOutputChannelDescriptor, modelUri: URI, @IFileService fileService: IFileService, @IModelService modelService: IModelService, @@ -314,7 +313,8 @@ class FileOutputChannel extends AbstractFileOutputChannel implements OutputChann } clear(till?: number): void { - this.loadModelPromise.then(() => { + const loadModelPromise: Promise = this.loadModelPromise ? this.loadModelPromise : Promise.resolve(); + loadModelPromise.then(() => { super.clear(till); this.update(); }); @@ -344,7 +344,7 @@ class FileOutputChannel extends AbstractFileOutputChannel implements OutputChann this.fileHandler.watch(this.etag); } - protected onModelWillDispose(model: ITextModel): void { + protected onModelWillDispose(model: ITextModel | null): void { this.fileHandler.unwatch(); } @@ -353,13 +353,15 @@ class FileOutputChannel extends AbstractFileOutputChannel implements OutputChann } update(size?: number): void { - if (!this.updateInProgress) { - this.updateInProgress = true; - if (isNumber(size) && this.endOffset > size) { // Reset - Content is removed - this.startOffset = this.endOffset = 0; - this.model.setValue(''); + if (this.model) { + if (!this.updateInProgress) { + this.updateInProgress = true; + if (isNumber(size) && this.endOffset > size) { // Reset - Content is removed + this.startOffset = this.endOffset = 0; + this.model.setValue(''); + } + this.modelUpdater.schedule(); } - this.modelUpdater.schedule(); } } } @@ -370,7 +372,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo private channels: Map = new Map(); private activeChannelIdInStorage: string; - private activeChannel: IOutputChannel; + private activeChannel: IOutputChannel | null; private readonly outputDir: string; private readonly _onActiveOutputChannel = new Emitter(); @@ -392,7 +394,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo @IContextKeyService private readonly contextKeyService: IContextKeyService, ) { super(); - this.activeChannelIdInStorage = this.storageService.get(OUTPUT_ACTIVE_CHANNEL_KEY, StorageScope.WORKSPACE, null); + this.activeChannelIdInStorage = this.storageService.get(OUTPUT_ACTIVE_CHANNEL_KEY, StorageScope.WORKSPACE, ''); this.outputDir = join(environmentService.logsPath, `output_${windowService.getCurrentWindowId()}_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`); // Register as text model content provider for output @@ -419,7 +421,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo this._register(this.storageService.onWillSaveState(() => this.saveState())); } - provideTextContent(resource: URI): Promise { + provideTextContent(resource: URI): Promise | null { const channel = this.getChannel(resource.path); if (channel) { return channel.loadModel(); @@ -447,15 +449,15 @@ export class OutputService extends Disposable implements IOutputService, ITextMo return promise.then(() => this._onActiveOutputChannel.fire(id)); } - getChannel(id: string): IOutputChannel { - return this.channels.get(id); + getChannel(id: string): IOutputChannel | null { + return this.channels.get(id) || null; } getChannelDescriptors(): IOutputChannelDescriptor[] { return Registry.as(Extensions.OutputChannels).getChannels(); } - getActiveChannel(): IOutputChannel { + getActiveChannel(): IOutputChannel | null { return this.activeChannel; } @@ -469,7 +471,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo } } - private onDidPanelOpen(panel: IPanel, preserveFocus: boolean): Promise { + private onDidPanelOpen(panel: IPanel | null, preserveFocus: boolean): Promise { if (panel && panel.getId() === OUTPUT_PANEL_ID) { this._outputPanel = this.panelService.getActivePanel(); if (this.activeChannel) { @@ -506,7 +508,9 @@ export class OutputService extends Disposable implements IOutputService, ITextMo this.showChannel(channel.id, true); } else { this.activeChannel = channel; - this._onActiveOutputChannel.fire(channel ? channel.id : undefined); + if (this.activeChannel) { + this._onActiveOutputChannel.fire(this.activeChannel.id); + } } } Registry.as(Extensions.OutputChannels).removeChannel(id); @@ -528,7 +532,8 @@ export class OutputService extends Disposable implements IOutputService, ITextMo return this.instantiationService.createInstance(FileOutputChannel, channelData, uri); } try { - return this.instantiationService.createInstance(OutputChannelBackedByFile, { id, label: channelData ? channelData.label : '' }, this.outputDir, uri); + const channelDescriptor: IFileOutputChannelDescriptor = { id, label: channelData ? channelData.label : '', log: false, file: URI.file(join(this.outputDir, `${id}.log`)) }; + return this.instantiationService.createInstance(OutputChannelBackedByFile, channelDescriptor, uri); } catch (e) { // Do not crash if spdlog rotating logger cannot be loaded (workaround for https://github.com/Microsoft/vscode/issues/47883) this.logService.error(e); @@ -584,7 +589,7 @@ export class LogContentProvider { ) { } - provideTextContent(resource: URI): Promise { + provideTextContent(resource: URI): Promise | null { if (resource.scheme === LOG_SCHEME) { let channel = this.getChannel(resource); if (channel) { @@ -594,7 +599,7 @@ export class LogContentProvider { return null; } - private getChannel(resource: URI): OutputChannel { + private getChannel(resource: URI): OutputChannel | undefined { const channelId = resource.path; let channel = this.channels.get(channelId); if (!channel) { @@ -624,9 +629,9 @@ class BufferredOutputChannel extends Disposable implements OutputChannel { readonly onDispose: Event = this._onDispose.event; private modelUpdater: RunOnceScheduler; - private model: ITextModel; + private model: ITextModel | null; private readonly bufferredContent: BufferedContent; - private lastReadId: number = undefined; + private lastReadId: number | undefined = undefined; constructor( protected readonly outputChannelIdentifier: IOutputChannelDescriptor, @@ -731,7 +736,9 @@ class BufferedContent { while (this.length > MAX_OUTPUT_LENGTH) { this.dataIds.shift(); const removed = this.data.shift(); - this.length -= removed.length; + if (removed) { + this.length -= removed.length; + } } } -- GitLab