use anyhow::Result;
use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[derive(Parser)]
#[command(name = "velox")]
#[command(version = "0.1.0")]
#[command(author = "fahimaloy")]
#[command(about = "đ Velox - A modern UI framework for Rust", long_about = None)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
#[command(about = "Create a new Velox project with scaffolding")]
Init {
name: String,
#[arg(long, short = 't', default_value = "default")]
template: String,
#[arg(long)]
local: Option<std::path::PathBuf>,
},
#[command(about = "Build project (default) or compile a .vx component")]
Build {
input: Option<PathBuf>,
#[arg(long, short = 'o')]
out_dir: Option<PathBuf>,
#[arg(long)]
release: bool,
},
#[command(about = "Build and run a project")]
Run {
#[arg(long)]
release: bool,
},
#[command(
about = "Start dev server with file watching",
long_about = "\
Start dev server with file watching.
FILE WATCHING
Changes are reported by the OS (inotify on Linux), not by polling, so a
save is picked up in milliseconds. `target/`, `.git`, `.vscode`, `.idea` and
dot-directories are excluded: `cargo build` writes thousands of files into
`target/`, and watching it is what exhausts the kernel's watch budget.
INOTIFY WATCH LIMIT (Linux)
Watching is backed by inotify, a finite kernel resource. If the limit is
exhausted, the dev server reports the error and keeps running, but files may
no longer be detected â press 'r' to rebuild by hand. Raise the limit with:
sudo sysctl -w fs.inotify.max_user_watches=524288
sudo sysctl -w fs.inotify.max_user_instances=1024
To persist it, write those two lines to a file in /etc/sysctl.d/ and run
`sudo sysctl --system`."
)]
Dev {
#[arg(long, short = 'w')]
watch: Option<PathBuf>,
#[arg(long)]
release: bool,
},
#[command(about = "Check .vx files for issues")]
Lint {
target: Option<PathBuf>,
#[arg(long)]
fix: bool,
},
#[command(about = "Add a component or other scaffold to the project")]
Add {
#[command(subcommand)]
what: AddCommand,
},
#[command(about = "Display version information")]
Version,
}
#[derive(Subcommand)]
enum AddCommand {
#[command(about = "Generate a new component .vx file")]
Component {
name: String,
#[arg(long, short = 's', value_name = "NAME,NAME")]
slots: Option<String>,
},
}
fn main() -> Result<()> {
env_logger::init();
let cli = Cli::parse();
match cli.command {
Commands::Init {
name,
template,
local,
} => {
let path = veloxc::commands::init_project_with_template_local(
&name,
&template,
local.as_deref(),
)?;
println!("â
Created Velox project at: {}", path.display());
println!("\nđ Next steps:");
println!(" cd {}", path.display());
println!(" velox dev");
}
Commands::Build {
input,
out_dir,
release,
} => {
if let Some(input) = input {
veloxc::build_cmd(&input, out_dir.as_deref(), veloxc::EmitMode::Render)?;
println!("âšī¸ The generated .rs file is source code, not an executable.");
} else {
veloxc::commands::build_current(release)?;
}
}
Commands::Run { release } => {
if release {
println!("đ¨ Building in release mode...");
veloxc::commands::build_current(true)?;
}
println!("âļī¸ Running project...");
veloxc::commands::run_current(release)?;
}
Commands::Dev { watch, release } => {
let dir = watch.unwrap_or_else(|| PathBuf::from("."));
veloxc::commands::dev_current(&dir, release)?;
}
Commands::Lint { target, fix } => {
let target = target.unwrap_or_else(|| PathBuf::from("src"));
if target.is_file() {
if fix {
println!("đ§ Lint+fix {}...", target.display());
veloxc::commands::fix_file_single(&target)?;
} else {
println!("đ Linting {}...", target.display());
veloxc::commands::lint_file(&target)?;
}
} else {
if fix {
println!("đ§ Lint+fix .vx files in {}...", target.display());
veloxc::commands::lint_directory_fix(&target, true)?;
} else {
println!("đ Linting .vx files in {}...", target.display());
veloxc::commands::lint_directory_fix(&target, false)?;
}
}
}
Commands::Add { what } => match what {
AddCommand::Component { name, slots } => {
veloxc::commands::add_component(&name, slots.as_deref())?;
}
},
Commands::Version => {
println!("velox {}", env!("CARGO_PKG_VERSION"));
println!("Edition: 2021");
#[cfg(target_os = "linux")]
println!("Platform: Linux");
#[cfg(target_os = "macos")]
println!("Platform: macOS");
#[cfg(target_os = "windows")]
println!("Platform: Windows");
}
}
Ok(())
}