Path: blob/main/src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts
5226 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { HierarchicalKind } from '../../../../base/common/hierarchicalKind.js';6import { IJSONSchema, TypeFromJsonSchema } from '../../../../base/common/jsonSchema.js';7import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';8import { escapeRegExpCharacters } from '../../../../base/common/strings.js';9import { ICodeEditor } from '../../../browser/editorBrowser.js';10import { EditorAction, EditorAction2, EditorCommand, ServicesAccessor } from '../../../browser/editorExtensions.js';11import { EditorContextKeys } from '../../../common/editorContextKeys.js';12import { autoFixCommandId, codeActionCommandId, fixAllCommandId, organizeImportsCommandId, quickFixCommandId, refactorCommandId, sourceActionCommandId } from './codeAction.js';13import * as nls from '../../../../nls.js';14import { MenuId } from '../../../../platform/actions/common/actions.js';15import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';16import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';17import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionFilter, CodeActionKind, CodeActionTriggerSource } from '../common/types.js';18import { CodeActionController } from './codeActionController.js';19import { SUPPORTED_CODE_ACTIONS } from './codeActionModel.js';20import { Codicon } from '../../../../base/common/codicons.js';2122function contextKeyForSupportedActions(kind: HierarchicalKind) {23return ContextKeyExpr.regex(24SUPPORTED_CODE_ACTIONS.keys()[0],25new RegExp('(\\s|^)' + escapeRegExpCharacters(kind.value) + '\\b'));26}2728const argsSchema = {29type: 'object',30defaultSnippets: [{ body: { kind: '' } }],31properties: {32'kind': {33type: 'string',34description: nls.localize('args.schema.kind', "Kind of the code action to run."),35},36'apply': {37type: 'string',38description: nls.localize('args.schema.apply', "Controls when the returned actions are applied."),39default: CodeActionAutoApply.IfSingle,40enum: [CodeActionAutoApply.First, CodeActionAutoApply.IfSingle, CodeActionAutoApply.Never],41enumDescriptions: [42nls.localize('args.schema.apply.first', "Always apply the first returned code action."),43nls.localize('args.schema.apply.ifSingle', "Apply the first returned code action if it is the only one."),44nls.localize('args.schema.apply.never', "Do not apply the returned code actions."),45]46},47'preferred': {48type: 'boolean',49default: false,50description: nls.localize('args.schema.preferred', "Controls if only preferred code actions should be returned."),51}52}53} as const satisfies IJSONSchema;5455function triggerCodeActionsForEditorSelection(56editor: ICodeEditor,57notAvailableMessage: string,58filter: CodeActionFilter | undefined,59autoApply: CodeActionAutoApply | undefined,60triggerAction: CodeActionTriggerSource = CodeActionTriggerSource.Default61): void {62if (editor.hasModel()) {63const controller = CodeActionController.get(editor);64controller?.manualTriggerAtCurrentPosition(notAvailableMessage, triggerAction, filter, autoApply);65}66}6768export class QuickFixAction extends EditorAction2 {6970constructor() {71super({72id: quickFixCommandId,73title: nls.localize2('quickfix.trigger.label', "Quick Fix..."),74precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),75icon: Codicon.lightBulb,76f1: true,77keybinding: {78when: EditorContextKeys.textInputFocus,79primary: KeyMod.CtrlCmd | KeyCode.Period,80weight: KeybindingWeight.EditorContrib81},82menu: {83id: MenuId.InlineChatEditorAffordance,84group: '0_quickfix',85order: 0,86when: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider)87}88});89}9091override runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor): void {92return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.quickFix.noneMessage', "No code actions available"), undefined, undefined, CodeActionTriggerSource.QuickFix);93}94}9596export class CodeActionCommand extends EditorCommand {9798constructor() {99super({100id: codeActionCommandId,101precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),102metadata: {103description: 'Trigger a code action',104args: [{ name: 'args', schema: argsSchema, }]105}106});107}108109public runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor, userArgs?: TypeFromJsonSchema<typeof argsSchema>): void {110const args = CodeActionCommandArgs.fromUser(userArgs, {111kind: HierarchicalKind.Empty,112apply: CodeActionAutoApply.IfSingle,113});114return triggerCodeActionsForEditorSelection(editor,115typeof userArgs?.kind === 'string'116? args.preferred117? nls.localize('editor.action.codeAction.noneMessage.preferred.kind', "No preferred code actions for '{0}' available", userArgs.kind)118: nls.localize('editor.action.codeAction.noneMessage.kind', "No code actions for '{0}' available", userArgs.kind)119: args.preferred120? nls.localize('editor.action.codeAction.noneMessage.preferred', "No preferred code actions available")121: nls.localize('editor.action.codeAction.noneMessage', "No code actions available"),122{123include: args.kind,124includeSourceActions: true,125onlyIncludePreferredActions: args.preferred,126},127args.apply);128}129}130131132export class RefactorAction extends EditorAction {133134constructor() {135super({136id: refactorCommandId,137label: nls.localize2('refactor.label', "Refactor..."),138precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),139kbOpts: {140kbExpr: EditorContextKeys.textInputFocus,141primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyR,142mac: {143primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KeyR144},145weight: KeybindingWeight.EditorContrib146},147contextMenuOpts: {148group: '1_modification',149order: 2,150when: ContextKeyExpr.and(151EditorContextKeys.writable,152contextKeyForSupportedActions(CodeActionKind.Refactor)),153},154metadata: {155description: 'Refactor...',156args: [{ name: 'args', schema: argsSchema }]157}158});159}160161public run(_accessor: ServicesAccessor, editor: ICodeEditor, userArgs?: TypeFromJsonSchema<typeof argsSchema>): void {162const args = CodeActionCommandArgs.fromUser(userArgs, {163kind: CodeActionKind.Refactor,164apply: CodeActionAutoApply.Never165});166return triggerCodeActionsForEditorSelection(editor,167typeof userArgs?.kind === 'string'168? args.preferred169? nls.localize('editor.action.refactor.noneMessage.preferred.kind', "No preferred refactorings for '{0}' available", userArgs.kind)170: nls.localize('editor.action.refactor.noneMessage.kind', "No refactorings for '{0}' available", userArgs.kind)171: args.preferred172? nls.localize('editor.action.refactor.noneMessage.preferred', "No preferred refactorings available")173: nls.localize('editor.action.refactor.noneMessage', "No refactorings available"),174{175include: CodeActionKind.Refactor.contains(args.kind) ? args.kind : HierarchicalKind.None,176onlyIncludePreferredActions: args.preferred177},178args.apply, CodeActionTriggerSource.Refactor);179}180}181182export class SourceAction extends EditorAction {183184constructor() {185super({186id: sourceActionCommandId,187label: nls.localize2('source.label', "Source Action..."),188precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),189contextMenuOpts: {190group: '1_modification',191order: 2.1,192when: ContextKeyExpr.and(193EditorContextKeys.writable,194contextKeyForSupportedActions(CodeActionKind.Source)),195},196metadata: {197description: 'Source Action...',198args: [{ name: 'args', schema: argsSchema }]199}200});201}202203public run(_accessor: ServicesAccessor, editor: ICodeEditor, userArgs?: TypeFromJsonSchema<typeof argsSchema>): void {204const args = CodeActionCommandArgs.fromUser(userArgs, {205kind: CodeActionKind.Source,206apply: CodeActionAutoApply.Never207});208return triggerCodeActionsForEditorSelection(editor,209typeof userArgs?.kind === 'string'210? args.preferred211? nls.localize('editor.action.source.noneMessage.preferred.kind', "No preferred source actions for '{0}' available", userArgs.kind)212: nls.localize('editor.action.source.noneMessage.kind', "No source actions for '{0}' available", userArgs.kind)213: args.preferred214? nls.localize('editor.action.source.noneMessage.preferred', "No preferred source actions available")215: nls.localize('editor.action.source.noneMessage', "No source actions available"),216{217include: CodeActionKind.Source.contains(args.kind) ? args.kind : HierarchicalKind.None,218includeSourceActions: true,219onlyIncludePreferredActions: args.preferred,220},221args.apply, CodeActionTriggerSource.SourceAction);222}223}224225export class OrganizeImportsAction extends EditorAction {226227constructor() {228super({229id: organizeImportsCommandId,230label: nls.localize2('organizeImports.label', "Organize Imports"),231precondition: ContextKeyExpr.and(232EditorContextKeys.writable,233contextKeyForSupportedActions(CodeActionKind.SourceOrganizeImports)),234kbOpts: {235kbExpr: EditorContextKeys.textInputFocus,236primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KeyO,237weight: KeybindingWeight.EditorContrib238},239metadata: {240description: nls.localize2('organizeImports.description', "Organize imports in the current file. Also called 'Optimize Imports' by some tools")241}242});243}244245public run(_accessor: ServicesAccessor, editor: ICodeEditor): void {246return triggerCodeActionsForEditorSelection(editor,247nls.localize('editor.action.organize.noneMessage', "No organize imports action available"),248{ include: CodeActionKind.SourceOrganizeImports, includeSourceActions: true },249CodeActionAutoApply.IfSingle, CodeActionTriggerSource.OrganizeImports);250}251}252253export class FixAllAction extends EditorAction {254255constructor() {256super({257id: fixAllCommandId,258label: nls.localize2('fixAll.label', "Fix All"),259precondition: ContextKeyExpr.and(260EditorContextKeys.writable,261contextKeyForSupportedActions(CodeActionKind.SourceFixAll))262});263}264265public run(_accessor: ServicesAccessor, editor: ICodeEditor): void {266return triggerCodeActionsForEditorSelection(editor,267nls.localize('fixAll.noneMessage', "No fix all action available"),268{ include: CodeActionKind.SourceFixAll, includeSourceActions: true },269CodeActionAutoApply.IfSingle, CodeActionTriggerSource.FixAll);270}271}272273export class AutoFixAction extends EditorAction {274275constructor() {276super({277id: autoFixCommandId,278label: nls.localize2('autoFix.label', "Auto Fix..."),279precondition: ContextKeyExpr.and(280EditorContextKeys.writable,281contextKeyForSupportedActions(CodeActionKind.QuickFix)),282kbOpts: {283kbExpr: EditorContextKeys.textInputFocus,284primary: KeyMod.Alt | KeyMod.Shift | KeyCode.Period,285mac: {286primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Period287},288weight: KeybindingWeight.EditorContrib289}290});291}292293public run(_accessor: ServicesAccessor, editor: ICodeEditor): void {294return triggerCodeActionsForEditorSelection(editor,295nls.localize('editor.action.autoFix.noneMessage', "No auto fixes available"),296{297include: CodeActionKind.QuickFix,298onlyIncludePreferredActions: true299},300CodeActionAutoApply.IfSingle, CodeActionTriggerSource.AutoFix);301}302}303304305