import * as vscode from 'vscode'; import SuggestedFix from './SuggestedFix'; /** * Collection of suggested fixes across multiple documents * * This stores `SuggestedFix` model objects and returns them via the * `vscode.CodeActionProvider` interface. */ export default class SuggestedFixCollection implements vscode.CodeActionProvider { public static PROVIDED_CODE_ACTION_KINDS = [vscode.CodeActionKind.QuickFix]; /** * Map of document URI strings to suggested fixes */ private suggestedFixes: Map<string, SuggestedFix[]>; constructor() { this.suggestedFixes = new Map(); } /** * Clears all suggested fixes across all documents */ public clear(): void { this.suggestedFixes = new Map(); } /** * Adds a suggested fix for the given diagnostic * * Some suggested fixes will appear in multiple diagnostics. For example, * forgetting a `mut` on a variable will suggest changing the delaration on * every mutable usage site. If the suggested fix has already been added * this method will instead associate the existing fix with the new * diagnostic. */ public addSuggestedFixForDiagnostic( suggestedFix: SuggestedFix, diagnostic: vscode.Diagnostic ): void { const fileUriString = suggestedFix.location.uri.toString(); const fileSuggestions = this.suggestedFixes.get(fileUriString) || []; const existingSuggestion = fileSuggestions.find(s => s.isEqual(suggestedFix) ); if (existingSuggestion) { // The existing suggestion also applies to this new diagnostic existingSuggestion.diagnostics.push(diagnostic); } else { // We haven't seen this suggestion before suggestedFix.diagnostics.push(diagnostic); fileSuggestions.push(suggestedFix); } this.suggestedFixes.set(fileUriString, fileSuggestions); } /** * Filters suggested fixes by their document and range and converts them to * code actions */ public provideCodeActions( document: vscode.TextDocument, range: vscode.Range ): vscode.CodeAction[] { const documentUriString = document.uri.toString(); const suggestedFixes = this.suggestedFixes.get(documentUriString); return (suggestedFixes || []) .filter(({ location }) => location.range.intersection(range)) .map(suggestedEdit => suggestedEdit.toCodeAction()); } }