Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/codeActions/browser/codeActionsContribution.ts
3296 views
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 { Emitter, Event } from '../../../../base/common/event.js';
7
import { HierarchicalKind } from '../../../../base/common/hierarchicalKind.js';
8
import { IJSONSchema, IJSONSchemaMap } from '../../../../base/common/jsonSchema.js';
9
import { Disposable } from '../../../../base/common/lifecycle.js';
10
import { editorConfigurationBaseNode } from '../../../../editor/common/config/editorConfigurationSchema.js';
11
import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js';
12
import { codeActionCommandId, refactorCommandId, sourceActionCommandId } from '../../../../editor/contrib/codeAction/browser/codeAction.js';
13
import { CodeActionKind } from '../../../../editor/contrib/codeAction/common/types.js';
14
import * as nls from '../../../../nls.js';
15
import { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationPropertySchema, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js';
16
import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';
17
import { Registry } from '../../../../platform/registry/common/platform.js';
18
import { IWorkbenchContribution } from '../../../common/contributions.js';
19
20
const createCodeActionsAutoSave = (description: string): IJSONSchema => {
21
return {
22
type: 'string',
23
enum: ['always', 'explicit', 'never', true, false],
24
enumDescriptions: [
25
nls.localize('alwaysSave', 'Triggers Code Actions on explicit saves and auto saves triggered by window or focus changes.'),
26
nls.localize('explicitSave', 'Triggers Code Actions only when explicitly saved'),
27
nls.localize('neverSave', 'Never triggers Code Actions on save'),
28
nls.localize('explicitSaveBoolean', 'Triggers Code Actions only when explicitly saved. This value will be deprecated in favor of "explicit".'),
29
nls.localize('neverSaveBoolean', 'Never triggers Code Actions on save. This value will be deprecated in favor of "never".')
30
],
31
default: 'explicit',
32
description: description
33
};
34
};
35
36
const createNotebookCodeActionsAutoSave = (description: string): IJSONSchema => {
37
return {
38
type: ['string', 'boolean'],
39
enum: ['explicit', 'never', true, false],
40
enumDescriptions: [
41
nls.localize('explicit', 'Triggers Code Actions only when explicitly saved.'),
42
nls.localize('never', 'Never triggers Code Actions on save.'),
43
nls.localize('explicitBoolean', 'Triggers Code Actions only when explicitly saved. This value will be deprecated in favor of "explicit".'),
44
nls.localize('neverBoolean', 'Triggers Code Actions only when explicitly saved. This value will be deprecated in favor of "never".')
45
],
46
default: 'explicit',
47
description: description
48
};
49
};
50
51
52
const codeActionsOnSaveSchema: IConfigurationPropertySchema = {
53
oneOf: [
54
{
55
type: 'object',
56
additionalProperties: {
57
type: 'string'
58
},
59
},
60
{
61
type: 'array',
62
items: { type: 'string' }
63
}
64
],
65
markdownDescription: nls.localize('editor.codeActionsOnSave', 'Run Code Actions for the editor on save. Code Actions must be specified and the editor must not be shutting down. When {0} is set to `afterDelay`, Code Actions will only be run when the file is saved explicitly. Example: `"source.organizeImports": "explicit" `', '`#files.autoSave#`'),
66
type: ['object', 'array'],
67
additionalProperties: {
68
type: 'string',
69
enum: ['always', 'explicit', 'never', true, false],
70
},
71
default: {},
72
scope: ConfigurationScope.LANGUAGE_OVERRIDABLE,
73
};
74
75
export const editorConfiguration = Object.freeze<IConfigurationNode>({
76
...editorConfigurationBaseNode,
77
properties: {
78
'editor.codeActionsOnSave': codeActionsOnSaveSchema
79
}
80
});
81
82
const notebookCodeActionsOnSaveSchema: IConfigurationPropertySchema = {
83
oneOf: [
84
{
85
type: 'object',
86
additionalProperties: {
87
type: 'string'
88
},
89
},
90
{
91
type: 'array',
92
items: { type: 'string' }
93
}
94
],
95
markdownDescription: nls.localize('notebook.codeActionsOnSave', 'Run a series of Code Actions for a notebook on save. Code Actions must be specified and the editor must not be shutting down. When {0} is set to `afterDelay`, Code Actions will only be run when the file is saved explicitly. Example: `"notebook.source.organizeImports": "explicit"`', '`#files.autoSave#`'),
96
type: 'object',
97
additionalProperties: {
98
type: ['string', 'boolean'],
99
enum: ['explicit', 'never', true, false],
100
// enum: ['explicit', 'always', 'never'], -- autosave support needs to be built first
101
// nls.localize('always', 'Always triggers Code Actions on save, including autosave, focus, and window change events.'),
102
},
103
default: {}
104
};
105
106
export const notebookEditorConfiguration = Object.freeze<IConfigurationNode>({
107
...editorConfigurationBaseNode,
108
properties: {
109
'notebook.codeActionsOnSave': notebookCodeActionsOnSaveSchema
110
}
111
});
112
113
export class CodeActionsContribution extends Disposable implements IWorkbenchContribution {
114
115
private readonly _onDidChangeSchemaContributions = this._register(new Emitter<void>());
116
117
private _allProvidedCodeActionKinds: HierarchicalKind[] = [];
118
119
constructor(
120
@IKeybindingService keybindingService: IKeybindingService,
121
@ILanguageFeaturesService private readonly languageFeatures: ILanguageFeaturesService
122
) {
123
super();
124
125
// TODO: @justschen caching of code actions based on extensions loaded: https://github.com/microsoft/vscode/issues/216019
126
this._register(
127
Event.runAndSubscribe(
128
Event.debounce(languageFeatures.codeActionProvider.onDidChange, () => { }, 1000),
129
() => {
130
this._allProvidedCodeActionKinds = this.getAllProvidedCodeActionKinds();
131
this.updateConfigurationSchema(this._allProvidedCodeActionKinds);
132
this._onDidChangeSchemaContributions.fire();
133
}));
134
135
this._register(keybindingService.registerSchemaContribution({
136
getSchemaAdditions: () => this.getKeybindingSchemaAdditions(),
137
onDidChange: this._onDidChangeSchemaContributions.event,
138
}));
139
}
140
141
private getAllProvidedCodeActionKinds(): Array<HierarchicalKind> {
142
const out = new Map<string, HierarchicalKind>();
143
for (const provider of this.languageFeatures.codeActionProvider.allNoModel()) {
144
for (const kind of provider.providedCodeActionKinds ?? []) {
145
out.set(kind, new HierarchicalKind(kind));
146
}
147
}
148
return Array.from(out.values());
149
}
150
151
private updateConfigurationSchema(allProvidedKinds: Iterable<HierarchicalKind>): void {
152
const properties: IJSONSchemaMap = { ...codeActionsOnSaveSchema.properties };
153
const notebookProperties: IJSONSchemaMap = { ...notebookCodeActionsOnSaveSchema.properties };
154
for (const codeActionKind of allProvidedKinds) {
155
if (CodeActionKind.Source.contains(codeActionKind) && !properties[codeActionKind.value]) {
156
properties[codeActionKind.value] = createCodeActionsAutoSave(nls.localize('codeActionsOnSave.generic', "Controls whether '{0}' actions should be run on file save.", codeActionKind.value));
157
notebookProperties[codeActionKind.value] = createNotebookCodeActionsAutoSave(nls.localize('codeActionsOnSave.generic', "Controls whether '{0}' actions should be run on file save.", codeActionKind.value));
158
}
159
}
160
codeActionsOnSaveSchema.properties = properties;
161
notebookCodeActionsOnSaveSchema.properties = notebookProperties;
162
163
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
164
.notifyConfigurationSchemaUpdated(editorConfiguration);
165
}
166
167
private getKeybindingSchemaAdditions(): IJSONSchema[] {
168
const conditionalSchema = (command: string, kinds: readonly string[]): IJSONSchema => {
169
return {
170
if: {
171
required: ['command'],
172
properties: {
173
'command': { const: command }
174
}
175
},
176
then: {
177
properties: {
178
'args': {
179
required: ['kind'],
180
properties: {
181
'kind': {
182
anyOf: [
183
{ enum: Array.from(kinds) },
184
{ type: 'string' },
185
]
186
}
187
}
188
}
189
}
190
}
191
};
192
};
193
194
const filterProvidedKinds = (ofKind: HierarchicalKind): string[] => {
195
const out = new Set<string>();
196
for (const providedKind of this._allProvidedCodeActionKinds) {
197
if (ofKind.contains(providedKind)) {
198
out.add(providedKind.value);
199
}
200
}
201
return Array.from(out);
202
};
203
204
return [
205
conditionalSchema(codeActionCommandId, filterProvidedKinds(HierarchicalKind.Empty)),
206
conditionalSchema(refactorCommandId, filterProvidedKinds(CodeActionKind.Refactor)),
207
conditionalSchema(sourceActionCommandId, filterProvidedKinds(CodeActionKind.Source)),
208
];
209
}
210
}
211
212