whi 0.8.1

Stupid simple PATH management
Documentation
use std::env;
use std::io::{self, BufWriter, StdoutLock};
use std::path::PathBuf;

use crate::cli::args::Args;
use crate::config;

mod path_ops;
mod query;
mod session;

fn handle_path_result(
    result: Result<String, String>,
    args: &Args,
    out: &mut BufWriter<StdoutLock<'_>>,
) -> i32 {
    match result {
        Ok(new_path) => {
            query::write_snapshot_safe(&new_path, args);
            query::output_path(out, &new_path)
        }
        Err(e) => {
            if !args.silent {
                eprintln!("Error: {e}");
            }
            2
        }
    }
}

fn get_current_exe_dir() -> Option<PathBuf> {
    env::current_exe()
        .ok()
        .and_then(|exe_path| exe_path.parent().map(std::path::Path::to_path_buf))
}

#[must_use]
pub fn run(args: &Args) -> i32 {
    if let Err(e) = config::runtime::ensure_config_exists() {
        eprintln!("Error: {e}");
        return 2;
    }

    let config = config::runtime::load_config().unwrap_or_default();

    if let Some(ref shell) = args.init_shell {
        return session::handle_init(shell);
    }

    if let Some(apply_target) = &args.apply_target {
        return session::handle_apply(apply_target, args.no_protect);
    }

    if let Some(profile_name) = &args.save_profile {
        return session::handle_save_profile(profile_name);
    }

    if let Some(profile_name) = &args.load_profile {
        return session::handle_load_profile(profile_name);
    }

    if let Some(profile_name) = &args.remove_profile {
        return session::handle_remove_profile(profile_name);
    }

    if args.reset {
        return session::handle_reset();
    }

    if let Some(history_action) = &args.history_action {
        return match history_action {
            crate::cli::args::HistoryAction::Undo(count) => session::handle_undo(*count),
            crate::cli::args::HistoryAction::Redo(count) => session::handle_redo(*count),
        };
    }

    if args.diff {
        return session::handle_diff(args.diff_full);
    }

    let path_var = match &args.path_override {
        Some(p) => p.clone(),
        None => env::var("PATH").unwrap_or_default(),
    };

    let searcher = crate::path::searcher::PathSearcher::new(&path_var);
    let stdout = io::stdout();
    let mut out = BufWriter::new(stdout.lock());

    if args.clean {
        return path_ops::handle_clean(&searcher, args, &mut out);
    }

    if !args.delete_targets.is_empty() {
        return path_ops::handle_delete(&searcher, &args.delete_targets, args, &mut out);
    }

    if let Some(path_edit) = &args.path_edit {
        return path_ops::handle_move_or_swap(&searcher, path_edit, args, &mut out);
    }

    if let Some(ref target) = args.prefer_target {
        return path_ops::handle_prefer(&searcher, target, args, &mut out);
    }

    query::run_query(&searcher, args, &config, &mut out)
}

mod atty {
    use crate::platform;
    use std::os::unix::io::AsRawFd;

    pub fn is(stream: Stream) -> bool {
        let fd = match stream {
            Stream::Stdout => std::io::stdout().as_raw_fd(),
            Stream::Stdin => std::io::stdin().as_raw_fd(),
        };

        platform::is_tty(fd)
    }

    #[derive(Copy, Clone)]
    pub enum Stream {
        Stdout,
        Stdin,
    }
}