use std::{ env::var, ffi::OsStr, fs::{ read, read_dir, read_to_string, write, }, io::Write, path::{ Path, PathBuf, }, process::{ Command, Stdio, }, }; use quote::quote; fn main() { println!("cargo::rerun-if-changed=nvim-treesitter/lua/nvim-treesitter/parsers.lua"); println!("cargo::rerun-if-changed=generate_parsers.lua"); let mut child = Command::new("lua") .arg("generate_parsers.lua") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() .expect("Failed to spawn process"); let mut stdin = child.stdin.take().expect("Failed to open stdin"); std::thread::spawn(move || { stdin .write_all( read(Path::new("nvim-treesitter/lua/nvim-treesitter/parsers.lua")) .expect("Failed to create parsers path") .as_ref(), ) .expect("Failed to write to stdin"); }) .join() .unwrap(); let output = child.wait_with_output().expect("Failed to read stdout"); write( PathBuf::from(format!("{}/_parsers.rs", var("OUT_DIR").unwrap())), output.stdout, ) .unwrap(); let query_dirs = read_dir(Path::new("nvim-treesitter/queries")) .expect("Failed to read nvim-treesitter/queries") .filter_map(|entry| { let path = entry.unwrap().path(); path.is_dir().then_some(path) }) .collect::>(); let queries = query_dirs .iter() .filter_map(|path| { read_dir(path) .map(|entries| { ( path.file_name().unwrap().to_str().unwrap(), entries.filter_map(|entry| entry.ok()), ) }) .ok() }) .map(|(lang, entries)| { let entries = entries.filter_map(|entry| { let path = entry.path(); match path.file_stem().map(OsStr::to_str).flatten() { Some(stem @ ("highlights" | "injections" | "locals")) => { let content = read_to_string(&path).expect("Query file should be valid UTF-8"); Some(quote! { (#stem, #content) }) } _ => None, } }); quote! { (#lang, HashMap::from([ #(#entries),* ])) } }); let code = quote! { pub static QUERIES: LazyLock>> = LazyLock::new(|| { HashMap::from([ #(#queries),* ]) }); }; let tree = &syn::parse2(code).unwrap(); let formatted = prettyplease::unparse(tree); write( PathBuf::from(format!("{}/_queries.rs", var("OUT_DIR").unwrap())), formatted, ) .unwrap(); }