Skip to content

Commit

Permalink
Merge pull request #494 from SamWilsn/sourcepos-front-matter
Browse files Browse the repository at this point in the history
Account for front matter when calculating `sourcepos`
  • Loading branch information
kivikakk authored Nov 29, 2024
2 parents 0d7e147 + 17cc1f1 commit 0c6e6e6
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 2 deletions.
23 changes: 23 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1141,13 +1141,36 @@ impl<'a, 'o> Parser<'a, 'o> {
&self.options.extension.front_matter_delimiter,
) {
if let Some((front_matter, rest)) = split_off_front_matter(s, delimiter) {
let lines = front_matter
.as_bytes()
.iter()
.filter(|b| **b == b'\n')
.count();

let mut stripped_front_matter = front_matter.to_string();
strings::remove_trailing_blank_lines(&mut stripped_front_matter);
let stripped_lines = stripped_front_matter
.as_bytes()
.iter()
.filter(|b| **b == b'\n')
.count();

let node = self.add_child(
self.root,
NodeValue::FrontMatter(front_matter.to_string()),
1,
);
s = rest;
self.finalize(node).unwrap();

node.data.borrow_mut().sourcepos = Sourcepos {
start: nodes::LineColumn { line: 1, column: 1 },
end: nodes::LineColumn {
line: 1 + stripped_lines,
column: delimiter.len(),
},
};
self.line_number += lines;
}
}

Expand Down
14 changes: 12 additions & 2 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod description_lists;
mod empty;
mod escaped_char_spans;
mod footnotes;
mod front_matter;
mod fuzz;
mod greentext;
mod header_ids;
Expand Down Expand Up @@ -237,10 +238,19 @@ fn asssert_node_eq<'a>(node: &'a AstNode<'a>, location: &[usize], expected: &Nod

macro_rules! sourcepos {
(($spsl:literal:$spsc:literal-$spel:literal:$spec:literal)) => {
($spsl, $spsc, $spel, $spec).into()
$crate::nodes::Sourcepos {
start: $crate::nodes::LineColumn {
line: $spsl,
column: $spsc,
},
end: $crate::nodes::LineColumn {
line: $spel,
column: $spec,
},
}
};
((XXX)) => {
(0, 1, 0, 1).into()
$crate::tests::sourcepos!((0:1-0:1))
};
}

Expand Down
181 changes: 181 additions & 0 deletions src/tests/front_matter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
use crate::{format_commonmark, parse_document, Arena, Options};

use super::*;

#[test]
fn round_trip_one_field() {
let mut options = Options::default();
options.extension.front_matter_delimiter = Some("---".to_owned());
let arena = Arena::new();
let input = "---\nlayout: post\n---\nText\n";
let root = parse_document(&arena, input, &options);
let mut buf = Vec::new();
format_commonmark(&root, &options, &mut buf).unwrap();
assert_eq!(&String::from_utf8(buf).unwrap(), input);
}

#[test]
fn round_trip_wide_delimiter() {
let mut options = Options::default();
options.extension.front_matter_delimiter = Some("\u{04fc}".to_owned());
let arena = Arena::new();
let input = "\u{04fc}\nlayout: post\n\u{04fc}\nText\n";
let root = parse_document(&arena, input, &options);
let mut buf = Vec::new();
format_commonmark(&root, &options, &mut buf).unwrap();
assert_eq!(&String::from_utf8(buf).unwrap(), input);
}

#[test]
fn ast_wide_delimiter() {
let input = "\u{04fc}\nlayout: post\n\u{04fc}\nText\n";

assert_ast_match_i(
input,
ast!((document (1:1-4:4) [
(frontmatter (1:1-3:2) [])
(paragraph (4:1-4:4) [
(text (4:1-4:4) [])
])
])),
|opts| opts.extension.front_matter_delimiter = Some("\u{04fc}".to_owned()),
);
}

#[test]
fn ast() {
let input = "q\nlayout: post\nq\nText\n";

assert_ast_match_i(
input,
ast!((document (1:1-4:4) [
(frontmatter (1:1-3:1) [])
(paragraph (4:1-4:4) [
(text (4:1-4:4) [])
])
])),
|opts| opts.extension.front_matter_delimiter = Some("q".to_owned()),
);
}

#[test]
fn ast_blank_line() {
let input = r#"---
a: b
---
hello world
"#;

assert_ast_match_i(
input,
ast!((document (1:1-5:11) [
(frontmatter (1:1-3:3) [])
(paragraph (5:1-5:11) [
(text (5:1-5:11) [])
])
])),
|opts| opts.extension.front_matter_delimiter = Some("---".to_owned()),
);
}

#[test]
fn ast_carriage_return() {
let input = "q\r\nlayout: post\r\nq\r\nText\r\n";

assert_ast_match_i(
input,
ast!((document (1:1-4:4) [
(frontmatter (1:1-3:1) [])
(paragraph (4:1-4:4) [
(text (4:1-4:4) [])
])
])),
|opts| opts.extension.front_matter_delimiter = Some("q".to_owned()),
);
}

#[test]
fn trailing_space_open() {
let input = "--- \nlayout: post\n---\nText\n";

let mut options = Options::default();
options.extension.front_matter_delimiter = Some("---".to_owned());
let arena = Arena::new();
let root = parse_document(&arena, input, &options);

let found = root
.descendants()
.filter(|n| matches!(n.data.borrow().value, NodeValue::FrontMatter(..)))
.next();

assert!(found.is_none(), "no FrontMatter expected");
}

#[test]
fn leading_space_open() {
let input = " ---\nlayout: post\n---\nText\n";

let mut options = Options::default();
options.extension.front_matter_delimiter = Some("---".to_owned());
let arena = Arena::new();
let root = parse_document(&arena, input, &options);

let found = root
.descendants()
.filter(|n| matches!(n.data.borrow().value, NodeValue::FrontMatter(..)))
.next();

assert!(found.is_none(), "no FrontMatter expected");
}

#[test]
fn leading_space_close() {
let input = "---\nlayout: post\n ---\nText\n";

let mut options = Options::default();
options.extension.front_matter_delimiter = Some("---".to_owned());
let arena = Arena::new();
let root = parse_document(&arena, input, &options);

let found = root
.descendants()
.filter(|n| matches!(n.data.borrow().value, NodeValue::FrontMatter(..)))
.next();

assert!(found.is_none(), "no FrontMatter expected");
}

#[test]
fn trailing_space_close() {
let input = "---\nlayout: post\n--- \nText\n";

let mut options = Options::default();
options.extension.front_matter_delimiter = Some("---".to_owned());
let arena = Arena::new();
let root = parse_document(&arena, input, &options);

let found = root
.descendants()
.filter(|n| matches!(n.data.borrow().value, NodeValue::FrontMatter(..)))
.next();

assert!(found.is_none(), "no FrontMatter expected");
}

#[test]
fn second_line() {
let input = "\n---\nlayout: post\n ---\nText\n";

let mut options = Options::default();
options.extension.front_matter_delimiter = Some("---".to_owned());
let arena = Arena::new();
let root = parse_document(&arena, input, &options);

let found = root
.descendants()
.filter(|n| matches!(n.data.borrow().value, NodeValue::FrontMatter(..)))
.next();

assert!(found.is_none(), "no FrontMatter expected");
}

0 comments on commit 0c6e6e6

Please sign in to comment.