Compare commits

...

12 Commits

Author SHA1 Message Date
Tom Alexander
3fb7cb82cd
Implement get_contents for document.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has failed
rust-build Build rust-build has succeeded
rust-test Build rust-test has failed
2023-11-01 01:22:43 -04:00
Tom Alexander
e0ec5c115f
Need a constant value for generic numbers. 2023-11-01 00:49:22 -04:00
Tom Alexander
f0868ba3ed
Add a post blank implementation to document. 2023-10-31 23:56:40 -04:00
Tom Alexander
425bc12353
Add implementations to calculate the new fields for heading. 2023-10-31 23:46:53 -04:00
Tom Alexander
03754be71e
Implement the new fields for section. 2023-10-31 23:16:57 -04:00
Tom Alexander
70002800c2
Implement the new fields for footnote definitions. 2023-10-31 23:12:04 -04:00
Tom Alexander
281c35677b
Implement the new fields for paragraph. 2023-10-31 23:06:43 -04:00
Tom Alexander
92d15c3d91
Fix clippy. 2023-10-31 22:58:17 -04:00
Tom Alexander
b1773ac90e
Get post blank for footnote references. 2023-10-31 22:58:17 -04:00
Tom Alexander
645d9abf9c
Support nil contents. 2023-10-31 22:58:17 -04:00
Tom Alexander
d2f2bdf88d
Implement get_contents for footnote references. 2023-10-31 22:58:17 -04:00
Tom Alexander
90ba17b68c
Switch to a numeric post-blank.
Turns out post-blank has different meanings to different object types so we need to return a number to properly do the compare.
2023-10-31 22:32:01 -04:00
14 changed files with 344 additions and 174 deletions

View File

@ -100,20 +100,26 @@ fn assert_bounds<'b, 's, S: StandardProperties<'s> + ?Sized>(
// Check contents-begin/contents-end
{
let (begin, end) = (
standard_properties
.contents_begin
.ok_or("Token should have a begin.")?,
standard_properties
.contents_end
.ok_or("Token should have an end.")?,
);
let (rust_begin, rust_end) = get_rust_byte_offsets(original_document, rust.get_contents()); // 0-based
let rust_begin_char_offset = original_document[..rust_begin].chars().count() + 1; // 1-based
let rust_end_char_offset =
rust_begin_char_offset + original_document[rust_begin..rust_end].chars().count(); // 1-based
if rust_begin_char_offset != begin || rust_end_char_offset != end {
Err(format!("Rust contents bounds (in chars) ({rust_begin}, {rust_end}) do not match emacs contents bounds ({emacs_begin}, {emacs_end})", rust_begin = rust_begin_char_offset, rust_end = rust_end_char_offset, emacs_begin=begin, emacs_end=end))?;
if let Some(rust_contents) = rust.get_contents() {
let (begin, end) = (
standard_properties
.contents_begin
.ok_or("Token should have a contents-begin.")?,
standard_properties
.contents_end
.ok_or("Token should have an contents-end.")?,
);
let (rust_begin, rust_end) = get_rust_byte_offsets(original_document, rust_contents); // 0-based
let rust_begin_char_offset = original_document[..rust_begin].chars().count() + 1; // 1-based
let rust_end_char_offset =
rust_begin_char_offset + original_document[rust_begin..rust_end].chars().count(); // 1-based
if rust_begin_char_offset != begin || rust_end_char_offset != end {
Err(format!("Rust contents bounds (in chars) ({rust_begin}, {rust_end}) do not match emacs contents bounds ({emacs_begin}, {emacs_end})", rust_begin = rust_begin_char_offset, rust_end = rust_end_char_offset, emacs_begin=begin, emacs_end=end))?;
}
} else if standard_properties.contents_begin.is_some()
|| standard_properties.contents_end.is_some()
{
Err(format!("Rust contents is None but emacs contents bounds are ({emacs_begin:?}, {emacs_end:?})", emacs_begin=standard_properties.contents_begin, emacs_end=standard_properties.contents_end))?;
}
}
@ -128,11 +134,11 @@ fn assert_post_blank<'b, 's, S: StandardProperties<'s> + ?Sized>(
rust: &'b S,
) -> Result<(), Box<dyn std::error::Error>> {
let standard_properties = get_emacs_standard_properties(emacs)?; // 1-based
let rust_post_blank = rust.get_post_blank().chars().count();
let rust_post_blank = rust.get_post_blank();
let emacs_post_blank = standard_properties
.post_blank
.ok_or("Token should have a post-blank.")?;
if rust_post_blank != emacs_post_blank {
if rust_post_blank as usize != emacs_post_blank {
Err(format!("Rust post-blank (in chars) {rust_post_blank} does not match emacs post-blank ({emacs_post_blank})", rust_post_blank = rust_post_blank, emacs_post_blank = emacs_post_blank))?;
}

View File

@ -75,6 +75,7 @@ where
let parser_context = parser_context.with_additional_node(&contexts[2]);
let element_matcher = parser_with_context!(element(true))(&parser_context);
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
let before_contents = remaining;
let (mut remaining, (mut children, _exit_contents)) =
many_till(include_input(element_matcher), exit_matcher)(remaining)?;
@ -90,13 +91,16 @@ where
}
}
let (remaining, _trailing_ws) =
let contents = get_consumed(before_contents, remaining);
let (remaining, post_blank) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,
FootnoteDefinition {
source: source.into(),
contents: Some(contents.into()),
post_blank: post_blank.map(Into::<&str>::into),
affiliated_keywords: parse_affiliated_keywords(
context.get_global_settings(),
affiliated_keywords,

View File

@ -2,6 +2,7 @@ use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::bytes::complete::tag_no_case;
use nom::combinator::all_consuming;
use nom::combinator::consumed;
use nom::combinator::map_parser;
use nom::combinator::verify;
use nom::multi::many1;
@ -59,7 +60,7 @@ fn anonymous_footnote<'b, 'g, 'r, 's>(
let initial_context = ContextElement::document_context();
let initial_context = Context::new(context.get_global_settings(), List::new(&initial_context));
let (remaining, children) = map_parser(
let (remaining, (contents, children)) = consumed(map_parser(
verify(
parser_with_context!(text_until_exit)(&parser_context),
|text| text.len() > 0,
@ -69,17 +70,19 @@ fn anonymous_footnote<'b, 'g, 'r, 's>(
&initial_context,
)))(i)
}),
)(remaining)?;
))(remaining)?;
let (remaining, _) = tag("]")(remaining)?;
let (remaining, _trailing_whitespace) =
let (remaining, post_blank) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,
FootnoteReference {
source: source.into(),
contents: Some(contents.into()),
post_blank: post_blank.map(Into::<&str>::into),
label: None,
definition: children,
},
@ -106,7 +109,7 @@ fn inline_footnote<'b, 'g, 'r, 's>(
let initial_context = ContextElement::document_context();
let initial_context = Context::new(context.get_global_settings(), List::new(&initial_context));
let (remaining, children) = map_parser(
let (remaining, (contents, children)) = consumed(map_parser(
verify(
parser_with_context!(text_until_exit)(&parser_context),
|text| text.len() > 0,
@ -116,17 +119,19 @@ fn inline_footnote<'b, 'g, 'r, 's>(
&initial_context,
)))(i)
}),
)(remaining)?;
))(remaining)?;
let (remaining, _) = tag("]")(remaining)?;
let (remaining, _trailing_whitespace) =
let (remaining, post_blank) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,
FootnoteReference {
source: source.into(),
contents: Some(contents.into()),
post_blank: post_blank.map(Into::<&str>::into),
label: Some(label_contents.into()),
definition: children,
},
@ -144,13 +149,15 @@ fn footnote_reference_only<'b, 'g, 'r, 's>(
let (remaining, _) = tag_no_case("[fn:")(input)?;
let (remaining, label_contents) = label(remaining)?;
let (remaining, _) = tag("]")(remaining)?;
let (remaining, _trailing_whitespace) =
let (remaining, post_blank) =
maybe_consume_object_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
Ok((
remaining,
FootnoteReference {
source: source.into(),
contents: None,
post_blank: post_blank.map(Into::<&str>::into),
label: Some(label_contents.into()),
definition: Vec::with_capacity(0),
},

View File

@ -1,4 +1,5 @@
use nom::branch::alt;
use nom::combinator::consumed;
use nom::combinator::eof;
use nom::combinator::recognize;
use nom::combinator::verify;
@ -45,14 +46,14 @@ where
let standard_set_object_matcher = parser_with_context!(standard_set_object)(&parser_context);
let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context);
let (remaining, (children, _exit_contents)) = verify(
let (remaining, (contents, (children, _exit_contents))) = consumed(verify(
many_till(standard_set_object_matcher, exit_matcher),
|(children, _exit_contents)| !children.is_empty(),
)(remaining)?;
))(remaining)?;
// Not checking parent exit matcher because if there are any children matched then we have a valid paragraph.
let (remaining, _trailing_ws) =
let (remaining, post_blank) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
@ -60,6 +61,8 @@ where
remaining,
Paragraph {
source: source.into(),
contents: Some(contents.into()),
post_blank: post_blank.map(Into::<&str>::into),
affiliated_keywords: parse_affiliated_keywords(
context.get_global_settings(),
affiliated_keywords,

View File

@ -1,3 +1,4 @@
use nom::combinator::consumed;
use nom::combinator::opt;
use nom::combinator::recognize;
use nom::combinator::verify;
@ -58,12 +59,12 @@ pub(crate) fn zeroth_section<'b, 'g, 'r, 's>(
many0(blank_line),
)))(input)?;
let (remaining, (mut children, _exit_contents)) = verify(
let (remaining, (contents, (mut children, _exit_contents))) = consumed(verify(
many_till(element_matcher, exit_matcher),
|(children, _exit_contents)| {
!children.is_empty() || comment_and_property_drawer_element.is_some()
},
)(remaining)?;
))(remaining)?;
if let Some((comment, property_drawer, _ws)) = comment_and_property_drawer_element {
children.insert(0, Element::PropertyDrawer(property_drawer));
@ -72,7 +73,7 @@ pub(crate) fn zeroth_section<'b, 'g, 'r, 's>(
}
}
let (remaining, _trailing_ws) =
let (remaining, post_blank) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
@ -80,6 +81,8 @@ pub(crate) fn zeroth_section<'b, 'g, 'r, 's>(
remaining,
Section {
source: source.into(),
contents: Some(contents.into()),
post_blank: post_blank.map(Into::<&str>::into),
children,
},
))
@ -115,12 +118,12 @@ pub(crate) fn section<'b, 'g, 'r, 's>(
remaining = remain;
input = remain;
}
let (remaining, (mut children, _exit_contents)) = verify(
let (remaining, (contents, (mut children, _exit_contents))) = consumed(verify(
many_till(element_matcher, exit_matcher),
|(children, _exit_contents)| {
!children.is_empty() || property_drawer_element.is_some() || planning_element.is_some()
},
)(remaining)?;
))(remaining)?;
if let Some(ele) = property_drawer_element.map(Element::PropertyDrawer) {
children.insert(0, ele);
}
@ -128,7 +131,7 @@ pub(crate) fn section<'b, 'g, 'r, 's>(
children.insert(0, ele)
}
let (remaining, _trailing_ws) =
let (remaining, post_blank) =
maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?;
let source = get_consumed(input, remaining);
@ -136,6 +139,8 @@ pub(crate) fn section<'b, 'g, 'r, 's>(
remaining,
Section {
source: source.into(),
contents: Some(contents.into()),
post_blank: post_blank.map(Into::<&str>::into),
children,
},
))

View File

@ -1,5 +1,6 @@
use super::macros::to_ast_node;
use super::CenterBlock;
use super::PostBlank;
use super::QuoteBlock;
use super::SpecialBlock;
use super::StandardProperties;
@ -323,7 +324,7 @@ impl<'r, 's> StandardProperties<'s> for AstNode<'r, 's> {
}
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
match self {
AstNode::Document(inner) => inner.get_contents(),
AstNode::Heading(inner) => inner.get_contents(),
@ -386,7 +387,7 @@ impl<'r, 's> StandardProperties<'s> for AstNode<'r, 's> {
}
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
match self {
AstNode::Document(inner) => inner.get_post_blank(),
AstNode::Heading(inner) => inner.get_post_blank(),

View File

@ -1,8 +1,10 @@
use std::path::PathBuf;
use super::remove_trailing::RemoveTrailing;
use super::Element;
use super::NodeProperty;
use super::Object;
use super::PostBlank;
use super::StandardProperties;
use super::Timestamp;
@ -38,6 +40,8 @@ pub struct Heading<'s> {
#[derive(Debug)]
pub struct Section<'s> {
pub source: &'s str,
pub contents: Option<&'s str>,
pub post_blank: Option<&'s str>,
pub children: Vec<Element<'s>>,
}
@ -58,12 +62,36 @@ impl<'s> StandardProperties<'s> for Document<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
todo!()
fn get_contents<'b>(&'b self) -> Option<&'s str> {
let post_blank = self.get_post_blank();
let mut content_lines = self
.source
.split_inclusive('\n')
.remove_trailing(post_blank);
let first_line = content_lines.next();
let last_line = content_lines.last().or(first_line);
match (first_line, last_line) {
(None, None) => None,
(None, Some(_)) | (Some(_), None) => unreachable!(),
(Some(first_line), Some(last_line)) => {
let first_line_offset = first_line.as_ptr() as usize;
let last_line_offset = last_line.as_ptr() as usize + last_line.len();
let source_offset = self.source.as_ptr() as usize;
debug_assert!(super::lesser_element::is_slice_of(self.source, first_line));
debug_assert!(super::lesser_element::is_slice_of(self.source, last_line));
Some(
&self.source[(first_line_offset - source_offset)
..(last_line_offset - first_line_offset)],
)
}
}
}
fn get_post_blank<'b>(&'b self) -> &'s str {
todo!()
fn get_post_blank(&self) -> PostBlank {
self.into_iter()
.last()
.map(|child| child.get_post_blank())
.unwrap_or(0)
}
}
@ -72,12 +100,16 @@ impl<'s> StandardProperties<'s> for Section<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
todo!()
fn get_contents<'b>(&'b self) -> Option<&'s str> {
self.contents
}
fn get_post_blank<'b>(&'b self) -> &'s str {
todo!()
fn get_post_blank(&self) -> PostBlank {
self.post_blank
.map(|text| text.lines().count())
.unwrap_or(0)
.try_into()
.expect("Too much post-blank to fit into a PostBlank.")
}
}
@ -86,12 +118,40 @@ impl<'s> StandardProperties<'s> for Heading<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
todo!()
fn get_contents<'b>(&'b self) -> Option<&'s str> {
let first_child = self.children.first();
let last_child = self.children.last();
match (first_child, last_child) {
(None, None) => None,
(None, Some(_)) | (Some(_), None) => unreachable!(),
(Some(first_child), Some(last_child)) => {
let first_child_offset = first_child.get_source().as_ptr() as usize;
let last_child_offset = {
let last_child_source = last_child.get_source();
last_child_source.as_ptr() as usize + last_child_source.len()
};
let source_offset = self.source.as_ptr() as usize;
debug_assert!(super::lesser_element::is_slice_of(
self.source,
first_child.get_source()
));
debug_assert!(super::lesser_element::is_slice_of(
self.source,
last_child.get_source()
));
Some(
&self.source[(first_child_offset - source_offset)
..(last_child_offset - first_child_offset)],
)
}
}
}
fn get_post_blank<'b>(&'b self) -> &'s str {
todo!()
fn get_post_blank(&self) -> PostBlank {
self.children
.last()
.map(|child| child.get_post_blank())
.unwrap_or(0)
}
}
@ -151,14 +211,14 @@ impl<'s> StandardProperties<'s> for DocumentElement<'s> {
}
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
match self {
DocumentElement::Heading(inner) => inner.get_contents(),
DocumentElement::Section(inner) => inner.get_contents(),
}
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
match self {
DocumentElement::Heading(inner) => inner.get_post_blank(),
DocumentElement::Section(inner) => inner.get_post_blank(),

View File

@ -20,6 +20,7 @@ use super::lesser_element::SrcBlock;
use super::lesser_element::VerseBlock;
use super::CenterBlock;
use super::Drawer;
use super::PostBlank;
use super::QuoteBlock;
use super::SpecialBlock;
use super::StandardProperties;
@ -83,7 +84,7 @@ impl<'s> StandardProperties<'s> for Element<'s> {
}
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
match self {
Element::Paragraph(inner) => inner.get_contents(),
Element::PlainList(inner) => inner.get_contents(),
@ -112,7 +113,7 @@ impl<'s> StandardProperties<'s> for Element<'s> {
}
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
match self {
Element::Paragraph(inner) => inner.get_post_blank(),
Element::PlainList(inner) => inner.get_post_blank(),

View File

@ -4,6 +4,7 @@ use super::lesser_element::TableCell;
use super::AffiliatedKeywords;
use super::Keyword;
use super::Object;
use super::PostBlank;
use super::StandardProperties;
#[derive(Debug)]
@ -81,6 +82,8 @@ pub struct DynamicBlock<'s> {
#[derive(Debug)]
pub struct FootnoteDefinition<'s> {
pub source: &'s str,
pub contents: Option<&'s str>,
pub post_blank: Option<&'s str>,
pub affiliated_keywords: AffiliatedKeywords<'s>,
pub label: &'s str,
pub children: Vec<Element<'s>>,
@ -132,11 +135,11 @@ impl<'s> StandardProperties<'s> for PlainList<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -146,11 +149,11 @@ impl<'s> StandardProperties<'s> for PlainListItem<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -160,11 +163,11 @@ impl<'s> StandardProperties<'s> for CenterBlock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -174,11 +177,11 @@ impl<'s> StandardProperties<'s> for QuoteBlock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -188,11 +191,11 @@ impl<'s> StandardProperties<'s> for SpecialBlock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -202,11 +205,11 @@ impl<'s> StandardProperties<'s> for DynamicBlock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -216,12 +219,16 @@ impl<'s> StandardProperties<'s> for FootnoteDefinition<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
todo!()
fn get_contents<'b>(&'b self) -> Option<&'s str> {
self.contents
}
fn get_post_blank<'b>(&'b self) -> &'s str {
todo!()
fn get_post_blank(&self) -> PostBlank {
self.post_blank
.map(|text| text.lines().count())
.unwrap_or(0)
.try_into()
.expect("Too much post-blank to fit into a PostBlank.")
}
}
@ -230,11 +237,11 @@ impl<'s> StandardProperties<'s> for Drawer<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -244,11 +251,11 @@ impl<'s> StandardProperties<'s> for PropertyDrawer<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -258,11 +265,11 @@ impl<'s> StandardProperties<'s> for NodeProperty<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -272,11 +279,11 @@ impl<'s> StandardProperties<'s> for Table<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -286,11 +293,11 @@ impl<'s> StandardProperties<'s> for TableRow<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}

View File

@ -16,6 +16,7 @@ use super::object::Object;
use super::AffiliatedKeywords;
use super::GetAffiliatedKeywords;
use super::PlainText;
use super::PostBlank;
use super::StandardProperties;
use super::Timestamp;
use crate::error::CustomError;
@ -24,6 +25,8 @@ use crate::error::Res;
#[derive(Debug)]
pub struct Paragraph<'s> {
pub source: &'s str,
pub contents: Option<&'s str>,
pub post_blank: Option<&'s str>,
pub affiliated_keywords: AffiliatedKeywords<'s>,
pub children: Vec<Object<'s>>,
}
@ -188,6 +191,8 @@ impl<'s> Paragraph<'s> {
pub(crate) fn of_text(source: &'s str, body: &'s str) -> Self {
Paragraph {
source,
contents: None, // TODO
post_blank: None, // TODO
affiliated_keywords: AffiliatedKeywords::default(),
children: vec![Object::PlainText(PlainText { source: body })],
}
@ -199,12 +204,16 @@ impl<'s> StandardProperties<'s> for Paragraph<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
todo!()
fn get_contents<'b>(&'b self) -> Option<&'s str> {
self.contents
}
fn get_post_blank<'b>(&'b self) -> &'s str {
todo!()
fn get_post_blank(&self) -> PostBlank {
self.post_blank
.map(|text| text.lines().count())
.unwrap_or(0)
.try_into()
.expect("Too much post-blank to fit into a PostBlank.")
}
}
@ -213,11 +222,11 @@ impl<'s> StandardProperties<'s> for TableCell<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -227,11 +236,11 @@ impl<'s> StandardProperties<'s> for Comment<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -241,11 +250,11 @@ impl<'s> StandardProperties<'s> for VerseBlock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -254,11 +263,11 @@ impl<'s> StandardProperties<'s> for CommentBlock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -267,11 +276,11 @@ impl<'s> StandardProperties<'s> for ExampleBlock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -280,11 +289,11 @@ impl<'s> StandardProperties<'s> for ExportBlock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -293,11 +302,11 @@ impl<'s> StandardProperties<'s> for SrcBlock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -307,11 +316,11 @@ impl<'s> StandardProperties<'s> for Clock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -321,11 +330,11 @@ impl<'s> StandardProperties<'s> for DiarySexp<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -335,11 +344,11 @@ impl<'s> StandardProperties<'s> for Planning<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -349,11 +358,11 @@ impl<'s> StandardProperties<'s> for FixedWidthArea<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -363,11 +372,11 @@ impl<'s> StandardProperties<'s> for HorizontalRule<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -377,11 +386,11 @@ impl<'s> StandardProperties<'s> for Keyword<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -391,11 +400,11 @@ impl<'s> StandardProperties<'s> for BabelCall<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -405,11 +414,11 @@ impl<'s> StandardProperties<'s> for LatexEnvironment<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -601,7 +610,7 @@ fn content_line<'s>(input: &'s str) -> Res<&'s str, (Option<&'s str>, &'s str)>
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
/// Check if the child string slice is a slice of the parent string slice.
fn is_slice_of(parent: &str, child: &str) -> bool {
pub(crate) 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;

View File

@ -6,6 +6,7 @@ mod greater_element;
mod lesser_element;
mod macros;
mod object;
mod remove_trailing;
mod standard_properties;
mod util;
pub use affiliated_keyword::AffiliatedKeyword;
@ -110,4 +111,5 @@ pub use object::WarningDelay;
pub use object::WarningDelayType;
pub use object::Year;
pub use object::YearInner;
pub use standard_properties::PostBlank;
pub use standard_properties::StandardProperties;

View File

@ -6,6 +6,7 @@ use super::util::coalesce_whitespace_if_line_break;
use super::util::remove_line_break;
use super::util::remove_whitespace_if_line_break;
use super::util::to_lowercase;
use super::PostBlank;
use super::StandardProperties;
#[derive(Debug)]
@ -191,6 +192,8 @@ pub struct ExportSnippet<'s> {
#[derive(Debug)]
pub struct FootnoteReference<'s> {
pub source: &'s str,
pub contents: Option<&'s str>,
pub post_blank: Option<&'s str>,
pub label: Option<&'s str>,
pub definition: Vec<Object<'s>>,
}
@ -519,11 +522,11 @@ impl<'s> StandardProperties<'s> for Bold<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -533,11 +536,11 @@ impl<'s> StandardProperties<'s> for Italic<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -547,11 +550,11 @@ impl<'s> StandardProperties<'s> for Underline<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -561,11 +564,11 @@ impl<'s> StandardProperties<'s> for StrikeThrough<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -575,11 +578,11 @@ impl<'s> StandardProperties<'s> for Code<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -589,11 +592,11 @@ impl<'s> StandardProperties<'s> for Verbatim<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -603,11 +606,11 @@ impl<'s> StandardProperties<'s> for RegularLink<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -617,11 +620,11 @@ impl<'s> StandardProperties<'s> for RadioLink<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -631,11 +634,11 @@ impl<'s> StandardProperties<'s> for RadioTarget<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -645,11 +648,11 @@ impl<'s> StandardProperties<'s> for PlainLink<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -659,11 +662,11 @@ impl<'s> StandardProperties<'s> for AngleLink<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -673,11 +676,11 @@ impl<'s> StandardProperties<'s> for OrgMacro<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -687,11 +690,11 @@ impl<'s> StandardProperties<'s> for Entity<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -701,11 +704,11 @@ impl<'s> StandardProperties<'s> for LatexFragment<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -715,11 +718,11 @@ impl<'s> StandardProperties<'s> for ExportSnippet<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -729,12 +732,16 @@ impl<'s> StandardProperties<'s> for FootnoteReference<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
todo!()
fn get_contents<'b>(&'b self) -> Option<&'s str> {
self.contents
}
fn get_post_blank<'b>(&'b self) -> &'s str {
todo!()
fn get_post_blank(&self) -> PostBlank {
self.post_blank
.map(|text| text.chars().count())
.unwrap_or(0)
.try_into()
.expect("Too much post-blank to fit into a PostBlank.")
}
}
@ -743,11 +750,11 @@ impl<'s> StandardProperties<'s> for Citation<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -757,11 +764,11 @@ impl<'s> StandardProperties<'s> for CitationReference<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -771,11 +778,11 @@ impl<'s> StandardProperties<'s> for InlineBabelCall<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -785,11 +792,11 @@ impl<'s> StandardProperties<'s> for InlineSourceBlock<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -799,11 +806,11 @@ impl<'s> StandardProperties<'s> for LineBreak<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -813,11 +820,11 @@ impl<'s> StandardProperties<'s> for Target<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -827,11 +834,11 @@ impl<'s> StandardProperties<'s> for StatisticsCookie<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -841,11 +848,11 @@ impl<'s> StandardProperties<'s> for Subscript<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -855,11 +862,11 @@ impl<'s> StandardProperties<'s> for Superscript<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -869,11 +876,11 @@ impl<'s> StandardProperties<'s> for Timestamp<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -883,11 +890,11 @@ impl<'s> StandardProperties<'s> for PlainText<'s> {
self.source
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
todo!()
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
todo!()
}
}
@ -1016,7 +1023,7 @@ impl<'s> StandardProperties<'s> for Object<'s> {
}
}
fn get_contents<'b>(&'b self) -> &'s str {
fn get_contents<'b>(&'b self) -> Option<&'s str> {
match self {
Object::Bold(inner) => inner.get_contents(),
Object::Italic(inner) => inner.get_contents(),
@ -1048,7 +1055,7 @@ impl<'s> StandardProperties<'s> for Object<'s> {
}
}
fn get_post_blank<'b>(&'b self) -> &'s str {
fn get_post_blank(&self) -> PostBlank {
match self {
Object::Bold(inner) => inner.get_post_blank(),
Object::Italic(inner) => inner.get_post_blank(),

View File

@ -0,0 +1,56 @@
pub(crate) trait RemoveTrailing: Iterator + Sized {
fn remove_trailing<R: Into<usize>>(self, amount_to_remove: R) -> RemoveTrailingIter<Self>;
}
impl<I> RemoveTrailing for I
where
I: Iterator,
{
fn remove_trailing<R: Into<usize>>(self, amount_to_remove: R) -> RemoveTrailingIter<Self> {
RemoveTrailingIter {
inner: self,
buffer: Vec::new(),
next_to_pop: 0,
amount_to_remove: amount_to_remove.into(),
}
}
}
pub(crate) struct RemoveTrailingIter<I: Iterator> {
inner: I,
buffer: Vec<I::Item>,
next_to_pop: usize,
amount_to_remove: usize,
}
impl<I: Iterator> Iterator for RemoveTrailingIter<I> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.buffer.len() < self.amount_to_remove {
self.buffer.reserve_exact(self.amount_to_remove);
}
while self.buffer.len() < self.amount_to_remove {
if let Some(elem) = self.inner.next() {
self.buffer.push(elem);
} else {
// The inner was smaller than amount_to_remove, so never return anything.
return None;
}
}
let new_value = self.inner.next();
if self.amount_to_remove == 0 {
return new_value;
}
if let Some(new_value) = new_value {
let ret = std::mem::replace(&mut self.buffer[self.next_to_pop], new_value);
self.next_to_pop = (self.next_to_pop + 1) % self.amount_to_remove;
Some(ret)
} else {
// We have exactly the amount in the buffer than we wanted to cut off, so stop returning values.
None
}
}
}

View File

@ -8,12 +8,12 @@ pub trait StandardProperties<'s> {
/// Get the slice of the AST node's contents.
///
/// This corresponds to :contents-begin to :contents-end
fn get_contents<'b>(&'b self) -> &'s str;
fn get_contents<'b>(&'b self) -> Option<&'s str>;
/// Get the slice of the AST node's post-blank text.
/// Get the ast node's post-blank.
///
/// This is optional whitespace following the node.
fn get_post_blank<'b>(&'b self) -> &'s str;
/// For objects this is a count of the characters of whitespace after the object. For elements this is a count of the line breaks following an element.
fn get_post_blank(&self) -> PostBlank;
}
// TODO: Write some debugging code to alert when any of the unknown fields below are non-nil in our test data so we can see what these fields represent.
@ -61,3 +61,5 @@ pub trait StandardProperties<'s> {
// X :parent - Some weird numeric reference to the containing object. Since we output a tree structure, I do not see any value in including this, especially considering the back-references would be a nightmare in rust.
// Special case: Plain text. Plain text counts :begin and :end from the start of the text (so :begin is always 0 AFAICT) and instead of including the full set of standard properties, it only includes :begin, :end, and :parent.
pub type PostBlank = u8;