Skip to main content

acta_build/
lib.rs

1//! Build-time helper for [acta](https://crates.io/crates/acta).
2//!
3//! Call from your `build.rs` to compute a sensible default `path_width` for
4//! [`acta::Formatter`] based on the longest source-file path in your project.
5//!
6//! # Example
7//!
8//! Add to your `Cargo.toml`:
9//!
10//! ```toml
11//! [build-dependencies]
12//! acta-build = "0.1"
13//! ```
14//!
15//! In `build.rs`:
16//!
17//! ```no_run
18//! # fn example() {
19//! let width = acta_build::walk_src_max_width("src", "src/");
20//! println!("cargo:rustc-env=ACTA_PATH_WIDTH={width}");
21//! println!("cargo:rerun-if-changed=src");
22//! # }
23//! ```
24//!
25//! Then in your code:
26//!
27//! ```ignore
28//! let width: usize = env!("ACTA_PATH_WIDTH").parse().unwrap_or(40);
29//! let formatter = acta::Formatter::new().with_path_width(width);
30//! ```
31
32use std::path::Path;
33use walkdir::WalkDir;
34
35const FALLBACK_WIDTH: usize = 40;
36const PADDING: usize = 4;
37
38/// Walk `dir` recursively, find every `.rs` file, and return
39/// `max(path_len_after_stripping(strip_prefix)) + 4`.
40///
41/// Returns [`FALLBACK_WIDTH`] (40) if `dir` does not exist or contains no
42/// `.rs` files — safe to call unconditionally from a `build.rs`.
43#[must_use]
44pub fn walk_src_max_width(dir: impl AsRef<Path>, strip_prefix: &str) -> usize {
45    WalkDir::new(dir.as_ref())
46        .into_iter()
47        .filter_map(Result::ok)
48        .filter(|e| e.path().extension().is_some_and(|ext| ext == "rs"))
49        .map(|e| {
50            let display = e.path().to_string_lossy().replace('\\', "/");
51            display.strip_prefix(strip_prefix).unwrap_or(&display).len()
52        })
53        .max()
54        .map_or(FALLBACK_WIDTH, |max| max + PADDING)
55}