Просмотр исходного кода

Open diff editor with virtual document for new files or edits

Saoud Rizwan 1 год назад
Родитель
Сommit
3fc5f2aac0
2 измененных файлов с 50 добавлено и 1 удалено
  1. 34 1
      src/ClaudeDev.ts
  2. 16 0
      src/extension.ts

+ 34 - 1
src/ClaudeDev.ts

@@ -383,7 +383,19 @@ export class ClaudeDev {
 					})
 					.join("")
 
-				vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false })
+				// Create virtual document with new file, then open diff editor
+				const fileName = path.basename(filePath)
+				vscode.commands.executeCommand(
+					"vscode.diff",
+					vscode.Uri.file(filePath),
+					// to create a virtual doc we use a uri scheme registered in extension.ts, which then converts this base64 content into a text document
+					// (providing file name with extension in the uri lets vscode know the language of the file and apply syntax highlighting)
+					vscode.Uri.parse(`claude-dev-diff:${fileName}`).with({
+						query: Buffer.from(newContent).toString("base64"),
+					}),
+					`${fileName}: Original ↔ Suggested Changes`
+				)
+
 				const { response, text } = await this.ask(
 					"tool",
 					JSON.stringify({
@@ -392,6 +404,10 @@ export class ClaudeDev {
 						diff: diffRepresentation,
 					} as ClaudeSayTool)
 				)
+				// close the diff view if it's open
+				if (vscode.window.activeTextEditor?.document.uri.scheme === "claude-dev-diff") {
+					await vscode.commands.executeCommand("workbench.action.closeActiveEditor")
+				}
 				if (response !== "yesButtonTapped") {
 					if (response === "textResponse" && text) {
 						await this.say("user_feedback", text)
@@ -401,12 +417,29 @@ export class ClaudeDev {
 				}
 
 				await fs.writeFile(filePath, newContent)
+				// Finish by opening the edited file in the editor
+				vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false })
 				return `Changes applied to ${filePath}:\n${diffResult}`
 			} else {
+				const fileName = path.basename(filePath)
+				vscode.commands.executeCommand(
+					"vscode.diff",
+					vscode.Uri.parse(`claude-dev-diff:${fileName}`).with({
+						query: Buffer.from("").toString("base64"),
+					}),
+					vscode.Uri.parse(`claude-dev-diff:${fileName}`).with({
+						query: Buffer.from(newContent).toString("base64"),
+					}),
+					`${fileName}: New File`
+				)
+
 				const { response, text } = await this.ask(
 					"tool",
 					JSON.stringify({ tool: "newFileCreated", path: filePath, content: newContent } as ClaudeSayTool)
 				)
+				if (vscode.window.activeTextEditor?.document.uri.scheme === "claude-dev-diff") {
+					await vscode.commands.executeCommand("workbench.action.closeActiveEditor")
+				}
 				if (response !== "yesButtonTapped") {
 					if (response === "textResponse" && text) {
 						await this.say("user_feedback", text)

+ 16 - 0
src/extension.ts

@@ -86,6 +86,22 @@ export function activate(context: vscode.ExtensionContext) {
 			sidebarProvider.postMessageToWebview({ type: "action", action: "settingsButtonTapped" })
 		})
 	)
+
+	/*
+	We use the text document content provider API to show a diff view for new files/edits by creating a virtual document for the new content.
+
+	- This API allows you to create readonly documents in VSCode from arbitrary sources, and works by claiming an uri-scheme for which your provider then returns text contents. The scheme must be provided when registering a provider and cannot change afterwards.
+	- Note how the provider doesn't create uris for virtual documents - its role is to provide contents given such an uri. In return, content providers are wired into the open document logic so that providers are always considered.
+	https://code.visualstudio.com/api/extension-guides/virtual-documents
+	*/
+	const diffContentProvider = new (class implements vscode.TextDocumentContentProvider {
+		provideTextDocumentContent(uri: vscode.Uri): string {
+			return Buffer.from(uri.query, "base64").toString("utf-8")
+		}
+	})()
+	context.subscriptions.push(
+		vscode.workspace.registerTextDocumentContentProvider("claude-dev-diff", diffContentProvider)
+	)
 }
 
 // This method is called when your extension is deactivated