Merge branch 'file_based_diff'
All checks were successful
rustfmt Build rustfmt has succeeded
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded

This commit is contained in:
Tom Alexander 2023-09-02 17:28:31 -04:00
commit acf1205e75
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
11 changed files with 130 additions and 28 deletions

View File

@ -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]

View File

@ -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;
"#

View File

@ -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"

View File

@ -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

View File

@ -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 "${@}"

View File

@ -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 "${@}"

View File

@ -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;

View File

@ -1,6 +1,9 @@
use std::path::Path;
use std::process::Command;
pub fn emacs_parse_org_document<C>(file_contents: C) -> Result<String, Box<dyn std::error::Error>>
pub fn emacs_parse_anonymous_org_document<C>(
file_contents: C,
) -> Result<String, Box<dyn std::error::Error>>
where
C: AsRef<str>,
{
@ -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<P>(file_path: P) -> Result<String, Box<dyn std::error::Error>>
where
P: AsRef<Path>,
{
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<String, Box<dyn std::error::Error>> {
(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<String, Box<dyn std::error::Error>> {
.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<String, Box<dyn std::error::Error>> {
(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<String, Box<dyn std::error::Error>> {
.arg("--eval")
.arg(elisp_script);
let out = proc.output()?;
let out = cmd.output()?;
out.status.exit_ok()?;
Ok(String::from_utf8(out.stderr)?)
}

View File

@ -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")]

View File

@ -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<dyn std::error::Error>> {
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn main_body() -> Result<(), Box<dyn std::error::Error>> {
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<String, Box<dyn std::error::Error>> {
@ -52,14 +64,12 @@ fn read_stdin_to_string() -> Result<String, Box<dyn std::error::Error>> {
}
#[cfg(feature = "compare")]
fn run_compare<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error::Error>> {
let emacs_version = get_emacs_version()?;
let org_mode_version = get_org_mode_version()?;
fn run_anonymous_parse<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error::Error>> {
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<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error:
}
#[cfg(not(feature = "compare"))]
fn run_compare<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error::Error>> {
fn run_anonymous_parse<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error::Error>> {
eprintln!(
"This program was built with compare disabled. Only parsing with organic, not comparing."
);
@ -90,3 +100,48 @@ fn run_compare<P: AsRef<str>>(org_contents: P) -> Result<(), Box<dyn std::error:
println!("{:#?}", rust_parsed);
Ok(())
}
#[cfg(feature = "compare")]
fn run_parse_on_file<P: AsRef<Path>>(org_path: P) -> Result<(), Box<dyn std::error::Error>> {
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<P: AsRef<Path>>(org_path: P) -> Result<(), Box<dyn std::error::Error>> {
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(())
}

View File

@ -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");