Skip to content

Commit 2b7cc6d

Browse files
committed
Automatically remove empty directories after file operations
1 parent 3889b63 commit 2b7cc6d

4 files changed

Lines changed: 77 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<a href="https://marketplace.visualstudio.com/items?itemName=robertpiosik.gemini-coder" target="_blank"><img src="https://img.shields.io/badge/Install-VS_Code_Marketplace-blue" alt="Get from Visual Studio Code Marketplace" /></a> <a href="https://x.com/CodeWebChat" target="_blank"><img src="https://img.shields.io/badge/Follow_on_X-@CodeWebChat-black" alt="Follow on X" /></a> <a href="https://reddit.com/r/CodeWebChat" target="_blank"><img src="https://img.shields.io/badge/Join_subreddit-r/CodeWebChat-orange" alt="Join subreddit /r/CodeWebChat" /></a> <a href="https://discord.com/invite/KJySXsrSX5" target="_blank"><img src="https://img.shields.io/badge/Chat-Discord-7289da" alt="Join Discord server" /></a>
44

5-
**A 100% free and open-source tool for AI pair programming.** Its simple, yet highly effecive workflow is designed for unmatched accuracy, speed and cost-efficiency—select context, type instructions and send prompt with a free chatbot or an API provider. When the model finishes, its response is ready for a one-click integration with the codebase.
5+
**A 100% free and open-source tool for AI pair programming.** Its simple, yet highly effecive workflow is designed for an unmatched accuracy, speed and cost-efficiency—select context, type instructions and send prompt with a free chatbot or an API provider. When the model finishes, its response is ready for a one-click integration with the codebase.
66

77
Available in VS Code, Cursor, and other forks.
88

packages/vscode/src/commands/apply-chat-response-command/handlers/patch-handler.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
apply_diff_patch,
1212
process_diff_patch
1313
} from '../utils/diff-patch-processor'
14+
import { remove_directory_if_empty } from '../utils/file-operations'
1415

1516
const execAsync = promisify(exec)
1617

@@ -219,6 +220,10 @@ async function process_modified_files(
219220
message: 'File was empty after patch, removed from disk.',
220221
data: { file_path }
221222
})
223+
await remove_directory_if_empty(
224+
path.dirname(safe_path),
225+
workspace_path
226+
)
222227
} catch (error) {
223228
Logger.error({
224229
function_name: 'process_modified_files',
@@ -376,6 +381,7 @@ const handle_deleted_file_patch = async (
376381
message: 'File deleted successfully.',
377382
data: { file_path }
378383
})
384+
await remove_directory_if_empty(path.dirname(safe_path), workspace_path)
379385
} else {
380386
Logger.warn({
381387
function_name: 'handle_deleted_file_patch',
@@ -442,6 +448,10 @@ const handle_rename_patch = async (
442448
data: { from: safe_from_path, to: safe_to_path }
443449
})
444450

451+
await remove_directory_if_empty(
452+
path.dirname(safe_from_path),
453+
workspace_path
454+
)
445455
await process_modified_files([to_path], workspace_path)
446456

447457
return { success: true, original_states, used_fallback: false }

packages/vscode/src/commands/apply-chat-response-command/utils/file-operations.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,49 @@ import { Logger } from '../../../utils/logger'
66
import { format_document } from './format-document'
77
import { OriginalFileState } from '../../../types/common'
88

9+
export async function remove_directory_if_empty(
10+
dir_path: string,
11+
workspace_root: string
12+
) {
13+
const normalized_dir = path.normalize(dir_path)
14+
const normalized_root = path.normalize(workspace_root)
15+
16+
if (
17+
!normalized_dir ||
18+
!normalized_dir.startsWith(normalized_root) ||
19+
normalized_dir == normalized_root
20+
) {
21+
return
22+
}
23+
24+
try {
25+
if (
26+
fs.existsSync(normalized_dir) &&
27+
fs.lstatSync(normalized_dir).isDirectory()
28+
) {
29+
const files = fs.readdirSync(normalized_dir)
30+
if (files.length == 0) {
31+
fs.rmdirSync(normalized_dir)
32+
Logger.log({
33+
function_name: 'remove_directory_if_empty',
34+
message: 'Removed empty directory',
35+
data: { dir_path: normalized_dir }
36+
})
37+
await remove_directory_if_empty(
38+
path.dirname(normalized_dir),
39+
workspace_root
40+
)
41+
}
42+
}
43+
} catch (error) {
44+
Logger.error({
45+
function_name: 'remove_directory_if_empty',
46+
message: 'Error removing empty directory',
47+
data: { error, dir_path: normalized_dir }
48+
})
49+
}
50+
}
51+
952
export async function create_file_if_needed(
1053
filePath: string,
1154
content: string,
@@ -202,6 +245,10 @@ export async function undo_files(
202245
message: 'New file deleted',
203246
data: safe_path
204247
})
248+
await remove_directory_if_empty(
249+
path.dirname(safe_path),
250+
workspace_root
251+
)
205252
} catch (err) {
206253
Logger.error({
207254
function_name: 'undo_files',

packages/vscode/src/commands/apply-chat-response-command/utils/review-applied-changes.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { createTwoFilesPatch } from 'diff'
66
import { create_safe_path } from '@/utils/path-sanitizer'
77
import { ViewProvider } from '@/view/backend/view-provider'
88
import { OriginalFileState } from '@/types/common'
9+
import { remove_directory_if_empty } from './file-operations'
910

1011
export type CodeReviewDecision =
1112
| { jump_to: { file_path: string; workspace_name?: string } }
@@ -272,13 +273,27 @@ export const review_applied_changes = async (
272273

273274
if (!file_to_toggle) return
274275

276+
let workspace_root = default_workspace
277+
if (
278+
file_to_toggle.reviewable_file.workspace_name &&
279+
workspace_map.has(file_to_toggle.reviewable_file.workspace_name)
280+
) {
281+
workspace_root = workspace_map.get(
282+
file_to_toggle.reviewable_file.workspace_name
283+
)!
284+
}
285+
275286
if (!is_checked) {
276287
if (file_to_toggle.reviewable_file.is_new) {
277288
try {
278289
if (fs.existsSync(file_to_toggle.sanitized_path)) {
279290
await vscode.workspace.fs.delete(
280291
vscode.Uri.file(file_to_toggle.sanitized_path)
281292
)
293+
await remove_directory_if_empty(
294+
path.dirname(file_to_toggle.sanitized_path),
295+
workspace_root
296+
)
282297
}
283298
} catch (e) {}
284299
} else {
@@ -294,6 +309,10 @@ export const review_applied_changes = async (
294309
await vscode.workspace.fs.delete(
295310
vscode.Uri.file(file_to_toggle.sanitized_path)
296311
)
312+
await remove_directory_if_empty(
313+
path.dirname(file_to_toggle.sanitized_path),
314+
workspace_root
315+
)
297316
}
298317
} catch (e) {}
299318
} else {

0 commit comments

Comments
 (0)