onpath/lib.rs
1#![deny(unsafe_code)]
2#![deny(missing_docs)]
3
4//! Safe, idempotent PATH management across shells and operating systems.
5//!
6//! `onpath` lets any Rust CLI tool or installer add directories to the user's
7//! PATH persistently — across Bash, Zsh, Fish, Nushell, `PowerShell`, Tcsh, Xonsh,
8//! and Windows (via the registry).
9//!
10//! # Quick Start
11//!
12//! ```no_run
13//! // Add ~/.myapp/bin to PATH for all detected shells
14//! let report = onpath::add("/home/user/.myapp/bin", "myapp")?;
15//! println!("{report}");
16//! # Ok::<(), onpath::Error>(())
17//! ```
18//!
19//! # How It Works
20//!
21//! On Unix, `onpath` uses a two-layer approach (pioneered by rustup):
22//!
23//! 1. **Env scripts** — Self-guarding shell scripts that check if the directory
24//! is already in PATH before adding it (e.g., `~/.myapp/env`, `~/.myapp/env.fish`).
25//!
26//! 2. **Source lines** — A single `source` line added to each shell's RC file,
27//! bracketed with identifiable markers for clean removal.
28//!
29//! On Windows, it modifies `HKCU\Environment\PATH` in the registry and broadcasts
30//! `WM_SETTINGCHANGE` to notify running applications.
31
32/// Conditional tracing macros. No-ops when the `tracing` feature is disabled.
33///
34/// `trace_debug` is only used in Unix-specific code paths.
35#[cfg(all(not(windows), feature = "tracing"))]
36macro_rules! trace_debug {
37 ($($arg:tt)*) => { ::tracing::debug!($($arg)*) }
38}
39#[cfg(all(not(windows), not(feature = "tracing")))]
40macro_rules! trace_debug {
41 ($($arg:tt)*) => {};
42}
43
44#[cfg(feature = "tracing")]
45macro_rules! trace_info {
46 ($($arg:tt)*) => { ::tracing::info!($($arg)*) }
47}
48#[cfg(not(feature = "tracing"))]
49macro_rules! trace_info {
50 ($($arg:tt)*) => {};
51}
52
53/// PATH position configuration.
54pub mod config;
55pub(crate) mod context;
56/// Error types for PATH management operations.
57pub mod error;
58/// The [`PathManager`] builder for configuring PATH operations.
59pub mod manager;
60pub(crate) mod normalize;
61#[cfg(not(windows))]
62pub(crate) mod rc;
63/// Report types describing actions taken during PATH operations.
64pub mod report;
65#[cfg(not(windows))]
66pub(crate) mod shell;
67/// Shell type identifiers shared across all platforms.
68pub mod shell_kind;
69
70/// Windows-specific PATH management via the registry.
71#[cfg(windows)]
72pub mod windows;
73
74pub use config::Position;
75pub use context::SystemContext;
76pub use error::Error;
77pub use manager::PathManager;
78pub use report::{Action, ActionKind, Report};
79pub use shell_kind::ShellKind;
80
81/// Convenience function: add a directory to PATH for all detected shells.
82///
83/// - `dir`: The directory to add to PATH (e.g., `~/.myapp/bin`)
84/// - `tool_name`: Unique name for markers and env file naming (e.g., `"myapp"`)
85///
86/// Env scripts are written to `dir`'s parent directory. For a different location,
87/// use [`PathManager`] with [`.env_dir()`](PathManager::env_dir).
88///
89/// # Errors
90///
91/// Returns [`Error::HomeDirNotFound`] if the home directory cannot be determined,
92/// [`Error::NoShellsDetected`] if no shells are found on Unix, or
93/// [`Error::FileWrite`] / [`Error::DirCreate`] on I/O failures.
94pub fn add(dir: impl AsRef<std::path::Path>, tool_name: &str) -> error::Result<Report> {
95 PathManager::new(dir.as_ref(), tool_name).add()
96}
97
98/// Convenience function: remove a directory from PATH for all detected shells.
99///
100/// - `dir`: The directory to remove from PATH
101/// - `tool_name`: The tool name used during installation
102///
103/// Env scripts are expected in `dir`'s parent directory. If they were written
104/// elsewhere, use [`PathManager`] with [`.env_dir()`](PathManager::env_dir).
105///
106/// # Errors
107///
108/// Returns [`Error::HomeDirNotFound`] if the home directory cannot be determined,
109/// or [`Error::FileWrite`] / [`Error::FileRead`] on I/O failures.
110pub fn remove(dir: impl AsRef<std::path::Path>, tool_name: &str) -> error::Result<Report> {
111 PathManager::new(dir.as_ref(), tool_name).remove()
112}