Skip to content

Commit b602c14

Browse files
committed
Don't invoke a provider if we know its code actions will be excluded
Fixes microsoft#84602
1 parent d6fba31 commit b602c14

2 files changed

Lines changed: 55 additions & 4 deletions

File tree

src/vs/editor/contrib/codeAction/test/codeAction.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,43 @@ suite('CodeAction', () => {
220220
}
221221
});
222222

223+
test('getCodeActions no invoke a provider that has been excluded #84602', async function () {
224+
const baseType = CodeActionKind.Refactor;
225+
const subType = CodeActionKind.Refactor.append('sub');
226+
227+
disposables.add(modes.CodeActionProviderRegistry.register('fooLang', staticCodeActionProvider(
228+
{ title: 'a', kind: baseType.value }
229+
)));
230+
231+
let didInvoke = false;
232+
disposables.add(modes.CodeActionProviderRegistry.register('fooLang', new class implements modes.CodeActionProvider {
233+
234+
providedCodeActionKinds = [subType.value];
235+
236+
provideCodeActions(): modes.ProviderResult<modes.CodeActionList> {
237+
didInvoke = true;
238+
return {
239+
actions: [
240+
{ title: 'x', kind: subType.value }
241+
],
242+
dispose: () => { }
243+
};
244+
}
245+
}));
246+
247+
{
248+
const { validActions: actions } = await getCodeActions(model, new Range(1, 1, 2, 1), {
249+
type: modes.CodeActionTriggerType.Auto, filter: {
250+
include: baseType,
251+
excludes: [subType],
252+
}
253+
}, CancellationToken.None);
254+
assert.strictEqual(didInvoke, false);
255+
assert.equal(actions.length, 1);
256+
assert.strictEqual(actions[0].title, 'a');
257+
}
258+
});
259+
223260
test('getCodeActions should not invoke code action providers filtered out by providedCodeActionKinds', async function () {
224261
let wasInvoked = false;
225262
const provider = new class implements modes.CodeActionProvider {

src/vs/editor/contrib/codeAction/types.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ export function mayIncludeActionsOfKind(filter: CodeActionFilter, providedKind:
5858
return false;
5959
}
6060

61+
if (filter.excludes) {
62+
if (filter.excludes.some(exclude => excludesAction(providedKind, exclude, filter.include))) {
63+
return false;
64+
}
65+
}
66+
6167
// Don't return source actions unless they are explicitly requested
6268
if (!filter.includeSourceActions && CodeActionKind.Source.contains(providedKind)) {
6369
return false;
@@ -77,10 +83,7 @@ export function filtersAction(filter: CodeActionFilter, action: CodeAction): boo
7783
}
7884

7985
if (filter.excludes) {
80-
if (actionKind && filter.excludes.some(exclude => {
81-
// Excludes are overwritten by includes
82-
return exclude.contains(actionKind) && (!filter.include || !filter.include.contains(actionKind));
83-
})) {
86+
if (actionKind && filter.excludes.some(exclude => excludesAction(actionKind, exclude, filter.include))) {
8487
return false;
8588
}
8689
}
@@ -101,6 +104,17 @@ export function filtersAction(filter: CodeActionFilter, action: CodeAction): boo
101104
return true;
102105
}
103106

107+
function excludesAction(providedKind: CodeActionKind, exclude: CodeActionKind, include: CodeActionKind | undefined): boolean {
108+
if (!exclude.contains(providedKind)) {
109+
return false;
110+
}
111+
if (include && exclude.contains(include)) {
112+
// The include is more specific, don't filter out
113+
return false;
114+
}
115+
return true;
116+
}
117+
104118
export interface CodeActionTrigger {
105119
readonly type: CodeActionTriggerType;
106120
readonly filter?: CodeActionFilter;

0 commit comments

Comments
 (0)