提交 a920f227 编写于 作者: S Sandeep Somavarapu

Fix #66685

上级 b257ca20
......@@ -16,6 +16,7 @@ export default {
MARKERS_PANEL_SHOW_SINGLELINE_MESSAGE: 'problems.action.showSinglelineMessage',
MARKER_OPEN_SIDE_ACTION_ID: 'problems.action.openToSide',
MARKER_SHOW_PANEL_ID: 'workbench.action.showErrorsWarnings',
MARKER_SHOW_QUICK_FIX: 'problems.action.showQuickFixes',
MarkerPanelFocusContextKey: new RawContextKey<boolean>('problemsViewFocus', false),
MarkerFocusContextKey: new RawContextKey<boolean>('problemFocus', false),
......
......@@ -53,6 +53,20 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: Constants.MARKER_SHOW_QUICK_FIX,
weight: KeybindingWeight.WorkbenchContrib,
when: Constants.MarkerFocusContextKey,
primary: KeyMod.CtrlCmd | KeyCode.US_DOT,
handler: (accessor, args: any) => {
const markersPanel = (<MarkersPanel>accessor.get(IPanelService).getActivePanel());
const focusedElement = markersPanel.getFocusElement();
if (focusedElement instanceof Marker) {
markersPanel.showQuickFixes(focusedElement);
}
}
});
// configuration
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
'id': 'problems',
......@@ -161,7 +175,7 @@ registerAction({
const panelService = accessor.get(IPanelService);
const panel = panelService.getActivePanel();
if (panel instanceof MarkersPanel) {
panel.markersViewState.multiline = true;
panel.markersViewModel.multiline = true;
}
},
title: localize('show multiline', "Show message in multiple lines"),
......@@ -177,7 +191,7 @@ registerAction({
const panelService = accessor.get(IPanelService);
const panel = panelService.getActivePanel();
if (panel instanceof MarkersPanel) {
panel.markersViewState.multiline = false;
panel.markersViewModel.multiline = false;
}
},
title: localize('show singleline', "Show message in single line"),
......
......@@ -14,7 +14,7 @@ import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/
import Constants from 'vs/workbench/parts/markers/electron-browser/constants';
import { Marker, ResourceMarkers, RelatedInformation, MarkersModel } from 'vs/workbench/parts/markers/electron-browser/markersModel';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { MarkersFilterActionItem, MarkersFilterAction, QuickFixAction, QuickFixActionItem, IMarkersFilterActionChangeEvent, IMarkerFilterController } from 'vs/workbench/parts/markers/electron-browser/markersPanelActions';
import { MarkersFilterActionItem, MarkersFilterAction, IMarkersFilterActionChangeEvent, IMarkerFilterController } from 'vs/workbench/parts/markers/electron-browser/markersPanelActions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import Messages from 'vs/workbench/parts/markers/electron-browser/messages';
import { RangeHighlightDecorations } from 'vs/workbench/browser/parts/editor/rangeDecorations';
......@@ -33,7 +33,7 @@ import { IExpression, getEmptyExpression } from 'vs/base/common/glob';
import { mixin, deepClone } from 'vs/base/common/objects';
import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { isAbsolute, join } from 'vs/base/common/paths';
import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, TreeElement, MarkersTreeAccessibilityProvider, MarkersViewState } from 'vs/workbench/parts/markers/electron-browser/markersTreeViewer';
import { FilterData, Filter, VirtualDelegate, ResourceMarkersRenderer, MarkerRenderer, RelatedInformationRenderer, TreeElement, MarkersTreeAccessibilityProvider, MarkersViewModel } from 'vs/workbench/parts/markers/electron-browser/markersTreeViewer';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Separator, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
......@@ -89,7 +89,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
private cachedFilterStats: { total: number; filtered: number; } | undefined = undefined;
private currentResourceGotAddedToMarkersData: boolean = false;
readonly markersViewState: MarkersViewState;
readonly markersViewModel: MarkersViewModel;
private disposables: IDisposable[] = [];
constructor(
......@@ -109,8 +109,8 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
super(Constants.MARKERS_PANEL_ID, telemetryService, themeService, storageService);
this.panelFoucusContextKey = Constants.MarkerPanelFocusContextKey.bindTo(contextKeyService);
this.panelState = this.getMemento(StorageScope.WORKSPACE);
this.markersViewState = new MarkersViewState(this.panelState['multiline']);
this.markersViewState.onDidChangeViewState(this.onDidChangeViewState, this, this.disposables);
this.markersViewModel = instantiationService.createInstance(MarkersViewModel, this.panelState['multiline']);
this.markersViewModel.onDidChange(this.onDidChangeViewState, this, this.disposables);
this.setCurrentActiveEditor();
}
......@@ -178,6 +178,13 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
return this.actions;
}
public showQuickFixes(marker: Marker): void {
const viewModel = this.markersViewModel.getViewModel(marker);
if (viewModel) {
viewModel.quickFixAction.run();
}
}
public openFileAtElement(element: any, preserveFocus: boolean, sideByside: boolean, pinned: boolean): boolean {
const { resource, selection, event, data } = element instanceof Marker ? { resource: element.resource, selection: element.range, event: 'problems.selectDiagnostic', data: this.getTelemetryData(element.marker) } :
element instanceof RelatedInformation ? { resource: element.raw.resource, selection: element.raw, event: 'problems.selectRelatedInformation', data: this.getTelemetryData(element.marker) } : { resource: null, selection: null, event: null, data: null };
......@@ -306,10 +313,10 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this));
const virtualDelegate = new VirtualDelegate(this.markersViewState);
const virtualDelegate = new VirtualDelegate(this.markersViewModel);
const renderers = [
this.instantiationService.createInstance(ResourceMarkersRenderer, this.treeLabels, onDidChangeRenderNodeCount.event),
this.instantiationService.createInstance(MarkerRenderer, this.markersViewState, a => this.getActionItem(a)),
this.instantiationService.createInstance(MarkerRenderer, this.markersViewModel),
this.instantiationService.createInstance(RelatedInformationRenderer)
];
this.filter = new Filter();
......@@ -408,11 +415,11 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
private onDidChangeModel(resources: URI[]) {
for (const resource of resources) {
this.markersViewState.remove(resource);
this.markersViewModel.remove(resource);
const resourceMarkers = this.markersWorkbenchService.markersModel.getResourceMarkers(resource);
if (resourceMarkers) {
for (const marker of resourceMarkers.markers) {
this.markersViewState.add(marker);
this.markersViewModel.add(marker);
}
}
}
......@@ -657,9 +664,6 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
this.filterInputActionItem = this.instantiationService.createInstance(MarkersFilterActionItem, this.filterAction, this);
return this.filterInputActionItem;
}
if (action.id === QuickFixAction.ID) {
return this.instantiationService.createInstance(QuickFixActionItem, action);
}
return super.getActionItem(action);
}
......@@ -701,7 +705,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
this.panelState['filter'] = this.filterAction.filterText;
this.panelState['filterHistory'] = this.filterAction.filterHistory;
this.panelState['useFilesExclude'] = this.filterAction.useFilesExclude;
this.panelState['multiline'] = this.markersViewState.multiline;
this.panelState['multiline'] = this.markersViewModel.multiline;
super.saveState();
}
......@@ -709,7 +713,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
public dispose(): void {
super.dispose();
this.tree.dispose();
this.markersViewState.dispose();
this.markersViewModel.dispose();
this.disposables = dispose(this.disposables);
}
}
\ No newline at end of file
......@@ -29,7 +29,7 @@ import { Marker } from 'vs/workbench/parts/markers/electron-browser/markersModel
import { IModelService } from 'vs/editor/common/services/modelService';
import { isEqual } from 'vs/base/common/resources';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Event } from 'vs/base/common/event';
import { Event, Emitter } from 'vs/base/common/event';
import { FilterOptions } from 'vs/workbench/parts/markers/electron-browser/markersFilterOptions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
......@@ -297,12 +297,16 @@ export class QuickFixAction extends Action {
private updated: boolean = false;
private disposables: IDisposable[] = [];
private _onShowQuickFixes: Emitter<void> = new Emitter<void>();
readonly onShowQuickFixes: Event<void> = this._onShowQuickFixes.event;
constructor(
readonly marker: Marker,
@IModelService modelService: IModelService,
@IMarkersWorkbenchService private readonly markerWorkbenchService: IMarkersWorkbenchService,
) {
super(QuickFixAction.ID, Messages.MARKERS_PANEL_ACTION_TOOLTIP_QUICKFIX, 'markers-panel-action-quickfix', false);
this.disposables.push(this._onShowQuickFixes);
if (modelService.getModel(this.marker.resource)) {
this.update();
} else {
......@@ -314,6 +318,11 @@ export class QuickFixAction extends Action {
}
}
run(): Promise<void> {
this._onShowQuickFixes.fire();
return Promise.resolve();
}
private update(): void {
if (!this.updated) {
this.markerWorkbenchService.hasQuickFixes(this.marker).then(hasFixes => this.enabled = hasFixes);
......@@ -338,13 +347,17 @@ export class QuickFixActionItem extends ActionItem {
public onClick(event: DOM.EventLike): void {
DOM.EventHelper.stop(event, true);
this.showQuickFixes();
}
public showQuickFixes(): void {
if (!this.element) {
return;
}
const elementPosition = DOM.getDomNodePagePosition(this.element);
this.markerWorkbenchService.getQuickFixActions((<QuickFixAction>this.getAction()).marker).then(actions => {
this.contextMenuService.showContextMenu({
getAnchor: () => ({ x: elementPosition.left + 10, y: elementPosition.top + elementPosition.height }),
getAnchor: () => ({ x: elementPosition.left + 10, y: elementPosition.top + elementPosition.height + 4 }),
getActions: () => actions
});
});
......
......@@ -16,8 +16,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IDisposable, dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { ActionBar, IActionItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
import { QuickFixAction } from 'vs/workbench/parts/markers/electron-browser/markersPanelActions';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { QuickFixAction, QuickFixActionItem } from 'vs/workbench/parts/markers/electron-browser/markersPanelActions';
import { ILabelService } from 'vs/platform/label/common/label';
import { dirname } from 'vs/base/common/resources';
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
......@@ -76,12 +76,12 @@ const enum TemplateId {
export class VirtualDelegate implements IListVirtualDelegate<TreeElement> {
constructor(private readonly markersViewState: MarkersViewState) { }
constructor(private readonly markersViewState: MarkersViewModel) { }
getHeight(element: TreeElement): number {
if (element instanceof Marker) {
const viewState = this.markersViewState.getViewState(element);
const noOfLines = !viewState || viewState.multiline ? element.lines.length : 1;
const viewModel = this.markersViewState.getViewModel(element);
const noOfLines = !viewModel || viewModel.multiline ? element.lines.length : 1;
return noOfLines * 22;
}
return 22;
......@@ -201,8 +201,7 @@ export class FileResourceMarkersRenderer extends ResourceMarkersRenderer {
export class MarkerRenderer implements ITreeRenderer<Marker, MarkerFilterData, IMarkerTemplateData> {
constructor(
private readonly markersViewState: MarkersViewState,
private actionItemProvider: IActionItemProvider,
private readonly markersViewState: MarkersViewModel,
@IInstantiationService protected instantiationService: IInstantiationService
) { }
......@@ -210,7 +209,7 @@ export class MarkerRenderer implements ITreeRenderer<Marker, MarkerFilterData, I
renderTemplate(container: HTMLElement): IMarkerTemplateData {
const data: IMarkerTemplateData = Object.create(null);
data.markerWidget = new MarkerWidget(container, this.markersViewState, this.actionItemProvider, this.instantiationService);
data.markerWidget = new MarkerWidget(container, this.markersViewState, this.instantiationService);
return data;
}
......@@ -234,14 +233,15 @@ class MarkerWidget extends Disposable {
constructor(
parent: HTMLElement,
private readonly markersViewState: MarkersViewState,
actionItemProvider: IActionItemProvider,
private instantiationService: IInstantiationService
private readonly markersViewModel: MarkersViewModel,
instantiationService: IInstantiationService
) {
super();
this.actionBar = this._register(new ActionBar(dom.append(parent, dom.$('.actions')), { actionItemProvider }));
this.actionBar = this._register(new ActionBar(dom.append(parent, dom.$('.actions')), {
actionItemProvider: (action) => action.id === QuickFixAction.ID ? instantiationService.createInstance(QuickFixActionItem, action) : null
}));
this.icon = dom.append(parent, dom.$('.icon'));
this.multilineActionbar = this._register(new ActionBar(dom.append(parent, dom.$('.multiline-actions')), { actionItemProvider }));
this.multilineActionbar = this._register(new ActionBar(dom.append(parent, dom.$('.multiline-actions'))));
this.messageAndDetailsContainer = dom.append(parent, dom.$('.marker-message-details'));
this._register(toDisposable(() => this.disposables = dispose(this.disposables)));
}
......@@ -254,38 +254,47 @@ class MarkerWidget extends Disposable {
}
dom.clearNode(this.messageAndDetailsContainer);
this.renderQuickfixActionbar(element);
this.icon.className = 'marker-icon ' + MarkerWidget.iconClassNameFor(element.marker);
this.renderQuickfixActionbar(element);
this.renderMultilineActionbar(element);
this.renderMessageAndDetails(element, filterData);
}
private renderQuickfixActionbar(marker: Marker): void {
const quickFixAction = this.instantiationService.createInstance(QuickFixAction, marker);
this.actionBar.push([quickFixAction], { icon: true, label: false });
dom.toggleClass(this.icon, 'quickFix', quickFixAction.enabled);
quickFixAction.onDidChange(({ enabled }) => {
if (!isUndefinedOrNull(enabled)) {
dom.toggleClass(this.icon, 'quickFix', enabled);
}
}, this, this.disposables);
const viewModel = this.markersViewModel.getViewModel(marker);
if (viewModel) {
const quickFixAction = viewModel.quickFixAction;
this.actionBar.push([quickFixAction], { icon: true, label: false });
dom.toggleClass(this.icon, 'quickFix', quickFixAction.enabled);
quickFixAction.onDidChange(({ enabled }) => {
if (!isUndefinedOrNull(enabled)) {
dom.toggleClass(this.icon, 'quickFix', enabled);
}
}, this, this.disposables);
quickFixAction.onShowQuickFixes(() => {
const quickFixActionItem = <QuickFixActionItem>this.actionBar.items[0];
if (quickFixActionItem) {
quickFixActionItem.showQuickFixes();
}
}, this, this.disposables);
}
}
private renderMultilineActionbar(marker: Marker): void {
const viewState = this.markersViewState.getViewState(marker);
const multiline = viewState && viewState.multiline;
const viewModel = this.markersViewModel.getViewModel(marker);
const multiline = viewModel && viewModel.multiline;
const action = new Action('problems.action.toggleMultiline');
action.enabled = viewState && marker.lines.length > 1;
action.enabled = viewModel && marker.lines.length > 1;
action.tooltip = multiline ? localize('single line', "Show message in single line") : localize('multi line', "Show message in multiple lines");
action.class = multiline ? 'octicon octicon-chevron-up' : 'octicon octicon-chevron-down';
action.run = () => { if (viewState) { viewState.multiline = !viewState.multiline; } return Promise.resolve(); };
action.run = () => { if (viewModel) { viewModel.multiline = !viewModel.multiline; } return Promise.resolve(); };
this.multilineActionbar.push([action], { icon: true, label: false });
}
private renderMessageAndDetails(element: Marker, filterData: MarkerFilterData) {
const { marker, lines } = element;
const viewState = this.markersViewState.getViewState(element);
const viewState = this.markersViewModel.getViewModel(element);
const multiline = !viewState || viewState.multiline;
const lineMatches = filterData && filterData.lineMatches || [];
const messageContainer = dom.append(this.messageAndDetailsContainer, dom.$('.marker-message'));
......@@ -461,10 +470,17 @@ export class Filter implements ITreeFilter<TreeElement, FilterData> {
}
}
export class MarkerViewState extends Disposable {
export class MarkerViewModel extends Disposable {
private readonly _onDidChangeViewState: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChangeViewState: Event<void> = this._onDidChangeViewState.event;
private readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChange: Event<void> = this._onDidChange.event;
constructor(
private readonly marker: Marker,
@IInstantiationService private instantiationService: IInstantiationService
) {
super();
}
private _multiline: boolean = true;
get multiline(): boolean {
......@@ -474,37 +490,48 @@ export class MarkerViewState extends Disposable {
set multiline(value: boolean) {
if (this._multiline !== value) {
this._multiline = value;
this._onDidChangeViewState.fire();
this._onDidChange.fire();
}
}
private _quickFixAction: QuickFixAction;
get quickFixAction(): QuickFixAction {
if (!this._quickFixAction) {
this._quickFixAction = this._register(this.instantiationService.createInstance(QuickFixAction, this.marker));
}
return this._quickFixAction;
}
}
export class MarkersViewState extends Disposable {
export class MarkersViewModel extends Disposable {
private readonly _onDidChangeViewState: Emitter<Marker | undefined> = this._register(new Emitter<Marker | undefined>());
readonly onDidChangeViewState: Event<Marker | undefined> = this._onDidChangeViewState.event;
private readonly _onDidChange: Emitter<Marker | undefined> = this._register(new Emitter<Marker | undefined>());
readonly onDidChange: Event<Marker | undefined> = this._onDidChange.event;
private readonly markersViewStates: Map<string, { viewState: MarkerViewState, disposables: IDisposable[] }> = new Map<string, { viewState: MarkerViewState, disposables: IDisposable[] }>();
private readonly markersViewStates: Map<string, { viewModel: MarkerViewModel, disposables: IDisposable[] }> = new Map<string, { viewModel: MarkerViewModel, disposables: IDisposable[] }>();
private readonly markersPerResource: Map<string, Marker[]> = new Map<string, Marker[]>();
private bulkUpdate: boolean = false;
constructor(multiline: boolean = true) {
constructor(
multiline: boolean = true,
@IInstantiationService private instantiationService: IInstantiationService
) {
super();
this._multiline = multiline;
}
add(marker: Marker): void {
if (!this.markersViewStates.has(marker.hash)) {
const disposables: IDisposable[] = [];
const viewState = new MarkerViewState();
viewState.multiline = this.multiline;
viewState.onDidChangeViewState(() => {
const viewModel = this.instantiationService.createInstance(MarkerViewModel, marker);
const disposables: IDisposable[] = [viewModel];
viewModel.multiline = this.multiline;
viewModel.onDidChange(() => {
if (!this.bulkUpdate) {
this._onDidChangeViewState.fire(marker);
this._onDidChange.fire(marker);
}
}, this, disposables);
this.markersViewStates.set(marker.hash, { viewState, disposables });
this.markersViewStates.set(marker.hash, { viewModel, disposables });
const markers = this.markersPerResource.get(marker.resource.toString()) || [];
markers.push(marker);
......@@ -524,9 +551,9 @@ export class MarkersViewState extends Disposable {
this.markersPerResource.delete(resource.toString());
}
getViewState(marker: Marker): MarkerViewState | null {
getViewModel(marker: Marker): MarkerViewModel | null {
const value = this.markersViewStates.get(marker.hash);
return value ? value.viewState : null;
return value ? value.viewModel : null;
}
private _multiline: boolean = true;
......@@ -541,15 +568,15 @@ export class MarkersViewState extends Disposable {
changed = true;
}
this.bulkUpdate = true;
this.markersViewStates.forEach(({ viewState }) => {
if (viewState.multiline !== value) {
viewState.multiline = value;
this.markersViewStates.forEach(({ viewModel }) => {
if (viewModel.multiline !== value) {
viewModel.multiline = value;
changed = true;
}
});
this.bulkUpdate = false;
if (changed) {
this._onDidChangeViewState.fire(undefined);
this._onDidChange.fire(undefined);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册