Skip to content

Commit

Permalink
Retrofit Header::parse to use new API style (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
scouten authored Jul 27, 2024
1 parent b92bb9e commit 5c4b3df
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 73 deletions.
4 changes: 2 additions & 2 deletions src/document/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ impl<'a> Document<'a> {
let i = source.discard_empty_lines();

let (i, header) = if i.starts_with("= ") {
let (i, header) = Header::parse(i).ok()?;
(i, Some(header))
let pr = Header::parse(i)?;
(pr.rem, Some(pr.t))
} else {
(i, None)
};
Expand Down
57 changes: 27 additions & 30 deletions src/document/header.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
use std::slice::Iter;

use nom::{
bytes::complete::tag,
character::complete::space1,
error::{Error, ErrorKind},
multi::many0,
Err, IResult,
use crate::{
document::Attribute, primitives::trim_input_for_rem, span::ParseResult, HasSpan, Span,
};

use crate::{document::Attribute, primitives::trim_input_for_rem, HasSpan, Span};

/// An AsciiDoc document may begin with a document header. The document header
/// encapsulates the document title, author and revision information,
/// document-wide attributes, and other document metadata.
Expand All @@ -21,27 +15,33 @@ pub struct Header<'a> {
}

impl<'a> Header<'a> {
pub(crate) fn parse(i: Span<'a>) -> IResult<Span, Self> {
pub(crate) fn parse(i: Span<'a>) -> Option<ParseResult<Self>> {
let source = i.discard_empty_lines();

// TEMPORARY: Titles are optional, but we're not prepared for that yet.
let (rem, title) = parse_title(source)?;
let (rem, attributes) = many0(Attribute::parse)(rem)?;
let title = parse_title(source)?;

let mut attributes: Vec<Attribute> = vec![];
let mut rem = title.rem;

// Header must be followed by an empty line.
if rem.take_empty_line().is_none() {
return Err(Err::Error(Error::new(rem, ErrorKind::NonEmpty)));
while let Ok(attr) = Attribute::parse(rem) {
attributes.push(attr.1);
rem = attr.0;
}

let source = trim_input_for_rem(source, rem);
Ok((
rem.discard_empty_lines(),
Self {
title: Some(title),

// Header must be followed by an empty line or EOF.
let pr = rem.take_empty_line()?;

Some(ParseResult {
t: Self {
title: Some(title.t),
attributes,
source,
},
))
rem: pr.rem.discard_empty_lines(),
})
}

/// Return a [`Span`] describing the document title, if there was one.
Expand All @@ -61,16 +61,13 @@ impl<'a> HasSpan<'a> for Header<'a> {
}
}

fn parse_title(i: Span<'_>) -> IResult<Span, Span<'_>> {
let line = i
.take_non_empty_line()
.ok_or(nom::Err::Error(nom::error::Error::new(
i,
nom::error::ErrorKind::TakeTill1,
)))?;

let (title, _) = tag("=")(line.t)?;
let (title, _) = space1(title)?;
fn parse_title(i: Span<'_>) -> Option<ParseResult<Span>> {
let line = i.take_non_empty_line()?;
let equal = line.t.take_prefix("=")?;
let ws = equal.rem.take_required_whitespace()?;

Ok((line.rem, title))
Some(ParseResult {
t: ws.rem,
rem: line.rem,
})
}
82 changes: 41 additions & 41 deletions src/tests/document/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,10 @@ fn impl_clone() {

#[test]
fn only_title() {
let (rem, block) = Header::parse(Span::new("= Just the Title")).unwrap();
let pr = Header::parse(Span::new("= Just the Title")).unwrap();

assert_eq!(
rem,
TSpan {
data: "",
line: 1,
col: 17,
offset: 16
}
);

assert_eq!(
block,
pr.t,
THeader {
title: Some(TSpan {
data: "Just the Title",
Expand All @@ -49,26 +39,26 @@ fn only_title() {
}
}
);
}

#[test]
fn trims_leading_spaces_in_title() {
// This is totally a judgement call on my part. As far as I can tell,
// the language doesn't describe behavior here.
let (rem, block) = Header::parse(Span::new("= Just the Title")).unwrap();

assert_eq!(
rem,
pr.rem,
TSpan {
data: "",
line: 1,
col: 20,
offset: 19
col: 17,
offset: 16
}
);
}

#[test]
fn trims_leading_spaces_in_title() {
// This is totally a judgement call on my part. As far as I can tell,
// the language doesn't describe behavior here.
let pr = Header::parse(Span::new("= Just the Title")).unwrap();

assert_eq!(
block,
pr.t,
THeader {
title: Some(TSpan {
data: "Just the Title",
Expand All @@ -85,24 +75,24 @@ fn trims_leading_spaces_in_title() {
}
}
);
}

#[test]
fn trims_trailing_spaces_in_title() {
let (rem, block) = Header::parse(Span::new("= Just the Title ")).unwrap();

assert_eq!(
rem,
pr.rem,
TSpan {
data: "",
line: 1,
col: 20,
offset: 19
}
);
}

#[test]
fn trims_trailing_spaces_in_title() {
let pr = Header::parse(Span::new("= Just the Title ")).unwrap();

assert_eq!(
block,
pr.t,
THeader {
title: Some(TSpan {
data: "Just the Title",
Expand All @@ -119,24 +109,24 @@ fn trims_trailing_spaces_in_title() {
}
}
);
}

#[test]
fn title_and_attribute() {
let (rem, block) = Header::parse(Span::new("= Just the Title\n:foo: bar\n\nblah")).unwrap();

assert_eq!(
rem,
pr.rem,
TSpan {
data: "blah",
line: 4,
col: 1,
offset: 28
data: "",
line: 1,
col: 20,
offset: 19
}
);
}

#[test]
fn title_and_attribute() {
let pr = Header::parse(Span::new("= Just the Title\n:foo: bar\n\nblah")).unwrap();

assert_eq!(
block,
pr.t,
THeader {
title: Some(TSpan {
data: "Just the Title",
Expand Down Expand Up @@ -172,4 +162,14 @@ fn title_and_attribute() {
}
}
);

assert_eq!(
pr.rem,
TSpan {
data: "blah",
line: 4,
col: 1,
offset: 28
}
);
}

0 comments on commit 5c4b3df

Please sign in to comment.