diff --git a/packages/vscode-tailwindcss/package.json b/packages/vscode-tailwindcss/package.json index 2f8cba5f..4f7523c4 100644 --- a/packages/vscode-tailwindcss/package.json +++ b/packages/vscode-tailwindcss/package.json @@ -65,6 +65,11 @@ "command": "tailwindCSS.sortSelection", "title": "Tailwind CSS: Sort Selection", "enablement": "editorHasSelection && (resourceScheme == file || resourceScheme == vscode-remote) && tailwindCSS.activeTextEditorSupportsClassSorting" + }, + { + "command": "tailwindCSS.applyAllCanonicalClasses", + "title": "Tailwind CSS: Apply All Canonical Class Suggestions", + "enablement": "editorTextFocus && (resourceScheme == file || resourceScheme == vscode-remote)" } ], "grammars": [ diff --git a/packages/vscode-tailwindcss/src/extension.ts b/packages/vscode-tailwindcss/src/extension.ts index 467d4e08..e0c28e40 100755 --- a/packages/vscode-tailwindcss/src/extension.ts +++ b/packages/vscode-tailwindcss/src/extension.ts @@ -14,6 +14,9 @@ import { SymbolInformation, Position, Range, + languages, + WorkspaceEdit, + TextEdit, } from 'vscode' import type { DocumentFilter, @@ -205,6 +208,79 @@ export async function activate(context: ExtensionContext) { }), ) + async function applyAllCanonicalClasses(): Promise { + if (!Window.activeTextEditor) { + return + } + + let { document } = Window.activeTextEditor + let folder = Workspace.getWorkspaceFolder(document.uri) + + if (!folder || isExcluded(document.uri.fsPath, folder)) { + return + } + + // Get all diagnostics for the current document + let allDiagnostics = languages.getDiagnostics(document.uri) + + // Filter for SuggestCanonicalClasses diagnostics + // The diagnostic code will be 'suggestCanonicalClasses' based on DiagnosticKind enum + let canonicalDiagnostics = allDiagnostics.filter( + (diagnostic) => diagnostic.code === 'suggestCanonicalClasses', + ) + + if (canonicalDiagnostics.length === 0) { + Window.showInformationMessage('No canonical class suggestions found in this document.') + return + } + + // Create a workspace edit to apply all suggestions + let workspaceEdit = new WorkspaceEdit() + let edits: TextEdit[] = [] + + // Sort diagnostics by position (from end to start) to avoid range invalidation + canonicalDiagnostics.sort((a, b) => { + if (a.range.start.line !== b.range.start.line) { + return b.range.start.line - a.range.start.line + } + return b.range.start.character - a.range.start.character + }) + + for (let diagnostic of canonicalDiagnostics) { + // Access the canonical class suggestion directly from the suggestions property + // Type assertion needed since languages.getDiagnostics returns vscode.Diagnostic + let canonicalClass = (diagnostic as any).suggestions?.[0] + if (canonicalClass) { + edits.push(TextEdit.replace(diagnostic.range, canonicalClass)) + } + } + + workspaceEdit.set(document.uri, edits) + + // Apply the workspace edit + let success = await Workspace.applyEdit(workspaceEdit) + + if (success) { + let count = edits.length + Window.showInformationMessage( + `Applied ${count} canonical class suggestion${count === 1 ? '' : 's'}.`, + ) + } else { + Window.showWarningMessage('Failed to apply canonical class suggestions.') + } + } + + context.subscriptions.push( + commands.registerCommand('tailwindCSS.applyAllCanonicalClasses', async () => { + try { + await applyAllCanonicalClasses() + } catch (error) { + let message = error instanceof Error ? error.message : 'Unknown error' + Window.showWarningMessage(`Couldn't apply canonical class suggestions: ${message}`) + } + }), + ) + context.subscriptions.push( Window.onDidChangeActiveTextEditor(async () => { await updateActiveTextEditorContext()