Skip to content

Commit f033645

Browse files
committed
Adding documentation.refactor proposed contribution point
For microsoft#86788
1 parent 74c8922 commit f033645

11 files changed

Lines changed: 220 additions & 14 deletions

File tree

extensions/typescript-language-features/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,20 @@
4545
"onCommand:typescript.openTsServerLog",
4646
"onCommand:workbench.action.tasks.runTask",
4747
"onCommand:_typescript.configurePlugin",
48+
"onCommand:_typescript.learnMoreAboutRefactorings",
4849
"onLanguage:jsonc"
4950
],
5051
"main": "./out/extension",
5152
"contributes": {
53+
"documentation": {
54+
"refactoring": [
55+
{
56+
"title": "%documentation.refactoring.title%",
57+
"when": "typescript.isManagedFile",
58+
"command": "_typescript.learnMoreAboutRefactorings"
59+
}
60+
]
61+
},
5262
"jsonValidation": [
5363
{
5464
"fileMatch": "package.json",

extensions/typescript-language-features/package.nls.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,5 +97,6 @@
9797
"codeActions.refactor.rewrite.parameters.toDestructured.title": "Convert parameters to destructured object",
9898
"codeActions.refactor.rewrite.property.generateAccessors.title": "Generate accessors",
9999
"codeActions.refactor.rewrite.property.generateAccessors.description": "Generate 'get' and 'set' accessors",
100-
"codeActions.source.organizeImports.title": "Organize imports"
100+
"codeActions.source.organizeImports.title": "Organize imports",
101+
"documentation.refactoring.title": "Learn more about JS/TS refactorings"
101102
}

extensions/typescript-language-features/src/commands/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { OpenTsServerLogCommand } from './openTsServerLog';
1313
import { ReloadJavaScriptProjectsCommand, ReloadTypeScriptProjectsCommand } from './reloadProject';
1414
import { RestartTsServerCommand } from './restartTsServer';
1515
import { SelectTypeScriptVersionCommand } from './selectTypeScriptVersion';
16+
import { LearnMoreAboutRefactoringsCommand } from './learnMoreAboutRefactorings';
1617

1718
export function registerCommands(
1819
commandManager: CommandManager,
@@ -27,4 +28,5 @@ export function registerCommands(
2728
commandManager.register(new TypeScriptGoToProjectConfigCommand(lazyClientHost));
2829
commandManager.register(new JavaScriptGoToProjectConfigCommand(lazyClientHost));
2930
commandManager.register(new ConfigurePluginCommand(pluginManager));
30-
}
31+
commandManager.register(new LearnMoreAboutRefactoringsCommand());
32+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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 * as vscode from 'vscode';
7+
import { Command } from '../utils/commandManager';
8+
9+
export class LearnMoreAboutRefactoringsCommand implements Command {
10+
public readonly id = '_typescript.learnMoreAboutRefactorings';
11+
12+
public execute() {
13+
vscode.env.openExternal(vscode.Uri.parse('https://go.microsoft.com/fwlink/?linkid=2114477'));
14+
}
15+
}

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

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { getDomNodePagePosition } from 'vs/base/browser/dom';
7+
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
78
import { IAnchor } from 'vs/base/browser/ui/contextview/contextview';
8-
import { Action } from 'vs/base/common/actions';
9+
import { Action, IAction } from 'vs/base/common/actions';
910
import { canceled } from 'vs/base/common/errors';
1011
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
1112
import { Lazy } from 'vs/base/common/lazy';
@@ -14,7 +15,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
1415
import { IPosition, Position } from 'vs/editor/common/core/position';
1516
import { ScrollType } from 'vs/editor/common/editorCommon';
1617
import { CodeAction } from 'vs/editor/common/modes';
17-
import { CodeActionSet, refactorCommandId, sourceActionCommandId, codeActionCommandId, organizeImportsCommandId, fixAllCommandId } from 'vs/editor/contrib/codeAction/codeAction';
18+
import { codeActionCommandId, CodeActionSet, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/codeAction';
1819
import { CodeActionAutoApply, CodeActionCommandArgs, CodeActionKind } from 'vs/editor/contrib/codeAction/types';
1920
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
2021
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -83,8 +84,7 @@ export class CodeActionMenu extends Disposable {
8384
this._visible = true;
8485
this._showingActions.value = codeActions;
8586

86-
const menuActions = actionsToShow.map(action =>
87-
new CodeActionAction(action, () => this._delegate.onSelectCodeAction(action)));
87+
const menuActions = this.getMenuActions(actionsToShow);
8888

8989
const anchor = Position.isIPosition(at) ? this._toCoords(at) : at || { x: 0, y: 0 };
9090
const resolver = this._keybindingResolver.getResolver();
@@ -101,6 +101,24 @@ export class CodeActionMenu extends Disposable {
101101
});
102102
}
103103

104+
private getMenuActions(actionsToShow: readonly CodeAction[]): IAction[] {
105+
const allActions = actionsToShow
106+
.map(action => new CodeActionAction(action, () => this._delegate.onSelectCodeAction(action)));
107+
108+
// Treat documentation actions as special
109+
const result: IAction[] = allActions
110+
.filter(action => !action.action.kind || !CodeActionKind.RefactorDocumentation.contains(new CodeActionKind(action.action.kind)));
111+
112+
const documentationActions = allActions
113+
.filter(action => action.action.kind && CodeActionKind.RefactorDocumentation.contains(new CodeActionKind(action.action.kind)));
114+
115+
if (documentationActions.length) {
116+
result.push(new Separator(), ...documentationActions);
117+
}
118+
119+
return result;
120+
}
121+
104122
private _toCoords(position: IPosition): { x: number, y: number } {
105123
if (!this._editor.hasModel()) {
106124
return { x: 0, y: 0 };

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export class CodeActionKind {
1414
public static readonly Empty = new CodeActionKind('');
1515
public static readonly QuickFix = new CodeActionKind('quickfix');
1616
public static readonly Refactor = new CodeActionKind('refactor');
17+
public static readonly RefactorDocumentation = new CodeActionKind('refactor.documentation');
1718
public static readonly Source = new CodeActionKind('source');
1819
public static readonly SourceOrganizeImports = CodeActionKind.Source.append('organizeImports');
1920
public static readonly SourceFixAll = CodeActionKind.Source.append('fixAll');

src/vs/workbench/contrib/codeActions/common/codeActions.contribution.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,28 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
7-
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
7+
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
88
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
99
import { Registry } from 'vs/platform/registry/common/platform';
1010
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
11-
import { CodeActionWorkbenchConfigurationContribution, editorConfiguration } from 'vs/workbench/contrib/codeActions/common/configuration';
12-
import { CodeActionsExtensionPoint, codeActionsExtensionPointDescriptor } from 'vs/workbench/contrib/codeActions/common/extensionPoint';
11+
import { CodeActionsContribution, editorConfiguration } from 'vs/workbench/contrib/codeActions/common/codeActionsContribution';
12+
import { CodeActionsExtensionPoint, codeActionsExtensionPointDescriptor } from 'vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint';
13+
import { CodeActionDocumentationContribution } from 'vs/workbench/contrib/codeActions/common/documentationContribution';
14+
import { DocumentationExtensionPoint, documentationExtensionPointDescriptor } from 'vs/workbench/contrib/codeActions/common/documentationExtensionPoint';
1315
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
1416

1517
const codeActionsExtensionPoint = ExtensionsRegistry.registerExtensionPoint<CodeActionsExtensionPoint[]>(codeActionsExtensionPointDescriptor);
18+
const documentationExtensionPoint = ExtensionsRegistry.registerExtensionPoint<DocumentationExtensionPoint>(documentationExtensionPointDescriptor);
1619

1720
Registry.as<IConfigurationRegistry>(Extensions.Configuration)
1821
.registerConfiguration(editorConfiguration);
1922

2023
class WorkbenchConfigurationContribution {
2124
constructor(
22-
@IKeybindingService keybindingsService: IKeybindingService,
25+
@IInstantiationService instantiationService: IInstantiationService,
2326
) {
24-
new CodeActionWorkbenchConfigurationContribution(codeActionsExtensionPoint, keybindingsService);
27+
instantiationService.createInstance(CodeActionsContribution, codeActionsExtensionPoint);
28+
instantiationService.createInstance(CodeActionDocumentationContribution, documentationExtensionPoint);
2529
}
2630
}
2731

src/vs/workbench/contrib/codeActions/common/configuration.ts renamed to src/vs/workbench/contrib/codeActions/common/codeActionsContribution.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { Extensions, IConfigurationNode, IConfigurationRegistry, ConfigurationSc
1515
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
1616
import { Registry } from 'vs/platform/registry/common/platform';
1717
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
18-
import { CodeActionsExtensionPoint, ContributedCodeAction } from 'vs/workbench/contrib/codeActions/common/extensionPoint';
18+
import { CodeActionsExtensionPoint, ContributedCodeAction } from 'vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint';
1919
import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
2020
import { editorConfigurationBaseNode } from 'vs/editor/common/config/commonEditorConfig';
2121

@@ -50,15 +50,15 @@ export const editorConfiguration = Object.freeze<IConfigurationNode>({
5050
}
5151
});
5252

53-
export class CodeActionWorkbenchConfigurationContribution extends Disposable implements IWorkbenchContribution {
53+
export class CodeActionsContribution extends Disposable implements IWorkbenchContribution {
5454

5555
private _contributedCodeActions: CodeActionsExtensionPoint[] = [];
5656

5757
private readonly _onDidChangeContributions = this._register(new Emitter<void>());
5858

5959
constructor(
6060
codeActionsExtensionPoint: IExtensionPoint<CodeActionsExtensionPoint[]>,
61-
keybindingService: IKeybindingService,
61+
@IKeybindingService keybindingService: IKeybindingService,
6262
) {
6363
super();
6464

src/vs/workbench/contrib/codeActions/common/extensionPoint.ts renamed to src/vs/workbench/contrib/codeActions/common/codeActionsExtensionPoint.ts

File renamed without changes.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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 { CancellationToken } from 'vs/base/common/cancellation';
7+
import { Disposable } from 'vs/base/common/lifecycle';
8+
import { Range } from 'vs/editor/common/core/range';
9+
import { Selection } from 'vs/editor/common/core/selection';
10+
import { ITextModel } from 'vs/editor/common/model';
11+
import { CodeAction, CodeActionContext, CodeActionList, CodeActionProvider, CodeActionProviderRegistry } from 'vs/editor/common/modes';
12+
import { CodeActionKind } from 'vs/editor/contrib/codeAction/types';
13+
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
14+
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
15+
import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
16+
import { DocumentationExtensionPoint } from './documentationExtensionPoint';
17+
18+
19+
export class CodeActionDocumentationContribution extends Disposable implements IWorkbenchContribution, CodeActionProvider {
20+
21+
private contributions: {
22+
title: string;
23+
when: ContextKeyExpr;
24+
command: string;
25+
}[] = [];
26+
27+
constructor(
28+
extensionPoint: IExtensionPoint<DocumentationExtensionPoint>,
29+
@IContextKeyService private readonly contextKeyService: IContextKeyService,
30+
) {
31+
super();
32+
33+
CodeActionProviderRegistry.register('*', this);
34+
35+
extensionPoint.setHandler(points => {
36+
this.contributions = [];
37+
for (const documentation of points) {
38+
if (!documentation.value.refactoring) {
39+
continue;
40+
}
41+
42+
for (const contribution of documentation.value.refactoring) {
43+
const precondition = ContextKeyExpr.deserialize(contribution.when);
44+
if (!precondition) {
45+
continue;
46+
}
47+
48+
this.contributions.push({
49+
title: contribution.title,
50+
when: precondition,
51+
command: contribution.command
52+
});
53+
54+
}
55+
}
56+
});
57+
}
58+
59+
async provideCodeActions(_model: ITextModel, _range: Range | Selection, context: CodeActionContext, _token: CancellationToken): Promise<CodeActionList> {
60+
if (!context.only || !CodeActionKind.Refactor.contains(new CodeActionKind(context.only))) {
61+
return {
62+
actions: [],
63+
dispose: () => { }
64+
};
65+
}
66+
67+
const actions: CodeAction[] = [];
68+
69+
for (const contribution of this.contributions) {
70+
if (!this.contextKeyService.contextMatchesRules(contribution.when)) {
71+
continue;
72+
}
73+
74+
actions.push({
75+
title: contribution.title,
76+
kind: CodeActionKind.RefactorDocumentation.value,
77+
command: {
78+
id: contribution.command,
79+
title: contribution.title
80+
}
81+
});
82+
}
83+
84+
return {
85+
actions,
86+
dispose: () => { }
87+
};
88+
}
89+
90+
public readonly providedCodeActionKinds = [CodeActionKind.RefactorDocumentation.value] as const;
91+
}

0 commit comments

Comments
 (0)