#20183 move current problem contribution to editor status

This commit is contained in:
Sandeep Somavarapu
2019-11-12 17:12:06 +01:00
parent 483a8a701d
commit a05e629253
2 changed files with 135 additions and 148 deletions
@@ -6,7 +6,7 @@
import 'vs/css!./media/editorstatus';
import * as nls from 'vs/nls';
import { runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { format } from 'vs/base/common/strings';
import { format, compare } from 'vs/base/common/strings';
import { extname, basename, isEqual } from 'vs/base/common/resources';
import { areFunctions, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
@@ -50,6 +50,8 @@ import { Event } from 'vs/base/common/event';
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
import { IMarker, IMarkerService, MarkerSeverity, IMarkerData } from 'vs/platform/markers/common/markers';
import { find } from 'vs/base/common/arrays';
class SideBySideEditorEncodingSupport implements IEncodingSupport {
constructor(private master: IEncodingSupport, private details: IEncodingSupport) { }
@@ -282,6 +284,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
private readonly eolElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly modeElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly metadataElement = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
private readonly currentProblemStatus: ShowCurrentMarkerInStatusbarContribution = this._register(this.instantiationService.createInstance(ShowCurrentMarkerInStatusbarContribution));
private readonly state = new State();
private readonly activeEditorListeners = this._register(new DisposableStore());
@@ -299,7 +302,8 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
@IConfigurationService private readonly configurationService: IConfigurationService,
@INotificationService private readonly notificationService: INotificationService,
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
@IStatusbarService private readonly statusbarService: IStatusbarService
@IStatusbarService private readonly statusbarService: IStatusbarService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
) {
super();
@@ -577,6 +581,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
this.onEncodingChange(activeControl, activeCodeEditor);
this.onIndentationChange(activeCodeEditor);
this.onMetadataChange(activeControl);
this.currentProblemStatus.update(activeCodeEditor);
// Dispose old active editor listeners
this.activeEditorListeners.clear();
@@ -594,6 +599,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
// Hook Listener for Selection changes
this.activeEditorListeners.add(activeCodeEditor.onDidChangeCursorPosition((event: ICursorPositionChangedEvent) => {
this.onSelectionChange(activeCodeEditor);
this.currentProblemStatus.update(activeCodeEditor);
}));
// Hook Listener for mode changes
@@ -604,6 +610,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
// Hook Listener for content changes
this.activeEditorListeners.add(activeCodeEditor.onDidChangeModelContent((e) => {
this.onEOLChange(activeCodeEditor);
this.currentProblemStatus.update(activeCodeEditor);
const selections = activeCodeEditor.getSelections();
if (selections) {
@@ -824,6 +831,130 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
}
}
class ShowCurrentMarkerInStatusbarContribution extends Disposable {
private readonly statusBarEntryAccessor: MutableDisposable<IStatusbarEntryAccessor>;
private editor: ICodeEditor | undefined = undefined;
private markers: IMarker[] = [];
private currentMarker: IMarker | null = null;
constructor(
@IStatusbarService private readonly statusbarService: IStatusbarService,
@IMarkerService private readonly markerService: IMarkerService,
@IConfigurationService private readonly configurationService: IConfigurationService,
) {
super();
this.statusBarEntryAccessor = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
this._register(markerService.onMarkerChanged(changedResources => this.onMarkerChanged(changedResources)));
this._register(Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('problems.showCurrentInStatus'))(() => this.updateStatus()));
}
update(editor: ICodeEditor | undefined): void {
this.editor = editor;
this.updateStatus();
}
private updateStatus(): void {
const previousMarker = this.currentMarker;
this.currentMarker = this.getMarker();
if (this.hasToUpdateStatus(previousMarker, this.currentMarker)) {
if (this.currentMarker) {
const line = this.currentMarker.message.split(/\r\n|\r|\n/g)[0];
const text = `${this.getType(this.currentMarker)} ${line}`;
if (!this.statusBarEntryAccessor.value) {
this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text: '' }, 'statusbar.currentProblem', nls.localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT);
}
this.statusBarEntryAccessor.value.update({ text });
} else {
this.statusBarEntryAccessor.clear();
}
}
}
private hasToUpdateStatus(previousMarker: IMarker | null, currentMarker: IMarker | null): boolean {
if (!currentMarker) {
return true;
}
if (!previousMarker) {
return true;
}
return IMarkerData.makeKey(previousMarker) !== IMarkerData.makeKey(currentMarker);
}
private getType(marker: IMarker): string {
switch (marker.severity) {
case MarkerSeverity.Error: return '$(error)';
case MarkerSeverity.Warning: return '$(warning)';
case MarkerSeverity.Info: return '$(info)';
}
return '';
}
private getMarker(): IMarker | null {
if (!this.configurationService.getValue<boolean>('problems.showCurrentInStatus')) {
return null;
}
if (!this.editor) {
return null;
}
const model = this.editor.getModel();
if (!model) {
return null;
}
const position = this.editor.getPosition();
if (!position) {
return null;
}
return find(this.markers, marker => Range.containsPosition(marker, position)) || null;
}
private onMarkerChanged(changedResources: ReadonlyArray<URI>): void {
if (!this.editor) {
return;
}
const model = this.editor.getModel();
if (!model) {
return;
}
if (model && !changedResources.some(r => isEqual(model.uri, r))) {
return;
}
this.updateMarkers();
}
private updateMarkers(): void {
if (!this.editor) {
return;
}
const model = this.editor.getModel();
if (!model) {
return;
}
if (model) {
this.markers = this.markerService.read({
resource: model.uri,
severities: MarkerSeverity.Error | MarkerSeverity.Warning | MarkerSeverity.Info
});
this.markers.sort(compareMarker);
} else {
this.markers = [];
}
this.updateStatus();
}
}
function compareMarker(a: IMarker, b: IMarker): number {
let res = compare(a.resource.toString(), b.resource.toString());
if (res === 0) {
res = MarkerSeverity.compare(a.severity, b.severity);
}
if (res === 0) {
res = Range.compareRangesUsingStarts(a, b);
}
return res;
}
function isWritableCodeEditor(codeEditor: ICodeEditor | undefined): boolean {
if (!codeEditor) {
return false;
@@ -25,21 +25,10 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ActivePanelContext } from 'vs/workbench/common/panel';
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
import { IMarkerService, MarkerStatistics, IMarker, MarkerSeverity, IMarkerData } from 'vs/platform/markers/common/markers';
import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Event } from 'vs/base/common/event';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { URI } from 'vs/base/common/uri';
import { isEqual } from 'vs/base/common/resources';
import { find } from 'vs/base/common/arrays';
import { Range } from 'vs/editor/common/core/range';
import { compare } from 'vs/base/common/strings';
registerSingleton(IMarkersWorkbenchService, MarkersWorkbenchService, false);
@@ -359,136 +348,3 @@ class MarkersStatusBarContributions extends Disposable implements IWorkbenchCont
}
workbenchRegistry.registerWorkbenchContribution(MarkersStatusBarContributions, LifecyclePhase.Restored);
class ShowCurrentMarkerInStatusbarContribution extends Disposable implements IEditorContribution {
public static readonly ID = 'editor.contrib.showCurrentMarkerInStatusbar';
private readonly rendererDisposable: MutableDisposable<ShowCurrentMarkerInStatusbarRenderer>;
constructor(
private readonly editor: ICodeEditor,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super();
this.rendererDisposable = new MutableDisposable<ShowCurrentMarkerInStatusbarRenderer>();
this.onDidConfigurationChange();
this._register(Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('problems.showCurrentInStatus'))(() => this.onDidConfigurationChange()));
}
private onDidConfigurationChange(): void {
this.rendererDisposable.clear();
if (this.configurationService.getValue<boolean>('problems.showCurrentInStatus')) {
this.rendererDisposable.value = this.instantiationService.createInstance(ShowCurrentMarkerInStatusbarRenderer, this.editor);
}
}
}
class ShowCurrentMarkerInStatusbarRenderer extends Disposable {
private readonly statusBarEntryAccessor: MutableDisposable<IStatusbarEntryAccessor>;
private markers: IMarker[] = [];
private currentMarker: IMarker | null = null;
constructor(
private readonly editor: ICodeEditor,
@IStatusbarService private readonly statusbarService: IStatusbarService,
@IMarkerService private readonly markerService: IMarkerService
) {
super();
this.statusBarEntryAccessor = this._register(new MutableDisposable<IStatusbarEntryAccessor>());
this._register(markerService.onMarkerChanged(changedResources => this.onMarkerChanged(changedResources)));
this._register(editor.onDidChangeModel(() => this.updateMarkers()));
this._register(editor.onDidChangeCursorPosition(() => this.render()));
this.render();
}
private render(): void {
const previousMarker = this.currentMarker;
this.currentMarker = this.getMarker();
if (this.hasToUpdateStatus(previousMarker, this.currentMarker)) {
this.updateStatus();
}
}
private hasToUpdateStatus(previousMarker: IMarker | null, currentMarker: IMarker | null): boolean {
if (!currentMarker) {
return true;
}
if (!previousMarker) {
return true;
}
return IMarkerData.makeKey(previousMarker) !== IMarkerData.makeKey(currentMarker);
}
private updateStatus(): void {
if (this.currentMarker) {
const line = this.currentMarker.message.split(/\r\n|\r|\n/g)[0];
const text = `${this.getType(this.currentMarker)} ${line}`;
if (this.statusBarEntryAccessor.value) {
this.statusBarEntryAccessor.value.update({ text });
} else {
this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text }, 'statusbar.currentProblem', localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT);
}
} else {
this.statusBarEntryAccessor.clear();
}
}
private getType(marker: IMarker): string {
switch (marker.severity) {
case MarkerSeverity.Error: return '$(error)';
case MarkerSeverity.Warning: return '$(warning)';
case MarkerSeverity.Info: return '$(info)';
}
return '';
}
private getMarker(): IMarker | null {
const model = this.editor.getModel();
if (!model) {
return null;
}
const position = this.editor.getPosition();
if (!position) {
return null;
}
return find(this.markers, marker => Range.containsPosition(marker, position)) || null;
}
private onMarkerChanged(changedResources: ReadonlyArray<URI>): void {
const editorModel = this.editor.getModel();
if (editorModel && !changedResources.some(r => isEqual(editorModel.uri, r))) {
return;
}
this.updateMarkers();
}
private updateMarkers(): void {
const editorModel = this.editor.getModel();
if (editorModel) {
this.markers = this.markerService.read({
resource: editorModel.uri,
severities: MarkerSeverity.Error | MarkerSeverity.Warning | MarkerSeverity.Info
});
this.markers.sort(compareMarker);
} else {
this.markers = [];
}
this.render();
}
}
function compareMarker(a: IMarker, b: IMarker): number {
let res = compare(a.resource.toString(), b.resource.toString());
if (res === 0) {
res = MarkerSeverity.compare(a.severity, b.severity);
}
if (res === 0) {
res = Range.compareRangesUsingStarts(a, b);
}
return res;
}
registerEditorContribution(ShowCurrentMarkerInStatusbarContribution.ID, ShowCurrentMarkerInStatusbarContribution);