未验证 提交 5ff2ccfc 编写于 作者: M Matt Bierner 提交者: GitHub

CodeActionProvider.providedKinds (#47702)

Adds a new optional  `CodeActionProviderMetadata`.  This is passed in`registerCodeActionProvider` and contains a list of`CodeActionKinds` that the provider may return. The list is used for deciding when to show the `refactor` and `source action` context menus. It is not used for filtering the returned code actions

Possibly helps address #45383
上级 dfbbea51
......@@ -91,11 +91,16 @@ export class OrganizeImportsContextManager {
export class OrganizeImportsCodeActionProvider implements vscode.CodeActionProvider {
private static readonly organizeImportsKind = vscode.CodeActionKind.Source.append('organizeImports');
public constructor(
private readonly client: ITypeScriptServiceClient
) { }
public readonly metadata: vscode.CodeActionProviderMetadata = {
providedCodeActionKinds: [OrganizeImportsCodeActionProvider.organizeImportsKind]
};
public provideCodeActions(
document: vscode.TextDocument,
_range: vscode.Range,
......@@ -110,7 +115,7 @@ export class OrganizeImportsCodeActionProvider implements vscode.CodeActionProvi
return [];
}
const action = new vscode.CodeAction(localize('oraganizeImportsAction.title', "Organize Imports"), vscode.CodeActionKind.Source.append('organizeImports'));
const action = new vscode.CodeAction(localize('oraganizeImportsAction.title', "Organize Imports"), OrganizeImportsCodeActionProvider.organizeImportsKind);
action.command = { title: '', command: OrganizeImportsCommand.Ids[0] };
return [action];
}
......
......@@ -96,6 +96,10 @@ export default class TypeScriptRefactorProvider implements vscode.CodeActionProv
commandManager.register(new SelectRefactorCommand(doRefactoringCommand));
}
public readonly metadata: vscode.CodeActionProviderMetadata = {
providedCodeActionKinds: [vscode.CodeActionKind.Refactor]
};
public async provideCodeActions(
document: vscode.TextDocument,
_range: vscode.Range,
......
......@@ -119,8 +119,12 @@ export default class LanguageProvider {
this.disposables.push(languages.registerSignatureHelpProvider(selector, new (await import('./features/signatureHelpProvider')).default(client), '(', ','));
this.disposables.push(languages.registerRenameProvider(selector, new (await import('./features/renameProvider')).default(client)));
this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/quickFixProvider')).default(client, this.formattingOptionsManager, commandManager, this.diagnosticsManager, this.bufferSyncSupport)));
this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/refactorProvider')).default(client, this.formattingOptionsManager, commandManager)));
this.disposables.push(languages.registerCodeActionsProvider(selector, new (await import('./features/organizeImports')).OrganizeImportsCodeActionProvider(client)));
const refactorProvider = new (await import('./features/refactorProvider')).default(client, this.formattingOptionsManager, commandManager);
this.disposables.push(languages.registerCodeActionsProvider(selector, refactorProvider, refactorProvider.metadata));
const organizeImportsProvider = new (await import('./features/organizeImports')).OrganizeImportsCodeActionProvider(client);
this.disposables.push(languages.registerCodeActionsProvider(selector, organizeImportsProvider, organizeImportsProvider.metadata));
await this.initFoldingProvider();
this.disposables.push(workspace.onDidChangeConfiguration(c => {
......
......@@ -364,6 +364,11 @@ export interface CodeActionProvider {
* Provide commands for the given document and range.
*/
provideCodeActions(model: model.ITextModel, range: Range, context: CodeActionContext, token: CancellationToken): CodeAction[] | Thenable<CodeAction[]>;
/**
* Optional list of of CodeActionKinds that this provider returns.
*/
providedCodeActionKinds?: string[];
}
/**
......
......@@ -25,7 +25,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { CodeActionAutoApply, CodeActionFilter, CodeActionKind } from './codeActionTrigger';
import { LightBulbWidget } from './lightBulbWidget';
import { QuickFixComputeEvent, QuickFixModel } from './quickFixModel';
import { QuickFixComputeEvent, QuickFixModel, HAS_REFACTOR_PROVIDER, HAS_SOURCE_ACTION_PROVIDER } from './quickFixModel';
import { QuickFixContextMenu } from './quickFixWidget';
export class QuickFixController implements IEditorContribution {
......@@ -52,7 +52,7 @@ export class QuickFixController implements IEditorContribution {
@optional(IFileService) private _fileService: IFileService
) {
this._editor = editor;
this._model = new QuickFixModel(this._editor, markerService);
this._model = new QuickFixModel(this._editor, markerService, contextKeyService);
this._quickFixContextMenu = new QuickFixContextMenu(editor, contextMenuService, action => this._onApplyCodeAction(action));
this._lightBulbWidget = new LightBulbWidget(editor);
......@@ -247,7 +247,8 @@ export class RefactorAction extends EditorAction {
},
menuOpts: {
group: '1_modification',
order: 2
order: 2,
when: ContextKeyExpr.and(EditorContextKeys.writable, HAS_REFACTOR_PROVIDER),
}
});
}
......@@ -273,7 +274,9 @@ export class SourceAction extends EditorAction {
precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider),
menuOpts: {
group: '1_modification',
order: 2.1
order: 2.1,
when: ContextKeyExpr.and(EditorContextKeys.writable, HAS_SOURCE_ACTION_PROVIDER),
}
});
}
......
......@@ -4,18 +4,22 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Event, Emitter, debounceEvent } from 'vs/base/common/event';
import { Emitter, Event, debounceEvent } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { CodeActionProviderRegistry, CodeAction } from 'vs/editor/common/modes';
import { CodeAction, CodeActionProviderRegistry } from 'vs/editor/common/modes';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { CodeActionKind, CodeActionTrigger } from './codeActionTrigger';
import { getCodeActions } from './quickFix';
import { CodeActionTrigger } from './codeActionTrigger';
import { Position } from 'vs/editor/common/core/position';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
export const HAS_REFACTOR_PROVIDER = new RawContextKey<boolean>('hasRefactorProvider', false);
export const HAS_SOURCE_ACTION_PROVIDER = new RawContextKey<boolean>('hasSourceActionProvider', false);
export class QuickFixOracle {
......@@ -141,11 +145,16 @@ export class QuickFixModel {
private _quickFixOracle: QuickFixOracle;
private _onDidChangeFixes = new Emitter<QuickFixComputeEvent>();
private _disposables: IDisposable[] = [];
private readonly _hasRefactorProvider: IContextKey<boolean>;
private readonly _hasSourceProvider: IContextKey<boolean>;
constructor(editor: ICodeEditor, markerService: IMarkerService) {
constructor(editor: ICodeEditor, markerService: IMarkerService, contextKeyService: IContextKeyService) {
this._editor = editor;
this._markerService = markerService;
this._hasRefactorProvider = HAS_REFACTOR_PROVIDER.bindTo(contextKeyService);
this._hasSourceProvider = HAS_SOURCE_ACTION_PROVIDER.bindTo(contextKeyService);
this._disposables.push(this._editor.onDidChangeModel(() => this._update()));
this._disposables.push(this._editor.onDidChangeModelLanguage(() => this._update()));
this._disposables.push(CodeActionProviderRegistry.onDidChange(this._update, this));
......@@ -174,8 +183,28 @@ export class QuickFixModel {
&& CodeActionProviderRegistry.has(this._editor.getModel())
&& !this._editor.getConfiguration().readOnly) {
let hasRefactorProvider = false;
let hasSourceProvider = false;
outer: for (const provider of CodeActionProviderRegistry.all(this._editor.getModel())) {
if (!provider.providedCodeActionKinds) {
continue;
}
for (const providedKind of provider.providedCodeActionKinds) {
hasRefactorProvider = hasRefactorProvider || CodeActionKind.Refactor.contains(providedKind);
hasSourceProvider = hasSourceProvider || CodeActionKind.Source.contains(providedKind);
if (hasRefactorProvider && hasSourceProvider) {
break outer;
}
}
}
this._hasRefactorProvider.set(hasRefactorProvider);
this._hasSourceProvider.set(hasSourceProvider);
this._quickFixOracle = new QuickFixOracle(this._editor, this._markerService, p => this._onDidChangeFixes.fire(p));
this._quickFixOracle.trigger({ type: 'auto' });
} else {
this._hasRefactorProvider.reset();
}
}
......
......@@ -2034,7 +2034,6 @@ declare module 'vscode' {
* A code action can be any command that is [known](#commands.getCommands) to the system.
*/
export interface CodeActionProvider {
/**
* Provide commands for the given document and range.
*
......@@ -2048,6 +2047,19 @@ declare module 'vscode' {
provideCodeActions(document: TextDocument, range: Range, context: CodeActionContext, token: CancellationToken): ProviderResult<(Command | CodeAction)[]>;
}
/**
* Metadata about the type of code actions that a [CodeActionProvider](#CodeActionProvider) providers
*/
export interface CodeActionProviderMetadata {
/**
* [CodeActionKinds](#CodeActionKind) that this provider may return.
*
* The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the provider
* may list our every specific kind they provide, such as `CodeActionKind.Refactor.Extract.append('function`)`
*/
readonly providedCodeActionKinds?: CodeActionKind[];
}
/**
* A code lens represents a [command](#Command) that should be shown along with
* source text, like the number of references, a way to run tests, etc.
......@@ -6123,9 +6135,10 @@ declare module 'vscode' {
*
* @param selector A selector that defines the documents this provider is applicable to.
* @param provider A code action provider.
* @param metadata Metadata about the kind of code actions the provider providers.
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
*/
export function registerCodeActionsProvider(selector: DocumentSelector, provider: CodeActionProvider): Disposable;
export function registerCodeActionsProvider(selector: DocumentSelector, provider: CodeActionProvider, metadata?: CodeActionProviderMetadata): Disposable;
/**
* Register a code lens provider.
......
......@@ -191,11 +191,12 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- quick fix
$registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[]): void {
$registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[], providedCodeActionKinds?: string[]): void {
this._registrations[handle] = modes.CodeActionProviderRegistry.register(toLanguageSelector(selector), <modes.CodeActionProvider>{
provideCodeActions: (model: ITextModel, range: EditorRange, context: modes.CodeActionContext, token: CancellationToken): Thenable<modes.CodeAction[]> => {
return this._heapService.trackRecursive(wireCancellationToken(token, this._proxy.$provideCodeActions(handle, model.uri, range, context))).then(MainThreadLanguageFeatures._reviveCodeActionDto);
}
},
providedCodeActionKinds
});
}
......
......@@ -271,8 +271,8 @@ export function createApiFactory(
match(selector: vscode.DocumentSelector, document: vscode.TextDocument): number {
return score(toLanguageSelector(selector), document.uri, document.languageId, true);
},
registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
return extHostLanguageFeatures.registerCodeActionProvider(checkSelector(selector), provider);
registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable {
return extHostLanguageFeatures.registerCodeActionProvider(checkSelector(selector), provider, metadata);
},
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
return extHostLanguageFeatures.registerCodeLensProvider(checkSelector(selector), provider);
......
......@@ -273,7 +273,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerHoverProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
$registerDocumentHighlightProvider(handle: number, selector: ISerializedDocumentFilter[]): void;
$registerReferenceSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
$registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
$registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[], supportedKinds?: string[]): void;
$registerDocumentFormattingSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
$registerRangeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[]): void;
$registerOnTypeFormattingSupport(handle: number, selector: ISerializedDocumentFilter[], autoFormatTriggerCharacters: string[]): void;
......
......@@ -1013,9 +1013,9 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
// --- quick fix
registerCodeActionProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider): vscode.Disposable {
registerCodeActionProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable {
const handle = this._addNewAdapter(new CodeActionAdapter(this._documents, this._commands.converter, this._diagnostics, provider));
this._proxy.$registerQuickFixSupport(handle, this._transformDocumentSelector(selector));
this._proxy.$registerQuickFixSupport(handle, this._transformDocumentSelector(selector), metadata && metadata.providedCodeActionKinds ? metadata.providedCodeActionKinds.map(kind => kind.value) : undefined);
return this._createDisposable(handle);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册