diff --git a/src/integrations/WorkspaceTracker.ts b/src/integrations/WorkspaceTracker.ts index aa3eeca..d868a15 100644 --- a/src/integrations/WorkspaceTracker.ts +++ b/src/integrations/WorkspaceTracker.ts @@ -11,27 +11,28 @@ class WorkspaceTracker { private filePaths: Set = new Set() constructor(provider: ClaudeDevProvider) { + console.log("WorkspaceTracker: Initializing") this.providerRef = new WeakRef(provider) this.registerListeners() } async initializeFilePaths() { + console.log("WorkspaceTracker: Initializing file paths") // should not auto get filepaths for desktop since it would immediately show permission popup before claude every creates a file if (!cwd) { + console.log("WorkspaceTracker: No workspace folder found") return } const [files, _] = await listFiles(cwd, true, 500) - files - .map((file) => { - const relativePath = path.relative(cwd, file) - return file.endsWith("/") ? relativePath + "/" : relativePath - }) - .forEach((file) => this.filePaths.add(file)) + console.log(`WorkspaceTracker: Found ${files.length} files`) + files.forEach((file) => this.filePaths.add(this.normalizeFilePath(file))) + console.log(this.filePaths) this.workspaceDidUpdate() } private registerListeners() { + console.log("WorkspaceTracker: Registering listeners") // Listen for file creation this.disposables.push(vscode.workspace.onDidCreateFiles(this.onFilesCreated.bind(this))) @@ -48,53 +49,65 @@ class WorkspaceTracker { this.disposables.push(vscode.workspace.onDidChangeWorkspaceFolders(this.onWorkspaceFoldersChanged.bind(this))) } - private onFilesCreated(event: vscode.FileCreateEvent) { - event.files.forEach(async (file) => { - this.filePaths.add(file.fsPath) - this.workspaceDidUpdate() - }) + private async onFilesCreated(event: vscode.FileCreateEvent) { + console.log(`WorkspaceTracker: Files created - ${event.files.length} file(s)`) + await Promise.all( + event.files.map(async (file) => { + await this.addFilePath(file.fsPath) + }) + ) + this.workspaceDidUpdate() } - private onFilesDeleted(event: vscode.FileDeleteEvent) { - event.files.forEach((file) => { - if (this.filePaths.delete(file.fsPath)) { - this.workspaceDidUpdate() - } - }) + private async onFilesDeleted(event: vscode.FileDeleteEvent) { + console.log(`WorkspaceTracker: Files deleted - ${event.files.length} file(s)`) + let updated = false + await Promise.all( + event.files.map(async (file) => { + if (await this.removeFilePath(file.fsPath)) { + updated = true + } + }) + ) + if (updated) { + this.workspaceDidUpdate() + } } - private onFilesRenamed(event: vscode.FileRenameEvent) { - event.files.forEach(async (file) => { - this.filePaths.delete(file.oldUri.fsPath) - this.filePaths.add(file.newUri.fsPath) - this.workspaceDidUpdate() - }) + private async onFilesRenamed(event: vscode.FileRenameEvent) { + console.log(`WorkspaceTracker: Files renamed - ${event.files.length} file(s)`) + await Promise.all( + event.files.map(async (file) => { + await this.removeFilePath(file.oldUri.fsPath) + await this.addFilePath(file.newUri.fsPath) + }) + ) + this.workspaceDidUpdate() } private async onFileChanged(event: vscode.TextDocumentChangeEvent) { - const filePath = event.document.uri.fsPath + const filePath = await this.addFilePath(event.document.uri.fsPath) if (!this.filePaths.has(filePath)) { + console.log(`WorkspaceTracker: New file changed - ${filePath}`) this.filePaths.add(filePath) this.workspaceDidUpdate() } } private async onWorkspaceFoldersChanged(event: vscode.WorkspaceFoldersChangeEvent) { + console.log( + `WorkspaceTracker: Workspace folders changed - Added: ${event.added.length}, Removed: ${event.removed.length}` + ) for (const folder of event.added) { const [files, _] = await listFiles(folder.uri.fsPath, true, 50) // at most 50 files - if (!cwd) { - continue - } - files - .map((file) => { - const relativePath = path.relative(cwd, file) - return file.endsWith("/") ? relativePath + "/" : relativePath - }) - .forEach((file) => this.filePaths.add(file)) + console.log(`WorkspaceTracker: Adding ${files.length} files from new folder`) + await Promise.all(files.map((file) => this.addFilePath(file))) } for (const folder of event.removed) { + const folderPath = await this.addFilePath(folder.uri.fsPath) + console.log(`WorkspaceTracker: Removing files from deleted folder - ${folderPath}`) this.filePaths.forEach((filePath) => { - if (filePath.startsWith(folder.uri.fsPath)) { + if (filePath.startsWith(folderPath)) { this.filePaths.delete(filePath) } }) @@ -103,19 +116,46 @@ class WorkspaceTracker { } private workspaceDidUpdate() { - console.log("Workspace updated. Current file paths:", Array.from(this.filePaths)) - // Add your logic here for when the workspace is updated + console.log(`WorkspaceTracker: Workspace updated. Current file count: ${this.filePaths.size}`) + if (!cwd) { + return + } this.providerRef.deref()?.postMessageToWebview({ type: "workspaceUpdated", - filePaths: Array.from(this.filePaths), + filePaths: Array.from(this.filePaths).map((file) => { + const relativePath = path.relative(cwd, file) + return file.endsWith("/") ? relativePath + "/" : relativePath + }), }) } - public getFilePaths(): string[] { - return Array.from(this.filePaths) + private normalizeFilePath(filePath: string): string { + const resolvedPath = path.resolve(filePath) + return filePath.endsWith("/") ? resolvedPath + "/" : resolvedPath + } + + private async addFilePath(filePath: string): Promise { + const normalizedPath = this.normalizeFilePath(filePath) + try { + const stat = await vscode.workspace.fs.stat(vscode.Uri.file(normalizedPath)) + const isDirectory = (stat.type & vscode.FileType.Directory) !== 0 + const pathWithSlash = isDirectory && !normalizedPath.endsWith("/") ? normalizedPath + "/" : normalizedPath + this.filePaths.add(pathWithSlash) + return pathWithSlash + } catch { + // If stat fails, assume it's a file (this can happen for newly created files) + this.filePaths.add(normalizedPath) + return normalizedPath + } + } + + private async removeFilePath(filePath: string): Promise { + const normalizedPath = this.normalizeFilePath(filePath) + return this.filePaths.delete(normalizedPath) || this.filePaths.delete(normalizedPath + "/") } public dispose() { + console.log("WorkspaceTracker: Disposing") this.disposables.forEach((d) => d.dispose()) } } diff --git a/src/parse-source-code/index.ts b/src/parse-source-code/index.ts index a0c56a6..4a595c7 100644 --- a/src/parse-source-code/index.ts +++ b/src/parse-source-code/index.ts @@ -90,7 +90,7 @@ export async function listFiles(dirPath: string, recursive: boolean, limit: numb cwd: dirPath, dot: true, // do not ignore hidden files/directories absolute: true, - markDirectories: true, // Append a / on any directories matched + markDirectories: true, // Append a / on any directories matched (/ is used on windows as well, so dont use path.sep) gitignore: recursive, // globby ignores any files that are gitignored ignore: recursive ? dirsToIgnore : undefined, // just in case there is no gitignore, we ignore sensible defaults onlyFiles: false, // true by default, false means it will list directories on their own too diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index 44aaa7d..cf47f52 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -144,24 +144,23 @@ vscode-dropdown::part(listbox) { } .mention-context-highlight { - background-color: var(--vscode-textLink-activeForeground, #3794ff); - opacity: 0.3; + background-color: color-mix(in srgb, var(--vscode-badge-foreground) 30%, transparent); border-radius: 3px; - box-shadow: 0 0 0 0.5px var(--vscode-textLink-activeForeground, #3794ff); + box-shadow: 0 0 0 0.5px color-mix(in srgb, var(--vscode-badge-foreground) 30%, transparent); color: transparent; - padding: 0.5px; + /* padding: 0.5px; margin: -0.5px; position: relative; - bottom: -0.5px; + bottom: -0.5px; */ } .mention-context-highlight-visible-with-shadow { - background-color: color-mix(in srgb, var(--vscode-badge-foreground) 35%, transparent); + background-color: color-mix(in srgb, var(--vscode-badge-foreground) 30%, transparent); border-radius: 3px; - box-shadow: 0 0 0 0.5px color-mix(in srgb, var(--vscode-badge-foreground) 35%, transparent); + box-shadow: 0 0 0 0.5px color-mix(in srgb, var(--vscode-badge-foreground) 30%, transparent); } .mention-context-highlight-visible-without-shadow { - background-color: color-mix(in srgb, var(--vscode-badge-foreground) 35%, transparent); + background-color: color-mix(in srgb, var(--vscode-badge-foreground) 30%, transparent); border-radius: 3px; }