diff --git a/src/syntax/combinator.rs b/src/syntax/combinator.rs
index 557e12d..a06478d 100644
--- a/src/syntax/combinator.rs
+++ b/src/syntax/combinator.rs
@@ -58,7 +58,7 @@ token_parser!(percent2_token, "%%", PERCENT2);
token_parser!(backslash_token, "\\", BACKSLASH);
token_parser!(underscore_token, "_", UNDERSCORE);
// token_parser!(star_token, "*", STAR);
-token_parser!(plus_token, "+", PLUS);
+// token_parser!(plus_token, "+", PLUS);
token_parser!(minus_token, "-", MINUS);
token_parser!(colon_token, ":", COLON);
token_parser!(colon2_token, "::", COLON2);
diff --git a/src/syntax/drawer.rs b/src/syntax/drawer.rs
index 471571c..691df50 100644
--- a/src/syntax/drawer.rs
+++ b/src/syntax/drawer.rs
@@ -1,15 +1,15 @@
use nom::{
bytes::complete::{tag_no_case, take_while1},
character::complete::{space0, space1},
- combinator::{iterator, map, opt},
+ combinator::{iterator, map, verify},
sequence::tuple,
IResult, InputTake,
};
use super::{
combinator::{
- blank_lines, colon_token, eol_or_eof, line_starts_iter, node, plus_token, trim_line_end,
- GreenElement, NodeBuilder,
+ blank_lines, colon_token, eol_or_eof, line_starts_iter, node, trim_line_end, GreenElement,
+ NodeBuilder,
},
element::element_nodes,
input::Input,
@@ -104,30 +104,37 @@ fn property_drawer_node_base(input: Input) -> IResult {
}
fn node_property_node(input: Input) -> IResult {
- map(
- tuple((
- space0,
- colon_token,
- take_while1(|c| c != ':' && c != '+'),
- opt(plus_token),
- colon_token,
- space1,
- trim_line_end,
- )),
- |(ws, colon, name, plus, colon_, ws_, (value, ws__, nl))| {
- let mut b = NodeBuilder::new();
- b.ws(ws);
- b.push(colon);
- b.text(name);
- b.push_opt(plus);
- b.push(colon_);
- b.ws(ws_);
- b.text(value);
- b.ws(ws__);
- b.nl(nl);
- b.finish(NODE_PROPERTY)
- },
- )(input)
+ let (input, ws1) = space0(input)?;
+ let (input, colon1) = colon_token(input)?;
+ let (input, (colon2, name)) = map(
+ verify(take_while1(|c| c != ' ' && c != '\t'), |i: &Input| {
+ i.ends_with(':')
+ }),
+ |input: Input| input.take_split(input.len() - 1),
+ )(input)?;
+ let (input, ws2) = space1(input)?;
+ let (input, (value, ws3, nl)) = trim_line_end(input)?;
+
+ let mut b = NodeBuilder::new();
+
+ b.ws(ws1);
+ b.push(colon1);
+
+ if name.ends_with("+") {
+ let (plus, name) = name.take_split(name.len() - 1);
+ b.text(name);
+ b.token(PLUS, plus);
+ } else {
+ b.text(name);
+ }
+
+ b.token(COLON, colon2);
+ b.ws(ws2);
+ b.text(value);
+ b.ws(ws3);
+ b.nl(nl);
+
+ Ok((input, b.finish(NODE_PROPERTY)))
}
#[cfg_attr(
@@ -149,9 +156,14 @@ pub fn drawer_node(input: Input) -> IResult {
#[test]
fn parse() {
- use crate::{ast::Drawer, tests::to_ast, ParseConfig};
+ use crate::{
+ ast::{Drawer, PropertyDrawer},
+ tests::to_ast,
+ ParseConfig,
+ };
let to_drawer = to_ast::(drawer_node);
+ let to_property_drawer = to_ast::(property_drawer_node);
insta::assert_debug_snapshot!(
to_drawer(
@@ -208,8 +220,53 @@ fn parse() {
"###
);
+ // https://github.com/PoiScript/orgize/issues/70#issuecomment-2099671563
+ insta::assert_debug_snapshot!(
+ to_property_drawer(r#":PROPERTIES:
+:header-args:clojure: :session *clojure-1*
+:NAME: VALUE
+:NAME+: VALUE
+:END:"#).syntax,
+ @r###"
+ PROPERTY_DRAWER@0..91
+ DRAWER_BEGIN@0..13
+ COLON@0..1 ":"
+ TEXT@1..11 "PROPERTIES"
+ COLON@11..12 ":"
+ NEW_LINE@12..13 "\n"
+ NODE_PROPERTY@13..59
+ COLON@13..14 ":"
+ TEXT@14..33 "header-args:clojure"
+ COLON@33..34 ":"
+ WHITESPACE@34..38 " "
+ TEXT@38..58 ":session *clojure-1*"
+ NEW_LINE@58..59 "\n"
+ NODE_PROPERTY@59..72
+ COLON@59..60 ":"
+ TEXT@60..64 "NAME"
+ COLON@64..65 ":"
+ WHITESPACE@65..66 " "
+ TEXT@66..71 "VALUE"
+ NEW_LINE@71..72 "\n"
+ NODE_PROPERTY@72..86
+ COLON@72..73 ":"
+ TEXT@73..77 "NAME"
+ PLUS@77..78 "+"
+ COLON@78..79 ":"
+ WHITESPACE@79..80 " "
+ TEXT@80..85 "VALUE"
+ NEW_LINE@85..86 "\n"
+ DRAWER_END@86..91
+ COLON@86..87 ":"
+ TEXT@87..90 "END"
+ COLON@90..91 ":"
+ "###
+ );
+
let config = &ParseConfig::default();
// https://github.com/PoiScript/orgize/issues/9
assert!(drawer_node((":SPAGHETTI:\n", config).into()).is_err());
+
+ assert!(property_drawer_node((":PROPERTIES:\n:NAME:VALUE\n:END:", config).into()).is_err());
}