Skip to content

Commit 1c736c9

Browse files
committed
git diff improvements.
splitting on both separators: uri.split(/[/\\]/) for getFileName/getFilePath. Prefer git diff stats for line counts and dropped full-content fallback for large files. Use getDiffStats() and simplify logic in mapDiffToFileChange(). Review issues Added fcoTextDocumentContentProvider.ts Added proper diff opening and closing of files to fcoTextDocumentContentProvider.ts better debounce and added batching timeoutRef should be cross-env safe. Prefer ReturnType<typeof setTimeout> over NodeJS.Timeout to avoid DOM vs Node typing issues. fixed language parenthesis issue
1 parent e6f0037 commit 1c736c9

File tree

9 files changed

+393
-80
lines changed

9 files changed

+393
-80
lines changed

src/extension.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { TerminalRegistry } from "./integrations/terminal/TerminalRegistry"
2828
import { McpServerManager } from "./services/mcp/McpServerManager"
2929
import { CodeIndexManager } from "./services/code-index/manager"
3030
import { MdmService } from "./services/mdm/MdmService"
31+
import { FcoTextDocumentContentProvider } from "./services/files-changed/FcoTextDocumentContentProvider"
3132
import { migrateSettings } from "./utils/migrateSettings"
3233
import { autoImportSettings } from "./utils/autoImportSettings"
3334
import { API } from "./extension/api"
@@ -253,6 +254,10 @@ export async function activate(context: vscode.ExtensionContext) {
253254
vscode.workspace.registerTextDocumentContentProvider(DIFF_VIEW_URI_SCHEME, diffContentProvider),
254255
)
255256

257+
// Register FCO (Files Changed Overview) diff content provider for performance optimization
258+
const fcoContentProvider = FcoTextDocumentContentProvider.getInstance()
259+
context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider("fco-diff", fcoContentProvider))
260+
256261
context.subscriptions.push(vscode.window.registerUriHandler({ handleUri }))
257262

258263
// Register code actions provider.
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import * as vscode from "vscode"
2+
3+
/**
4+
* Dedicated TextDocumentContentProvider for Files Changed Overview (FCO) diff viewing.
5+
* Eliminates base64 encoding in query strings by storing content in memory and serving it on-demand.
6+
*/
7+
export class FcoTextDocumentContentProvider implements vscode.TextDocumentContentProvider {
8+
private contentStore = new Map<string, string>()
9+
private fileToUriMapping = new Map<string, { beforeUri: string; afterUri: string }>()
10+
private static instance: FcoTextDocumentContentProvider
11+
12+
static getInstance(): FcoTextDocumentContentProvider {
13+
if (!this.instance) {
14+
this.instance = new FcoTextDocumentContentProvider()
15+
}
16+
return this.instance
17+
}
18+
19+
/**
20+
* Provides text document content for FCO diff URIs.
21+
* Called by VS Code when it needs the actual content for a URI.
22+
*/
23+
provideTextDocumentContent(uri: vscode.Uri): string {
24+
const content = this.contentStore.get(uri.path)
25+
if (!content) {
26+
console.warn(`FcoTextDocumentContentProvider: No content found for URI path: ${uri.path}`)
27+
return ""
28+
}
29+
return content
30+
}
31+
32+
/**
33+
* Stores before/after content for a diff session and returns clean URIs.
34+
* Uses content-based stable IDs to prevent duplicate diffs for same content.
35+
* No base64 encoding - content is stored in memory and served on-demand.
36+
*/
37+
storeDiffContent(
38+
beforeContent: string,
39+
afterContent: string,
40+
filePath?: string,
41+
): { beforeUri: string; afterUri: string } {
42+
// Create stable ID based on file path and content hash to prevent duplicates
43+
const contentHash = this.hashContent(beforeContent + afterContent + (filePath || ""))
44+
const beforeKey = `before-${contentHash}`
45+
const afterKey = `after-${contentHash}`
46+
47+
// Check if already exists - reuse existing URIs to prevent duplicate diffs
48+
if (this.contentStore.has(beforeKey)) {
49+
const beforeUri = `fco-diff:${beforeKey}`
50+
const afterUri = `fco-diff:${afterKey}`
51+
52+
// Update file mapping in case filePath changed
53+
if (filePath) {
54+
this.fileToUriMapping.set(filePath, { beforeUri, afterUri })
55+
}
56+
57+
return { beforeUri, afterUri }
58+
}
59+
60+
// Store new content in memory
61+
this.contentStore.set(beforeKey, beforeContent)
62+
this.contentStore.set(afterKey, afterContent)
63+
64+
// Return clean URIs without any base64 content
65+
const beforeUri = `fco-diff:${beforeKey}`
66+
const afterUri = `fco-diff:${afterKey}`
67+
68+
// Track file path to URI mapping for cleanup
69+
if (filePath) {
70+
this.fileToUriMapping.set(filePath, { beforeUri, afterUri })
71+
}
72+
73+
return { beforeUri, afterUri }
74+
}
75+
76+
/**
77+
* Get URIs for a specific file path (for diff tab management)
78+
*/
79+
getUrisForFile(filePath: string): { beforeUri: string; afterUri: string } | undefined {
80+
return this.fileToUriMapping.get(filePath)
81+
}
82+
83+
/**
84+
* Clean up all content associated with a specific file path
85+
*/
86+
cleanupFile(filePath: string): void {
87+
const uris = this.fileToUriMapping.get(filePath)
88+
if (uris) {
89+
this.cleanup([uris.beforeUri, uris.afterUri])
90+
this.fileToUriMapping.delete(filePath)
91+
}
92+
}
93+
94+
/**
95+
* Cleanup stored content to prevent memory leaks.
96+
* Should be called when diff tabs are closed.
97+
*/
98+
cleanup(uris: string[]): void {
99+
uris.forEach((uri) => {
100+
const key = uri.replace("fco-diff:", "")
101+
if (this.contentStore.delete(key)) {
102+
console.debug(`FcoTextDocumentContentProvider: Cleaned up content for ${key}`)
103+
}
104+
})
105+
}
106+
107+
/**
108+
* Create a stable hash from content for consistent IDs
109+
*/
110+
private hashContent(content: string): string {
111+
// Simple hash for stable IDs - ensures same content gets same ID
112+
let hash = 0
113+
for (let i = 0; i < content.length; i++) {
114+
const char = content.charCodeAt(i)
115+
hash = (hash << 5) - hash + char
116+
hash = hash & hash // Convert to 32-bit integer
117+
}
118+
return Math.abs(hash).toString(36)
119+
}
120+
121+
/**
122+
* Get total number of stored content items (for debugging/monitoring)
123+
*/
124+
getStoredContentCount(): number {
125+
return this.contentStore.size
126+
}
127+
128+
/**
129+
* Clear all stored content (for testing or cleanup)
130+
*/
131+
clearAll(): void {
132+
this.contentStore.clear()
133+
this.fileToUriMapping.clear()
134+
}
135+
}

src/services/files-changed/FilesChangedManager.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { diffLines } from "diff"
2-
31
import { FileChange, FileChangeset } from "@roo-code/types"
42
import type { FileContextTracker } from "../../core/context-tracking/FileContextTracker"
53

@@ -74,28 +72,6 @@ export class FilesChangedManager {
7472
public dispose(): void {
7573
this.clearFiles()
7674
}
77-
78-
/**
79-
* Utility helper for callers that need to compute diff stats themselves.
80-
*/
81-
public static calculateLineDifferences(
82-
originalContent: string,
83-
newContent: string,
84-
): { linesAdded: number; linesRemoved: number } {
85-
const hunks = diffLines(originalContent ?? "", newContent ?? "")
86-
let linesAdded = 0
87-
let linesRemoved = 0
88-
89-
for (const hunk of hunks) {
90-
if (hunk.added) {
91-
linesAdded += hunk.count ?? 0
92-
} else if (hunk.removed) {
93-
linesRemoved += hunk.count ?? 0
94-
}
95-
}
96-
97-
return { linesAdded, linesRemoved }
98-
}
9975
}
10076

10177
// Export the error types for backward compatibility

0 commit comments

Comments
 (0)