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