diff --git a/Cargo.toml b/Cargo.toml index 159f2621..638017ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ path = "src/lib.rs" [[bin]] # This bin exists for development purposes only. The real target of this crate is the library. -name = "compare" +name = "parse" path = "src/main.rs" [dependencies] diff --git a/build.rs b/build.rs index 56366106..d76733e2 100644 --- a/build.rs +++ b/build.rs @@ -73,7 +73,7 @@ fn write_header(test_file: &mut File) { #[feature(exit_status_error)] use organic::compare_document; use organic::parser::document; -use organic::emacs_parse_org_document; +use organic::emacs_parse_anonymous_org_document; use organic::parser::sexp::sexp_with_padding; "# diff --git a/scripts/callgrind.bash b/scripts/callgrind.bash index 4046e370..cc5ad927 100755 --- a/scripts/callgrind.bash +++ b/scripts/callgrind.bash @@ -7,7 +7,7 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$DIR/../" RUSTFLAGS="-C opt-level=0" cargo build --no-default-features -valgrind --tool=callgrind --callgrind-out-file=callgrind.out target/debug/compare +valgrind --tool=callgrind --callgrind-out-file=callgrind.out target/debug/parse echo "You probably want to run:" echo "callgrind_annotate --auto=yes callgrind.out" diff --git a/scripts/perf.bash b/scripts/perf.bash index 11070240..db63647b 100755 --- a/scripts/perf.bash +++ b/scripts/perf.bash @@ -16,7 +16,7 @@ function main { additional_flags+=(--profile "$PROFILE") fi cargo build --no-default-features "${additional_flags[@]}" - perf record --freq=2000 --call-graph dwarf --output=perf.data target/${PROFILE}/compare + perf record --freq=2000 --call-graph dwarf --output=perf.data target/${PROFILE}/parse # Convert to a format firefox will read # flags to consider --show-info diff --git a/scripts/time_parse.bash b/scripts/time_parse.bash index 0efbbba3..70e2a576 100755 --- a/scripts/time_parse.bash +++ b/scripts/time_parse.bash @@ -17,7 +17,7 @@ function main { additional_flags+=(--profile "$PROFILE") fi cargo build --no-default-features "${additional_flags[@]}" - time ./target/${PROFILE}/compare + time ./target/${PROFILE}/parse } main "${@}" diff --git a/src/compare/mod.rs b/src/compare/mod.rs index d5b2cf35..094dda5f 100644 --- a/src/compare/mod.rs +++ b/src/compare/mod.rs @@ -2,6 +2,7 @@ mod diff; mod parse; mod util; pub use diff::compare_document; -pub use parse::emacs_parse_org_document; +pub use parse::emacs_parse_anonymous_org_document; +pub use parse::emacs_parse_file_org_document; pub use parse::get_emacs_version; pub use parse::get_org_mode_version; diff --git a/src/compare/parse.rs b/src/compare/parse.rs index 0b70120f..700b5b1f 100644 --- a/src/compare/parse.rs +++ b/src/compare/parse.rs @@ -1,6 +1,9 @@ +use std::path::Path; use std::process::Command; -pub fn emacs_parse_org_document(file_contents: C) -> Result> +pub fn emacs_parse_anonymous_org_document( + file_contents: C, +) -> Result> where C: AsRef, { @@ -15,14 +18,46 @@ where escaped_file_contents = escaped_file_contents ); let mut cmd = Command::new("emacs"); - let proc = cmd + let cmd = cmd .arg("-q") .arg("--no-site-file") .arg("--no-splash") .arg("--batch") .arg("--eval") .arg(elisp_script); - let out = proc.output()?; + let out = cmd.output()?; + out.status.exit_ok()?; + let org_sexp = out.stderr; + Ok(String::from_utf8(org_sexp)?) +} + +pub fn emacs_parse_file_org_document

(file_path: P) -> Result> +where + P: AsRef, +{ + let file_path = file_path.as_ref().canonicalize()?; + let containing_directory = file_path.parent().ok_or(format!( + "Failed to get containing directory for path {}", + file_path.display() + ))?; + let elisp_script = format!( + r#"(progn + (org-mode) + (message "%s" (pp-to-string (org-element-parse-buffer))) +)"# + ); + let mut cmd = Command::new("emacs"); + let cmd = cmd + .current_dir(containing_directory) + .arg("-q") + .arg("--no-site-file") + .arg("--no-splash") + .arg("--batch") + .arg("--insert") + .arg(file_path.as_os_str()) + .arg("--eval") + .arg(elisp_script); + let out = cmd.output()?; out.status.exit_ok()?; let org_sexp = out.stderr; Ok(String::from_utf8(org_sexp)?) @@ -55,7 +90,7 @@ pub fn get_emacs_version() -> Result> { (message "%s" (version)) )"#; let mut cmd = Command::new("emacs"); - let proc = cmd + let cmd = cmd .arg("-q") .arg("--no-site-file") .arg("--no-splash") @@ -63,7 +98,7 @@ pub fn get_emacs_version() -> Result> { .arg("--eval") .arg(elisp_script); - let out = proc.output()?; + let out = cmd.output()?; out.status.exit_ok()?; Ok(String::from_utf8(out.stderr)?) } @@ -74,7 +109,7 @@ pub fn get_org_mode_version() -> Result> { (message "%s" (org-version nil t nil)) )"#; let mut cmd = Command::new("emacs"); - let proc = cmd + let cmd = cmd .arg("-q") .arg("--no-site-file") .arg("--no-splash") @@ -82,7 +117,7 @@ pub fn get_org_mode_version() -> Result> { .arg("--eval") .arg(elisp_script); - let out = proc.output()?; + let out = cmd.output()?; out.status.exit_ok()?; Ok(String::from_utf8(out.stderr)?) } diff --git a/src/lib.rs b/src/lib.rs index 6b38c30a..513e5c92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,9 @@ mod compare; #[cfg(feature = "compare")] pub use compare::compare_document; #[cfg(feature = "compare")] -pub use compare::emacs_parse_org_document; +pub use compare::emacs_parse_anonymous_org_document; +#[cfg(feature = "compare")] +pub use compare::emacs_parse_file_org_document; #[cfg(feature = "compare")] pub use compare::get_emacs_version; #[cfg(feature = "compare")] diff --git a/src/main.rs b/src/main.rs index c61f9ef2..968cd2dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,15 @@ #![feature(round_char_boundary)] +#![feature(exact_size_is_empty)] use std::io::Read; +use std::path::Path; use ::organic::parser::document; #[cfg(feature = "compare")] use organic::compare_document; #[cfg(feature = "compare")] -use organic::emacs_parse_org_document; +use organic::emacs_parse_anonymous_org_document; +#[cfg(feature = "compare")] +use organic::emacs_parse_file_org_document; #[cfg(feature = "compare")] use organic::get_emacs_version; #[cfg(feature = "compare")] @@ -39,8 +43,16 @@ fn main() -> Result<(), Box> { #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] fn main_body() -> Result<(), Box> { - let org_contents = read_stdin_to_string()?; - run_compare(org_contents) + let args = std::env::args(); + if args.is_empty() { + let org_contents = read_stdin_to_string()?; + run_anonymous_parse(org_contents) + } else { + for arg in args.skip(1) { + run_parse_on_file(arg)? + } + Ok(()) + } } fn read_stdin_to_string() -> Result> { @@ -52,14 +64,12 @@ fn read_stdin_to_string() -> Result> { } #[cfg(feature = "compare")] -fn run_compare>(org_contents: P) -> Result<(), Box> { - let emacs_version = get_emacs_version()?; - let org_mode_version = get_org_mode_version()?; +fn run_anonymous_parse>(org_contents: P) -> Result<(), Box> { let org_contents = org_contents.as_ref(); - eprintln!("Using emacs version: {}", emacs_version.trim()); - eprintln!("Using org-mode version: {}", org_mode_version.trim()); + eprintln!("Using emacs version: {}", get_emacs_version()?.trim()); + eprintln!("Using org-mode version: {}", get_org_mode_version()?.trim()); let (remaining, rust_parsed) = document(org_contents).map_err(|e| e.to_string())?; - let org_sexp = emacs_parse_org_document(org_contents)?; + let org_sexp = emacs_parse_anonymous_org_document(org_contents)?; let (_remaining, parsed_sexp) = sexp_with_padding(org_sexp.as_str()).map_err(|e| e.to_string())?; @@ -82,7 +92,7 @@ fn run_compare>(org_contents: P) -> Result<(), Box>(org_contents: P) -> Result<(), Box> { +fn run_anonymous_parse>(org_contents: P) -> Result<(), Box> { eprintln!( "This program was built with compare disabled. Only parsing with organic, not comparing." ); @@ -90,3 +100,48 @@ fn run_compare>(org_contents: P) -> Result<(), Box>(org_path: P) -> Result<(), Box> { + let org_path = org_path.as_ref(); + eprintln!("Using emacs version: {}", get_emacs_version()?.trim()); + eprintln!("Using org-mode version: {}", get_org_mode_version()?.trim()); + // TODO: This should take into account the original file path when parsing in Organic, not just in emacs. + let org_contents = std::fs::read_to_string(org_path)?; + let org_contents = org_contents.as_str(); + let (remaining, rust_parsed) = document(org_contents).map_err(|e| e.to_string())?; + let org_sexp = emacs_parse_file_org_document(org_path)?; + let (_remaining, parsed_sexp) = + sexp_with_padding(org_sexp.as_str()).map_err(|e| e.to_string())?; + + println!("{}\n\n\n", org_contents); + println!("{}", org_sexp); + println!("{:#?}", rust_parsed); + + // We do the diffing after printing out both parsed forms in case the diffing panics + let diff_result = compare_document(&parsed_sexp, &rust_parsed)?; + diff_result.print(org_contents)?; + + if diff_result.is_bad() { + Err("Diff results do not match.")?; + } + if remaining != "" { + Err(format!("There was unparsed text remaining: {}", remaining))?; + } + + Ok(()) +} + +#[cfg(not(feature = "compare"))] +fn run_parse_on_file>(org_path: P) -> Result<(), Box> { + let org_path = org_path.as_ref(); + eprintln!( + "This program was built with compare disabled. Only parsing with organic, not comparing." + ); + // TODO: This should take into account the original file path when parsing + let org_contents = std::fs::read_to_string(org_path)?; + let org_contents = org_contents.as_str(); + let (_remaining, rust_parsed) = document(org_contents).map_err(|e| e.to_string())?; + println!("{:#?}", rust_parsed); + Ok(()) +} diff --git a/tests/test_template b/tests/test_template index a8b80318..2dd2ed4f 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(org_contents.as_str()).expect("Use emacs to parse org file."); + let org_sexp = emacs_parse_anonymous_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");