parent
74c8922d31
commit
f0336455ed
11 changed files with 220 additions and 14 deletions
|
@ -45,10 +45,20 @@
|
|||
"onCommand:typescript.openTsServerLog",
|
||||
"onCommand:workbench.action.tasks.runTask",
|
||||
"onCommand:_typescript.configurePlugin",
|
||||
"onCommand:_typescript.learnMoreAboutRefactorings",
|
||||
"onLanguage:jsonc"
|
||||
],
|
||||
"main": "./out/extension",
|
||||
"contributes": {
|
||||
"documentation": {
|
||||
"refactoring": [
|
||||
{
|
||||
"title": "%documentation.refactoring.title%",
|
||||
"when": "typescript.isManagedFile",
|
||||
"command": "_typescript.learnMoreAboutRefactorings"
|
||||
}
|
||||
]
|
||||
},
|
||||
"jsonValidation": [
|
||||
{
|
||||
"fileMatch": "package.json",
|
||||
|
|
|
@ -97,5 +97,6 @@
|
|||
"codeActions.refactor.rewrite.parameters.toDestructured.title": "Convert parameters to destructured object",
|
||||
"codeActions.refactor.rewrite.property.generateAccessors.title": "Generate accessors",
|
||||
"codeActions.refactor.rewrite.property.generateAccessors.description": "Generate 'get' and 'set' accessors",
|
||||
"codeActions.source.organizeImports.title": "Organize imports"
|
||||
"codeActions.source.organizeImports.title": "Organize imports",
|
||||
"documentation.refactoring.title": "Learn more about JS/TS refactorings"
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import { OpenTsServerLogCommand } from './openTsServerLog';
|
|||
import { ReloadJavaScriptProjectsCommand, ReloadTypeScriptProjectsCommand } from './reloadProject';
|
||||
import { RestartTsServerCommand } from './restartTsServer';
|
||||
import { SelectTypeScriptVersionCommand } from './selectTypeScriptVersion';
|
||||
import { LearnMoreAboutRefactoringsCommand } from './learnMoreAboutRefactorings';
|
||||
|
||||
export function registerCommands(
|
||||
commandManager: CommandManager,
|
||||
|
@ -27,4 +28,5 @@ export function registerCommands(
|
|||
commandManager.register(new TypeScriptGoToProjectConfigCommand(lazyClientHost));
|
||||
commandManager.register(new JavaScriptGoToProjectConfigCommand(lazyClientHost));
|
||||
commandManager.register(new ConfigurePluginCommand(pluginManager));
|
||||
commandManager.register(new LearnMoreAboutRefactoringsCommand());
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { Command } from '../utils/commandManager';
|
||||
|
||||
export class LearnMoreAboutRefactoringsCommand implements Command {
|
||||
public readonly id = '_typescript.learnMoreAboutRefactorings';
|
||||
|
||||
public execute() {
|
||||
vscode.env.openExternal(vscode.Uri.parse('https://go.microsoft.com/fwlink/?linkid=2114477'));
|
||||
}
|
||||
}
|
|
@ -4,8 +4,9 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { getDomNodePagePosition } from 'vs/base/browser/dom';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IAnchor } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { canceled } from 'vs/base/common/errors';
|
||||
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
|
@ -14,7 +15,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { CodeAction } from 'vs/editor/common/modes';
|
||||
import { CodeActionSet, refactorCommandId, sourceActionCommandId, codeActionCommandId, organizeImportsCommandId, fixAllCommandId } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { codeActionCommandId, CodeActionSet, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/codeAction';
|
||||
import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionKind } from 'vs/editor/contrib/codeAction/types';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
|
@ -83,8 +84,7 @@ export class CodeActionMenu extends Disposable {
|
|||
this._visible = true;
|
||||
this._showingActions.value = codeActions;
|
||||
|
||||
const menuActions = actionsToShow.map(action =>
|
||||
new CodeActionAction(action, () => this._delegate.onSelectCodeAction(action)));
|
||||
const menuActions = this.getMenuActions(actionsToShow);
|
||||
|
||||
const anchor = Position.isIPosition(at) ? this._toCoords(at) : at || { x: 0, y: 0 };
|
||||
const resolver = this._keybindingResolver.getResolver();
|
||||
|
@ -101,6 +101,24 @@ export class CodeActionMenu extends Disposable {
|
|||
});
|
||||
}
|
||||
|
||||
private getMenuActions(actionsToShow: readonly CodeAction[]): IAction[] {
|
||||
const allActions = actionsToShow
|
||||
.map(action => new CodeActionAction(action, () => this._delegate.onSelectCodeAction(action)));
|
||||
|
||||
// Treat documentation actions as special
|
||||
const result: IAction[] = allActions
|
||||
.filter(action => !action.action.kind || !CodeActionKind.RefactorDocumentation.contains(new CodeActionKind(action.action.kind)));
|
||||
|
||||
const documentationActions = allActions
|
||||
.filter(action => action.action.kind && CodeActionKind.RefactorDocumentation.contains(new CodeActionKind(action.action.kind)));
|
||||
|
||||
if (documentationActions.length) {
|
||||
result.push(new Separator(), ...documentationActions);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private _toCoords(position: IPosition): { x: number, y: number } {
|
||||
if (!this._editor.hasModel()) {
|
||||
return { x: 0, y: 0 };
|
||||
|
|
|
@ -14,6 +14,7 @@ export class CodeActionKind {
|
|||
public static readonly Empty = new CodeActionKind('');
|
||||
public static readonly QuickFix = new CodeActionKind('quickfix');
|
||||
public static readonly Refactor = new CodeActionKind('refactor');
|
||||
public static readonly RefactorDocumentation = new CodeActionKind('refactor.documentation');
|
||||
public static readonly Source = new CodeActionKind('source');
|
||||
public static readonly SourceOrganizeImports = CodeActionKind.Source.append('organizeImports');
|
||||
public static readonly SourceFixAll = CodeActionKind.Source.append('fixAll');
|
||||
|
|
|
@ -4,24 +4,28 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
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 { CodeActionWorkbenchConfigurationContribution, editorConfiguration } from 'vs/workbench/contrib/codeActions/common/configuration';
|
||||
import { CodeActionsExtensionPoint, codeActionsExtensionPointDescriptor } from 'vs/workbench/contrib/codeActions/common/extensionPoint';
|
||||
import { CodeActionsContribution, editorConfiguration } from 'vs/workbench/contrib/codeActions/common/codeActionsContribution';
|
||||
import { CodeActionsExtensionPoint, codeActionsExtensionPointDescriptor } from 'vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint';
|
||||
import { CodeActionDocumentationContribution } from 'vs/workbench/contrib/codeActions/common/documentationContribution';
|
||||
import { DocumentationExtensionPoint, documentationExtensionPointDescriptor } from 'vs/workbench/contrib/codeActions/common/documentationExtensionPoint';
|
||||
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
|
||||
const codeActionsExtensionPoint = ExtensionsRegistry.registerExtensionPoint<CodeActionsExtensionPoint[]>(codeActionsExtensionPointDescriptor);
|
||||
const documentationExtensionPoint = ExtensionsRegistry.registerExtensionPoint<DocumentationExtensionPoint>(documentationExtensionPointDescriptor);
|
||||
|
||||
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
|
||||
.registerConfiguration(editorConfiguration);
|
||||
|
||||
class WorkbenchConfigurationContribution {
|
||||
constructor(
|
||||
@IKeybindingService keybindingsService: IKeybindingService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
) {
|
||||
new CodeActionWorkbenchConfigurationContribution(codeActionsExtensionPoint, keybindingsService);
|
||||
instantiationService.createInstance(CodeActionsContribution, codeActionsExtensionPoint);
|
||||
instantiationService.createInstance(CodeActionDocumentationContribution, documentationExtensionPoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import { Extensions, IConfigurationNode, IConfigurationRegistry, ConfigurationSc
|
|||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { CodeActionsExtensionPoint, ContributedCodeAction } from 'vs/workbench/contrib/codeActions/common/extensionPoint';
|
||||
import { CodeActionsExtensionPoint, ContributedCodeAction } from 'vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint';
|
||||
import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { editorConfigurationBaseNode } from 'vs/editor/common/config/commonEditorConfig';
|
||||
|
||||
|
@ -50,7 +50,7 @@ export const editorConfiguration = Object.freeze<IConfigurationNode>({
|
|||
}
|
||||
});
|
||||
|
||||
export class CodeActionWorkbenchConfigurationContribution extends Disposable implements IWorkbenchContribution {
|
||||
export class CodeActionsContribution extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private _contributedCodeActions: CodeActionsExtensionPoint[] = [];
|
||||
|
||||
|
@ -58,7 +58,7 @@ export class CodeActionWorkbenchConfigurationContribution extends Disposable imp
|
|||
|
||||
constructor(
|
||||
codeActionsExtensionPoint: IExtensionPoint<CodeActionsExtensionPoint[]>,
|
||||
keybindingService: IKeybindingService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
) {
|
||||
super();
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { CodeAction, CodeActionContext, CodeActionList, CodeActionProvider, CodeActionProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { CodeActionKind } from 'vs/editor/contrib/codeAction/types';
|
||||
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { DocumentationExtensionPoint } from './documentationExtensionPoint';
|
||||
|
||||
|
||||
export class CodeActionDocumentationContribution extends Disposable implements IWorkbenchContribution, CodeActionProvider {
|
||||
|
||||
private contributions: {
|
||||
title: string;
|
||||
when: ContextKeyExpr;
|
||||
command: string;
|
||||
}[] = [];
|
||||
|
||||
constructor(
|
||||
extensionPoint: IExtensionPoint<DocumentationExtensionPoint>,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
) {
|
||||
super();
|
||||
|
||||
CodeActionProviderRegistry.register('*', this);
|
||||
|
||||
extensionPoint.setHandler(points => {
|
||||
this.contributions = [];
|
||||
for (const documentation of points) {
|
||||
if (!documentation.value.refactoring) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const contribution of documentation.value.refactoring) {
|
||||
const precondition = ContextKeyExpr.deserialize(contribution.when);
|
||||
if (!precondition) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.contributions.push({
|
||||
title: contribution.title,
|
||||
when: precondition,
|
||||
command: contribution.command
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async provideCodeActions(_model: ITextModel, _range: Range | Selection, context: CodeActionContext, _token: CancellationToken): Promise<CodeActionList> {
|
||||
if (!context.only || !CodeActionKind.Refactor.contains(new CodeActionKind(context.only))) {
|
||||
return {
|
||||
actions: [],
|
||||
dispose: () => { }
|
||||
};
|
||||
}
|
||||
|
||||
const actions: CodeAction[] = [];
|
||||
|
||||
for (const contribution of this.contributions) {
|
||||
if (!this.contextKeyService.contextMatchesRules(contribution.when)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
actions.push({
|
||||
title: contribution.title,
|
||||
kind: CodeActionKind.RefactorDocumentation.value,
|
||||
command: {
|
||||
id: contribution.command,
|
||||
title: contribution.title
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
actions,
|
||||
dispose: () => { }
|
||||
};
|
||||
}
|
||||
|
||||
public readonly providedCodeActionKinds = [CodeActionKind.RefactorDocumentation.value] as const;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 DocumentationExtensionPointFields {
|
||||
when = 'when',
|
||||
title = 'title',
|
||||
command = 'command',
|
||||
}
|
||||
|
||||
export interface RefactoringDocumentationExtensionPoint {
|
||||
readonly [DocumentationExtensionPointFields.title]: string;
|
||||
readonly [DocumentationExtensionPointFields.when]: string;
|
||||
readonly [DocumentationExtensionPointFields.command]: string;
|
||||
}
|
||||
|
||||
export interface DocumentationExtensionPoint {
|
||||
readonly refactoring?: readonly RefactoringDocumentationExtensionPoint[];
|
||||
}
|
||||
|
||||
const documentationExtensionPointSchema = Object.freeze<IConfigurationPropertySchema>({
|
||||
type: 'object',
|
||||
description: nls.localize('contributes.documentation', "Contributed documentation."),
|
||||
properties: {
|
||||
'refactoring': {
|
||||
type: 'array',
|
||||
description: nls.localize('contributes.documentation.refactorings', "Contributed documentation for refactorings."),
|
||||
items: {
|
||||
type: 'object',
|
||||
description: nls.localize('contributes.documentation.refactoring', "Contributed documentation for refactoring."),
|
||||
required: [
|
||||
DocumentationExtensionPointFields.title,
|
||||
DocumentationExtensionPointFields.when,
|
||||
DocumentationExtensionPointFields.command
|
||||
],
|
||||
properties: {
|
||||
[DocumentationExtensionPointFields.title]: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.documentation.refactoring.title', "Label for the documentation used in the UI."),
|
||||
},
|
||||
[DocumentationExtensionPointFields.when]: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.documentation.refactoring.when', "When clause."),
|
||||
},
|
||||
[DocumentationExtensionPointFields.command]: {
|
||||
type: 'string',
|
||||
description: nls.localize('contributes.documentation.refactoring.command', "Command executed."),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const documentationExtensionPointDescriptor = {
|
||||
extensionPoint: 'documentation',
|
||||
deps: [languagesExtPoint],
|
||||
jsonSchema: documentationExtensionPointSchema
|
||||
};
|
Loading…
Reference in a new issue