diff --git a/org_mode_samples/greater_element/greater_block/center/empty_with_name_inside.org b/org_mode_samples/greater_element/greater_block/center/empty_with_name_inside.org new file mode 100644 index 0000000..50f1988 --- /dev/null +++ b/org_mode_samples/greater_element/greater_block/center/empty_with_name_inside.org @@ -0,0 +1,8 @@ +#+begin_center + +#+end_center + +#+begin_center +#+NAME: foo + +#+end_center diff --git a/src/parser/diary_sexp.rs b/src/parser/diary_sexp.rs index 774ac01..5c506f5 100644 --- a/src/parser/diary_sexp.rs +++ b/src/parser/diary_sexp.rs @@ -8,6 +8,7 @@ use nom::sequence::tuple; use super::keyword::affiliated_keyword; use super::org_source::OrgSource; +use super::util::get_name; use crate::context::RefContext; use crate::error::Res; use crate::parser::util::get_consumed; @@ -30,7 +31,7 @@ pub(crate) fn diary_sexp<'b, 'g, 'r, 's>( remaining, DiarySexp { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), }, )) } diff --git a/src/parser/drawer.rs b/src/parser/drawer.rs index 7c30357..c78f80d 100644 --- a/src/parser/drawer.rs +++ b/src/parser/drawer.rs @@ -13,6 +13,7 @@ use nom::sequence::tuple; use super::keyword::affiliated_keyword; use super::org_source::OrgSource; +use super::util::get_name; use crate::context::parser_with_context; use crate::context::ContextElement; use crate::context::ExitClass; @@ -93,7 +94,7 @@ pub(crate) fn drawer<'b, 'g, 'r, 's>( remaining, Drawer { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), drawer_name: drawer_name.into(), children, }, diff --git a/src/parser/dynamic_block.rs b/src/parser/dynamic_block.rs index 85001d5..b9a9d5e 100644 --- a/src/parser/dynamic_block.rs +++ b/src/parser/dynamic_block.rs @@ -19,6 +19,7 @@ use nom::sequence::tuple; use super::keyword::affiliated_keyword; use super::org_source::OrgSource; +use super::util::get_name; use crate::context::parser_with_context; use crate::context::ContextElement; use crate::context::ExitClass; @@ -100,7 +101,7 @@ pub(crate) fn dynamic_block<'b, 'g, 'r, 's>( remaining, DynamicBlock { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), block_name: name.into(), parameters: parameters.map(|val| val.into()), children, diff --git a/src/parser/fixed_width_area.rs b/src/parser/fixed_width_area.rs index 1cf0a74..951455d 100644 --- a/src/parser/fixed_width_area.rs +++ b/src/parser/fixed_width_area.rs @@ -12,6 +12,7 @@ use nom::sequence::tuple; use super::keyword::affiliated_keyword; use super::org_source::OrgSource; +use super::util::get_name; use super::util::only_space1; use super::util::org_line_ending; use crate::context::parser_with_context; @@ -39,7 +40,7 @@ pub(crate) fn fixed_width_area<'b, 'g, 'r, 's>( remaining, FixedWidthArea { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), }, )) } diff --git a/src/parser/footnote_definition.rs b/src/parser/footnote_definition.rs index 937d920..dee1b9d 100644 --- a/src/parser/footnote_definition.rs +++ b/src/parser/footnote_definition.rs @@ -13,6 +13,7 @@ use nom::sequence::tuple; use super::keyword::affiliated_keyword; use super::org_source::OrgSource; +use super::util::get_name; use super::util::include_input; use super::util::WORD_CONSTITUENT_CHARACTERS; use crate::context::parser_with_context; @@ -87,7 +88,7 @@ pub(crate) fn footnote_definition<'b, 'g, 'r, 's>( remaining, FootnoteDefinition { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), 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 15e7637..338b26f 100644 --- a/src/parser/greater_block.rs +++ b/src/parser/greater_block.rs @@ -19,6 +19,7 @@ use nom::sequence::tuple; use super::keyword::affiliated_keyword; use super::org_source::OrgSource; +use super::util::get_name; use super::util::in_section; use crate::context::parser_with_context; use crate::context::ContextElement; @@ -36,6 +37,7 @@ use crate::parser::util::get_consumed; use crate::parser::util::start_of_line; use crate::types::CenterBlock; use crate::types::Element; +use crate::types::Keyword; use crate::types::Paragraph; use crate::types::QuoteBlock; use crate::types::SetSource; @@ -60,9 +62,9 @@ pub(crate) fn greater_block<'b, 'g, 'r, 's>( ))(remaining)?; let name = Into::<&str>::into(name); let (remaining, element) = match name.to_lowercase().as_str() { - "center" => center_block(context, remaining, input)?, - "quote" => quote_block(context, remaining, input)?, - _ => special_block(name)(context, remaining, input)?, + "center" => center_block(context, remaining, input, &affiliated_keywords)?, + "quote" => quote_block(context, remaining, input, &affiliated_keywords)?, + _ => special_block(name)(context, remaining, input, &affiliated_keywords)?, }; Ok((remaining, element)) } @@ -72,6 +74,7 @@ fn center_block<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, original_input: OrgSource<'s>, + affiliated_keywords: &Vec>, ) -> Res, Element<'s>> { let (remaining, (source, children)) = greater_block_body(context, input, original_input, "center", "center block")?; @@ -79,7 +82,7 @@ fn center_block<'b, 'g, 'r, 's>( remaining, Element::CenterBlock(CenterBlock { source, - name: None, // TODO + name: get_name(&affiliated_keywords), children, }), )) @@ -90,6 +93,7 @@ fn quote_block<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, original_input: OrgSource<'s>, + affiliated_keywords: &Vec>, ) -> Res, Element<'s>> { let (remaining, (source, children)) = greater_block_body(context, input, original_input, "quote", "quote block")?; @@ -97,7 +101,7 @@ fn quote_block<'b, 'g, 'r, 's>( remaining, Element::QuoteBlock(QuoteBlock { source, - name: None, // TODO + name: get_name(&affiliated_keywords), children, }), )) @@ -109,11 +113,19 @@ fn special_block<'s>( RefContext<'b, 'g, 'r, 's>, OrgSource<'s>, OrgSource<'s>, + &Vec>, ) -> Res, Element<'s>> + 's { let context_name = format!("special block {}", name); - move |context, input, original_input| { - _special_block(context, input, original_input, name, context_name.as_str()) + move |context, input, original_input, affiliated_keywords| { + _special_block( + context, + input, + original_input, + name, + context_name.as_str(), + affiliated_keywords, + ) } } @@ -124,6 +136,7 @@ fn _special_block<'c, 'b, 'g, 'r, 's>( original_input: OrgSource<'s>, name: &'s str, context_name: &'c str, + affiliated_keywords: &Vec>, ) -> Res, Element<'s>> { let (remaining, parameters) = opt(tuple((space1, parameters)))(input)?; let (remaining, (source, children)) = @@ -132,7 +145,7 @@ fn _special_block<'c, 'b, 'g, 'r, 's>( remaining, Element::SpecialBlock(SpecialBlock { source, - name: None, // TODO + name: get_name(&affiliated_keywords), children, 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 d90923d..7dca25c 100644 --- a/src/parser/horizontal_rule.rs +++ b/src/parser/horizontal_rule.rs @@ -11,6 +11,7 @@ use nom::sequence::tuple; use super::keyword::affiliated_keyword; use super::org_source::OrgSource; +use super::util::get_name; use crate::context::RefContext; use crate::error::Res; use crate::parser::util::start_of_line; @@ -33,7 +34,7 @@ pub(crate) fn horizontal_rule<'b, 'g, 'r, 's>( remaining, HorizontalRule { source: rule.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), }, )) } diff --git a/src/parser/keyword.rs b/src/parser/keyword.rs index 5ea956d..34739bc 100644 --- a/src/parser/keyword.rs +++ b/src/parser/keyword.rs @@ -19,6 +19,7 @@ use nom::sequence::tuple; use super::org_source::BracketDepth; use super::org_source::OrgSource; +use super::util::get_name; use crate::context::Matcher; use crate::context::RefContext; use crate::error::CustomError; @@ -62,7 +63,7 @@ fn _filtered_keyword<'s, F: Matcher>( remaining, Keyword { source: consumed_input.into(), - name: None, // TODO + name: None, // To be populated by the caller if this keyword is in a context to support affiliated keywords. key: parsed_key.into(), value: "".into(), }, @@ -80,7 +81,7 @@ fn _filtered_keyword<'s, F: Matcher>( remaining, Keyword { source: consumed_input.into(), - name: None, // TODO + name: None, // To be populated by the caller if this keyword is in a context to support affiliated keywords. key: parsed_key.into(), value: parsed_value.into(), }, @@ -93,7 +94,9 @@ pub(crate) fn keyword<'b, 'g, 'r, 's>( input: OrgSource<'s>, ) -> Res, Keyword<'s>> { let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?; - filtered_keyword(regular_keyword_key)(input) + let (remaining, mut kw) = filtered_keyword(regular_keyword_key)(input)?; + kw.name = get_name(&affiliated_keywords); + Ok((remaining, kw)) } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] @@ -112,7 +115,7 @@ pub(crate) fn babel_call_keyword<'b, 'g, 'r, 's>( remaining, BabelCall { source: kw.source, - name: None, // TODO + name: get_name(&affiliated_keywords), key: kw.key, value: kw.value, }, diff --git a/src/parser/latex_environment.rs b/src/parser/latex_environment.rs index 7e64567..b175d70 100644 --- a/src/parser/latex_environment.rs +++ b/src/parser/latex_environment.rs @@ -15,6 +15,7 @@ use nom::sequence::tuple; use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::get_consumed; +use super::util::get_name; use crate::context::parser_with_context; use crate::context::ContextElement; use crate::context::ContextMatcher; @@ -57,7 +58,7 @@ pub(crate) fn latex_environment<'b, 'g, 'r, 's>( remaining, LatexEnvironment { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), }, )) } diff --git a/src/parser/lesser_block.rs b/src/parser/lesser_block.rs index 050dbc9..a1fedb5 100644 --- a/src/parser/lesser_block.rs +++ b/src/parser/lesser_block.rs @@ -14,11 +14,14 @@ use nom::combinator::opt; use nom::combinator::peek; use nom::combinator::recognize; use nom::combinator::verify; +use nom::multi::many0; use nom::multi::many_till; use nom::multi::separated_list1; use nom::sequence::tuple; +use super::keyword::affiliated_keyword; use super::org_source::OrgSource; +use super::util::get_name; use crate::context::parser_with_context; use crate::context::ContextElement; use crate::context::ContextMatcher; @@ -50,6 +53,7 @@ pub(crate) fn verse_block<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, VerseBlock<'s>> { + let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?; let (remaining, _) = lesser_block_begin("verse")(context, input)?; let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?; let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?; @@ -93,7 +97,7 @@ pub(crate) fn verse_block<'b, 'g, 'r, 's>( remaining, VerseBlock { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), data: parameters.map(|parameters| Into::<&str>::into(parameters)), children, }, @@ -105,6 +109,7 @@ pub(crate) fn comment_block<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, CommentBlock<'s>> { + let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?; let (remaining, _) = lesser_block_begin("comment")(context, input)?; let (remaining, _parameters) = opt(tuple((space1, data)))(remaining)?; let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?; @@ -129,7 +134,7 @@ pub(crate) fn comment_block<'b, 'g, 'r, 's>( remaining, CommentBlock { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), contents: contents.into(), }, )) @@ -140,6 +145,7 @@ pub(crate) fn example_block<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, ExampleBlock<'s>> { + let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?; let (remaining, _) = lesser_block_begin("example")(context, input)?; let (remaining, parameters) = opt(tuple((space1, example_switches)))(remaining)?; let (remaining, _nl) = recognize(tuple((space0, line_ending)))(remaining)?; @@ -183,7 +189,7 @@ pub(crate) fn example_block<'b, 'g, 'r, 's>( remaining, ExampleBlock { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), switches, number_lines, preserve_indent, @@ -200,6 +206,7 @@ pub(crate) fn export_block<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, ExportBlock<'s>> { + let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?; let (remaining, _) = lesser_block_begin("export")(context, input)?; // https://orgmode.org/worg/org-syntax.html#Blocks claims that export blocks must have a single word for data but testing shows no data and multi-word data still parses as an export block. let (remaining, parameters) = opt(tuple((space1, data)))(remaining)?; @@ -229,7 +236,7 @@ pub(crate) fn export_block<'b, 'g, 'r, 's>( remaining, ExportBlock { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), data: parameters.map(|parameters| Into::<&str>::into(parameters)), contents: contents.into(), }, @@ -241,6 +248,7 @@ pub(crate) fn src_block<'b, 'g, 'r, 's>( context: RefContext<'b, 'g, 'r, 's>, input: OrgSource<'s>, ) -> Res, SrcBlock<'s>> { + let (input, affiliated_keywords) = many0(affiliated_keyword)(input)?; let (remaining, _) = lesser_block_begin("src")(context, input)?; // https://orgmode.org/worg/org-syntax.html#Blocks claims that data is mandatory and must follow the LANGUAGE SWITCHES ARGUMENTS pattern but testing has shown that no data and incorrect data here will still parse to a src block. let (remaining, language) = opt(map(tuple((space1, switch_word(true))), |(_, language)| { @@ -289,7 +297,7 @@ pub(crate) fn src_block<'b, 'g, 'r, 's>( remaining, SrcBlock { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), language: language.map(Into::<&str>::into), switches, parameters: parameters.map(Into::<&str>::into), diff --git a/src/parser/paragraph.rs b/src/parser/paragraph.rs index 2576e35..82a8f6c 100644 --- a/src/parser/paragraph.rs +++ b/src/parser/paragraph.rs @@ -12,6 +12,7 @@ use super::keyword::affiliated_keyword; use super::org_source::OrgSource; use super::util::blank_line; use super::util::get_consumed; +use super::util::get_name; use crate::context::parser_with_context; use crate::context::ContextElement; use crate::context::ExitClass; @@ -51,7 +52,7 @@ pub(crate) fn paragraph<'b, 'g, 'r, 's>( remaining, Paragraph { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), children, }, )) diff --git a/src/parser/plain_list.rs b/src/parser/plain_list.rs index 92e6007..f33ba0d 100644 --- a/src/parser/plain_list.rs +++ b/src/parser/plain_list.rs @@ -22,6 +22,7 @@ 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::get_name; use super::util::include_input; use super::util::indentation_level; use super::util::non_whitespace_character; @@ -154,7 +155,7 @@ pub(crate) fn plain_list<'b, 'g, 'r, 's>( remaining, PlainList { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), 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/table.rs b/src/parser/table.rs index e1de64c..2fc7967 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -18,6 +18,7 @@ use super::keyword::table_formula_keyword; use super::object_parser::table_cell_set_object; use super::org_source::OrgSource; use super::util::exit_matcher_parser; +use super::util::get_name; use super::util::org_line_ending; use crate::context::parser_with_context; use crate::context::ContextElement; @@ -70,7 +71,7 @@ pub(crate) fn org_mode_table<'b, 'g, 'r, 's>( remaining, Table { source: source.into(), - name: None, // TODO + name: get_name(&affiliated_keywords), formulas, children, }, diff --git a/src/types/lesser_element.rs b/src/types/lesser_element.rs index a7cfa4d..91091fc 100644 --- a/src/types/lesser_element.rs +++ b/src/types/lesser_element.rs @@ -148,12 +148,15 @@ pub enum SwitchNumberLines { } impl<'s> Paragraph<'s> { + /// Generate a paragraph of the passed in text with no additional properties. + /// + /// This is used for elements that support an "empty" content like greater blocks. pub(crate) fn of_text(input: &'s str) -> Self { let mut objects = Vec::with_capacity(1); objects.push(Object::PlainText(PlainText { source: input })); Paragraph { source: input, - name: None, // TODO + name: None, children: objects, } }