diff --git a/Cargo.toml b/Cargo.toml index 5aee591..b6287b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ repository = "https://github.com/scouten/asciidoc-parser" rust-version = "1.72.0" [dependencies] +nom = "7.1" diff --git a/src/lib.rs b/src/lib.rs index 9ce09c2..069f003 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ #![deny(warnings)] #![doc = include_str!("../README.md")] +pub(crate) mod primitives; pub mod strings; #[cfg(test)] diff --git a/src/primitives/line.rs b/src/primitives/line.rs new file mode 100644 index 0000000..9fe0975 --- /dev/null +++ b/src/primitives/line.rs @@ -0,0 +1,26 @@ +use nom::{bytes::complete::take_till, IResult}; + +#[allow(dead_code)] // TEMPORARY +pub(crate) fn line(input: &str) -> IResult<&str, &str> { + take_till(|c| c == '\n')(input) + .map(|ri| trim_rem_start_matches(ri, '\n')) + .map(|ri| trim_rem_end_matches(ri, '\r')) +} + +#[allow(dead_code)] // TEMPORARY +fn trim_rem_start_matches<'a>(rem_inp: (&'a str, &'a str), c: char) -> (&'a str, &'a str) { + if let Some(rem) = rem_inp.0.strip_prefix(c) { + (rem, rem_inp.1) + } else { + rem_inp + } +} + +#[allow(dead_code)] // TEMPORARY +fn trim_rem_end_matches<'a>(rem_inp: (&'a str, &'a str), c: char) -> (&'a str, &'a str) { + if let Some(inp) = rem_inp.1.strip_suffix(c) { + (rem_inp.0, inp) + } else { + rem_inp + } +} diff --git a/src/primitives/mod.rs b/src/primitives/mod.rs new file mode 100644 index 0000000..bfaed2a --- /dev/null +++ b/src/primitives/mod.rs @@ -0,0 +1,6 @@ +//! Contains various primitive parsing routines. +//! Not part of the public API surface. + +mod line; +#[allow(unused_imports)] +pub(crate) use line::line; diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 9f5f73e..79bc492 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -6,4 +6,5 @@ #![allow(clippy::unwrap_used)] mod fixtures; +mod primitives; mod strings; diff --git a/src/tests/primitives/line.rs b/src/tests/primitives/line.rs new file mode 100644 index 0000000..2d6288c --- /dev/null +++ b/src/tests/primitives/line.rs @@ -0,0 +1,37 @@ +mod fn_line { + use crate::primitives::line; + + #[test] + fn empty_source() { + assert_eq!(line(""), Ok(("", ""))); + } + + #[test] + fn simple_line() { + assert_eq!(line("abc"), Ok(("", "abc"))); + } + + #[test] + fn consumes_lf() { + // Should consume but not return \n. + assert_eq!(line("abc\ndef"), Ok(("def", "abc"))); + } + + #[test] + fn consumes_crlf() { + // Should consume but not return \r\n. + assert_eq!(line("abc\r\ndef"), Ok(("def", "abc"))); + } + + #[test] + fn doesnt_consume_lfcr() { + // Should consume \n but not a subsequent \r. + assert_eq!(line("abc\n\rdef"), Ok(("\rdef", "abc"))); + } + + #[test] + fn doesnt_consume_standalone_cr() { + // Shouldn't terminate line at \r without \n. + assert_eq!(line("abc\rdef"), Ok(("", "abc\rdef"))); + } +} diff --git a/src/tests/primitives/mod.rs b/src/tests/primitives/mod.rs new file mode 100644 index 0000000..dcd89fc --- /dev/null +++ b/src/tests/primitives/mod.rs @@ -0,0 +1 @@ +mod line;