onpath 0.2.0

Get your tools on the PATH — cross-shell, cross-platform, zero fuss
Documentation
#![deny(unsafe_code)]
#![deny(missing_docs)]

//! Safe, idempotent PATH management across shells and operating systems.
//!
//! `onpath` lets any Rust CLI tool or installer add directories to the user's
//! PATH persistently — across Bash, Zsh, Fish, Nushell, `PowerShell`, Tcsh, Xonsh,
//! and Windows (via the registry).
//!
//! # Quick Start
//!
//! ```no_run
//! // Add ~/.myapp/bin to PATH for all detected shells
//! let report = onpath::add("/home/user/.myapp/bin", "myapp")?;
//! println!("{report}");
//! # Ok::<(), onpath::Error>(())
//! ```
//!
//! # How It Works
//!
//! On Unix, `onpath` uses a two-layer approach (pioneered by rustup):
//!
//! 1. **Env scripts** — Self-guarding shell scripts that check if the directory
//!    is already in PATH before adding it (e.g., `~/.myapp/env`, `~/.myapp/env.fish`).
//!
//! 2. **Source lines** — A single `source` line added to each shell's RC file,
//!    bracketed with identifiable markers for clean removal.
//!
//! On Windows, it modifies `HKCU\Environment\PATH` in the registry and broadcasts
//! `WM_SETTINGCHANGE` to notify running applications.

/// Conditional tracing macros. No-ops when the `tracing` feature is disabled.
///
/// `trace_debug` is only used in Unix-specific code paths.
#[cfg(all(not(windows), feature = "tracing"))]
macro_rules! trace_debug {
    ($($arg:tt)*) => { ::tracing::debug!($($arg)*) }
}
#[cfg(all(not(windows), not(feature = "tracing")))]
macro_rules! trace_debug {
    ($($arg:tt)*) => {};
}

#[cfg(feature = "tracing")]
macro_rules! trace_info {
    ($($arg:tt)*) => { ::tracing::info!($($arg)*) }
}
#[cfg(not(feature = "tracing"))]
macro_rules! trace_info {
    ($($arg:tt)*) => {};
}

/// PATH position configuration.
pub mod config;
pub(crate) mod context;
/// Error types for PATH management operations.
pub mod error;
/// The [`PathManager`] builder for configuring PATH operations.
pub mod manager;
pub(crate) mod normalize;
#[cfg(not(windows))]
pub(crate) mod rc;
/// Report types describing actions taken during PATH operations.
pub mod report;
#[cfg(not(windows))]
pub(crate) mod shell;
/// Shell type identifiers shared across all platforms.
pub mod shell_kind;

/// Windows-specific PATH management via the registry.
#[cfg(windows)]
pub mod windows;

pub use config::Position;
pub use context::SystemContext;
pub use error::Error;
pub use manager::PathManager;
pub use report::{Action, ActionKind, Report};
pub use shell_kind::ShellKind;

/// Convenience function: add a directory to PATH for all detected shells.
///
/// - `dir`: The directory to add to PATH (e.g., `~/.myapp/bin`)
/// - `tool_name`: Unique name for markers and env file naming (e.g., `"myapp"`)
///
/// Env scripts are written to `dir`'s parent directory. For a different location,
/// use [`PathManager`] with [`.env_dir()`](PathManager::env_dir).
///
/// # Errors
///
/// Returns [`Error::HomeDirNotFound`] if the home directory cannot be determined,
/// [`Error::NoShellsDetected`] if no shells are found on Unix, or
/// [`Error::FileWrite`] / [`Error::DirCreate`] on I/O failures.
pub fn add(dir: impl AsRef<std::path::Path>, tool_name: &str) -> error::Result<Report> {
    PathManager::new(dir.as_ref(), tool_name).add()
}

/// Convenience function: remove a directory from PATH for all detected shells.
///
/// - `dir`: The directory to remove from PATH
/// - `tool_name`: The tool name used during installation
///
/// Env scripts are expected in `dir`'s parent directory. If they were written
/// elsewhere, use [`PathManager`] with [`.env_dir()`](PathManager::env_dir).
///
/// # Errors
///
/// Returns [`Error::HomeDirNotFound`] if the home directory cannot be determined,
/// or [`Error::FileWrite`] / [`Error::FileRead`] on I/O failures.
pub fn remove(dir: impl AsRef<std::path::Path>, tool_name: &str) -> error::Result<Report> {
    PathManager::new(dir.as_ref(), tool_name).remove()
}