1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//! Shared directory walker helpers built on the `ignore` crate.
//!
//! All file traversal in vtcode should go through these builders so that
//! `.gitignore`, `.ignore`, `.git/exclude`, and the centralized exclusion
//! constants are applied consistently.
use ignore::{DirEntry, WalkBuilder};
use std::path::Path;
use crate::exclusions::DEFAULT_EXCLUDED_DIRS;
/// Build a multi-threaded [`WalkBuilder`] with sensible defaults.
///
/// - Respects `.gitignore`, `.ignore`, `.git/exclude`, and parent ignore files
/// - Does not follow symlinks
/// - Uses the `ignore` crate's default thread pool
///
/// Callers that need to prune additional directories should use
/// [`filter_entry`](WalkBuilder::filter_entry) with [`is_excluded_dir`].
pub fn build_default_walker(root: &Path) -> WalkBuilder {
let mut builder = WalkBuilder::new(root);
apply_defaults(&mut builder);
builder
}
/// Build a single-threaded [`WalkBuilder`] with the same defaults as
/// [`build_default_walker`].
///
/// Use this in synchronous contexts where spawning the `ignore` crate's
/// thread pool would be wasteful (e.g., inside `spawn_blocking` closures
/// that already run on a dedicated thread).
pub fn build_walker_single_threaded(root: &Path) -> WalkBuilder {
let mut builder = WalkBuilder::new(root);
builder.threads(1);
apply_defaults(&mut builder);
builder
}
/// Apply standard walker defaults to an existing [`WalkBuilder`].
///
/// Sets gitignore support, hidden file visibility, and symlink policy.
/// Callers that need additional customization (e.g., parallel walkers,
/// symlink following) can call this then override specific settings.
pub fn apply_defaults(builder: &mut WalkBuilder) {
// Respect all standard ignore-file mechanisms.
builder.git_ignore(true);
builder.git_global(true);
builder.git_exclude(true);
builder.ignore(true);
builder.parents(true);
// Do not follow symlinks by default.
builder.follow_links(false);
// Do not skip hidden files by default. The `ignore` crate skips them
// by default, but the previous traversal code did not. Callers that
// want to hide dotfiles should filter them explicitly.
builder.hidden(false);
}
/// Returns `true` if `entry` is a directory whose name appears in
/// [`DEFAULT_EXCLUDED_DIRS`].
///
/// Intended for use inside [`WalkBuilder::filter_entry`] closures:
///
/// ```ignore
/// builder.filter_entry(|entry| !vtcode_commons::walk::is_excluded_dir(entry));
/// ```
pub fn is_excluded_dir(entry: &DirEntry) -> bool {
if !entry.file_type().is_some_and(|ft| ft.is_dir()) {
return false;
}
entry
.file_name()
.to_str()
.is_some_and(|name| DEFAULT_EXCLUDED_DIRS.contains(&name))
}