mirror of
https://github.com/Gmaker689/ai-diff-preview.git
synced 2026-10-08 18:31:51 +08:00
feat: 初始化 AI Code Diff Preview 插件项目
- 核心架构搭建:四层架构设计(触发层、隔离层、Diff引擎、UI层) - 快照管理器:管理 Base/Suggest 双版本,隔离 AI 生成代码 - Diff 引擎:基于 Myers 算法计算差异,生成变更块 - 内联装饰器:红绿高亮显示删除/新增行 - CodeLens 提供器:提供 Accept/Reject 按钮 - 事务处理:Accept/Reject 原子化操作 - Claude Hooks 集成:支持 after_code_edit/after_write_file 事件 - 状态栏显示:实时显示变更状态 - 基础测试用例:7 个测试全部通过 技术栈:TypeScript + VSCode Extension API + diff 库 + esbuild
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* 快照管理器 - 管理文件的 Base/Suggest 双版本
|
||||
*/
|
||||
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { Snapshot, DiffChunk, ChunkStatus } from '../models/types';
|
||||
|
||||
export class SnapshotManager {
|
||||
private snapshots: Map<string, Snapshot> = new Map();
|
||||
private filePathIndex: Map<string, string> = new Map(); // filePath -> snapshotId
|
||||
|
||||
/**
|
||||
* 创建 Base 快照
|
||||
*/
|
||||
createBaseSnapshot(filePath: string, baseContent: string): string {
|
||||
const id = uuidv4();
|
||||
const snapshot: Snapshot = {
|
||||
id,
|
||||
filePath,
|
||||
baseContent,
|
||||
suggestContent: '',
|
||||
timestamp: Date.now(),
|
||||
chunks: [],
|
||||
status: 'active',
|
||||
};
|
||||
|
||||
this.snapshots.set(id, snapshot);
|
||||
this.filePathIndex.set(filePath, id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用 AI 生成的 Patch
|
||||
*/
|
||||
applyPatch(snapshotId: string, patch: string, chunks: DiffChunk[]): void {
|
||||
const snapshot = this.snapshots.get(snapshotId);
|
||||
if (!snapshot) {
|
||||
throw new Error(`快照不存在: ${snapshotId}`);
|
||||
}
|
||||
|
||||
snapshot.suggestContent = patch;
|
||||
snapshot.chunks = chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取快照
|
||||
*/
|
||||
getSnapshot(snapshotId: string): Snapshot | undefined {
|
||||
return this.snapshots.get(snapshotId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件路径获取快照
|
||||
*/
|
||||
getSnapshotByFilePath(filePath: string): Snapshot | undefined {
|
||||
const snapshotId = this.filePathIndex.get(filePath);
|
||||
if (!snapshotId) return undefined;
|
||||
return this.snapshots.get(snapshotId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新变更块状态
|
||||
*/
|
||||
updateChunkStatus(snapshotId: string, chunkId: string, status: ChunkStatus): void {
|
||||
const snapshot = this.snapshots.get(snapshotId);
|
||||
if (!snapshot) return;
|
||||
|
||||
const chunk = snapshot.chunks.find(c => c.id === chunkId);
|
||||
if (chunk) {
|
||||
chunk.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新变更块状态
|
||||
*/
|
||||
updateAllChunksStatus(snapshotId: string, status: ChunkStatus): void {
|
||||
const snapshot = this.snapshots.get(snapshotId);
|
||||
if (!snapshot) return;
|
||||
|
||||
snapshot.chunks.forEach(chunk => {
|
||||
chunk.status = status;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记快照完成
|
||||
*/
|
||||
completeSnapshot(snapshotId: string): void {
|
||||
const snapshot = this.snapshots.get(snapshotId);
|
||||
if (!snapshot) return;
|
||||
|
||||
snapshot.status = 'completed';
|
||||
this.filePathIndex.delete(snapshot.filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消快照
|
||||
*/
|
||||
cancelSnapshot(snapshotId: string): void {
|
||||
const snapshot = this.snapshots.get(snapshotId);
|
||||
if (!snapshot) return;
|
||||
|
||||
snapshot.status = 'cancelled';
|
||||
this.filePathIndex.delete(snapshot.filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除快照
|
||||
*/
|
||||
deleteSnapshot(snapshotId: string): void {
|
||||
const snapshot = this.snapshots.get(snapshotId);
|
||||
if (snapshot) {
|
||||
this.filePathIndex.delete(snapshot.filePath);
|
||||
}
|
||||
this.snapshots.delete(snapshotId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有活跃快照
|
||||
*/
|
||||
getActiveSnapshots(): Snapshot[] {
|
||||
return Array.from(this.snapshots.values()).filter(s => s.status === 'active');
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否有活跃快照
|
||||
*/
|
||||
hasActiveSnapshot(filePath: string): boolean {
|
||||
const snapshotId = this.filePathIndex.get(filePath);
|
||||
if (!snapshotId) return false;
|
||||
const snapshot = this.snapshots.get(snapshotId);
|
||||
return snapshot?.status === 'active';
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理已完成或取消的快照
|
||||
*/
|
||||
cleanup(): void {
|
||||
for (const [id, snapshot] of this.snapshots.entries()) {
|
||||
if (snapshot.status !== 'active') {
|
||||
this.filePathIndex.delete(snapshot.filePath);
|
||||
this.snapshots.delete(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user