btl 0.2.0

Btl is a simple library that makes shell scripting with rust easier. It was originally written with the purposes of being used for build.rs files, but it can be used for more complex purposes. It's main premise is about making shell scripting easier to work with rust. This works both on windows and unix machines. Originally designed in linux, not tested on Windows or Mac yet, but they should work since the library is platform-agnostic.
Documentation



use proc_macro::TokenStream;
use quote::{quote};
use syn::parse::{Parse, ParseStream, Result};
use syn::{parse_macro_input, Expr, Token};

struct Commands {
    fmt: Vec<String>,
    args: Vec<String>,
}


impl Parse for Commands {
    fn parse(input: ParseStream) -> Result<Self> {



        let mut fmt: Vec<String> = vec![];
        let mut args: Vec<String> = vec![];
        // Parse all commands loop
        
        'cmd: loop {
            let cmd = match input.parse::<Expr>() {
                Ok(cmd) => cmd,
                Err(_) => break
            };
            
            let mut current_expr = vec![];
            
            loop {
                if input.parse::<Token![;]>().is_ok() {

                    fmt.push(quote!{#cmd}.to_string());
                    args.push(quote!{#(,#current_expr)*}.to_string());

                    continue 'cmd;
                }

                current_expr.push(input.parse::<Expr>().unwrap());
            }
            


            
        }

        Ok(Commands{fmt: fmt, args: args})


    }
}

#[proc_macro]
pub fn shell(input: TokenStream) -> TokenStream {

    if input.to_string().len() == 0 {
        return "".to_string().parse().unwrap()
    }

    let Commands {
        fmt, args
    } = parse_macro_input!(input as Commands);

    let key = std::time::SystemTime::elapsed(&std::time::UNIX_EPOCH).unwrap().as_nanos();
    println!("{}", key);
    let args = args.join("");
    let fmt = fmt.join(format!(" {}", key).as_str());
    let fmt = fmt.replace(format!("\" {}\"", key).as_str(), " && ");

    let out;
    if cfg!(target_os = "windows") {
        out = format!("
std::process::Command::new(\"cmd\")
.arg(\"-c\")
.arg(&[\"/C\", format!({}{}).as_str()])
.spawn()
.unwrap()
.wait()
.unwrap();
", fmt, args);
    } else {
        out = format!("
std::process::Command::new(\"sh\")
.arg(\"-c\")
.arg(format!({}{}))
.spawn()
.unwrap()
.wait()
.unwrap();
", fmt, args);
    }

    out.to_string().parse().unwrap()
}


#[proc_macro]
pub fn detach(input: TokenStream) -> TokenStream {

    if input.to_string().len() == 0 {
        return "".to_string().parse().unwrap()
    }

    let Commands {
        fmt, args
    } = parse_macro_input!(input as Commands);

    let key = std::time::SystemTime::elapsed(&std::time::UNIX_EPOCH).unwrap().as_nanos();
    println!("{}", key);
    let args = args.join("");
    let fmt = fmt.join(format!(" {}", key).as_str());
    let fmt = fmt.replace(format!("\" {}\"", key).as_str(), " && ");

    let out;
    if cfg!(target_os = "windows") {
        out = format!("
std::process::Command::new(\"cmd\")
.arg(\"-c\")
.arg(&[\"/C\", format!({}{}).as_str()])
.spawn()
.unwrap();
", fmt, args);
    } else {
        out = format!("
std::process::Command::new(\"sh\")
.arg(\"-c\")
.arg(format!({}{}))
.spawn()
.unwrap();
", fmt, args);
    }

    out.to_string().parse().unwrap()
}