Compare commits
6 Commits
cf383fa394
...
v0.1.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26f41b83aa | ||
|
|
e4c0e32536 | ||
|
|
37e85158ea | ||
|
|
6589a755a6 | ||
|
|
a651b79e77 | ||
|
|
98de5e4ec5 |
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "organic"
|
name = "organic"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
authors = ["Tom Alexander <tom@fizz.buzz>"]
|
authors = ["Tom Alexander <tom@fizz.buzz>"]
|
||||||
description = "An org-mode parser."
|
description = "An org-mode parser."
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
4
build.rs
4
build.rs
@@ -71,10 +71,6 @@ fn write_header(test_file: &mut File) {
|
|||||||
test_file,
|
test_file,
|
||||||
r#"
|
r#"
|
||||||
#[feature(exit_status_error)]
|
#[feature(exit_status_error)]
|
||||||
use organic::compare_document;
|
|
||||||
use organic::parser::parse;
|
|
||||||
use organic::emacs_parse_anonymous_org_document;
|
|
||||||
use organic::parser::sexp::sexp_with_padding;
|
|
||||||
|
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,18 +1,9 @@
|
|||||||
#![feature(round_char_boundary)]
|
#![feature(round_char_boundary)]
|
||||||
#![feature(exact_size_is_empty)]
|
#![feature(exact_size_is_empty)]
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use ::organic::parser::parse;
|
use organic::compare::run_anonymous_compare;
|
||||||
use organic::compare_document;
|
use organic::compare::run_compare_on_file;
|
||||||
use organic::emacs_parse_anonymous_org_document;
|
|
||||||
use organic::emacs_parse_file_org_document;
|
|
||||||
use organic::get_emacs_version;
|
|
||||||
use organic::get_org_mode_version;
|
|
||||||
use organic::parser::parse_with_settings;
|
|
||||||
use organic::parser::sexp::sexp_with_padding;
|
|
||||||
use organic::GlobalSettings;
|
|
||||||
use organic::LocalFileAccessInterface;
|
|
||||||
|
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
use crate::init_tracing::init_telemetry;
|
use crate::init_tracing::init_telemetry;
|
||||||
@@ -43,10 +34,10 @@ fn main_body() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let args = std::env::args().skip(1);
|
let args = std::env::args().skip(1);
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
let org_contents = read_stdin_to_string()?;
|
let org_contents = read_stdin_to_string()?;
|
||||||
run_anonymous_parse(org_contents)
|
run_anonymous_compare(org_contents)
|
||||||
} else {
|
} else {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
run_parse_on_file(arg)?
|
run_compare_on_file(arg)?
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -59,64 +50,3 @@ fn read_stdin_to_string() -> Result<String, Box<dyn std::error::Error>> {
|
|||||||
.read_to_string(&mut stdin_contents)?;
|
.read_to_string(&mut stdin_contents)?;
|
||||||
Ok(stdin_contents)
|
Ok(stdin_contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
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: {}", get_emacs_version()?.trim());
|
|
||||||
eprintln!("Using org-mode version: {}", get_org_mode_version()?.trim());
|
|
||||||
let rust_parsed = parse(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())?;
|
|
||||||
|
|
||||||
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.")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
let parent_directory = org_path
|
|
||||||
.parent()
|
|
||||||
.ok_or("Should be contained inside a directory.")?;
|
|
||||||
let org_contents = std::fs::read_to_string(org_path)?;
|
|
||||||
let org_contents = org_contents.as_str();
|
|
||||||
let file_access_interface = LocalFileAccessInterface {
|
|
||||||
working_directory: Some(parent_directory.to_path_buf()),
|
|
||||||
};
|
|
||||||
let global_settings = {
|
|
||||||
let mut global_settings = GlobalSettings::default();
|
|
||||||
global_settings.file_access = &file_access_interface;
|
|
||||||
global_settings
|
|
||||||
};
|
|
||||||
let rust_parsed = parse_with_settings(org_contents, &global_settings)?;
|
|
||||||
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.")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|||||||
73
src/compare/compare.rs
Normal file
73
src/compare/compare.rs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use crate::compare::diff::compare_document;
|
||||||
|
use crate::compare::parse::emacs_parse_anonymous_org_document;
|
||||||
|
use crate::compare::parse::emacs_parse_file_org_document;
|
||||||
|
use crate::compare::parse::get_emacs_version;
|
||||||
|
use crate::compare::parse::get_org_mode_version;
|
||||||
|
use crate::compare::sexp::sexp;
|
||||||
|
use crate::parser::parse;
|
||||||
|
use crate::parser::parse_with_settings;
|
||||||
|
use crate::GlobalSettings;
|
||||||
|
use crate::LocalFileAccessInterface;
|
||||||
|
|
||||||
|
pub fn run_anonymous_compare<P: AsRef<str>>(
|
||||||
|
org_contents: P,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let org_contents = org_contents.as_ref();
|
||||||
|
eprintln!("Using emacs version: {}", get_emacs_version()?.trim());
|
||||||
|
eprintln!("Using org-mode version: {}", get_org_mode_version()?.trim());
|
||||||
|
let rust_parsed = parse(org_contents)?;
|
||||||
|
let org_sexp = emacs_parse_anonymous_org_document(org_contents)?;
|
||||||
|
let (_remaining, parsed_sexp) = sexp(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.")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_compare_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());
|
||||||
|
let parent_directory = org_path
|
||||||
|
.parent()
|
||||||
|
.ok_or("Should be contained inside a directory.")?;
|
||||||
|
let org_contents = std::fs::read_to_string(org_path)?;
|
||||||
|
let org_contents = org_contents.as_str();
|
||||||
|
let file_access_interface = LocalFileAccessInterface {
|
||||||
|
working_directory: Some(parent_directory.to_path_buf()),
|
||||||
|
};
|
||||||
|
let global_settings = {
|
||||||
|
let mut global_settings = GlobalSettings::default();
|
||||||
|
global_settings.file_access = &file_access_interface;
|
||||||
|
global_settings
|
||||||
|
};
|
||||||
|
let rust_parsed = parse_with_settings(org_contents, &global_settings)?;
|
||||||
|
let org_sexp = emacs_parse_file_org_document(org_path)?;
|
||||||
|
let (_remaining, parsed_sexp) = sexp(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.")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use super::sexp::unquote;
|
||||||
|
use super::sexp::Token;
|
||||||
use super::util::assert_bounds;
|
use super::util::assert_bounds;
|
||||||
use super::util::assert_name;
|
use super::util::assert_name;
|
||||||
use super::util::get_property;
|
use super::util::get_property;
|
||||||
use crate::parser::sexp::unquote;
|
|
||||||
use crate::parser::sexp::Token;
|
|
||||||
use crate::types::AngleLink;
|
use crate::types::AngleLink;
|
||||||
use crate::types::Bold;
|
use crate::types::Bold;
|
||||||
use crate::types::Citation;
|
use crate::types::Citation;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
|
mod compare;
|
||||||
mod diff;
|
mod diff;
|
||||||
mod parse;
|
mod parse;
|
||||||
|
mod sexp;
|
||||||
mod util;
|
mod util;
|
||||||
pub use diff::compare_document;
|
pub use compare::run_anonymous_compare;
|
||||||
pub use parse::emacs_parse_anonymous_org_document;
|
pub use compare::run_compare_on_file;
|
||||||
pub use parse::emacs_parse_file_org_document;
|
|
||||||
pub use parse::get_emacs_version;
|
|
||||||
pub use parse::get_org_mode_version;
|
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ use nom::sequence::delimited;
|
|||||||
use nom::sequence::preceded;
|
use nom::sequence::preceded;
|
||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use super::org_source::convert_error;
|
|
||||||
use super::org_source::OrgSource;
|
|
||||||
use super::util::get_consumed;
|
|
||||||
use crate::error::Res;
|
use crate::error::Res;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -99,6 +96,25 @@ impl<'s> Token<'s> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the child string slice is a slice of the parent string slice.
|
||||||
|
fn is_slice_of(parent: &str, child: &str) -> bool {
|
||||||
|
let parent_start = parent.as_ptr() as usize;
|
||||||
|
let parent_end = parent_start + parent.len();
|
||||||
|
let child_start = child.as_ptr() as usize;
|
||||||
|
let child_end = child_start + child.len();
|
||||||
|
child_start >= parent_start && child_end <= parent_end
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a slice of the string that was consumed in a parser using the original input to the parser and the remaining input after the parser.
|
||||||
|
pub fn get_consumed<'s>(input: &'s str, remaining: &'s str) -> &'s str {
|
||||||
|
assert!(is_slice_of(input, remaining));
|
||||||
|
let source = {
|
||||||
|
let offset = remaining.as_ptr() as usize - input.as_ptr() as usize;
|
||||||
|
&input[..offset]
|
||||||
|
};
|
||||||
|
source.into()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn unquote(text: &str) -> Result<String, Box<dyn std::error::Error>> {
|
pub(crate) fn unquote(text: &str) -> Result<String, Box<dyn std::error::Error>> {
|
||||||
let mut out = String::with_capacity(text.len());
|
let mut out = String::with_capacity(text.len());
|
||||||
if !text.starts_with(r#"""#) {
|
if !text.starts_with(r#"""#) {
|
||||||
@@ -136,29 +152,20 @@ pub(crate) fn unquote(text: &str) -> Result<String, Box<dyn std::error::Error>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
pub fn sexp_with_padding<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
pub fn sexp<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
let (remaining, _) = multispace0(input)?;
|
let (remaining, _) = multispace0(input)?;
|
||||||
let remaining = OrgSource::new(remaining);
|
let (remaining, tkn) = token(remaining).map(|(rem, out)| (Into::<&str>::into(rem), out))?;
|
||||||
let (remaining, tkn) = token(remaining)
|
|
||||||
.map(|(rem, out)| (Into::<&str>::into(rem), out))
|
|
||||||
.map_err(convert_error)?;
|
|
||||||
let (remaining, _) = multispace0(remaining)?;
|
let (remaining, _) = multispace0(remaining)?;
|
||||||
Ok((remaining, tkn))
|
Ok((remaining, tkn))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn sexp<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
fn token<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
let (remaining, tkn) = token(input)?;
|
|
||||||
Ok((remaining, tkn))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
|
||||||
fn token<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
|
||||||
alt((list, vector, atom))(input)
|
alt((list, vector, atom))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn list<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
fn list<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
let (remaining, _) = tag("(")(input)?;
|
let (remaining, _) = tag("(")(input)?;
|
||||||
let (remaining, children) = delimited(
|
let (remaining, children) = delimited(
|
||||||
multispace0,
|
multispace0,
|
||||||
@@ -170,7 +177,7 @@ fn list<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn vector<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
fn vector<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
let (remaining, _) = tag("[")(input)?;
|
let (remaining, _) = tag("[")(input)?;
|
||||||
let (remaining, children) = delimited(
|
let (remaining, children) = delimited(
|
||||||
multispace0,
|
multispace0,
|
||||||
@@ -182,7 +189,7 @@ fn vector<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn atom<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
fn atom<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
not(peek(one_of(")]")))(input)?;
|
not(peek(one_of(")]")))(input)?;
|
||||||
alt((
|
alt((
|
||||||
text_with_properties,
|
text_with_properties,
|
||||||
@@ -193,7 +200,7 @@ fn atom<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn unquoted_atom<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
fn unquoted_atom<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
let (remaining, body) = take_till1(|c| match c {
|
let (remaining, body) = take_till1(|c| match c {
|
||||||
' ' | '\t' | '\r' | '\n' | ')' | ']' => true,
|
' ' | '\t' | '\r' | '\n' | ')' | ']' => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
@@ -202,7 +209,7 @@ fn unquoted_atom<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn quoted_atom<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
fn quoted_atom<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
let (remaining, _) = tag(r#"""#)(input)?;
|
let (remaining, _) = tag(r#"""#)(input)?;
|
||||||
let (remaining, _) = escaped(
|
let (remaining, _) = escaped(
|
||||||
take_till1(|c| match c {
|
take_till1(|c| match c {
|
||||||
@@ -218,7 +225,7 @@ fn quoted_atom<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
|
||||||
fn hash_notation<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
fn hash_notation<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
let (remaining, _) = tag("#<")(input)?;
|
let (remaining, _) = tag("#<")(input)?;
|
||||||
let (remaining, _body) = take_till1(|c| match c {
|
let (remaining, _body) = take_till1(|c| match c {
|
||||||
'>' => true,
|
'>' => true,
|
||||||
@@ -229,7 +236,7 @@ fn hash_notation<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
|||||||
Ok((remaining, Token::Atom(source.into())))
|
Ok((remaining, Token::Atom(source.into())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn text_with_properties<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, Token<'s>> {
|
fn text_with_properties<'s>(input: &'s str) -> Res<&'s str, Token<'s>> {
|
||||||
let (remaining, _) = tag("#(")(input)?;
|
let (remaining, _) = tag("#(")(input)?;
|
||||||
let (remaining, (text, props)) = delimited(
|
let (remaining, (text, props)) = delimited(
|
||||||
multispace0,
|
multispace0,
|
||||||
@@ -259,7 +266,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn simple() {
|
fn simple() {
|
||||||
let input = " (foo bar baz ) ";
|
let input = " (foo bar baz ) ";
|
||||||
let (remaining, parsed) = sexp_with_padding(input).expect("Parse the input");
|
let (remaining, parsed) = sexp(input).expect("Parse the input");
|
||||||
assert_eq!(remaining, "");
|
assert_eq!(remaining, "");
|
||||||
assert!(match parsed {
|
assert!(match parsed {
|
||||||
Token::Atom(_) => false,
|
Token::Atom(_) => false,
|
||||||
@@ -272,7 +279,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn quoted() {
|
fn quoted() {
|
||||||
let input = r#" ("foo" bar baz ) "#;
|
let input = r#" ("foo" bar baz ) "#;
|
||||||
let (remaining, parsed) = sexp_with_padding(input).expect("Parse the input");
|
let (remaining, parsed) = sexp(input).expect("Parse the input");
|
||||||
assert_eq!(remaining, "");
|
assert_eq!(remaining, "");
|
||||||
assert!(match parsed {
|
assert!(match parsed {
|
||||||
Token::Atom(_) => false,
|
Token::Atom(_) => false,
|
||||||
@@ -296,7 +303,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn quoted_containing_paren() {
|
fn quoted_containing_paren() {
|
||||||
let input = r#" (foo "b(a)r" baz ) "#;
|
let input = r#" (foo "b(a)r" baz ) "#;
|
||||||
let (remaining, parsed) = sexp_with_padding(input).expect("Parse the input");
|
let (remaining, parsed) = sexp(input).expect("Parse the input");
|
||||||
assert_eq!(remaining, "");
|
assert_eq!(remaining, "");
|
||||||
assert!(match parsed {
|
assert!(match parsed {
|
||||||
Token::List(_) => true,
|
Token::List(_) => true,
|
||||||
@@ -332,7 +339,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn string_containing_escaped_characters() {
|
fn string_containing_escaped_characters() {
|
||||||
let input = r#" (foo "\\( x=2 \\)" bar) "#;
|
let input = r#" (foo "\\( x=2 \\)" bar) "#;
|
||||||
let (remaining, parsed) = sexp_with_padding(input).expect("Parse the input");
|
let (remaining, parsed) = sexp(input).expect("Parse the input");
|
||||||
assert_eq!(remaining, "");
|
assert_eq!(remaining, "");
|
||||||
assert!(match parsed {
|
assert!(match parsed {
|
||||||
Token::Atom(_) => false,
|
Token::Atom(_) => false,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::parser::sexp::Token;
|
use super::sexp::Token;
|
||||||
use crate::types::Source;
|
use crate::types::Source;
|
||||||
|
|
||||||
/// Check if the child string slice is a slice of the parent string slice.
|
/// Check if the child string slice is a slice of the parent string slice.
|
||||||
|
|||||||
12
src/lib.rs
12
src/lib.rs
@@ -4,17 +4,7 @@
|
|||||||
// TODO: #![warn(missing_docs)]
|
// TODO: #![warn(missing_docs)]
|
||||||
|
|
||||||
#[cfg(feature = "compare")]
|
#[cfg(feature = "compare")]
|
||||||
mod compare;
|
pub mod compare;
|
||||||
#[cfg(feature = "compare")]
|
|
||||||
pub use compare::compare_document;
|
|
||||||
#[cfg(feature = "compare")]
|
|
||||||
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")]
|
|
||||||
pub use compare::get_org_mode_version;
|
|
||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
mod error;
|
mod error;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use crate::types::Object;
|
|||||||
///
|
///
|
||||||
/// This is the main entry point for Organic. It will parse the full contents of the input string as an org-mode document.
|
/// This is the main entry point for Organic. It will parse the full contents of the input string as an org-mode document.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn parse<'s>(input: &'s str) -> Result<Document<'s>, String> {
|
pub fn parse<'s>(input: &'s str) -> Result<Document<'s>, Box<dyn std::error::Error>> {
|
||||||
parse_with_settings(input, &GlobalSettings::default())
|
parse_with_settings(input, &GlobalSettings::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ pub fn parse<'s>(input: &'s str) -> Result<Document<'s>, String> {
|
|||||||
pub fn parse_with_settings<'g, 's>(
|
pub fn parse_with_settings<'g, 's>(
|
||||||
input: &'s str,
|
input: &'s str,
|
||||||
global_settings: &'g GlobalSettings<'g, 's>,
|
global_settings: &'g GlobalSettings<'g, 's>,
|
||||||
) -> Result<Document<'s>, String> {
|
) -> Result<Document<'s>, Box<dyn std::error::Error>> {
|
||||||
let initial_context = ContextElement::document_context();
|
let initial_context = ContextElement::document_context();
|
||||||
let initial_context = Context::new(global_settings, List::new(&initial_context));
|
let initial_context = Context::new(global_settings, List::new(&initial_context));
|
||||||
let wrapped_input = OrgSource::new(input);
|
let wrapped_input = OrgSource::new(input);
|
||||||
@@ -49,7 +49,7 @@ pub fn parse_with_settings<'g, 's>(
|
|||||||
all_consuming(parser_with_context!(document_org_source)(&initial_context))(wrapped_input)
|
all_consuming(parser_with_context!(document_org_source)(&initial_context))(wrapped_input)
|
||||||
.map_err(|err| err.to_string())
|
.map_err(|err| err.to_string())
|
||||||
.map(|(_remaining, parsed_document)| parsed_document);
|
.map(|(_remaining, parsed_document)| parsed_document);
|
||||||
ret
|
Ok(ret?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a full org-mode document.
|
/// Parse a full org-mode document.
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ mod property_drawer;
|
|||||||
mod radio_link;
|
mod radio_link;
|
||||||
mod regular_link;
|
mod regular_link;
|
||||||
mod section;
|
mod section;
|
||||||
#[cfg(feature = "compare")]
|
|
||||||
pub mod sexp;
|
|
||||||
mod statistics_cookie;
|
mod statistics_cookie;
|
||||||
mod subscript_and_superscript;
|
mod subscript_and_superscript;
|
||||||
mod table;
|
mod table;
|
||||||
|
|||||||
@@ -64,5 +64,5 @@ pub use object::Target;
|
|||||||
pub use object::Timestamp;
|
pub use object::Timestamp;
|
||||||
pub use object::Underline;
|
pub use object::Underline;
|
||||||
pub use object::Verbatim;
|
pub use object::Verbatim;
|
||||||
pub use source::SetSource;
|
pub(crate) use source::SetSource;
|
||||||
pub use source::Source;
|
pub use source::Source;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pub trait Source<'s> {
|
pub trait Source<'s> {
|
||||||
fn get_source(&'s self) -> &'s str;
|
fn get_source(&'s self) -> &'s str;
|
||||||
}
|
}
|
||||||
pub trait SetSource<'s> {
|
pub(crate) trait SetSource<'s> {
|
||||||
fn set_source(&mut self, source: &'s str);
|
fn set_source(&mut self, source: &'s str);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,7 @@
|
|||||||
#[test]
|
#[test]
|
||||||
fn {name}() {{
|
fn {name}() -> Result<(), Box<dyn std::error::Error>> {{
|
||||||
let todo_org_path = "{path}";
|
let org_path = "{path}";
|
||||||
let org_contents = std::fs::read_to_string(todo_org_path).expect("Read org file.");
|
let org_contents = std::fs::read_to_string(org_path).expect("Read org file.");
|
||||||
println!("{{}}", org_contents);
|
organic::compare::run_anonymous_compare(org_contents.as_str())?;
|
||||||
let org_sexp = emacs_parse_anonymous_org_document(org_contents.as_str()).expect("Use emacs to parse org file.");
|
Ok(())
|
||||||
println!("{{}}", org_sexp);
|
|
||||||
let (_remaining, parsed_sexp) = sexp_with_padding(org_sexp.as_str()).expect("Sexp Parse failure");
|
|
||||||
let rust_parsed = parse(org_contents.as_str()).expect("Org Parse failure");
|
|
||||||
println!("{{:#?}}", rust_parsed);
|
|
||||||
let diff_result =
|
|
||||||
compare_document(&parsed_sexp, &rust_parsed).expect("Compare parsed documents.");
|
|
||||||
diff_result
|
|
||||||
.print(org_contents.as_str())
|
|
||||||
.expect("Print document parse tree diff.");
|
|
||||||
assert!(!diff_result.is_bad());
|
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user