#![allow(unused, warnings)]
use color_eyre::{
Result,
config::{HookBuilder, Theme},
eyre::Context,
};
use tracing_subscriber::prelude::*;
const ZV_RECURSION_MAX: u32 = 1;
#[tokio::main]
async fn main() -> Result<()> {
#[cfg(windows)]
apply_windows_security_mitigations();
check_recursion_with_context("zv main")?;
#[cfg(feature = "dotenv")]
dotenv::dotenv().ok();
yansi::whenever(yansi::Condition::TTY_AND_COLOR);
if yansi::is_enabled() {
HookBuilder::default()
.display_env_section(cfg!(debug_assertions))
.display_location_section(cfg!(debug_assertions))
.install()?;
} else {
HookBuilder::default()
.theme(Theme::new())
.display_env_section(cfg!(debug_assertions))
.display_location_section(cfg!(debug_assertions))
.install()?;
}
init_tracing()?;
let program_name = get_program_name()?;
match program_name.as_str() {
"zv" => cli::zv_main().await,
"zig" => cli::zig_main().await,
"zls" => cli::zls_main().await,
_ => {
eprintln!(
"Unknown invocation: {}. This binary should be invoked as 'zv', 'zig', or 'zls'.",
program_name
);
std::process::exit(1);
}
}
}
fn init_tracing() -> Result<()> {
let zv_log = std::env::var("ZV_LOG").is_ok();
if zv_log {
tracing_subscriber::registry()
.with(
tracing_subscriber::fmt::layer()
.with_target(true) .with_filter(
tracing_subscriber::EnvFilter::try_from_env("ZV_LOG")
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("zv=warn")),
),
)
.init();
} else {
tracing_subscriber::registry()
.with(
tracing_subscriber::fmt::layer()
.with_target(false) .with_level(true) .with_thread_ids(false)
.with_thread_names(false)
.with_file(false)
.with_line_number(false)
.without_time() .with_filter(tracing_subscriber::EnvFilter::new("zv=info")),
)
.init();
}
Ok(())
}
fn get_program_name() -> Result<String> {
let program_path = std::env::args_os()
.next()
.ok_or_else(|| color_eyre::eyre::eyre!("Failed to get program name from args"))?;
let file_name = std::path::Path::new(&program_path)
.file_name()
.ok_or_else(|| color_eyre::eyre::eyre!("Failed to get executable filename"))?
.to_string_lossy();
let name = if cfg!(windows) && file_name.ends_with(".exe") {
file_name.strip_suffix(".exe").unwrap().to_string()
} else {
file_name.to_string()
};
Ok(name)
}
#[cfg(windows)]
pub fn apply_windows_security_mitigations() {
use windows_sys::Win32::System::LibraryLoader::{
LOAD_LIBRARY_SEARCH_SYSTEM32, LOAD_LIBRARY_SEARCH_USER_DIRS, SetDefaultDllDirectories,
};
let search_flags = LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS;
unsafe {
let result = SetDefaultDllDirectories(search_flags);
assert_ne!(result, 0, "Failed to set secure DLL directories");
}
tracing::debug!("Applied Windows DLL security mitigations");
}
pub fn check_recursion_with_context(context: &str) -> Result<()> {
let recursion_count = std::env::var("ZV_RECURSION_COUNT")
.unwrap_or_else(|_| "0".to_string())
.parse::<u32>()
.unwrap_or(0);
if recursion_count > ZV_RECURSION_MAX {
eprintln!(
"Error: Too many recursive calls detected in {} (depth: {}). \
The zv binary may be calling itself infinitely.",
context, recursion_count
);
std::process::exit(1);
}
Ok(())
}
mod app;
mod cli;
mod shell;
mod templates;
mod tools;
mod types;
pub use app::App;
pub use shell::*;
pub use templates::*;
pub use types::*;