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
This commit is contained in:
parent
dfbbea5157
commit
5ff2ccfc28
11 changed files with 87 additions and 23 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
17
src/vs/vscode.d.ts
vendored
17
src/vs/vscode.d.ts
vendored
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue