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.
This commit is contained in:
Tom Alexander 2023-10-04 20:01:09 -04:00
parent a26640355c
commit d8102b7bc2
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
32 changed files with 324 additions and 59 deletions

View File

@ -0,0 +1,10 @@
* Headline
before
#+NAME: foo
:candle:
inside
the drawer
:end:
after

View File

@ -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:

View File

@ -0,0 +1,4 @@
#+NAME: foo
#+begin_center
#+end_center

View File

@ -0,0 +1,4 @@
#+NAME: foo
#+begin_quote
#+end_quote

View File

@ -0,0 +1,6 @@
#+NAME: foo
#+begin_defun
foo
{{{bar(baz)}}}
#+end_defun

View File

@ -0,0 +1,2 @@
#+NAME: foo
1. bar

View File

@ -0,0 +1,2 @@
#+NAME: foo
#+call: foo(bar="baz")

View File

@ -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]

View File

@ -0,0 +1,2 @@
#+NAME: foo
# Comments cannot have affiliated keywords.

View File

@ -0,0 +1,2 @@
#+NAME: foo
%%(foo)

View File

@ -0,0 +1,2 @@
#+NAME: foo
: bar

View File

@ -0,0 +1,2 @@
#+NAME: foo
-----

View File

@ -0,0 +1,2 @@
#+NAME: foo
#+FOO: BAR

View File

@ -0,0 +1,4 @@
#+NAME: foo
\begin{foo}
bar
\end{foo}

View File

@ -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<DiffEntry<'b, 's>, Box<dyn std::error::Error>> {
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<DiffEntry<'b, 's>, Box<dyn std::error::Error>> {
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<DiffEntry<'b, 's>, Box<dyn std::error::Error>> {
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<DiffEntry<'b, 's>, Box<dyn std::error::Error>> {
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<DiffEntry<'b, 's>, Box<dyn std::error::Error>> {
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<DiffEntry<'b, 's>, Box<dyn std::error::Error>> {
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(),

View File

@ -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<OrgSource<'s>, 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
},
))
}

View File

@ -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,
},
))

View File

@ -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,
},

View File

@ -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<OrgSource<'s>, ()> {
// TODO: What about affiliated keywords in the detect_* functions?
if alt((
parser_with_context!(detect_plain_list)(context),
detect_footnote_definition,

View File

@ -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<OrgSource<'s>, 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
},
))
}

View File

@ -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(),
},

View File

@ -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<OrgSource<'s>, 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)),
}),
))

View File

@ -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<OrgSource<'s>, 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
},
))
}

View File

@ -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<OrgSource<'s>, 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<OrgSource<'s>, 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,
},

View File

@ -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<OrgSource<'s>, 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
},
))
}

View File

@ -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<OrgSource<'s>, 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: &paragraph_end,

View File

@ -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<OrgSource<'s>, 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(),
},

View File

@ -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()),
},
))

View File

@ -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<OrgSource<'s>, 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,
},

View File

@ -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<PlainListItem<'s>>,
}
@ -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<Element<'s>>,
}
#[derive(Debug)]
pub struct QuoteBlock<'s> {
pub source: &'s str,
pub name: Option<&'s str>,
pub children: Vec<Element<'s>>,
}
#[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<Element<'s>>,
}
@ -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<Element<'s>>,
}
@ -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<Element<'s>>,
}
@ -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<Element<'s>>,
}
@ -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<Keyword<'s>>,
pub children: Vec<TableRow<'s>>,
}

View File

@ -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.