提交 5b146aa6 编写于 作者: S Sandeep Somavarapu

Cache code actions for a file and do not ask for code actions always for showing light bulb

上级 f9db8d78
......@@ -4,15 +4,25 @@
*--------------------------------------------------------------------------------------------*/
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { MarkersModel, compareMarkersByUri } from './markersModel';
import { MarkersModel, compareMarkersByUri, Marker } from './markersModel';
import { Disposable } from 'vs/base/common/lifecycle';
import { IMarkerService, MarkerSeverity, IMarker } from 'vs/platform/markers/common/markers';
import { IMarkerService, MarkerSeverity, IMarker, IMarkerData } from 'vs/platform/markers/common/markers';
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
import { localize } from 'vs/nls';
import Constants from './constants';
import { URI } from 'vs/base/common/uri';
import { groupBy } from 'vs/base/common/arrays';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IAction, Action } from 'vs/base/common/actions';
import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { CodeAction } from 'vs/editor/common/modes';
import { Range } from 'vs/editor/common/core/range';
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
export const IMarkersWorkbenchService = createDecorator<IMarkersWorkbenchService>('markersWorkbenchService');
......@@ -24,6 +34,8 @@ export interface IFilter {
export interface IMarkersWorkbenchService {
_serviceBrand: any;
readonly markersModel: MarkersModel;
hasQuickFixes(marker: Marker): Promise<boolean>;
getQuickFixActions(marker: Marker): Promise<IAction[]>;
}
export class MarkersWorkbenchService extends Disposable implements IMarkersWorkbenchService {
......@@ -31,9 +43,15 @@ export class MarkersWorkbenchService extends Disposable implements IMarkersWorkb
readonly markersModel: MarkersModel;
private readonly allFixesCache: Map<string, Promise<CodeAction[]>> = new Map<string, Promise<CodeAction[]>>();
constructor(
@IMarkerService private markerService: IMarkerService,
@IInstantiationService instantiationService: IInstantiationService
@IInstantiationService instantiationService: IInstantiationService,
@IBulkEditService private bulkEditService: IBulkEditService,
@ICommandService private commandService: ICommandService,
@IEditorService private editorService: IEditorService,
@IModelService private modelService: IModelService
) {
super();
this.markersModel = this._register(instantiationService.createInstance(MarkersModel, this.readMarkers()));
......@@ -47,6 +65,7 @@ export class MarkersWorkbenchService extends Disposable implements IMarkersWorkb
private onMarkerChanged(resources: URI[]): void {
for (const resource of resources) {
this.allFixesCache.delete(resource.toString());
this.markersModel.setResourceMarkers(resource, this.readMarkers(resource));
}
}
......@@ -55,6 +74,67 @@ export class MarkersWorkbenchService extends Disposable implements IMarkersWorkb
return this.markerService.read({ resource, severities: MarkerSeverity.Error | MarkerSeverity.Warning | MarkerSeverity.Info });
}
async getQuickFixActions(marker: Marker): Promise<IAction[]> {
const codeActions = await this.getFixes(marker);
return codeActions.map(codeAction => new Action(
codeAction.command ? codeAction.command.id : codeAction.title,
codeAction.title,
void 0,
true,
() => {
return this.openFileAtMarker(marker)
.then(() => applyCodeAction(codeAction, this.bulkEditService, this.commandService));
}));
}
async hasQuickFixes(marker: Marker): Promise<boolean> {
if (!this.modelService.getModel(marker.resource)) {
// Return early, If the model is not yet created
return false;
}
let allFixesPromise = this.allFixesCache.get(marker.resource.toString());
if (!allFixesPromise) {
allFixesPromise = this._getFixes(marker.resource);
this.allFixesCache.set(marker.resource.toString(), allFixesPromise);
}
const allFixes = await allFixesPromise;
if (allFixes.length) {
const markerKey = IMarkerData.makeKey(marker.marker);
for (const fix of allFixes) {
if (fix.diagnostics && fix.diagnostics.some(d => IMarkerData.makeKey(d) === markerKey)) {
return true;
}
}
}
return false;
}
private openFileAtMarker(element: Marker): Promise<void> {
const { resource, selection } = { resource: element.resource, selection: element.range };
return this.editorService.openEditor({
resource,
options: {
selection,
preserveFocus: true,
pinned: false,
revealIfVisible: true
},
}, ACTIVE_GROUP).then(() => null);
}
private getFixes(marker: Marker): Promise<CodeAction[]> {
return this._getFixes(marker.resource, new Range(marker.range.startLineNumber, marker.range.startColumn, marker.range.endLineNumber, marker.range.endColumn));
}
private async _getFixes(uri: URI, range?: Range): Promise<CodeAction[]> {
const model = this.modelService.getModel(uri);
if (model) {
const codeActions = await getCodeActions(model, range ? range : model.getFullModelRange(), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } });
return codeActions;
}
return [];
}
}
export class ActivityUpdater extends Disposable implements IWorkbenchContribution {
......
......@@ -579,8 +579,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
const result: IAction[] = [];
if (element instanceof Marker) {
const quickFixAction = this.instantiationService.createInstance(QuickFixAction, element);
const quickFixActions = await quickFixAction.getQuickFixActions();
const quickFixActions = await this.markersWorkbenchService.getQuickFixActions(element);
if (quickFixActions.length) {
result.push(...quickFixActions);
result.push(new Separator());
......
......@@ -5,7 +5,7 @@
import { Delayer } from 'vs/base/common/async';
import * as DOM from 'vs/base/browser/dom';
import { Action, IAction, IActionChangeEvent } from 'vs/base/common/actions';
import { Action, IActionChangeEvent } from 'vs/base/common/actions';
import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox';
import { KeyCode } from 'vs/base/common/keyCodes';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
......@@ -26,19 +26,9 @@ import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ContextScopedHistoryInputBox } from 'vs/platform/widget/browser/contextScopedHistoryWidget';
import { Marker } from 'vs/workbench/parts/markers/electron-browser/markersModel';
import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
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 { CodeAction } from 'vs/editor/common/modes';
import { Range } from 'vs/editor/common/core/range';
import { IMarkerData } from 'vs/platform/markers/common/markers';
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
import { URI } from 'vs/base/common/uri';
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
import { Event } from 'vs/base/common/event';
import { FilterOptions } from 'vs/workbench/parts/markers/electron-browser/markersFilterOptions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
......@@ -304,15 +294,12 @@ export class QuickFixAction extends Action {
public static readonly ID: string = 'workbench.actions.problems.quickfix';
private updated: boolean = false;
private _allFixesPromise: Promise<CodeAction[]>;
private disposables: IDisposable[] = [];
constructor(
readonly marker: Marker,
@IBulkEditService private bulkEditService: IBulkEditService,
@ICommandService private commandService: ICommandService,
@IEditorService private editorService: IEditorService,
@IModelService private modelService: IModelService
@IModelService modelService: IModelService,
@IMarkersWorkbenchService private markerWorkbenchService: IMarkersWorkbenchService,
) {
super(QuickFixAction.ID, Messages.MARKERS_PANEL_ACTION_TOOLTIP_QUICKFIX, 'markers-panel-action-quickfix', false);
if (modelService.getModel(this.marker.resource)) {
......@@ -328,70 +315,11 @@ export class QuickFixAction extends Action {
private update(): void {
if (!this.updated) {
this.hasFixes(this.marker).then(hasFixes => this.enabled = hasFixes);
this.markerWorkbenchService.hasQuickFixes(this.marker).then(hasFixes => this.enabled = hasFixes);
this.updated = true;
}
}
async getQuickFixActions(): Promise<IAction[]> {
const codeActions = await this.getFixes(this.marker);
return codeActions.map(codeAction => new Action(
codeAction.command ? codeAction.command.id : codeAction.title,
codeAction.title,
void 0,
true,
() => {
return this.openFileAtMarker(this.marker)
.then(() => applyCodeAction(codeAction, this.bulkEditService, this.commandService));
}));
}
public openFileAtMarker(element: Marker): Promise<void> {
const { resource, selection } = { resource: element.resource, selection: element.range };
return this.editorService.openEditor({
resource,
options: {
selection,
preserveFocus: true,
pinned: false,
revealIfVisible: true
},
}, ACTIVE_GROUP).then(() => void 0);
}
private getFixes(marker: Marker): Promise<CodeAction[]> {
return this._getFixes(marker.resource, new Range(marker.range.startLineNumber, marker.range.startColumn, marker.range.endLineNumber, marker.range.endColumn));
}
private async hasFixes(marker: Marker): Promise<boolean> {
if (!this.modelService.getModel(marker.resource)) {
// Return early, If the model is not yet created
return false;
}
if (!this._allFixesPromise) {
this._allFixesPromise = this._getFixes(marker.resource);
}
const allFixes = await this._allFixesPromise;
if (allFixes.length) {
const markerKey = IMarkerData.makeKey(marker.marker);
for (const fix of allFixes) {
if (fix.diagnostics && fix.diagnostics.some(d => IMarkerData.makeKey(d) === markerKey)) {
return true;
}
}
}
return false;
}
private async _getFixes(uri: URI, range?: Range): Promise<CodeAction[]> {
const model = this.modelService.getModel(uri);
if (model) {
const codeActions = await getCodeActions(model, range ? range : model.getFullModelRange(), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } });
return codeActions;
}
return [];
}
dispose(): void {
dispose(this.disposables);
super.dispose();
......@@ -401,7 +329,8 @@ export class QuickFixAction extends Action {
export class QuickFixActionItem extends ActionItem {
constructor(action: QuickFixAction,
@IContextMenuService private contextMenuService: IContextMenuService
@IContextMenuService private contextMenuService: IContextMenuService,
@IMarkersWorkbenchService private markerWorkbenchService: IMarkersWorkbenchService
) {
super(null, action, { icon: true, label: false });
}
......@@ -412,7 +341,7 @@ export class QuickFixActionItem extends ActionItem {
return;
}
const elementPosition = DOM.getDomNodePagePosition(this.element);
(<QuickFixAction>this.getAction()).getQuickFixActions().then(actions => {
this.markerWorkbenchService.getQuickFixActions((<QuickFixAction>this.getAction()).marker).then(actions => {
this.contextMenuService.showContextMenu({
getAnchor: () => ({ x: elementPosition.left + 10, y: elementPosition.top + elementPosition.height }),
getActions: () => actions
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册