aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
diff options
context:
space:
mode:
authorRyan Cumming <[email protected]>2019-06-27 12:30:23 +0100
committerRyan Cumming <[email protected]>2019-06-29 08:39:36 +0100
commitabc0784e57610a0cceca63301489918015418df6 (patch)
tree05aec9fef88f31cee82e3507903a1dbcd6b4d30d /editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
parent0e1912de528b5092c10eedaf94c43c67d5f86f1a (diff)
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.
Diffstat (limited to 'editors/code/src/utils/diagnostics/SuggestedFixCollection.ts')
-rw-r--r--editors/code/src/utils/diagnostics/SuggestedFixCollection.ts74
1 files changed, 74 insertions, 0 deletions
diff --git a/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts b/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
new file mode 100644
index 000000000..3b0bf7468
--- /dev/null
+++ b/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
@@ -0,0 +1,74 @@
1import * as vscode from 'vscode';
2import SuggestedFix from './SuggestedFix';
3
4/**
5 * Collection of suggested fixes across multiple documents
6 *
7 * This stores `SuggestedFix` model objects and returns them via the
8 * `vscode.CodeActionProvider` interface.
9 */
10export default class SuggestedFixCollection
11 implements vscode.CodeActionProvider {
12 public static PROVIDED_CODE_ACTION_KINDS = [vscode.CodeActionKind.QuickFix];
13
14 private suggestedFixes: Map<string, SuggestedFix[]>;
15
16 constructor() {
17 this.suggestedFixes = new Map();
18 }
19
20 /**
21 * Clears all suggested fixes across all documents
22 */
23 public clear(): void {
24 this.suggestedFixes = new Map();
25 }
26
27 /**
28 * Adds a suggested fix for the given diagnostic
29 *
30 * Some suggested fixes will appear in multiple diagnostics. For example,
31 * forgetting a `mut` on a variable will suggest changing the delaration on
32 * every mutable usage site. If the suggested fix has already been added
33 * this method will instead associate the existing fix with the new
34 * diagnostic.
35 */
36 public addSuggestedFixForDiagnostic(
37 suggestedFix: SuggestedFix,
38 diagnostic: vscode.Diagnostic
39 ): void {
40 const fileUriString = suggestedFix.location.uri.toString();
41 const fileSuggestions = this.suggestedFixes.get(fileUriString) || [];
42
43 const existingSuggestion = fileSuggestions.find(s =>
44 s.isEqual(suggestedFix)
45 );
46
47 if (existingSuggestion) {
48 // The existing suggestion also applies to this new diagnostic
49 existingSuggestion.diagnostics.push(diagnostic);
50 } else {
51 // We haven't seen this suggestion before
52 suggestedFix.diagnostics.push(diagnostic);
53 fileSuggestions.push(suggestedFix);
54 }
55
56 this.suggestedFixes.set(fileUriString, fileSuggestions);
57 }
58
59 /**
60 * Filters suggested fixes by their document and range and converts them to
61 * code actions
62 */
63 public provideCodeActions(
64 document: vscode.TextDocument,
65 range: vscode.Range
66 ): vscode.CodeAction[] {
67 const documentUriString = document.uri.toString();
68
69 const suggestedFixes = this.suggestedFixes.get(documentUriString);
70 return (suggestedFixes || [])
71 .filter(({ location }) => location.range.intersection(range))
72 .map(suggestedEdit => suggestedEdit.toCodeAction());
73 }
74}