From abc0784e57610a0cceca63301489918015418df6 Mon Sep 17 00:00:00 2001 From: Ryan Cumming Date: Thu, 27 Jun 2019 21:30:23 +1000 Subject: Fix `cargo watch` code action filtering There are two issues with the implementation of `provideCodeActions` introduced in #1439: 1. We're returning the code action based on the file its diagnostic is in; not the file the suggested fix is in. I'm not sure how often fixes are suggested cross-file but it's something we should handle. 2. We're not filtering code actions based on the passed range. The means if there is any suggestion in a file we'll show an action for every line of the file. I naively thought that VS Code would filter for us but that was wrong. Unfortunately the VS Code `CodeAction` object is very complex - it can handle edits across multiple files, run commands, etc. This makes it complex to check them for equality or see if any of their edits intersects with a specified range. To make it easier to work with suggestions this introduces a `SuggestedFix` model object and a `SuggestFixCollection` code action provider. This is a layer between the raw Rust JSON and VS Code's `CodeAction`s. I was reluctant to introduce another layer of abstraction here but my attempt to work directly with VS Code's model objects was worse. --- editors/code/src/utils/diagnostics/SuggestedFix.ts | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 editors/code/src/utils/diagnostics/SuggestedFix.ts (limited to 'editors/code/src/utils/diagnostics/SuggestedFix.ts') diff --git a/editors/code/src/utils/diagnostics/SuggestedFix.ts b/editors/code/src/utils/diagnostics/SuggestedFix.ts new file mode 100644 index 000000000..b1be2a225 --- /dev/null +++ b/editors/code/src/utils/diagnostics/SuggestedFix.ts @@ -0,0 +1,67 @@ +import * as vscode from 'vscode'; + +import { SuggestionApplicability } from './rust'; + +/** + * Model object for text replacements suggested by the Rust compiler + * + * This is an intermediate form between the raw `rustc` JSON and a + * `vscode.CodeAction`. It's optimised for the use-cases of + * `SuggestedFixCollection`. + */ +export default class SuggestedFix { + public readonly title: string; + public readonly location: vscode.Location; + public readonly replacement: string; + public readonly applicability: SuggestionApplicability; + + /** + * Diagnostics this suggested fix could resolve + */ + public diagnostics: vscode.Diagnostic[]; + + constructor( + title: string, + location: vscode.Location, + replacement: string, + applicability: SuggestionApplicability = SuggestionApplicability.Unspecified + ) { + this.title = title; + this.location = location; + this.replacement = replacement; + this.applicability = applicability; + this.diagnostics = []; + } + + /** + * Determines if this suggested fix is equivalent to another instance + */ + public isEqual(other: SuggestedFix): boolean { + return ( + this.title === other.title && + this.location.range.isEqual(other.location.range) && + this.replacement === other.replacement && + this.applicability === other.applicability + ); + } + + /** + * Converts this suggested fix to a VS Code Quick Fix code action + */ + public toCodeAction(): vscode.CodeAction { + const codeAction = new vscode.CodeAction( + this.title, + vscode.CodeActionKind.QuickFix + ); + + const edit = new vscode.WorkspaceEdit(); + edit.replace(this.location.uri, this.location.range, this.replacement); + codeAction.edit = edit; + + codeAction.isPreferred = + this.applicability === SuggestionApplicability.MachineApplicable; + + codeAction.diagnostics = [...this.diagnostics]; + return codeAction; + } +} -- cgit v1.2.3