mod cli;
use anyhow::Context;
use clap::{CommandFactory, Parser, Subcommand};
use cli::config::ConfigArgs;
use cli::format::FormatArgs;
use cli::run::RunArgs;
use cli::scratch::ScratchCommandArgs;
use cli::snapshot::SnapshotArgs;
use rested::config::{
get_env_from_dir_path, get_env_from_dir_path_or_from_home_dir, get_env_from_home_dir,
};
use rested::editing::edit;
use rested::interpreter::environment::Environment;
use rested::ENV_FILE_NAME;
use tracing::{error, info};
use std::collections::HashMap;
use std::fs;
#[derive(Parser, Debug)]
#[command(author, version, about)]
struct Cli {
#[command(subcommand)]
command: Command,
#[arg(short, long, default_value = "info", global = true)]
level: tracing::Level,
}
#[derive(Debug, Subcommand)]
enum Command {
Run(RunArgs),
Fmt(FormatArgs),
Scratch(ScratchCommandArgs),
Snap(SnapshotArgs),
Env {
#[arg(long)]
cwd: bool,
#[command(subcommand)]
command: EnvCommand,
},
Completion {
shell: clap_complete::Shell,
},
Lsp,
Config(ConfigArgs),
}
#[derive(Debug, Subcommand)]
enum EnvCommand {
Show,
Edit,
Set {
#[arg(short = 'n', long)]
namespace: Option<String>,
name: String,
value: String,
},
NS {
#[command(subcommand)]
command: EnvNamespaceCommand,
},
}
#[derive(Debug, Subcommand)]
enum EnvNamespaceCommand {
Add {
name: String,
},
Rm {
name: String,
},
}
fn main() {
let cli = Cli::parse();
tracing_subscriber::fmt()
.with_max_level(cli.level)
.with_writer(std::io::stderr)
.init();
if let Err(e) = run(cli) {
error!("{:#}", e);
}
}
fn run(cli: Cli) -> anyhow::Result<()> {
match cli.command {
Command::Env { command, cwd } => {
let mut env = if cwd {
let path = std::env::current_dir()?;
get_env_from_dir_path(&path).or_else(|_| {
Environment::new(path.join(ENV_FILE_NAME))
.context("failed to load the environment for rstd")
})?
} else {
get_env_from_home_dir()?
};
match command {
EnvCommand::Set {
name,
value,
namespace,
} => {
if let Some(ns) = namespace {
env.select_variables_namespace(ns);
}
info!("setting variable '{}' with value '{}'", name, value);
env.set_variable(name, value)?;
}
EnvCommand::NS { command } => match command {
EnvNamespaceCommand::Add { name } => {
info!("adding namespace: {name}");
env.namespaced_variables.insert(name, HashMap::new());
env.save_to_file()?;
}
EnvNamespaceCommand::Rm { name } => {
info!("removing namespace: {name}");
env.namespaced_variables.remove(&name);
env.save_to_file()?;
}
},
EnvCommand::Show => println!("{}", fs::read_to_string(env.env_file_name)?),
EnvCommand::Edit => edit(&env.env_file_name)?,
}
}
Command::Completion { shell } => {
clap_complete::generate(shell, &mut Cli::command(), "rstd", &mut std::io::stdout())
}
Command::Lsp => rested::language_server::start(cli.level),
Command::Run(run) => {
let full_path = run.file.as_ref().and_then(|path| path.canonicalize().ok());
let workspace = full_path.as_ref().and_then(|p| p.parent());
if let Some(path) = full_path.as_ref() {
info!("script to run: {:?}", path);
}
if let Some(workspace) = workspace.as_ref() {
info!("identified workspace: {:?}", workspace);
}
let env = get_env_from_dir_path_or_from_home_dir(workspace)?;
run.handle(env)?
}
Command::Scratch(scratch) => {
let env = get_env_from_home_dir()?;
scratch.handle(env)?
}
Command::Config(config) => config.handle()?,
Command::Fmt(fmt) => fmt.handle()?,
Command::Snap(snap) => {
let full_path = snap.file.as_ref().and_then(|path| path.canonicalize().ok());
let workspace = full_path.as_ref().and_then(|p| p.parent());
if let Some(path) = full_path.as_ref() {
info!("script to snapshot: {:?}", path);
}
if let Some(workspace) = workspace.as_ref() {
info!("identified workspace: {:?}", workspace);
}
let env = get_env_from_dir_path_or_from_home_dir(workspace)?;
snap.handle(env)?
}
};
Ok(())
}