From d8102b7bc24e5b5fe316a835f35fc41017062939 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 4 Oct 2023 20:01:09 -0400 Subject: [PATCH] Move the affiliated keywords parser inside the specific element parsers. We need access to the affiliated keywords to do things like set the name of the element, and only half the element parsers are allowed to have affiliated keywords, so it makes sense to move it inside the specific parsers. --- .../greater_element/drawer/name.org | 10 + .../greater_element/dynamic_block/name.org | 7 + .../greater_block/center/name.org | 4 + .../greater_block/quote/name.org | 4 + .../greater_block/special/name.org | 6 + .../greater_element/plain_list/name.org | 2 + .../lesser_element/babel_call/name.org | 2 + .../babel_call.org => babel_call/simple.org} | 0 .../lesser_element/clock/name.org | 3 + .../lesser_element/comment/name.org | 2 + .../lesser_element/diary_sexp/name.org | 2 + .../lesser_element/fixed_width_area/name.org | 2 + .../lesser_element/horizontal_rule/name.org | 2 + .../lesser_element/keyword/name.org | 2 + .../lesser_element/latex_environment/name.org | 4 + src/compare/diff.rs | 197 +++++++++++++++--- src/parser/diary_sexp.rs | 8 +- src/parser/drawer.rs | 7 +- src/parser/dynamic_block.rs | 7 +- src/parser/element_parser.rs | 20 +- src/parser/fixed_width_area.rs | 4 + src/parser/footnote_definition.rs | 4 + src/parser/greater_block.rs | 18 +- src/parser/horizontal_rule.rs | 8 +- src/parser/keyword.rs | 13 +- src/parser/latex_environment.rs | 5 + src/parser/paragraph.rs | 5 + src/parser/plain_list.rs | 5 + src/parser/property_drawer.rs | 4 +- src/parser/table.rs | 4 + src/types/greater_element.rs | 16 +- src/types/lesser_element.rs | 6 + 32 files changed, 324 insertions(+), 59 deletions(-) create mode 100644 org_mode_samples/greater_element/drawer/name.org create mode 100644 org_mode_samples/greater_element/dynamic_block/name.org create mode 100644 org_mode_samples/greater_element/greater_block/center/name.org create mode 100644 org_mode_samples/greater_element/greater_block/quote/name.org create mode 100644 org_mode_samples/greater_element/greater_block/special/name.org create mode 100644 org_mode_samples/greater_element/plain_list/name.org create mode 100644 org_mode_samples/lesser_element/babel_call/name.org rename org_mode_samples/lesser_element/{keyword/babel_call.org => babel_call/simple.org} (100%) create mode 100644 org_mode_samples/lesser_element/clock/name.org create mode 100644 org_mode_samples/lesser_element/comment/name.org create mode 100644 org_mode_samples/lesser_element/diary_sexp/name.org create mode 100644 org_mode_samples/lesser_element/fixed_width_area/name.org create mode 100644 org_mode_samples/lesser_element/horizontal_rule/name.org create mode 100644 org_mode_samples/lesser_element/keyword/name.org create mode 100644 org_mode_samples/lesser_element/latex_environment/name.org diff --git a/org_mode_samples/greater_element/drawer/name.org b/org_mode_samples/greater_element/drawer/name.org new file mode 100644 index 00000000..41b7c3d4 --- /dev/null +++ b/org_mode_samples/greater_element/drawer/name.org @@ -0,0 +1,10 @@ +* Headline +before +#+NAME: foo +:candle: +inside + +the drawer +:end: + +after diff --git a/org_mode_samples/greater_element/dynamic_block/name.org b/org_mode_samples/greater_element/dynamic_block/name.org new file mode 100644 index 00000000..4da2f796 --- /dev/null +++ b/org_mode_samples/greater_element/dynamic_block/name.org @@ -0,0 +1,7 @@ +#+NAME: foo +#+BEGIN: clocktable :scope file :maxlevel 2 +#+CAPTION: Clock summary at [2023-08-25 Fri 05:34] +| Headline | Time | +|--------------+--------| +| *Total time* | *0:00* | +#+END: diff --git a/org_mode_samples/greater_element/greater_block/center/name.org b/org_mode_samples/greater_element/greater_block/center/name.org new file mode 100644 index 00000000..e0f9c0cf --- /dev/null +++ b/org_mode_samples/greater_element/greater_block/center/name.org @@ -0,0 +1,4 @@ +#+NAME: foo +#+begin_center + +#+end_center diff --git a/org_mode_samples/greater_element/greater_block/quote/name.org b/org_mode_samples/greater_element/greater_block/quote/name.org new file mode 100644 index 00000000..fe2fa3a4 --- /dev/null +++ b/org_mode_samples/greater_element/greater_block/quote/name.org @@ -0,0 +1,4 @@ +#+NAME: foo +#+begin_quote + +#+end_quote diff --git a/org_mode_samples/greater_element/greater_block/special/name.org b/org_mode_samples/greater_element/greater_block/special/name.org new file mode 100644 index 00000000..6b513b12 --- /dev/null +++ b/org_mode_samples/greater_element/greater_block/special/name.org @@ -0,0 +1,6 @@ +#+NAME: foo +#+begin_defun +foo + +{{{bar(baz)}}} +#+end_defun diff --git a/org_mode_samples/greater_element/plain_list/name.org b/org_mode_samples/greater_element/plain_list/name.org new file mode 100644 index 00000000..d80b7ba8 --- /dev/null +++ b/org_mode_samples/greater_element/plain_list/name.org @@ -0,0 +1,2 @@ +#+NAME: foo +1. bar diff --git a/org_mode_samples/lesser_element/babel_call/name.org b/org_mode_samples/lesser_element/babel_call/name.org new file mode 100644 index 00000000..da7aea93 --- /dev/null +++ b/org_mode_samples/lesser_element/babel_call/name.org @@ -0,0 +1,2 @@ +#+NAME: foo +#+call: foo(bar="baz") diff --git a/org_mode_samples/lesser_element/keyword/babel_call.org b/org_mode_samples/lesser_element/babel_call/simple.org similarity index 100% rename from org_mode_samples/lesser_element/keyword/babel_call.org rename to org_mode_samples/lesser_element/babel_call/simple.org diff --git a/org_mode_samples/lesser_element/clock/name.org b/org_mode_samples/lesser_element/clock/name.org new file mode 100644 index 00000000..c169fbac --- /dev/null +++ b/org_mode_samples/lesser_element/clock/name.org @@ -0,0 +1,3 @@ +CLOCK: [2023-04-21 Fri 19:32]--[2023-04-21 Fri 19:35] => 0:03 +#+NAME: foo +CLOCK: [2023-04-21 Fri 19:43] diff --git a/org_mode_samples/lesser_element/comment/name.org b/org_mode_samples/lesser_element/comment/name.org new file mode 100644 index 00000000..815b8d48 --- /dev/null +++ b/org_mode_samples/lesser_element/comment/name.org @@ -0,0 +1,2 @@ +#+NAME: foo +# Comments cannot have affiliated keywords. diff --git a/org_mode_samples/lesser_element/diary_sexp/name.org b/org_mode_samples/lesser_element/diary_sexp/name.org new file mode 100644 index 00000000..34e6155b --- /dev/null +++ b/org_mode_samples/lesser_element/diary_sexp/name.org @@ -0,0 +1,2 @@ +#+NAME: foo +%%(foo) diff --git a/org_mode_samples/lesser_element/fixed_width_area/name.org b/org_mode_samples/lesser_element/fixed_width_area/name.org new file mode 100644 index 00000000..482c0d26 --- /dev/null +++ b/org_mode_samples/lesser_element/fixed_width_area/name.org @@ -0,0 +1,2 @@ +#+NAME: foo +: bar diff --git a/org_mode_samples/lesser_element/horizontal_rule/name.org b/org_mode_samples/lesser_element/horizontal_rule/name.org new file mode 100644 index 00000000..252fc4f1 --- /dev/null +++ b/org_mode_samples/lesser_element/horizontal_rule/name.org @@ -0,0 +1,2 @@ +#+NAME: foo +----- diff --git a/org_mode_samples/lesser_element/keyword/name.org b/org_mode_samples/lesser_element/keyword/name.org new file mode 100644 index 00000000..51bc2fad --- /dev/null +++ b/org_mode_samples/lesser_element/keyword/name.org @@ -0,0 +1,2 @@ +#+NAME: foo +#+FOO: BAR diff --git a/org_mode_samples/lesser_element/latex_environment/name.org b/org_mode_samples/lesser_element/latex_environment/name.org new file mode 100644 index 00000000..51a64715 --- /dev/null +++ b/org_mode_samples/lesser_element/latex_environment/name.org @@ -0,0 +1,4 @@ +#+NAME: foo +\begin{foo} +bar +\end{foo} diff --git a/src/compare/diff.rs b/src/compare/diff.rs index f4e82d01..a4ba0833 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -879,6 +879,16 @@ fn compare_plain_list<'b, 's>( let mut this_status = DiffStatus::Good; let mut message = None; + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } + // Compare type // :type is an unquoted atom of either descriptive, ordered, or unordered let list_type = get_property_unquoted_atom(emacs, ":type")?; @@ -1037,8 +1047,18 @@ fn compare_center_block<'b, 's>( ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); - let this_status = DiffStatus::Good; - let message = None; + let mut this_status = DiffStatus::Good; + let mut message = None; + + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); @@ -1062,8 +1082,18 @@ fn compare_quote_block<'b, 's>( ) -> Result, Box> { let children = emacs.as_list()?; let mut child_status = Vec::new(); - let this_status = DiffStatus::Good; - let message = None; + let mut this_status = DiffStatus::Good; + let mut message = None; + + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); @@ -1090,14 +1120,24 @@ fn compare_special_block<'b, 's>( let mut this_status = DiffStatus::Good; let mut message = None; - // Compare type - let special_block_type = - get_property_quoted_string(emacs, ":type")?.ok_or("Special blocks should have a name.")?; - if special_block_type != rust.name { + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { this_status = DiffStatus::Bad; message = Some(format!( "Name mismatch (emacs != rust) {:?} != {:?}", - special_block_type, rust.name + name, rust.name + )); + } + + // Compare type + let special_block_type = + get_property_quoted_string(emacs, ":type")?.ok_or("Special blocks should have a name.")?; + if special_block_type != rust.block_type { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + special_block_type, rust.block_type )); } @@ -1140,14 +1180,24 @@ fn compare_dynamic_block<'b, 's>( let mut this_status = DiffStatus::Good; let mut message = None; - // Compare block-name - let block_name = get_property_quoted_string(emacs, ":block-name")? - .ok_or("Dynamic blocks should have a name.")?; - if block_name != rust.name { + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { this_status = DiffStatus::Bad; message = Some(format!( "Name mismatch (emacs != rust) {:?} != {:?}", - block_name, rust.name + name, rust.name + )); + } + + // Compare block-name + let block_name = get_property_quoted_string(emacs, ":block-name")? + .ok_or("Dynamic blocks should have a name.")?; + if block_name != rust.block_name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + block_name, rust.block_name )); } @@ -1191,6 +1241,16 @@ fn compare_footnote_definition<'b, 's>( let mut message = None; // TODO: Compare :pre-blank + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } + // Compare label let label = get_property_quoted_string(emacs, ":label")? .ok_or("Footnote definitions should have a name.")?; @@ -1259,10 +1319,9 @@ fn compare_drawer<'b, 's>( let mut this_status = DiffStatus::Good; let mut message = None; - // Compare drawer-name - let name = - get_property_quoted_string(emacs, ":drawer-name")?.ok_or("Drawers should have a name.")?; - if name != rust.name { + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { this_status = DiffStatus::Bad; message = Some(format!( "Name mismatch (emacs != rust) {:?} != {:?}", @@ -1270,6 +1329,17 @@ fn compare_drawer<'b, 's>( )); } + // Compare drawer-name + let drawer_name = + get_property_quoted_string(emacs, ":drawer-name")?.ok_or("Drawers should have a name.")?; + if drawer_name != rust.drawer_name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Drawer name mismatch (emacs != rust) {:?} != {:?}", + drawer_name, rust.drawer_name + )); + } + for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { child_status.push(compare_ast_node(source, emacs_child, rust_child.into())?); } @@ -1322,11 +1392,11 @@ fn compare_node_property<'b, 's>( // Compare key let key = get_property_quoted_string(emacs, ":key")?.ok_or("Node properties should have a key.")?; - if key != rust.name { + if key != rust.property_name { this_status = DiffStatus::Bad; message = Some(format!( "Key mismatch (emacs != rust) {:?} != {:?}", - key, rust.name + key, rust.property_name )); } @@ -1365,6 +1435,16 @@ fn compare_table<'b, 's>( let mut this_status = DiffStatus::Good; let mut message = None; + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } + // Compare formulas // // :tblfm is either nil or a list () filled with quoted strings containing the value for any tblfm keywords at the end of the table. @@ -2004,11 +2084,21 @@ fn compare_diary_sexp<'b, 's>( emacs: &'b Token<'s>, rust: &'b DiarySexp<'s>, ) -> Result, Box> { - let this_status = DiffStatus::Good; - let message = None; + let mut this_status = DiffStatus::Good; + let mut message = None; // TODO: Compare :value + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } + Ok(DiffResult { status: this_status, name: rust.get_elisp_name(), @@ -2097,11 +2187,21 @@ fn compare_fixed_width_area<'b, 's>( rust: &'b FixedWidthArea<'s>, ) -> Result, Box> { let child_status = Vec::new(); - let this_status = DiffStatus::Good; - let message = None; + let mut this_status = DiffStatus::Good; + let mut message = None; // TODO: Compare :value + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } + Ok(DiffResult { status: this_status, name: rust.get_elisp_name(), @@ -2119,8 +2219,18 @@ fn compare_horizontal_rule<'b, 's>( rust: &'b HorizontalRule<'s>, ) -> Result, Box> { let child_status = Vec::new(); - let this_status = DiffStatus::Good; - let message = None; + let mut this_status = DiffStatus::Good; + let mut message = None; + + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } Ok(DiffResult { status: this_status, @@ -2142,6 +2252,16 @@ fn compare_keyword<'b, 's>( let mut this_status = DiffStatus::Good; let mut message = None; + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } + let key = unquote( get_property(emacs, ":key")? .ok_or("Emacs keywords should have a :key")? @@ -2188,6 +2308,17 @@ fn compare_babel_call<'b, 's>( let mut message = None; // TODO: Compare :call :inside-header :arguments :end-header + + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } + let value = unquote( get_property(emacs, ":value")? .ok_or("Emacs keywords should have a :value")? @@ -2218,11 +2349,21 @@ fn compare_latex_environment<'b, 's>( rust: &'b LatexEnvironment<'s>, ) -> Result, Box> { let child_status = Vec::new(); - let this_status = DiffStatus::Good; - let message = None; + let mut this_status = DiffStatus::Good; + let mut message = None; // TODO: Compare :value + // Compare name + let name = get_property_quoted_string(emacs, ":name")?; + if name.as_ref().map(String::as_str) != rust.name { + this_status = DiffStatus::Bad; + message = Some(format!( + "Name mismatch (emacs != rust) {:?} != {:?}", + name, rust.name + )); + } + Ok(DiffResult { status: this_status, name: rust.get_elisp_name(), diff --git a/src/parser/diary_sexp.rs b/src/parser/diary_sexp.rs index ac1957bc..1a82ff07 100644 --- a/src/parser/diary_sexp.rs +++ b/src/parser/diary_sexp.rs @@ -3,9 +3,12 @@ use nom::bytes::complete::is_not; use nom::bytes::complete::tag; use nom::character::complete::line_ending; use nom::combinator::eof; +use nom::multi::many0; use nom::sequence::tuple; +use super::keyword::affiliated_keyword; use super::org_source::OrgSource; +use crate::context::parser_with_context; use crate::context::RefContext; use crate::error::Res; use crate::parser::util::get_consumed; @@ -14,9 +17,11 @@ use crate::types::DiarySexp; #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] pub(crate) fn diary_sexp<'b, 'g, 'r, 's>( - _context: RefContext<'b, 'g, 'r, 's>, + context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, DiarySexp<'s>> { + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; start_of_line(input)?; let (remaining, _clock) = tag("%%(")(input)?; let (remaining, _contents) = is_not("\r\n")(remaining)?; @@ -27,6 +32,7 @@ pub(crate) fn diary_sexp<'b, 'g, 'r, 's>( remaining, DiarySexp { source: source.into(), + name: None, // TODO }, )) } diff --git a/src/parser/drawer.rs b/src/parser/drawer.rs index 0d28e459..630488e9 100644 --- a/src/parser/drawer.rs +++ b/src/parser/drawer.rs @@ -7,9 +7,11 @@ use nom::character::complete::space0; use nom::combinator::eof; use nom::combinator::not; use nom::combinator::recognize; +use nom::multi::many0; use nom::multi::many_till; use nom::sequence::tuple; +use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use crate::context::parser_with_context; use crate::context::ContextElement; @@ -41,6 +43,8 @@ pub(crate) fn drawer<'b, 'g, 'r, 's>( "Cannot nest objects of the same element".into(), )))); } + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; start_of_line(input)?; let (remaining, _leading_whitespace) = space0(input)?; let (remaining, (_open_colon, drawer_name, _close_colon, _new_line)) = tuple(( @@ -90,7 +94,8 @@ pub(crate) fn drawer<'b, 'g, 'r, 's>( remaining, Drawer { source: source.into(), - name: drawer_name.into(), + name: None, // TODO + drawer_name: drawer_name.into(), children, }, )) diff --git a/src/parser/dynamic_block.rs b/src/parser/dynamic_block.rs index 53681487..1872c0f5 100644 --- a/src/parser/dynamic_block.rs +++ b/src/parser/dynamic_block.rs @@ -17,6 +17,7 @@ use nom::multi::many_till; use nom::sequence::preceded; use nom::sequence::tuple; +use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use crate::context::parser_with_context; use crate::context::ContextElement; @@ -47,6 +48,9 @@ pub(crate) fn dynamic_block<'b, 'g, 'r, 's>( "Cannot nest objects of the same element".into(), )))); } + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; + start_of_line(input)?; let (remaining, _leading_whitespace) = space0(input)?; let (remaining, (_, name, parameters, _, _)) = tuple(( @@ -97,7 +101,8 @@ pub(crate) fn dynamic_block<'b, 'g, 'r, 's>( remaining, DynamicBlock { source: source.into(), - name: name.into(), + name: None, // TODO + block_name: name.into(), parameters: parameters.map(|val| val.into()), children, }, diff --git a/src/parser/element_parser.rs b/src/parser/element_parser.rs index 5bc49339..5349650d 100644 --- a/src/parser/element_parser.rs +++ b/src/parser/element_parser.rs @@ -1,8 +1,5 @@ use nom::branch::alt; use nom::combinator::map; -use nom::combinator::not; -use nom::multi::many0; -use nom::sequence::tuple; use super::clock::clock; use super::comment::comment; @@ -79,8 +76,6 @@ fn _element<'b, 'g, 'r, 's>( let paragraph_matcher = parser_with_context!(paragraph)(context); let latex_environment_matcher = parser_with_context!(latex_environment)(context); - // TODO: Affiliated keywords cannot be on comments, clocks, headings, inlinetasks, items, node properties, planning, property drawers, sections, and table rows - let (remaining, mut affiliated_keywords) = many0(affiliated_keyword_matcher)(input)?; let (remaining, mut element) = match alt(( map(plain_list_matcher, Element::PlainList), greater_block_matcher, @@ -100,28 +95,20 @@ fn _element<'b, 'g, 'r, 's>( map(horizontal_rule_matcher, Element::HorizontalRule), map(latex_environment_matcher, Element::LatexEnvironment), map(babel_keyword_matcher, Element::BabelCall), - map( - map( - tuple((not(affiliated_keyword_matcher), keyword_matcher)), - |(_, kw)| kw, - ), - Element::Keyword, - ), - ))(remaining) + map(keyword_matcher, Element::Keyword), + ))(input) { the_ok @ Ok(_) => the_ok, Err(_) => { if can_be_paragraph { - match map(paragraph_matcher, Element::Paragraph)(remaining) { + match map(paragraph_matcher, Element::Paragraph)(input) { the_ok @ Ok(_) => the_ok, Err(_) => { // TODO: Because this function expects a single element, if there are multiple affiliated keywords before an element that cannot have affiliated keywords, we end up re-parsing the affiliated keywords many times. - affiliated_keywords.clear(); map(affiliated_keyword_matcher, Element::Keyword)(input) } } } else { - affiliated_keywords.clear(); map(affiliated_keyword_matcher, Element::Keyword)(input) } } @@ -149,6 +136,7 @@ fn _detect_element<'b, 'g, 'r, 's>( input: OrgSource<'s>, can_be_paragraph: bool, ) -> Res, ()> { + // TODO: What about affiliated keywords in the detect_* functions? if alt(( parser_with_context!(detect_plain_list)(context), detect_footnote_definition, diff --git a/src/parser/fixed_width_area.rs b/src/parser/fixed_width_area.rs index f5015914..0d67770e 100644 --- a/src/parser/fixed_width_area.rs +++ b/src/parser/fixed_width_area.rs @@ -10,6 +10,7 @@ use nom::multi::many0; use nom::sequence::preceded; use nom::sequence::tuple; +use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::only_space1; use super::util::org_line_ending; @@ -26,6 +27,8 @@ pub(crate) fn fixed_width_area<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, FixedWidthArea<'s>> { + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; let fixed_width_area_line_matcher = parser_with_context!(fixed_width_area_line)(context); let exit_matcher = parser_with_context!(exit_matcher_parser)(context); let (remaining, _first_line) = fixed_width_area_line_matcher(input)?; @@ -37,6 +40,7 @@ pub(crate) fn fixed_width_area<'b, 'g, 'r, 's>( remaining, FixedWidthArea { source: source.into(), + name: None, // TODO }, )) } diff --git a/src/parser/footnote_definition.rs b/src/parser/footnote_definition.rs index 857c0a0d..a7660ae9 100644 --- a/src/parser/footnote_definition.rs +++ b/src/parser/footnote_definition.rs @@ -11,6 +11,7 @@ use nom::multi::many1; use nom::multi::many_till; use nom::sequence::tuple; +use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::include_input; use super::util::WORD_CONSTITUENT_CHARACTERS; @@ -41,6 +42,8 @@ pub(crate) fn footnote_definition<'b, 'g, 'r, 's>( "Cannot nest objects of the same element".into(), )))); } + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; start_of_line(input)?; // Cannot be indented. let (remaining, (_, lbl, _, _, _)) = tuple(( @@ -85,6 +88,7 @@ pub(crate) fn footnote_definition<'b, 'g, 'r, 's>( remaining, FootnoteDefinition { source: source.into(), + name: None, // TODO label: lbl.into(), children: children.into_iter().map(|(_, item)| item).collect(), }, diff --git a/src/parser/greater_block.rs b/src/parser/greater_block.rs index d61fb21d..47c0bf7d 100644 --- a/src/parser/greater_block.rs +++ b/src/parser/greater_block.rs @@ -17,6 +17,7 @@ use nom::multi::many_till; use nom::sequence::preceded; use nom::sequence::tuple; +use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::in_section; use crate::context::parser_with_context; @@ -45,6 +46,8 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, Element<'s>> { + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; start_of_line(input)?; let (remaining, _leading_whitespace) = space0(input)?; let (remaining, (_begin, name)) = tuple(( @@ -75,7 +78,11 @@ fn center_block<'b, 'g, 'r, 's>( greater_block_body(context, input, original_input, "center", "center block")?; Ok(( remaining, - Element::CenterBlock(CenterBlock { source, children }), + Element::CenterBlock(CenterBlock { + source, + name: None, // TODO + children, + }), )) } @@ -89,7 +96,11 @@ fn quote_block<'b, 'g, 'r, 's>( greater_block_body(context, input, original_input, "quote", "quote block")?; Ok(( remaining, - Element::QuoteBlock(QuoteBlock { source, children }), + Element::QuoteBlock(QuoteBlock { + source, + name: None, // TODO + children, + }), )) } @@ -122,8 +133,9 @@ fn _special_block<'c, 'b, 'g, 'r, 's>( remaining, Element::SpecialBlock(SpecialBlock { source, + name: None, // TODO children, - name, + block_type: name, parameters: parameters.map(|(_, parameters)| Into::<&str>::into(parameters)), }), )) diff --git a/src/parser/horizontal_rule.rs b/src/parser/horizontal_rule.rs index 9a7413ab..a471dc2a 100644 --- a/src/parser/horizontal_rule.rs +++ b/src/parser/horizontal_rule.rs @@ -5,10 +5,13 @@ use nom::character::complete::space0; use nom::combinator::eof; use nom::combinator::recognize; use nom::combinator::verify; +use nom::multi::many0; use nom::multi::many1_count; use nom::sequence::tuple; +use super::keyword::affiliated_keyword; use super::org_source::OrgSource; +use crate::context::parser_with_context; use crate::context::RefContext; use crate::error::Res; use crate::parser::util::start_of_line; @@ -16,9 +19,11 @@ use crate::types::HorizontalRule; #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] pub(crate) fn horizontal_rule<'b, 'g, 'r, 's>( - _context: RefContext<'b, 'g, 'r, 's>, + context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, HorizontalRule<'s>> { + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; start_of_line(input)?; let (remaining, rule) = recognize(tuple(( space0, @@ -30,6 +35,7 @@ pub(crate) fn horizontal_rule<'b, 'g, 'r, 's>( remaining, HorizontalRule { source: rule.into(), + name: None, // TODO }, )) } diff --git a/src/parser/keyword.rs b/src/parser/keyword.rs index 9253590f..4026ab33 100644 --- a/src/parser/keyword.rs +++ b/src/parser/keyword.rs @@ -13,11 +13,13 @@ use nom::combinator::not; use nom::combinator::peek; use nom::combinator::recognize; use nom::combinator::verify; +use nom::multi::many0; use nom::multi::many_till; use nom::sequence::tuple; use super::org_source::BracketDepth; use super::org_source::OrgSource; +use crate::context::parser_with_context; use crate::context::Matcher; use crate::context::RefContext; use crate::error::CustomError; @@ -61,6 +63,7 @@ fn _filtered_keyword<'s, F: Matcher>( remaining, Keyword { source: consumed_input.into(), + name: None, // TODO key: parsed_key.into(), value: "".into(), }, @@ -78,6 +81,7 @@ fn _filtered_keyword<'s, F: Matcher>( remaining, Keyword { source: consumed_input.into(), + name: None, // TODO key: parsed_key.into(), value: parsed_value.into(), }, @@ -86,9 +90,11 @@ fn _filtered_keyword<'s, F: Matcher>( #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] pub(crate) fn keyword<'b, 'g, 'r, 's>( - _context: RefContext<'b, 'g, 'r, 's>, + context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, Keyword<'s>> { + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; filtered_keyword(regular_keyword_key)(input) } @@ -102,14 +108,17 @@ pub(crate) fn affiliated_keyword<'b, 'g, 'r, 's>( #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] pub(crate) fn babel_call_keyword<'b, 'g, 'r, 's>( - _context: RefContext<'b, 'g, 'r, 's>, + context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, BabelCall<'s>> { + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; let (remaining, kw) = filtered_keyword(babel_call_key)(input)?; Ok(( remaining, BabelCall { source: kw.source, + name: None, // TODO key: kw.key, value: kw.value, }, diff --git a/src/parser/latex_environment.rs b/src/parser/latex_environment.rs index 9635ad8b..97469a3b 100644 --- a/src/parser/latex_environment.rs +++ b/src/parser/latex_environment.rs @@ -8,9 +8,11 @@ use nom::character::complete::space0; use nom::combinator::eof; use nom::combinator::peek; use nom::combinator::recognize; +use nom::multi::many0; use nom::multi::many_till; use nom::sequence::tuple; +use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::get_consumed; use crate::context::parser_with_context; @@ -29,6 +31,8 @@ pub(crate) fn latex_environment<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, LatexEnvironment<'s>> { + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; start_of_line(input)?; let (remaining, _leading_whitespace) = space0(input)?; let (remaining, (_opening, name, _open_close_brace, _ws, _line_ending)) = tuple(( @@ -54,6 +58,7 @@ pub(crate) fn latex_environment<'b, 'g, 'r, 's>( remaining, LatexEnvironment { source: source.into(), + name: None, // TODO }, )) } diff --git a/src/parser/paragraph.rs b/src/parser/paragraph.rs index 049fe784..591e4dbd 100644 --- a/src/parser/paragraph.rs +++ b/src/parser/paragraph.rs @@ -2,11 +2,13 @@ use nom::branch::alt; use nom::combinator::eof; use nom::combinator::recognize; use nom::combinator::verify; +use nom::multi::many0; use nom::multi::many1; use nom::multi::many_till; use nom::sequence::tuple; use super::element_parser::detect_element; +use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::blank_line; use super::util::get_consumed; @@ -26,6 +28,9 @@ pub(crate) fn paragraph<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, Paragraph<'s>> { + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; + let parser_context = ContextElement::ExitMatcherNode(ExitMatcherNode { class: ExitClass::Gamma, exit_matcher: ¶graph_end, diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index 61f8b6b2..164ed9ca 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -19,6 +19,7 @@ use nom::multi::many_till; use nom::sequence::tuple; use super::element_parser::element; +use super::keyword::affiliated_keyword; use super::object_parser::standard_set_object; use super::org_source::OrgSource; use super::util::include_input; @@ -78,6 +79,9 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, PlainList<'s>> { + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; + let contexts = [ ContextElement::Context("plain list"), ContextElement::ConsumeTrailingWhitespace(true), @@ -150,6 +154,7 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>( remaining, PlainList { source: source.into(), + name: None, // TODO list_type: first_item_list_type.expect("Plain lists require at least one element."), children: children.into_iter().map(|(_start, item)| item).collect(), }, diff --git a/src/parser/property_drawer.rs b/src/parser/property_drawer.rs index 06a4ac52..99f01778 100644 --- a/src/parser/property_drawer.rs +++ b/src/parser/property_drawer.rs @@ -120,7 +120,7 @@ fn node_property<'b, 'g, 'r, 's>( remaining, NodeProperty { source: source.into(), - name: Into::<&str>::into(name), + property_name: Into::<&str>::into(name), value: None, }, )) @@ -133,7 +133,7 @@ fn node_property<'b, 'g, 'r, 's>( remaining, NodeProperty { source: source.into(), - name: Into::<&str>::into(name), + property_name: Into::<&str>::into(name), value: Some(value.into()), }, )) diff --git a/src/parser/table.rs b/src/parser/table.rs index 1d27ed6d..e9445b78 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -13,6 +13,7 @@ use nom::multi::many1; use nom::multi::many_till; use nom::sequence::tuple; +use super::keyword::affiliated_keyword; use super::keyword::table_formula_keyword; use super::object_parser::table_cell_set_object; use super::org_source::OrgSource; @@ -38,6 +39,8 @@ pub(crate) fn org_mode_table<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, Table<'s>> { + let (input, affiliated_keywords) = + many0(parser_with_context!(affiliated_keyword)(context))(input)?; start_of_line(input)?; peek(tuple((space0, tag("|"))))(input)?; @@ -68,6 +71,7 @@ pub(crate) fn org_mode_table<'b, 'g, 'r, 's>( remaining, Table { source: source.into(), + name: None, // TODO formulas, children, }, diff --git a/src/types/greater_element.rs b/src/types/greater_element.rs index 17d7cd2e..7f2bede4 100644 --- a/src/types/greater_element.rs +++ b/src/types/greater_element.rs @@ -7,6 +7,7 @@ use super::StandardProperties; #[derive(Debug)] pub struct PlainList<'s> { pub source: &'s str, + pub name: Option<&'s str>, pub list_type: PlainListType, pub children: Vec>, } @@ -46,19 +47,22 @@ pub enum CheckboxType { #[derive(Debug)] pub struct CenterBlock<'s> { pub source: &'s str, + pub name: Option<&'s str>, pub children: Vec>, } #[derive(Debug)] pub struct QuoteBlock<'s> { pub source: &'s str, + pub name: Option<&'s str>, pub children: Vec>, } #[derive(Debug)] pub struct SpecialBlock<'s> { pub source: &'s str, - pub name: &'s str, + pub name: Option<&'s str>, + pub block_type: &'s str, pub parameters: Option<&'s str>, pub children: Vec>, } @@ -66,7 +70,8 @@ pub struct SpecialBlock<'s> { #[derive(Debug)] pub struct DynamicBlock<'s> { pub source: &'s str, - pub name: &'s str, + pub name: Option<&'s str>, + pub block_name: &'s str, pub parameters: Option<&'s str>, pub children: Vec>, } @@ -74,6 +79,7 @@ pub struct DynamicBlock<'s> { #[derive(Debug)] pub struct FootnoteDefinition<'s> { pub source: &'s str, + pub name: Option<&'s str>, pub label: &'s str, pub children: Vec>, } @@ -81,7 +87,8 @@ pub struct FootnoteDefinition<'s> { #[derive(Debug)] pub struct Drawer<'s> { pub source: &'s str, - pub name: &'s str, + pub name: Option<&'s str>, + pub drawer_name: &'s str, pub children: Vec>, } @@ -94,13 +101,14 @@ pub struct PropertyDrawer<'s> { #[derive(Debug)] pub struct NodeProperty<'s> { pub source: &'s str, - pub name: &'s str, + pub property_name: &'s str, pub value: Option<&'s str>, } #[derive(Debug)] pub struct Table<'s> { pub source: &'s str, + pub name: Option<&'s str>, pub formulas: Vec>, pub children: Vec>, } diff --git a/src/types/lesser_element.rs b/src/types/lesser_element.rs index 759ad996..a7cfa4d4 100644 --- a/src/types/lesser_element.rs +++ b/src/types/lesser_element.rs @@ -91,6 +91,7 @@ pub struct Clock<'s> { #[derive(Debug)] pub struct DiarySexp<'s> { pub source: &'s str, + pub name: Option<&'s str>, } #[derive(Debug)] @@ -104,16 +105,19 @@ pub struct Planning<'s> { #[derive(Debug)] pub struct FixedWidthArea<'s> { pub source: &'s str, + pub name: Option<&'s str>, } #[derive(Debug)] pub struct HorizontalRule<'s> { pub source: &'s str, + pub name: Option<&'s str>, } #[derive(Debug)] pub struct Keyword<'s> { pub source: &'s str, + pub name: Option<&'s str>, pub key: &'s str, pub value: &'s str, } @@ -121,6 +125,7 @@ pub struct Keyword<'s> { #[derive(Debug)] pub struct BabelCall<'s> { pub source: &'s str, + pub name: Option<&'s str>, pub key: &'s str, pub value: &'s str, } @@ -128,6 +133,7 @@ pub struct BabelCall<'s> { #[derive(Debug)] pub struct LatexEnvironment<'s> { pub source: &'s str, + pub name: Option<&'s str>, } /// A line number used in switches to lesser blocks.