use clap::Subcommand;
use eyre::Result;
use lux_lib::{
config::Config,
path::{BinPath, PackagePath, Paths},
};
use strum_macros::{Display, EnumString, VariantNames};
use clap::{Args, ValueEnum};
use crate::utils::project::current_project_or_user_tree;
#[derive(Args)]
pub struct Path {
#[command(subcommand)]
cmd: Option<PathCmd>,
#[clap(default_value_t = false)]
#[arg(long)]
prepend: bool,
}
#[derive(Subcommand, PartialEq, Eq, Debug, Clone)]
#[clap(rename_all = "kebab_case")]
enum PathCmd {
Full(FullArgs),
Lua,
C,
Bin,
Init,
}
impl Default for PathCmd {
fn default() -> Self {
Self::Full(FullArgs::default())
}
}
#[derive(Args, PartialEq, Eq, Debug, Clone, Default)]
struct FullArgs {
#[clap(default_value_t = false)]
#[arg(long)]
no_bin: bool,
#[clap(default_value_t = false)]
#[arg(long)]
no_loader: bool,
#[clap(default_value_t = Shell::default())]
#[arg(long)]
shell: Shell,
}
#[derive(EnumString, VariantNames, Display, ValueEnum, PartialEq, Eq, Debug, Clone)]
#[strum(serialize_all = "lowercase")]
#[derive(Default)]
enum Shell {
#[default]
Posix,
Fish,
Nu,
}
pub async fn path(path_data: Path, config: Config) -> Result<()> {
let tree = current_project_or_user_tree(&config)?;
let paths = Paths::new(&tree)?;
let cmd = path_data.cmd.unwrap_or_default();
let prepend = path_data.prepend;
match cmd {
PathCmd::Full(args) => {
let mut result = String::new();
let no_loader = args.no_loader || {
if tree.version().lux_lib_dir().is_none() {
eprintln!(
"⚠️ WARNING: lux-lua library not found.
Cannot use the `lux.loader`.
To suppress this warning, run `lx path full --no-loader`.
"
);
true
} else {
false
}
};
let shell = args.shell;
let package_path = mk_package_path(&paths, prepend);
if !package_path.is_empty() {
result.push_str(format_export(&shell, "LUA_PATH", &package_path).as_str());
result.push('\n')
}
let package_cpath = mk_package_cpath(&paths, prepend);
if !package_cpath.is_empty() {
result.push_str(format_export(&shell, "LUA_CPATH", &package_cpath).as_str());
result.push('\n')
}
if !args.no_bin {
let path = mk_bin_path(&paths, prepend)?;
if !path.is_empty() {
result.push_str(format_export(&shell, "PATH", &path).as_str());
result.push('\n')
}
}
if !no_loader {
result.push_str(format_export(&shell, "LUA_INIT", &paths.init()).as_str());
result.push('\n')
}
println!("{}", &result);
}
PathCmd::Lua => println!("{}", &mk_package_path(&paths, prepend)),
PathCmd::C => println!("{}", &mk_package_cpath(&paths, prepend)),
PathCmd::Bin => println!("{}", &mk_bin_path(&paths, prepend)?),
PathCmd::Init => println!("{}", paths.init()),
}
Ok(())
}
fn mk_package_path(paths: &Paths, prepend: bool) -> PackagePath {
if prepend {
paths.package_path_prepended()
} else {
paths.package_path().clone()
}
}
fn mk_package_cpath(paths: &Paths, prepend: bool) -> PackagePath {
if prepend {
paths.package_cpath_prepended()
} else {
paths.package_cpath().clone()
}
}
fn mk_bin_path(paths: &Paths, prepend: bool) -> Result<BinPath> {
let mut result = if prepend {
BinPath::from_env()
} else {
BinPath::default()
};
result.prepend(paths.path());
Ok(result)
}
fn format_export<D>(shell: &Shell, var_name: &str, var: &D) -> String
where
D: std::fmt::Display,
{
match shell {
Shell::Posix => format!("export {var_name}='{var}';"),
Shell::Fish => format!("set -x {var_name} \"{var}\";"),
Shell::Nu => format!("$env.{var_name} = \"{var}\";"),
}
}