Skip to content

Commit 76f3be0

Browse files
authored
Cleaning up code action menu code (microsoft#160724)
- Move keybinding resolver to own file - Use list methods instead of re-implementing them - Reduce duplicated use state
1 parent 2514759 commit 76f3be0

File tree

5 files changed

+143
-182
lines changed

5 files changed

+143
-182
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { ResolvedKeybinding } from 'vs/base/common/keybindings';
7+
import { Lazy } from 'vs/base/common/lazy';
8+
import { CodeAction } from 'vs/editor/common/languages';
9+
import { codeActionCommandId, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/browser/codeAction';
10+
import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionKind } from 'vs/editor/contrib/codeAction/browser/types';
11+
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
12+
13+
export interface ResolveCodeActionKeybinding {
14+
readonly kind: CodeActionKind;
15+
readonly preferred: boolean;
16+
readonly resolvedKeybinding: ResolvedKeybinding;
17+
}
18+
19+
export class CodeActionKeybindingResolver {
20+
private static readonly codeActionCommands: readonly string[] = [
21+
refactorCommandId,
22+
codeActionCommandId,
23+
sourceActionCommandId,
24+
organizeImportsCommandId,
25+
fixAllCommandId
26+
];
27+
28+
constructor(
29+
private readonly keybindingService: IKeybindingService
30+
) { }
31+
32+
public getResolver(): (action: CodeAction) => ResolvedKeybinding | undefined {
33+
// Lazy since we may not actually ever read the value
34+
const 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'
39+
let commandArgs = item.commandArgs;
40+
if (item.command === organizeImportsCommandId) {
41+
commandArgs = { kind: CodeActionKind.SourceOrganizeImports.value };
42+
} else if (item.command === fixAllCommandId) {
43+
commandArgs = { kind: CodeActionKind.SourceFixAll.value };
44+
}
45+
46+
return {
47+
resolvedKeybinding: item.resolvedKeybinding!,
48+
...CodeActionCommandArgs.fromUser(commandArgs, {
49+
kind: CodeActionKind.None,
50+
apply: CodeActionAutoApply.Never
51+
})
52+
};
53+
}));
54+
55+
return (action) => {
56+
if (action.kind) {
57+
const binding = this.bestKeybindingForCodeAction(action, allCodeActionBindings.getValue());
58+
return binding?.resolvedKeybinding;
59+
}
60+
return undefined;
61+
};
62+
}
63+
64+
private bestKeybindingForCodeAction(
65+
action: CodeAction,
66+
candidates: readonly ResolveCodeActionKeybinding[]
67+
): ResolveCodeActionKeybinding | undefined {
68+
if (!action.kind) {
69+
return undefined;
70+
}
71+
const kind = new CodeActionKind(action.kind);
72+
73+
return candidates
74+
.filter(candidate => candidate.kind.contains(kind))
75+
.filter(candidate => {
76+
if (candidate.preferred) {
77+
// If the candidate keybinding only applies to preferred actions, the this action must also be preferred
78+
return action.isPreferred;
79+
}
80+
return true;
81+
})
82+
.reduceRight((currentBest, candidate) => {
83+
if (!currentBest) {
84+
return candidate;
85+
}
86+
// Select the more specific binding
87+
return currentBest.kind.contains(candidate.kind) ? candidate : currentBest;
88+
}, undefined as ResolveCodeActionKeybinding | undefined);
89+
}
90+
}

0 commit comments

Comments
 (0)