diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 605b3443f43b6c07ddb9256c4a9661fc198dca1b..82c9026bf41e71c75b5f0244de1a8d8375777d9c 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -869,38 +869,26 @@ ], "codeActions": [ { - "kind": "refactor.extract.constant", - "title": "%codeActions.refactor.extract.constant%", - "selector": [ - { - "language": "javascript" - }, - { - "language": "javascriptreact" - }, - { - "language": "typescript" - }, - { - "language": "typescriptreact" - } - ] - }, - { - "kind": "source.organizeImports", - "title": "%codeActions.source.organizeImports%", - "selector": [ - { - "language": "javascript" - }, + "languages": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact" + ], + "actions": [ { - "language": "javascriptreact" + "kind": "refactor.extract.constant", + "title": "%codeActions.refactor.extract.constant.title%", + "description": "%codeActions.refactor.extract.constant.description%" }, { - "language": "typescript" + "kind": "refactor.extract.function", + "title": "%codeActions.refactor.extract.function.title%", + "description": "%codeActions.refactor.extract.function.description%" }, { - "language": "typescriptreact" + "kind": "source.organizeImports", + "title": "%codeActions.source.organizeImports.title%" } ] } diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index bf8014744f4c8b7376c8b33a179a7f0cf7ffae7f..fe9728e36de43c24d2762f6040a5562addeb836c 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -76,6 +76,9 @@ "configuration.surveys.enabled": "Enabled/disable occasional surveys that help us improve VS Code's JavaScript and TypeScript support.", "configuration.suggest.completeJSDocs": "Enable/disable suggestion to complete JSDoc comments.", "typescript.preferences.renameShorthandProperties": "Enable/disable introducing aliases for object shorthand properties during renames. Requires using TypeScript 3.4 or newer in the workspace.", - "codeActions.refactor.extract.constant": "Extract constant", - "codeActions.source.organizeImports": "Organize imports" + "codeActions.refactor.extract.constant.title": "Extract constant", + "codeActions.refactor.extract.constant.description": "Extract an expression to constant.", + "codeActions.refactor.extract.function.title": "Extract function", + "codeActions.refactor.extract.function.description": "Extract an expression to method or function.", + "codeActions.source.organizeImports.title": "Organize imports" } diff --git a/src/vs/workbench/contrib/codeActions/common/configuration.ts b/src/vs/workbench/contrib/codeActions/common/configuration.ts index 59da6a7f65fbf670fcf8f28408d890a166941410..169729b041d5019cfa63e251099697ba3fe68c39 100644 --- a/src/vs/workbench/contrib/codeActions/common/configuration.ts +++ b/src/vs/workbench/contrib/codeActions/common/configuration.ts @@ -7,6 +7,7 @@ import { flatten } from 'vs/base/common/arrays'; import { Emitter } from 'vs/base/common/event'; import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; import { Disposable } from 'vs/base/common/lifecycle'; +import { values } from 'vs/base/common/map'; import { CodeActionCommand, RefactorAction, SourceAction } from 'vs/editor/contrib/codeAction/codeActionCommands'; import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; import * as nls from 'vs/nls'; @@ -14,7 +15,7 @@ import { Extensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platf import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { CodeActionExtensionPointFields, CodeActionsExtensionPoint } from 'vs/workbench/contrib/codeActions/common/extensionPoint'; +import { CodeActionsExtensionPoint, ContributedCodeAction } from 'vs/workbench/contrib/codeActions/common/extensionPoint'; import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry'; const codeActionsOnSaveDefaultProperties = Object.freeze({ @@ -88,22 +89,24 @@ export class CodeActionWorkbenchContribution extends Disposable implements IWork } private getSourceActions(contributions: readonly CodeActionsExtensionPoint[]) { + const defaultKinds = Object.keys(codeActionsOnSaveDefaultProperties).map(value => new CodeActionKind(value)); const sourceActions = new Map(); for (const contribution of contributions) { - const kind = new CodeActionKind(contribution[CodeActionExtensionPointFields.kind]); - const defaultKinds = Object.keys(codeActionsOnSaveDefaultProperties).map(value => new CodeActionKind(value)); - if (CodeActionKind.Source.contains(kind) - // Exclude any we already included by default - && !defaultKinds.some(defaultKind => defaultKind.contains(kind)) - ) { - sourceActions.set(kind.value, contribution); + for (const action of contribution.actions) { + const kind = new CodeActionKind(action.kind); + if (CodeActionKind.Source.contains(kind) + // Exclude any we already included by default + && !defaultKinds.some(defaultKind => defaultKind.contains(kind)) + ) { + sourceActions.set(kind.value, action); + } } } return sourceActions; } private getSchemaAdditions(): IJSONSchema[] { - const conditionalSchema = (command: string, values: string[]): IJSONSchema => { + const conditionalSchema = (command: string, actions: readonly ContributedCodeAction[]): IJSONSchema => { return { if: { properties: { @@ -118,7 +121,10 @@ export class CodeActionWorkbenchContribution extends Disposable implements IWork properties: { 'kind': { anyOf: [ - { enum: values }, + { + enum: actions.map(action => action.kind), + enumDescriptions: actions.map(action => action.description ?? action.title), + }, { type: 'string' }, ] } @@ -129,10 +135,16 @@ export class CodeActionWorkbenchContribution extends Disposable implements IWork }; }; - const getActions = (ofKind: CodeActionKind): string[] => { - return this._contributedCodeActions - .map(desc => desc[CodeActionExtensionPointFields.kind]) - .filter(kind => ofKind.contains(new CodeActionKind(kind))); + const getActions = (ofKind: CodeActionKind): ContributedCodeAction[] => { + const allActions = flatten(this._contributedCodeActions.map(desc => desc.actions.slice())); + + const out = new Map(); + for (const action of allActions) { + if (!out.has(action.kind) && ofKind.contains(new CodeActionKind(action.kind))) { + out.set(action.kind, action); + } + } + return values(out); }; return [ diff --git a/src/vs/workbench/contrib/codeActions/common/extensionPoint.ts b/src/vs/workbench/contrib/codeActions/common/extensionPoint.ts index 54a81df6fe4745933eed29ba447c7b415ed988d6..cb89084f8197833253f10924059c49185db6e312 100644 --- a/src/vs/workbench/contrib/codeActions/common/extensionPoint.ts +++ b/src/vs/workbench/contrib/codeActions/common/extensionPoint.ts @@ -8,58 +8,57 @@ import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/c import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService'; export enum CodeActionExtensionPointFields { + languages = 'languages', + actions = 'actions', kind = 'kind', title = 'title', - selector = 'selector', - selectorLanguage = 'language', - selectorScheme = 'scheme', + description = 'description' } -export interface CodeActionsExtensionPoint { +export interface ContributedCodeAction { readonly [CodeActionExtensionPointFields.kind]: string; readonly [CodeActionExtensionPointFields.title]: string; - readonly [CodeActionExtensionPointFields.selector]: { - readonly [CodeActionExtensionPointFields.selectorLanguage]: string; - readonly [CodeActionExtensionPointFields.selectorScheme]: string; - }; + readonly [CodeActionExtensionPointFields.description]?: string; +} + +export interface CodeActionsExtensionPoint { + readonly [CodeActionExtensionPointFields.languages]: readonly string[]; + readonly [CodeActionExtensionPointFields.actions]: readonly ContributedCodeAction[]; } -const codeActionsExtensionPointSchema: IConfigurationPropertySchema = { +const codeActionsExtensionPointSchema = Object.freeze({ type: 'array', markdownDescription: nls.localize('contributes.codeActions', "Configure which editor to use for a resource."), items: { type: 'object', - required: [CodeActionExtensionPointFields.kind, CodeActionExtensionPointFields.title, CodeActionExtensionPointFields.selector], + required: [CodeActionExtensionPointFields.languages, CodeActionExtensionPointFields.actions], properties: { - [CodeActionExtensionPointFields.kind]: { - type: 'string', - markdownDescription: nls.localize('contributes.codeActions.kind', "`CodeActionKind` of the contributed code action."), - }, - [CodeActionExtensionPointFields.title]: { - type: 'string', - description: nls.localize('contributes.codeActions.title', "Human readable name for the code action."), - }, - [CodeActionExtensionPointFields.selector]: { + [CodeActionExtensionPointFields.languages]: { type: 'array', - description: nls.localize('contributes.codeActions.selector', "Files that the code actions are enabled for."), - items: { - type: 'object', - required: [CodeActionExtensionPointFields.selectorLanguage], - properties: { - [CodeActionExtensionPointFields.selectorLanguage]: { - type: 'string', - description: nls.localize('contributes.codeActions.selector.language', "Language mode that the code action is enabled for."), - }, - [CodeActionExtensionPointFields.selectorScheme]: { - type: 'string', - description: nls.localize('contributes.codeActions.selector.scheme', "File scheme that the code action is enabled for."), - } + description: nls.localize('contributes.codeActions.languages', "Language modes that the code actions are enabled for."), + items: { type: 'string' } + }, + [CodeActionExtensionPointFields.actions]: { + type: 'object', + required: [CodeActionExtensionPointFields.kind, CodeActionExtensionPointFields.title], + properties: { + [CodeActionExtensionPointFields.kind]: { + type: 'string', + markdownDescription: nls.localize('contributes.codeActions.kind', "`CodeActionKind` of the contributed code action."), + }, + [CodeActionExtensionPointFields.title]: { + type: 'string', + description: nls.localize('contributes.codeActions.title', "Label for the code action used in the UI."), + }, + [CodeActionExtensionPointFields.description]: { + type: 'string', + description: nls.localize('contributes.codeActions.description', "Description of what the code action does."), }, } - }, + } } } -}; +}); export const codeActionsExtensionPointDescriptor = { extensionPoint: 'codeActions',