提交 979273be 编写于 作者: S Sandeep Somavarapu

Fix #69689

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