diff --git a/scripts/run_docker_compare.bash b/scripts/run_docker_compare.bash index f3164067..ace3efa4 100755 --- a/scripts/run_docker_compare.bash +++ b/scripts/run_docker_compare.bash @@ -13,9 +13,8 @@ REALPATH=$(command -v uu-realpath || command -v realpath) MAKE=$(command -v gmake || command -v make) function main { - local org_file="$($REALPATH "$1")" build_container - launch_container "$org_file" + launch_container } function build_container { @@ -23,22 +22,13 @@ function build_container { } function launch_container { - local org_file="$1" local additional_flags=() local additional_args=() - local init_script=$(cat <(file_path: C) -> Result> +pub fn emacs_parse_org_document(file_contents: C) -> Result> where - C: AsRef, + C: AsRef, { - let elisp_script = r#"(progn + let escaped_file_contents = escape_elisp_string(file_contents); + let elisp_script = format!(r#"(progn + (erase-buffer) + (insert "{escaped_file_contents}") (org-mode) (message "%s" (pp-to-string (org-element-parse-buffer))) -)"#; +)"#, escaped_file_contents=escaped_file_contents); let mut cmd = Command::new("emacs"); let proc = cmd .arg("-q") .arg("--no-site-file") .arg("--no-splash") .arg("--batch") - .arg("--insert") - .arg(file_path.as_ref().as_os_str()) .arg("--eval") .arg(elisp_script); let out = proc.output()?; @@ -24,3 +24,25 @@ where let org_sexp = out.stderr; Ok(String::from_utf8(org_sexp)?) } + +fn escape_elisp_string(file_contents: C) -> String +where + C: AsRef, +{ + let source = file_contents.as_ref(); + let source_len = source.len(); + // We allocate a string 10% larger than the source to account for escape characters. Without this, we would have more allocations during processing. + let mut output = String::with_capacity(source_len + (source_len / 10)); + for c in source.chars() { + match c { + '"' | '\\' => { + output.push('\\'); + output.push(c); + } + _ => { + output.push(c); + } + } + } + output +} diff --git a/src/main.rs b/src/main.rs index 9f76e493..b48fab1c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ #![feature(round_char_boundary)] -use std::path::Path; +#[cfg(feature = "compare")] +use std::io::Read; #[cfg(feature = "compare")] use ::organic::parser::document; @@ -36,22 +37,26 @@ fn main() -> Result<(), Box> { #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn main_body() -> Result<(), Box> { - run_compare( - std::env::args() - .nth(1) - .ok_or("Pass a single file into this script.")?, - ) + let org_contents = read_stdin_to_string()?; + run_compare(org_contents) +} + +fn read_stdin_to_string() -> Result> { + let mut stdin_contents = String::new(); + std::io::stdin() + .lock() + .read_to_string(&mut stdin_contents)?; + Ok(stdin_contents) } #[cfg(feature = "compare")] -fn run_compare>(todo_org_path: P) -> Result<(), Box> { - let org_contents = std::fs::read_to_string(todo_org_path.as_ref())?; - let (remaining, rust_parsed) = document(org_contents.as_str()).expect("Org Parse failure"); - let org_sexp = emacs_parse_org_document(todo_org_path.as_ref())?; +fn run_compare>(org_contents: P) -> Result<(), Box> { + let (remaining, rust_parsed) = document(org_contents.as_ref()).expect("Org Parse failure"); + let org_sexp = emacs_parse_org_document(org_contents.as_ref())?; let (_remaining, parsed_sexp) = sexp_with_padding(org_sexp.as_str()).expect("Sexp Parse failure"); - println!("{}\n\n\n", org_contents.as_str()); + println!("{}\n\n\n", org_contents.as_ref()); println!("{}", org_sexp); println!("{:#?}", rust_parsed); diff --git a/tests/test_template b/tests/test_template index c9a99038..442db660 100644 --- a/tests/test_template +++ b/tests/test_template @@ -3,7 +3,7 @@ fn {name}() {{ let todo_org_path = "{path}"; let org_contents = std::fs::read_to_string(todo_org_path).expect("Read org file."); println!("{{}}", org_contents); - let org_sexp = emacs_parse_org_document(todo_org_path).expect("Use emacs to parse org file."); + let org_sexp = emacs_parse_org_document(org_contents.as_str()).expect("Use emacs to parse org file."); println!("{{}}", org_sexp); let (_remaining, parsed_sexp) = sexp_with_padding(org_sexp.as_str()).expect("Sexp Parse failure"); let (remaining, rust_parsed) = document(org_contents.as_str()).expect("Org Parse failure");