import * as vscode from "vscode"; import * as path from "path"; import { GitService } from "./GitService"; export class GViewProvider implements vscode.WebviewViewProvider { public static readonly viewType = "gitcommitfilter.view"; private _view?: vscode.WebviewView; constructor( private context: vscode.ExtensionContext, private readonly _gitService: GitService ) {} public resolveWebviewView( webviewView: vscode.WebviewView, context: vscode.WebviewViewResolveContext ) { webviewView.webview.options = { enableScripts: true }; this._view = webviewView; webviewView.webview.html = this.generateHtml(webviewView); // 添加事件监听器 webviewView.webview.onDidReceiveMessage( (message: { command: any; text: any; filePath: any; hash: any; }) => { switch (message.command) { case "filterCommits": const filterText = message.text; this.filterCommits(filterText); return; case "openFile": const filePath = message.filePath; const commit = message.hash; this.openDiff(commit, filePath); return; } }, undefined, this.context.subscriptions ); } private makeUri(repoPath:string, filePath:string, commit:string) { const repoUri = vscode.Uri.file(repoPath) const fUri = vscode.Uri.joinPath(repoUri, filePath); const params = { path: fUri.fsPath, ref: commit } return fUri.with({ scheme: 'git',path:fUri.path, query: JSON.stringify(params) }); } private async openDiff(commitId: string, filePath: string) { const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; if (!workspaceFolder) { vscode.window.showErrorMessage('Please open a workspace folder first'); return; } try { const rawPrevCommit = await this._gitService.getPreviousCommit(commitId); const previousCommitId = rawPrevCommit?.trim(); // 去除可能的换行符 if (!previousCommitId) { vscode.window.showErrorMessage('Cannot find previous commit'); return; } // 编码处理 const encodedCommit = encodeURIComponent(commitId.trim()); const encodedPrevCommit = encodeURIComponent(previousCommitId); const sanitizedWorkPath = workspaceFolder.replace(/\\/g, '/') .replace(/'/g, "'") .replace(/ /g, " "); const sanitizedFilePath = filePath.replace(/\\/g, '/') .replace(/'/g, "'") .replace(/ /g, " "); // 构造 URI const currentUri = this.makeUri(sanitizedWorkPath, sanitizedFilePath, encodedCommit); const previousUri = this.makeUri(sanitizedWorkPath, sanitizedFilePath, encodedPrevCommit); await vscode.commands.executeCommand( "vscode.diff", previousUri, currentUri, `Changes: ${path.basename(filePath)} (${previousCommitId.slice(0,7)} → ${commitId.slice(0,7)})` ); } catch (error) { vscode.window.showErrorMessage(`Failed to open diff: ${error instanceof Error ? error.message : error}`); } } generateHtml(webviewView: vscode.WebviewView) { return ` Git Commit Filter
过滤
`; } private async filterCommits(filterText: string) { if (this._view) { const commits = await this._gitService.getCommits(filterText); this._view.webview.postMessage({ command: "updateCommits", commits }); } } }