preview_changes_enhanced
Preview code changes in multiple formats like unified, side-by-side, stat, or word-diff. Control context lines, ignore whitespace, filter by file pattern, and set working directory.
Instructions
Enhanced change preview with multiple format options
Tool call template
This tool declares no required parameters. Add optional parameters from the input schema as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {},
"name": "preview_changes_enhanced"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| format | No | Preview format | |
| contextLines | No | Number of context lines | |
| ignoreWhitespace | No | Ignore whitespace changes | |
| filePattern | No | File pattern filter | |
| cwd | No | Working directory |
Implementation Reference
- src/services/GitService.ts:1410-1598 (handler)The main handler function for 'preview_changes_enhanced'. Accepts options: format, contextLines, ignoreWhitespace, filePattern, cwd. Checks git repo, retrieves staged/unstaged diffs (with optional file pattern filtering), builds an enhanced preview output with summary stats.
async previewChangesEnhanced(options: { format?: 'unified' | 'side-by-side' | 'stat' | 'word-diff'; contextLines?: number; ignoreWhitespace?: boolean; filePattern?: string; cwd?: string; } = {}): Promise<ToolResult> { try { const { format = 'unified', contextLines = 3, ignoreWhitespace = false, filePattern, cwd } = options; const workingDir = cwd || this.workspaceService.getCurrentWorkspace(); // Check if we're in a git repository first const gitCheckResult = await this.gitCommand(['rev-parse', '--git-dir'], workingDir); if (gitCheckResult.isError) { return { isError: true, content: [{ type: 'text', text: `Failed to preview changes: ${gitCheckResult.content[0]?.text || 'Not a git repository'}` }] }; } let output = `Change Preview (${format} format):\n\n`; // Add format-specific headers and options if (format === 'side-by-side') { output += 'Side-by-side comparison:\n\n'; } else if (ignoreWhitespace) { output += 'Ignoring whitespace changes:\n\n'; } else if (filePattern) { output += `File Pattern: ${filePattern}\n\n`; } output += 'Enhanced Change Preview:\n\n'; // Get unstaged changes const unstagedOptions: GitDiffOptions = { staged: false, format, contextLines, ignoreWhitespace, cwd: workingDir }; // Get staged changes const stagedOptions: GitDiffOptions = { staged: true, format, contextLines, ignoreWhitespace, cwd: workingDir }; // Apply file pattern filtering if specified if (filePattern) { // Get list of files matching pattern first const statusResult = await this.gitStatus({ cwd: workingDir }); if (!statusResult.isError && statusResult.content[0]?.text) { const statusLines = statusResult.content[0].text.split('\n').filter(line => line.trim()); const matchingFiles = statusLines .map(line => line.substring(2).trim()) // Remove git status prefix .filter(filename => { // Simple glob matching for *.ext pattern if (filePattern.startsWith('*.')) { const ext = filePattern.substring(2); return filename.endsWith(ext); } // For other patterns, use simple includes for now return filename.includes(filePattern.replace('*', '')); }); // If we have matching files, process them individually if (matchingFiles.length > 0) { let unstagedChanges = ''; let stagedChanges = ''; for (const file of matchingFiles) { const unstagedFileResult = await this.enhancedGitDiff({ ...unstagedOptions, file }); const stagedFileResult = await this.enhancedGitDiff({ ...stagedOptions, file }); if (!unstagedFileResult.isError && unstagedFileResult.content[0]?.text?.trim() && !unstagedFileResult.content[0].text.includes('No changes found')) { unstagedChanges += unstagedFileResult.content[0].text + '\n'; } if (!stagedFileResult.isError && stagedFileResult.content[0]?.text?.trim() && !stagedFileResult.content[0].text.includes('No changes found')) { stagedChanges += stagedFileResult.content[0].text + '\n'; } } // Display filtered results if (stagedChanges) { output += 'Staged Changes:\n'; output += stagedChanges; output += '\n'; } if (unstagedChanges) { output += 'Unstaged Changes:\n'; output += unstagedChanges; output += '\n'; } } else { output += `No files matching pattern "${filePattern}" have changes.\n`; } } } else { // No file pattern filtering - get all changes const unstagedResult = await this.enhancedGitDiff(unstagedOptions); const stagedResult = await this.enhancedGitDiff(stagedOptions); // Display staged changes if (!stagedResult.isError && stagedResult.content[0]?.text?.trim() && !stagedResult.content[0].text.includes('Command completed successfully') && !stagedResult.content[0].text.includes('No changes found')) { output += 'Staged Changes:\n'; output += stagedResult.content[0].text; output += '\n\n'; } // Display unstaged changes if (!unstagedResult.isError && unstagedResult.content[0]?.text?.trim() && !unstagedResult.content[0].text.includes('Command completed successfully') && !unstagedResult.content[0].text.includes('No changes found')) { output += 'Unstaged Changes:\n'; output += unstagedResult.content[0].text; output += '\n\n'; } } // Get stats for both const stagedStats = await this.getDiffStats({ staged: true, cwd: workingDir }); const unstagedStats = await this.getDiffStats({ staged: false, cwd: workingDir }); output += '=== SUMMARY ===\n'; if (!stagedStats.isError && stagedStats.content[0]?._meta) { const meta = stagedStats.content[0]._meta as any; if (meta.filesChanged > 0) { output += `Staged: ${meta.filesChanged} files, +${meta.insertions}/-${meta.deletions} lines\n`; } } if (!unstagedStats.isError && unstagedStats.content[0]?._meta) { const meta = unstagedStats.content[0]._meta as any; if (meta.filesChanged > 0) { output += `Unstaged: ${meta.filesChanged} files, +${meta.insertions}/-${meta.deletions} lines\n`; } } if (!output.includes('STAGED CHANGES') && !output.includes('UNSTAGED CHANGES')) { output += 'No changes to preview'; } return { content: [{ type: 'text', text: output, _meta: { format, stagedStats: stagedStats.content[0]?._meta, unstagedStats: unstagedStats.content[0]?._meta } }] }; } catch (error) { return { isError: true, content: [{ type: 'text', text: `Enhanced preview failed: ${error instanceof Error ? error.message : String(error)}` }] }; - src/toolDefinitions.ts:824-843 (schema)Input schema definition for 'preview_changes_enhanced' tool. Defines properties: format (enum: unified, side-by-side, stat, word-diff), contextLines, ignoreWhitespace, filePattern, cwd.
{ name: 'preview_changes_enhanced', description: 'Enhanced change preview with multiple format options', inputSchema: { type: 'object', properties: { format: { type: 'string', enum: ['unified', 'side-by-side', 'stat', 'word-diff'], description: 'Preview format' }, contextLines: { type: 'number', description: 'Number of context lines' }, ignoreWhitespace: { type: 'boolean', description: 'Ignore whitespace changes' }, filePattern: { type: 'string', description: 'File pattern filter' }, cwd: { type: 'string', description: 'Working directory' } } } }, // Enhanced File Operations & Diff Management - src/index.ts:450-451 (registration)Registration/case branch in index.ts that routes 'preview_changes_enhanced' to gitService.previewChangesEnhanced(args).
case 'preview_changes_enhanced': return await this.gitService.previewChangesEnhanced(args); - src/services/GitService.ts:1454-1469 (helper)Helper calls to getDiffStats and enhancedGitDiff used within the previewChangesEnhanced handler to retrieve and format diff data for both staged and unstaged changes.
const unstagedOptions: GitDiffOptions = { staged: false, format, contextLines, ignoreWhitespace, cwd: workingDir }; // Get staged changes const stagedOptions: GitDiffOptions = { staged: true, format, contextLines, ignoreWhitespace, cwd: workingDir };