mirror of
https://github.com/Microsoft/vscode
synced 2024-08-26 20:39:37 +00:00
Split codeActonController to own file
This commit is contained in:
parent
fe01a19db1
commit
4eb65f974d
|
@ -14,6 +14,9 @@ import { ITextModel } from 'vs/editor/common/model';
|
|||
import { CodeAction, CodeActionContext, CodeActionProviderRegistry, CodeActionTrigger as CodeActionTriggerKind } from 'vs/editor/common/modes';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { CodeActionKind, CodeActionTrigger, filtersAction, mayIncludeActionsOfKind, CodeActionFilter } from './codeActionTrigger';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
|
||||
export function getCodeActions(
|
||||
model: ITextModel,
|
||||
|
@ -78,6 +81,21 @@ function codeActionsComparator(a: CodeAction, b: CodeAction): number {
|
|||
}
|
||||
}
|
||||
|
||||
export async function applyCodeAction(
|
||||
action: CodeAction,
|
||||
bulkEditService: IBulkEditService,
|
||||
commandService: ICommandService,
|
||||
editor?: ICodeEditor,
|
||||
): Promise<void> {
|
||||
if (action.edit) {
|
||||
await bulkEditService.apply(action.edit, { editor });
|
||||
}
|
||||
if (action.command) {
|
||||
await commandService.executeCommand(action.command.id, ...(action.command.arguments || []));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
registerLanguageCommand('_executeCodeActionProvider', function (accessor, args) {
|
||||
const { resource, range, kind } = args;
|
||||
if (!(resource instanceof URI) || !Range.isIRange(range)) {
|
||||
|
|
|
@ -3,30 +3,18 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancelablePromise } from 'vs/base/common/async';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, EditorCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { CodeAction } from 'vs/editor/common/modes';
|
||||
import { MessageController } from 'vs/editor/contrib/message/messageController';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
import { CodeActionModel, SUPPORTED_CODE_ACTIONS, CodeActionsState } from './codeActionModel';
|
||||
import { CodeActionAutoApply, CodeActionFilter, CodeActionKind } from './codeActionTrigger';
|
||||
import { CodeActionContextMenu } from './codeActionWidget';
|
||||
import { LightBulbWidget } from './lightBulbWidget';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { CodeActionController } from './codeActionController';
|
||||
import { SUPPORTED_CODE_ACTIONS } from './codeActionModel';
|
||||
import { CodeActionAutoApply, CodeActionFilter, CodeActionKind } from './codeActionTrigger';
|
||||
|
||||
function contextKeyForSupportedActions(kind: CodeActionKind) {
|
||||
return ContextKeyExpr.regex(
|
||||
|
@ -34,132 +22,6 @@ function contextKeyForSupportedActions(kind: CodeActionKind) {
|
|||
new RegExp('(\\s|^)' + escapeRegExpCharacters(kind.value) + '\\b'));
|
||||
}
|
||||
|
||||
export class QuickFixController implements IEditorContribution {
|
||||
|
||||
private static readonly ID = 'editor.contrib.quickFixController';
|
||||
|
||||
public static get(editor: ICodeEditor): QuickFixController {
|
||||
return editor.getContribution<QuickFixController>(QuickFixController.ID);
|
||||
}
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _model: CodeActionModel;
|
||||
private _codeActionContextMenu: CodeActionContextMenu;
|
||||
private _lightBulbWidget: LightBulbWidget;
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
private _activeRequest: CancelablePromise<CodeAction[]> | undefined;
|
||||
|
||||
constructor(editor: ICodeEditor,
|
||||
@IMarkerService markerService: IMarkerService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IProgressService progressService: IProgressService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
|
||||
) {
|
||||
this._editor = editor;
|
||||
this._model = new CodeActionModel(this._editor, markerService, contextKeyService, progressService);
|
||||
this._codeActionContextMenu = new CodeActionContextMenu(editor, contextMenuService, action => this._onApplyCodeAction(action));
|
||||
this._lightBulbWidget = new LightBulbWidget(editor);
|
||||
|
||||
this._updateLightBulbTitle();
|
||||
|
||||
this._disposables.push(
|
||||
this._codeActionContextMenu.onDidExecuteCodeAction(_ => this._model.trigger({ type: 'auto', filter: {} })),
|
||||
this._lightBulbWidget.onClick(this._handleLightBulbSelect, this),
|
||||
this._model.onDidChangeState(e => this._onDidChangeCodeActionsState(e)),
|
||||
this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this)
|
||||
);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._model.dispose();
|
||||
dispose(this._disposables);
|
||||
}
|
||||
|
||||
private _onDidChangeCodeActionsState(newState: CodeActionsState.State): void {
|
||||
if (this._activeRequest) {
|
||||
this._activeRequest.cancel();
|
||||
this._activeRequest = undefined;
|
||||
}
|
||||
|
||||
if (newState.type === CodeActionsState.Type.Triggered) {
|
||||
this._activeRequest = newState.actions;
|
||||
|
||||
if (newState.trigger.filter && newState.trigger.filter.kind) {
|
||||
// Triggered for specific scope
|
||||
newState.actions.then(fixes => {
|
||||
if (fixes.length > 0) {
|
||||
// Apply if we only have one action or requested autoApply
|
||||
if (newState.trigger.autoApply === CodeActionAutoApply.First || (newState.trigger.autoApply === CodeActionAutoApply.IfSingle && fixes.length === 1)) {
|
||||
this._onApplyCodeAction(fixes[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._codeActionContextMenu.show(newState.actions, newState.position);
|
||||
|
||||
}).catch(onUnexpectedError);
|
||||
} else if (newState.trigger.type === 'manual') {
|
||||
this._codeActionContextMenu.show(newState.actions, newState.position);
|
||||
} else {
|
||||
// auto magically triggered
|
||||
// * update an existing list of code actions
|
||||
// * manage light bulb
|
||||
if (this._codeActionContextMenu.isVisible) {
|
||||
this._codeActionContextMenu.show(newState.actions, newState.position);
|
||||
} else {
|
||||
this._lightBulbWidget.tryShow(newState);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this._lightBulbWidget.hide();
|
||||
}
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return QuickFixController.ID;
|
||||
}
|
||||
|
||||
private _handleLightBulbSelect(e: { x: number, y: number, state: CodeActionsState.Triggered }): void {
|
||||
this._codeActionContextMenu.show(e.state.actions, e);
|
||||
}
|
||||
|
||||
public triggerFromEditorSelection(filter?: CodeActionFilter, autoApply?: CodeActionAutoApply): Promise<CodeAction[] | undefined> {
|
||||
return this._model.trigger({ type: 'manual', filter, autoApply });
|
||||
}
|
||||
|
||||
private _updateLightBulbTitle(): void {
|
||||
const kb = this._keybindingService.lookupKeybinding(QuickFixAction.Id);
|
||||
let title: string;
|
||||
if (kb) {
|
||||
title = nls.localize('quickFixWithKb', "Show Fixes ({0})", kb.getLabel());
|
||||
} else {
|
||||
title = nls.localize('quickFix', "Show Fixes");
|
||||
}
|
||||
this._lightBulbWidget.title = title;
|
||||
}
|
||||
|
||||
private _onApplyCodeAction(action: CodeAction): Promise<void> {
|
||||
return applyCodeAction(action, this._bulkEditService, this._commandService, this._editor);
|
||||
}
|
||||
}
|
||||
|
||||
export async function applyCodeAction(
|
||||
action: CodeAction,
|
||||
bulkEditService: IBulkEditService,
|
||||
commandService: ICommandService,
|
||||
editor?: ICodeEditor,
|
||||
): Promise<void> {
|
||||
if (action.edit) {
|
||||
await bulkEditService.apply(action.edit, { editor });
|
||||
}
|
||||
if (action.command) {
|
||||
await commandService.executeCommand(action.command.id, ...(action.command.arguments || []));
|
||||
}
|
||||
}
|
||||
|
||||
function showCodeActionsForEditorSelection(
|
||||
editor: ICodeEditor,
|
||||
notAvailableMessage: string,
|
||||
|
@ -170,7 +32,7 @@ function showCodeActionsForEditorSelection(
|
|||
return;
|
||||
}
|
||||
|
||||
const controller = QuickFixController.get(editor);
|
||||
const controller = CodeActionController.get(editor);
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { CodeActionCommand, OrganizeImportsAction, QuickFixAction, QuickFixController, RefactorAction, SourceAction, AutoFixAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
|
||||
import { CodeActionCommand, OrganizeImportsAction, QuickFixAction, RefactorAction, SourceAction, AutoFixAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
|
||||
import { CodeActionController } from 'vs/editor/contrib/codeAction/codeActionController';
|
||||
|
||||
|
||||
registerEditorContribution(QuickFixController);
|
||||
registerEditorContribution(CodeActionController);
|
||||
registerEditorAction(QuickFixAction);
|
||||
registerEditorAction(RefactorAction);
|
||||
registerEditorAction(SourceAction);
|
||||
|
|
136
src/vs/editor/contrib/codeAction/codeActionController.ts
Normal file
136
src/vs/editor/contrib/codeAction/codeActionController.ts
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { CancelablePromise } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { CodeAction } from 'vs/editor/common/modes';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
import { QuickFixAction } from './codeActionCommands';
|
||||
import { CodeActionModel, CodeActionsState } from './codeActionModel';
|
||||
import { CodeActionAutoApply, CodeActionFilter } from './codeActionTrigger';
|
||||
import { CodeActionContextMenu } from './codeActionWidget';
|
||||
import { LightBulbWidget } from './lightBulbWidget';
|
||||
import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
|
||||
export class CodeActionController implements IEditorContribution {
|
||||
|
||||
private static readonly ID = 'editor.contrib.quickFixController';
|
||||
|
||||
public static get(editor: ICodeEditor): CodeActionController {
|
||||
return editor.getContribution<CodeActionController>(CodeActionController.ID);
|
||||
}
|
||||
|
||||
private _editor: ICodeEditor;
|
||||
private _model: CodeActionModel;
|
||||
private _codeActionContextMenu: CodeActionContextMenu;
|
||||
private _lightBulbWidget: LightBulbWidget;
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
private _activeRequest: CancelablePromise<CodeAction[]> | undefined;
|
||||
|
||||
constructor(editor: ICodeEditor,
|
||||
@IMarkerService markerService: IMarkerService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IProgressService progressService: IProgressService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@ICommandService private readonly _commandService: ICommandService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
|
||||
) {
|
||||
this._editor = editor;
|
||||
this._model = new CodeActionModel(this._editor, markerService, contextKeyService, progressService);
|
||||
this._codeActionContextMenu = new CodeActionContextMenu(editor, contextMenuService, action => this._onApplyCodeAction(action));
|
||||
this._lightBulbWidget = new LightBulbWidget(editor);
|
||||
|
||||
this._updateLightBulbTitle();
|
||||
|
||||
this._disposables.push(
|
||||
this._codeActionContextMenu.onDidExecuteCodeAction(_ => this._model.trigger({ type: 'auto', filter: {} })),
|
||||
this._lightBulbWidget.onClick(this._handleLightBulbSelect, this),
|
||||
this._model.onDidChangeState(e => this._onDidChangeCodeActionsState(e)),
|
||||
this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this)
|
||||
);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._model.dispose();
|
||||
dispose(this._disposables);
|
||||
}
|
||||
|
||||
private _onDidChangeCodeActionsState(newState: CodeActionsState.State): void {
|
||||
if (this._activeRequest) {
|
||||
this._activeRequest.cancel();
|
||||
this._activeRequest = undefined;
|
||||
}
|
||||
|
||||
if (newState.type === CodeActionsState.Type.Triggered) {
|
||||
this._activeRequest = newState.actions;
|
||||
|
||||
if (newState.trigger.filter && newState.trigger.filter.kind) {
|
||||
// Triggered for specific scope
|
||||
newState.actions.then(fixes => {
|
||||
if (fixes.length > 0) {
|
||||
// Apply if we only have one action or requested autoApply
|
||||
if (newState.trigger.autoApply === CodeActionAutoApply.First || (newState.trigger.autoApply === CodeActionAutoApply.IfSingle && fixes.length === 1)) {
|
||||
this._onApplyCodeAction(fixes[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._codeActionContextMenu.show(newState.actions, newState.position);
|
||||
|
||||
}).catch(onUnexpectedError);
|
||||
} else if (newState.trigger.type === 'manual') {
|
||||
this._codeActionContextMenu.show(newState.actions, newState.position);
|
||||
} else {
|
||||
// auto magically triggered
|
||||
// * update an existing list of code actions
|
||||
// * manage light bulb
|
||||
if (this._codeActionContextMenu.isVisible) {
|
||||
this._codeActionContextMenu.show(newState.actions, newState.position);
|
||||
} else {
|
||||
this._lightBulbWidget.tryShow(newState);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this._lightBulbWidget.hide();
|
||||
}
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return CodeActionController.ID;
|
||||
}
|
||||
|
||||
private _handleLightBulbSelect(e: { x: number, y: number, state: CodeActionsState.Triggered }): void {
|
||||
this._codeActionContextMenu.show(e.state.actions, e);
|
||||
}
|
||||
|
||||
public triggerFromEditorSelection(filter?: CodeActionFilter, autoApply?: CodeActionAutoApply): Promise<CodeAction[] | undefined> {
|
||||
return this._model.trigger({ type: 'manual', filter, autoApply });
|
||||
}
|
||||
|
||||
private _updateLightBulbTitle(): void {
|
||||
const kb = this._keybindingService.lookupKeybinding(QuickFixAction.Id);
|
||||
let title: string;
|
||||
if (kb) {
|
||||
title = nls.localize('quickFixWithKb', "Show Fixes ({0})", kb.getLabel());
|
||||
} else {
|
||||
title = nls.localize('quickFix', "Show Fixes");
|
||||
}
|
||||
this._lightBulbWidget.title = title;
|
||||
}
|
||||
|
||||
private _onApplyCodeAction(action: CodeAction): Promise<void> {
|
||||
return applyCodeAction(action, this._bulkEditService, this._commandService, this._editor);
|
||||
}
|
||||
}
|
|
@ -20,8 +20,7 @@ import { IIdentifiedSingleEditOperation, ISingleEditOperation, ITextModel } from
|
|||
import { CodeAction } from 'vs/editor/common/modes';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
||||
import { shouldSynchronizeModel } from 'vs/editor/common/services/modelService';
|
||||
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
|
||||
import { getCodeActions, applyCodeAction } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
|
||||
import { getDocumentFormattingEdits, FormatMode } from 'vs/editor/contrib/format/format';
|
||||
import { FormattingEdit } from 'vs/editor/contrib/format/formattingEdit';
|
||||
|
|
|
@ -36,14 +36,13 @@ import { fillResourceDataTransfers } from 'vs/workbench/browser/dnd';
|
|||
import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { getCodeActions, applyCodeAction } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { CodeAction } from 'vs/editor/common/modes';
|
||||
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 { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands';
|
||||
|
||||
export type TreeElement = ResourceMarkers | Marker | RelatedInformation;
|
||||
|
||||
|
|
Loading…
Reference in a new issue