Skip to content

Commit ba96d02

Browse files
committed
Add streaming diff animation features from bugbash branch
- Add messages.ts with streaming diff animation support - Add complete diffAnimation module with: - Animation queue management - Chat processing capabilities - Diff analysis and animation control - File system management - VSCode integration - Webview management - Streaming diff controller
1 parent 4028800 commit ba96d02

File tree

12 files changed

+3703
-38
lines changed

12 files changed

+3703
-38
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# DiffAnimation Module Refactoring
2+
3+
## Overview
4+
5+
The `diffAnimation` directory has been refactored from 2 large files (~1700 lines total) into 9 smaller, focused modules following the Single Responsibility Principle. This improves maintainability, testability, and code organization while preserving all existing functionality.
6+
7+
## File Structure
8+
9+
### Core Files
10+
11+
- **`diffAnimationHandler.ts`** - Main orchestrator and public API (reduced from ~800 to ~300 lines)
12+
- **`diffAnimationController.ts`** - Animation control and coordination (reduced from ~900 to ~400 lines)
13+
14+
### Supporting Components
15+
16+
- **`types.ts`** - Shared TypeScript interfaces and types
17+
- **`fileSystemManager.ts`** - File system operations, path resolution, and file watching
18+
- **`chatProcessor.ts`** - Chat message processing and tool use handling
19+
- **`animationQueueManager.ts`** - Animation queuing and coordination logic
20+
- **`webviewManager.ts`** - Webview creation, HTML generation, and messaging
21+
- **`diffAnalyzer.ts`** - Diff calculation, line parsing, and scan planning
22+
- **`vscodeIntegration.ts`** - VS Code API integration and utilities
23+
24+
## Architecture
25+
26+
```
27+
DiffAnimationHandler (Main Entry Point)
28+
├── FileSystemManager (File Operations)
29+
├── ChatProcessor (Message Processing)
30+
├── AnimationQueueManager (Queue Management)
31+
└── DiffAnimationController (Animation Control)
32+
├── WebviewManager (UI Management)
33+
├── DiffAnalyzer (Diff Logic)
34+
└── VSCodeIntegration (VS Code APIs)
35+
```
36+
37+
## Key Benefits
38+
39+
### 1. **Improved Maintainability**
40+
41+
- Each component has a single, clear responsibility
42+
- Easier to locate and modify specific functionality
43+
- Reduced cognitive load when working on individual features
44+
45+
### 2. **Better Testability**
46+
47+
- Components can be unit tested in isolation
48+
- Dependencies are injected, making mocking easier
49+
- Clear interfaces between components
50+
51+
### 3. **Enhanced Reusability**
52+
53+
- Components can be reused in different contexts
54+
- Easier to extract functionality for other features
55+
- Clear separation of concerns
56+
57+
### 4. **Preserved Functionality**
58+
59+
- All existing public APIs remain unchanged
60+
- No breaking changes to external consumers
61+
- Backward compatibility maintained
62+
63+
## Component Responsibilities
64+
65+
### FileSystemManager
66+
67+
- File system watching and event handling
68+
- Path resolution and normalization
69+
- File content capture and preparation
70+
- Directory creation and file operations
71+
72+
### ChatProcessor
73+
74+
- Chat message parsing and processing
75+
- Tool use detection and handling
76+
- Message deduplication
77+
- File write preparation coordination
78+
79+
### AnimationQueueManager
80+
81+
- Animation queuing for concurrent file changes
82+
- Animation state management
83+
- Queue processing and coordination
84+
- Statistics and monitoring
85+
86+
### WebviewManager
87+
88+
- Webview panel creation and management
89+
- HTML content generation
90+
- Message passing between extension and webview
91+
- Auto-scroll control and user interaction handling
92+
93+
### DiffAnalyzer
94+
95+
- Diff calculation and analysis
96+
- Changed region detection
97+
- Scan plan creation for animations
98+
- Animation timing calculations
99+
- Complexity analysis for optimization
100+
101+
### VSCodeIntegration
102+
103+
- VS Code API abstractions
104+
- Built-in diff view integration
105+
- Editor operations and file management
106+
- Status messages and user notifications
107+
- Configuration and theme management
108+
109+
## Migration Notes
110+
111+
### For Developers
112+
113+
- Import paths remain the same for main classes
114+
- All public methods and interfaces are preserved
115+
- Internal implementation is now modular but transparent to consumers
116+
117+
### For Testing
118+
119+
- Individual components can now be tested in isolation
120+
- Mock dependencies can be easily injected
121+
- Test coverage can be more granular and focused
122+
123+
### For Future Development
124+
125+
- New features can be added to specific components
126+
- Components can be enhanced without affecting others
127+
- Clear boundaries make refactoring safer and easier
128+
129+
## ESLint Compliance
130+
131+
All files follow the project's ESLint configuration:
132+
133+
- Proper TypeScript typing
134+
- Consistent code formatting
135+
- No unused imports or variables
136+
- Proper error handling patterns
137+
138+
## Performance Considerations
139+
140+
- No performance impact from refactoring
141+
- Same memory usage patterns
142+
- Identical animation behavior
143+
- Preserved optimization strategies
144+
145+
## Future Enhancements
146+
147+
The modular structure enables several future improvements:
148+
149+
1. **Enhanced Testing**: Unit tests for individual components
150+
2. **Performance Monitoring**: Better metrics collection per component
151+
3. **Feature Extensions**: Easier addition of new animation types
152+
4. **Configuration**: Component-level configuration options
153+
5. **Debugging**: Better error isolation and debugging capabilities
154+
155+
## Conclusion
156+
157+
This refactoring successfully breaks down the large `diffAnimation` codebase into manageable, focused components while maintaining full backward compatibility and functionality. The new structure provides a solid foundation for future development and maintenance.
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { getLogger } from 'aws-core-vscode/shared'
7+
import { QueuedAnimation, PendingFileWrite } from './types'
8+
import { FileSystemManager } from './fileSystemManager'
9+
10+
export class AnimationQueueManager {
11+
// Track which files are being animated
12+
private animatingFiles = new Set<string>()
13+
// Animation queue for handling multiple changes
14+
private animationQueue = new Map<string, QueuedAnimation[]>()
15+
16+
constructor(
17+
private fileSystemManager: FileSystemManager,
18+
private startFullAnimation: (
19+
filePath: string,
20+
originalContent: string,
21+
newContent: string,
22+
toolUseId: string
23+
) => Promise<void>,
24+
private startPartialAnimation: (
25+
filePath: string,
26+
originalContent: string,
27+
newContent: string,
28+
changeLocation: { startLine: number; endLine: number },
29+
toolUseId: string
30+
) => Promise<void>
31+
) {}
32+
33+
/**
34+
* Check if a file is currently being animated
35+
*/
36+
public isAnimating(filePath: string): boolean {
37+
return this.animatingFiles.has(filePath)
38+
}
39+
40+
/**
41+
* Mark file as animating
42+
*/
43+
public markAsAnimating(filePath: string): void {
44+
this.animatingFiles.add(filePath)
45+
}
46+
47+
/**
48+
* Mark file as no longer animating
49+
*/
50+
public markAsNotAnimating(filePath: string): void {
51+
this.animatingFiles.delete(filePath)
52+
}
53+
54+
/**
55+
* Queue an animation for later processing
56+
*/
57+
public queueAnimation(filePath: string, animation: QueuedAnimation): void {
58+
const queue = this.animationQueue.get(filePath) || []
59+
queue.push(animation)
60+
this.animationQueue.set(filePath, queue)
61+
getLogger().info(`[AnimationQueueManager] 📋 Queued animation for ${filePath} (queue size: ${queue.length})`)
62+
}
63+
64+
/**
65+
* Start animation and handle queuing logic
66+
*/
67+
public async startAnimation(filePath: string, pendingWrite: PendingFileWrite, newContent: string): Promise<void> {
68+
// If already animating, queue the change
69+
if (this.isAnimating(filePath)) {
70+
this.queueAnimation(filePath, {
71+
originalContent: pendingWrite.originalContent,
72+
newContent,
73+
toolUseId: pendingWrite.toolUseId,
74+
changeLocation: pendingWrite.changeLocation,
75+
})
76+
return
77+
}
78+
79+
// Mark as animating
80+
this.markAsAnimating(filePath)
81+
82+
try {
83+
// Check if we have change location for partial update
84+
if (pendingWrite.changeLocation) {
85+
// Use partial animation for targeted changes
86+
await this.startPartialAnimation(
87+
filePath,
88+
pendingWrite.originalContent,
89+
newContent,
90+
pendingWrite.changeLocation,
91+
pendingWrite.toolUseId
92+
)
93+
} else {
94+
// Use full file animation
95+
await this.startFullAnimation(
96+
filePath,
97+
pendingWrite.originalContent,
98+
newContent,
99+
pendingWrite.toolUseId
100+
)
101+
}
102+
103+
// Process queued animations
104+
await this.processQueuedAnimations(filePath)
105+
} finally {
106+
// Always mark as not animating when done
107+
this.markAsNotAnimating(filePath)
108+
}
109+
}
110+
111+
/**
112+
* Process queued animations for a file
113+
*/
114+
private async processQueuedAnimations(filePath: string): Promise<void> {
115+
const queue = this.animationQueue.get(filePath)
116+
if (!queue || queue.length === 0) {
117+
return
118+
}
119+
120+
const next = queue.shift()
121+
if (!next) {
122+
return
123+
}
124+
125+
getLogger().info(
126+
`[AnimationQueueManager] 🎯 Processing queued animation for ${filePath} (${queue.length} remaining)`
127+
)
128+
129+
// Use the current file content as the "original" for the next animation
130+
const currentContent = await this.fileSystemManager.getCurrentFileContent(filePath)
131+
132+
// Create a new pending write for the queued animation
133+
const queuedPendingWrite: PendingFileWrite = {
134+
filePath,
135+
originalContent: currentContent,
136+
toolUseId: next.toolUseId,
137+
timestamp: Date.now(),
138+
changeLocation: next.changeLocation,
139+
}
140+
141+
// Recursively start the next animation
142+
await this.startAnimation(filePath, queuedPendingWrite, next.newContent)
143+
}
144+
145+
/**
146+
* Get animation statistics
147+
*/
148+
public getAnimationStats(): { animatingCount: number; queuedCount: number; filePaths: string[] } {
149+
let queuedCount = 0
150+
for (const queue of this.animationQueue.values()) {
151+
queuedCount += queue.length
152+
}
153+
154+
return {
155+
animatingCount: this.animatingFiles.size,
156+
queuedCount,
157+
filePaths: Array.from(this.animatingFiles),
158+
}
159+
}
160+
161+
/**
162+
* Clear all queues and reset state
163+
*/
164+
public clearAll(): void {
165+
this.animatingFiles.clear()
166+
this.animationQueue.clear()
167+
getLogger().info('[AnimationQueueManager] 🧹 Cleared all animation queues and state')
168+
}
169+
170+
/**
171+
* Clear queue for a specific file
172+
*/
173+
public clearFileQueue(filePath: string): void {
174+
this.animationQueue.delete(filePath)
175+
this.markAsNotAnimating(filePath)
176+
getLogger().info(`[AnimationQueueManager] 🧹 Cleared queue for ${filePath}`)
177+
}
178+
}

0 commit comments

Comments
 (0)