diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 3f8c3cec51f..2e2a20d89ad 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -42,6 +42,10 @@ "name": "vs/workbench/contrib/callHierarchy", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/codeActions", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/comments", "project": "vscode-workbench" diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 3cd4609ed89..605b3443f43 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -866,6 +866,44 @@ } } } + ], + "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" + }, + { + "language": "javascriptreact" + }, + { + "language": "typescript" + }, + { + "language": "typescriptreact" + } + ] + } ] } } diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index 26e036bb992..bf8014744f4 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -75,5 +75,7 @@ "typescript.suggest.enabled": "Enabled/disable autocomplete suggestions.", "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." + "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" } diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index e2fce4cc8df..c7f50efd2d9 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -477,29 +477,6 @@ const editorConfiguration: IConfigurationNode = { default: 20_000, description: nls.localize('maxTokenizationLineLength', "Lines above this length will not be tokenized for performance reasons") }, - 'editor.codeActionsOnSave': { - type: 'object', - properties: { - 'source.organizeImports': { - type: 'boolean', - description: nls.localize('codeActionsOnSave.organizeImports', "Controls whether organize imports action should be run on file save.") - }, - 'source.fixAll': { - type: 'boolean', - description: nls.localize('codeActionsOnSave.fixAll', "Controls whether auto fix action should be run on file save.") - } - }, - 'additionalProperties': { - type: 'boolean' - }, - default: {}, - description: nls.localize('codeActionsOnSave', "Code action kinds to be run on save.") - }, - 'editor.codeActionsOnSaveTimeout': { - type: 'number', - default: 750, - description: nls.localize('codeActionsOnSaveTimeout', "Timeout in milliseconds after which the code actions that are run on save are cancelled.") - }, 'diffEditor.maxComputationTime': { type: 'number', default: 5000, diff --git a/src/vs/workbench/contrib/codeActions/common/codeActions.contribution.ts b/src/vs/workbench/contrib/codeActions/common/codeActions.contribution.ts new file mode 100644 index 00000000000..b20e6cdb76a --- /dev/null +++ b/src/vs/workbench/contrib/codeActions/common/codeActions.contribution.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; +import { CodeActionConfigurationManager, editorConfiguration } from 'vs/workbench/contrib/codeActions/common/configuration'; +import { CodeActionsExtensionPoint, codeActionsExtensionPointDescriptor } from 'vs/workbench/contrib/codeActions/common/extensionPoint'; +import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; + +const codeActionsExtensionPoint = ExtensionsRegistry.registerExtensionPoint(codeActionsExtensionPointDescriptor); + +Registry.as(Extensions.Configuration) + .registerConfiguration(editorConfiguration); + +Registry.as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution( + class { + constructor() { + // tslint:disable-next-line: no-unused-expression + new CodeActionConfigurationManager(codeActionsExtensionPoint); + } + }, + LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/codeActions/common/configuration.ts b/src/vs/workbench/contrib/codeActions/common/configuration.ts new file mode 100644 index 00000000000..e1e18930755 --- /dev/null +++ b/src/vs/workbench/contrib/codeActions/common/configuration.ts @@ -0,0 +1,85 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { flatten } from 'vs/base/common/arrays'; +import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; +import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; +import * as nls from 'vs/nls'; +import { Extensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +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 { IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; + +const codeActionsOnSaveDefaultProperties = Object.freeze({ + 'source.fixAll': { + type: 'boolean', + description: nls.localize('codeActionsOnSave.fixAll', "Controls whether auto fix action should be run on file save.") + } +}); + +const codeActionsOnSaveSchema: IJSONSchema = { + type: 'object', + properties: codeActionsOnSaveDefaultProperties, + 'additionalProperties': { + type: 'boolean' + }, + default: {}, + description: nls.localize('codeActionsOnSave', "Code action kinds to be run on save.") +}; + +export const editorConfiguration = Object.freeze({ + id: 'editor', + order: 5, + type: 'object', + title: nls.localize('editorConfigurationTitle', "Editor"), + overridable: true, + properties: { + 'editor.codeActionsOnSave': codeActionsOnSaveSchema, + 'editor.codeActionsOnSaveTimeout': { + type: 'number', + default: 750, + description: nls.localize('codeActionsOnSaveTimeout', "Timeout in milliseconds after which the code actions that are run on save are cancelled.") + }, + } +}); + +export class CodeActionConfigurationManager implements IWorkbenchContribution { + constructor( + codeActionsExtensionPoint: IExtensionPoint + ) { + codeActionsExtensionPoint.setHandler(extensionPoints => { + const newProperties: IJSONSchemaMap = { ...codeActionsOnSaveDefaultProperties }; + for (const [sourceAction, props] of this.getSourceActions(extensionPoints)) { + newProperties[sourceAction] = { + type: 'boolean', + description: nls.localize( + 'codeActionsOnSave.generic', + "Controls whether '{0}' actions should be run on file save.", + props.title) + }; + } + codeActionsOnSaveSchema.properties = newProperties; + + Registry.as(Extensions.Configuration) + .notifyConfigurationSchemaUpdated(editorConfiguration); + }); + } + + private getSourceActions(extensionPoints: readonly IExtensionPointUser[]) { + const sourceActions = new Map(); + for (const contribution of flatten(extensionPoints.map(x => x.value))) { + 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); + } + } + return sourceActions; + } +} diff --git a/src/vs/workbench/contrib/codeActions/common/extensionPoint.ts b/src/vs/workbench/contrib/codeActions/common/extensionPoint.ts new file mode 100644 index 00000000000..54a81df6fe4 --- /dev/null +++ b/src/vs/workbench/contrib/codeActions/common/extensionPoint.ts @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; +import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService'; + +export enum CodeActionExtensionPointFields { + kind = 'kind', + title = 'title', + selector = 'selector', + selectorLanguage = 'language', + selectorScheme = 'scheme', +} + +export interface CodeActionsExtensionPoint { + readonly [CodeActionExtensionPointFields.kind]: string; + readonly [CodeActionExtensionPointFields.title]: string; + readonly [CodeActionExtensionPointFields.selector]: { + readonly [CodeActionExtensionPointFields.selectorLanguage]: string; + readonly [CodeActionExtensionPointFields.selectorScheme]: string; + }; +} + +const codeActionsExtensionPointSchema: IConfigurationPropertySchema = { + 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], + 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]: { + 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."), + } + }, + } + }, + } + } +}; + +export const codeActionsExtensionPointDescriptor = { + extensionPoint: 'codeActions', + deps: [languagesExtPoint], + jsonSchema: codeActionsExtensionPointSchema +}; diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 9a714a0f96a..90b12c9104f 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -253,4 +253,7 @@ import 'vs/workbench/contrib/feedback/browser/feedback.contribution'; // User Data Sync import 'vs/workbench/contrib/userDataSync/browser/userDataSync.contribution'; +// Code Actions +import 'vs/workbench/contrib/codeActions/common/codeActions.contribution'; + //#endregion