原地址:https://github.com/hoovercj/vscode-extension-tutorial
Commands and CodeActionProviders
Actions that should appear in the command palette (ctrl+shift+p) are declared in packages.json as a command. The generated Hello World extension has an example of this. These can then be registered by an extension to trigger any function with the line vscode.commands.registerCommand(‘extension.commandId’, functionNameOrDefinition).
However, for an action that is context specific and shouldn’t be in the command palette, don’t register it in packages.json. But then how will it be triggered? That’s where CodeActionProviders come in.
A CodeActionProvider makes the lightbulb show up in VS Code allowing users to perform refactorings, fix spelling mistakes, etc.
The CodeActionProvider interface defines a single method named provideCodeActions(). A class that implements this interface and registers with VS Code will have its provideCodeActions() method called whenever the user selects text or places the cursor in an area that contains a Diagnostic. It is up to the extension, then, to return an array of actions that are applicable for that Diagnostic.
The objects returned by provideCodeActions() are nothing more than references to a command as discussed above and an array of arguments to pass it. These will display as options if the user clicks the lightbulb. And when the user clicks on the lightbulb? The arguments are passed to whatever function the extension registered for that command as described above.
The code below illustrates how to add code actions to the HaskellLintingProvider class shown above. provideCodeActions() receives the diagnostics as a member of CodeActionContext and returns an array with a single command. runCodeAction() is the function that we want to trigger if a user selects our action. Using the arguments passed along with the command it uses a WorkspaceEdit to fix a users code according to the suggestions of hlint.
Copy the following code into the body of HaskellLintingProvider from src/features/hlintProvider after the doHlint() function.
// src/features/hlintProvider.ts
private static commandId: string = 'haskell.hlint.runCodeAction'; public provideCodeActions(document: vscode.TextDocument, range: vscode.Range, context: vscode.CodeActionContext, token: vscode.CancellationToken): vscode.Command[] { let diagnostic:vscode.Diagnostic = context.diagnostics[0]; return [{ title: "Accept hlint suggestion", command: HaskellLintingProvider.commandId, arguments: [document, diagnostic.range, diagnostic.message] }]; } private runCodeAction(document: vscode.TextDocument, range: vscode.Range, message:string): any { let fromRegex:RegExp = /.*Replace:(.*)==>.*/g let fromMatch:RegExpExecArray = fromRegex.exec(message.replace(/\s/g, '')); let from = fromMatch[1]; let to:string = document.getText(range).replace(/\s/g, '') if (from === to) { let newText = /.*==>\s(.*)/g.exec(message)[1] let edit = new vscode.WorkspaceEdit(); edit.replace(document.uri, range, newText); return vscode.workspace.applyEdit(edit); } else { vscode.window.showErrorMessage("The suggestion was not applied because it is out of date. You might have tried to apply the same edit twice."); } }