diff --git a/Cargo.toml b/Cargo.toml index 159f262..638017e 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 5636610..d76733e 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 4046e37..cc5ad92 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 1107024..db63647 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/run_docker_compare.bash b/scripts/run_docker_compare.bash index 30cdb92..7ac76e6 100755 --- a/scripts/run_docker_compare.bash +++ b/scripts/run_docker_compare.bash @@ -9,14 +9,13 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" : ${BACKTRACE:="NO"} # or YES to print a rust backtrace when panicking : ${NO_COLOR:=""} # Set to anything to disable color output - cd "$DIR/../" REALPATH=$(command -v uu-realpath || command -v realpath) MAKE=$(command -v gmake || command -v make) function main { build_container - launch_container + launch_container "${@}" } function build_container { @@ -51,7 +50,17 @@ function launch_container { additional_flags+=(--env RUST_BACKTRACE=full) fi - docker run "${additional_flags[@]}" --init --rm -i --mount type=tmpfs,destination=/tmp -v "$($REALPATH ./):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source --entrypoint "" organic-test "${additional_args[@]}" + if [ $# -gt 0 ]; then + # If we passed in args, we need to forward them along + for path in "${@}"; do + local full_path=$($REALPATH "$path") + local containing_folder=$(dirname "$full_path") + local file_name=$(basename "$full_path") + docker run "${additional_flags[@]}" --init --rm -i --mount type=tmpfs,destination=/tmp -v "${containing_folder}:/input:ro" -v "$($REALPATH ./):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source --entrypoint "" organic-test "${additional_args[@]}" -- "/input/$file_name" + done + else + docker run "${additional_flags[@]}" --init --rm -i --mount type=tmpfs,destination=/tmp -v "$($REALPATH ./):/source:ro" --mount source=cargo-cache,target=/usr/local/cargo/registry --mount source=rust-cache,target=/target --env CARGO_TARGET_DIR=/target -w /source --entrypoint "" organic-test "${additional_args[@]}" + fi } main "${@}" diff --git a/scripts/time_parse.bash b/scripts/time_parse.bash index 0efbbba..817bada 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 d5b2cf3..094dda5 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 0b70120..700b5b1 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 6b38c30..513e5c9 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 c61f9ef..968cd2d 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 a8b8031..2dd2ed4 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");