CodeAction api change proposal
Closed this issue · 4 comments
Follow up on #34597 and #34595, as part of #33555
Problem
#33555 describes a few key issues with using code actions for refactorings. Along with these concerns, we'd also like to be able to do the following:
- Sort code actions so that fixes for errors show up first
- Group code actions by type / by the error they fix
- Provide a better UI for code actions that tells users which actions address which problems in the code
Proposal
This proposal subsumes the proposals of #34597 and #34595 and is based on discussions @kieferrm and I had. It is based on the following observations:
- The semantics of when we want to show quick fixes vs refactorings is different. The automatic lightbulb does not make as much sense for refactorings
- However the API and implementation of quick fixes and refactorings will be very similar.
This proposal extends the CodeAction API to let us differentiate between quick fixes and refactorings. Using this, we can then specialized the UX for each of theses
VS Code API Changes
/**
* New enum that identifies the type of a code action
*/
enum class CodeActionType {
// Standard type. Would be used for existing CodeActionProviders that return Commands
Default = 0 ,
// Fixes a diagnostic from the CodeActionContext
QuickFix = 1,
// Perform a refactorng
Refactoring = 2
}
/**
* New interface that provides additional info about a code action
*/
interface CodeAction {
// Command the performs the action
// In later iterations we could change this to be a `string | WorkspaceEdit`
action: string
// Title of the action
// The reason we don't just use the `Command` type here is that we will likely want
// to support `WorkspaceEdit` as a future option for action
title: string
// Type of the action
type: CodeActionType
// List of diagnostics this code action resolves
addresses?: Diagnostic[]
// Identifier for the action, such as `"extract method"`
// This would be used for creating keybinding for specific code actions
id?: string
}
/**
* Add a new `requestedTypes` field to the `CodeActionContext`
*/
export interface CodeActionContext {
readonly diagnostics: Diagnostic[]
// List of types to compute.
// Any code actions that are returned that are not in the list will also be filtered out by vscode
readonly requestedTypes: CodeActionType[]
}
/**
* Update the `CodeActionProvider` to either return `Commands` or `CodeActions`
*/
export interface CodeActionProvider {
provideCodeActions(document: TextDocument, range: Range, context: CodeActionContext, token: CancellationToken): ProviderResult<Command[] | CodeAction[]>;
}
Code action context menu UX changes
Using the additional information provided by the new CodeAction
interface, we would update the code action context menu to display the following:
- Add a symbol next to next each code action in the context menu. These symbols would use the
CodeActionType
to differentiate types of code actions. - In the case of
QuickFix
code actions, also use diagnostic severity to display a different symbol for quick fixes for errors and quick fixes for warnings - Sort the code actions so that fixes for errors show up first
- Surface information about the diagnostic that a code action fixes in the menu
Code action trigger changes
Using the CodeActionType
, we can now differentiate quick fixes and refactorings. We would then change when we show each type:
-
The existing lightbulb /
editor.action.quickFix
would request code actions withCodeActionType.Standard
andCodeActionType.QuickFix
. Refactoring code actions would be filtered out. -
A new
editor.action.refactor
command would request code actions only ofCodeActionType.Refactor
and display these in the context menu
Keybinding for code actions
Introduce a new editor.action.codeAction
command. This command would take an optional list of code action ids.
When the command is triggered, it would request all code actions that are currently available, but only show those that match the requested ids
. If only a single code action matches the id, it would be applied automatically
This would allow us to setup keybindings such as:
{
"key": "cmd+r cmd+e",
"command": "editor.action.codeAction",
"args": [
"extract method"
]
}
@mjbvz Something I thought while writing some jsdoc is if we should just make the edits
be a WorkspaceEdit
? I think that makes it more explicit and doesn't add a burden for those that want to make 'local' changes only. So instead of
export class CodeAction {
//...
edits?: TextEdit[] | WorkspaceEdit;
have this
export class CodeAction {
//...
edit: WorkspaceEdit;
Thoughts? Ideas?
I'm fine with this. I think we should keep edit
optional though since sometimes you only want to provide a command. Should I make the change?