Path: blob/main/src/vs/editor/contrib/codeAction/browser/codeActionKeybindingResolver.ts
3296 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 { ResolvedKeybinding } from '../../../../base/common/keybindings.js';7import { Lazy } from '../../../../base/common/lazy.js';8import { CodeAction } from '../../../common/languages.js';9import { codeActionCommandId, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from './codeAction.js';10import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionKind } from '../common/types.js';11import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';1213interface ResolveCodeActionKeybinding {14readonly kind: HierarchicalKind;15readonly preferred: boolean;16readonly resolvedKeybinding: ResolvedKeybinding;17}1819export class CodeActionKeybindingResolver {20private static readonly codeActionCommands: readonly string[] = [21refactorCommandId,22codeActionCommandId,23sourceActionCommandId,24organizeImportsCommandId,25fixAllCommandId26];2728constructor(29@IKeybindingService private readonly keybindingService: IKeybindingService30) { }3132public getResolver(): (action: CodeAction) => ResolvedKeybinding | undefined {33// Lazy since we may not actually ever read the value34const allCodeActionBindings = new Lazy<readonly ResolveCodeActionKeybinding[]>(() => this.keybindingService.getKeybindings()35.filter(item => CodeActionKeybindingResolver.codeActionCommands.indexOf(item.command!) >= 0)36.filter(item => item.resolvedKeybinding)37.map((item): ResolveCodeActionKeybinding => {38// Special case these commands since they come built-in with VS Code and don't use 'commandArgs'39let commandArgs = item.commandArgs;40if (item.command === organizeImportsCommandId) {41commandArgs = { kind: CodeActionKind.SourceOrganizeImports.value };42} else if (item.command === fixAllCommandId) {43commandArgs = { kind: CodeActionKind.SourceFixAll.value };44}4546return {47resolvedKeybinding: item.resolvedKeybinding!,48...CodeActionCommandArgs.fromUser(commandArgs, {49kind: HierarchicalKind.None,50apply: CodeActionAutoApply.Never51})52};53}));5455return (action) => {56if (action.kind) {57const binding = this.bestKeybindingForCodeAction(action, allCodeActionBindings.value);58return binding?.resolvedKeybinding;59}60return undefined;61};62}6364private bestKeybindingForCodeAction(65action: CodeAction,66candidates: readonly ResolveCodeActionKeybinding[]67): ResolveCodeActionKeybinding | undefined {68if (!action.kind) {69return undefined;70}71const kind = new HierarchicalKind(action.kind);7273return candidates74.filter(candidate => candidate.kind.contains(kind))75.filter(candidate => {76if (candidate.preferred) {77// If the candidate keybinding only applies to preferred actions, the this action must also be preferred78return action.isPreferred;79}80return true;81})82.reduceRight((currentBest, candidate) => {83if (!currentBest) {84return candidate;85}86// Select the more specific binding87return currentBest.kind.contains(candidate.kind) ? candidate : currentBest;88}, undefined as ResolveCodeActionKeybinding | undefined);89}90}919293