From eab9eb68ec55c34491a036a202e1ea9f7289ea5d Mon Sep 17 00:00:00 2001 From: PoiScript Date: Tue, 11 Jun 2024 14:42:06 +0800 Subject: [PATCH] feat: support use_sub_superscript config --- src/config.rs | 31 +++++++++++ src/syntax/object.rs | 12 +++- src/syntax/subscript_superscript.rs | 86 +++++++++++++++++------------ 3 files changed, 91 insertions(+), 38 deletions(-) diff --git a/src/config.rs b/src/config.rs index 8776c8e..a51db78 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,27 @@ use crate::syntax::document::document_node; use crate::Org; +#[derive(Clone, Debug)] +pub enum UseSubSuperscript { + Nil, + Brace, + True, +} + +impl UseSubSuperscript { + pub fn is_nil(&self) -> bool { + matches!(self, UseSubSuperscript::Nil) + } + + pub fn is_true(&self) -> bool { + matches!(self, UseSubSuperscript::True) + } + + pub fn is_brace(&self) -> bool { + matches!(self, UseSubSuperscript::Brace) + } +} + /// Parse configuration #[derive(Clone, Debug)] pub struct ParseConfig { @@ -11,6 +32,15 @@ pub struct ParseConfig { pub parsed_keywords: Vec, + /// Control sub/superscript parsing + /// + /// Equivalent to `org-use-sub-superscripts` + /// + /// - `UseSubSuperscript::Nil`: disable parsing + /// - `UseSubSuperscript::True`: enable parsing + /// - `UseSubSuperscript::Brace`: enable parsing, but braces are required + pub use_sub_superscript: UseSubSuperscript, + /// Affiliated keywords /// /// Equivalent to [`org-element-affiliated-keywords`](https://git.sr.ht/~bzg/org-mode/tree/6f960f3c6a4dfe137fbd33fef9f7dadfd229600c/item/lisp/org-element.el#L331) @@ -36,6 +66,7 @@ impl Default for ParseConfig { todo_keywords: (vec!["TODO".into()], vec!["DONE".into()]), dual_keywords: vec!["CAPTION".into(), "RESULTS".into()], parsed_keywords: vec!["CAPTION".into()], + use_sub_superscript: UseSubSuperscript::True, affiliated_keywords: vec![ "CAPTION".into(), "DATA".into(), diff --git a/src/syntax/object.rs b/src/syntax/object.rs index a76cc67..5cc3947 100644 --- a/src/syntax/object.rs +++ b/src/syntax/object.rs @@ -128,8 +128,16 @@ pub fn minimal_object_nodes(input: Input) -> Vec { b'~' if emphasis::verify_pre(pre.s) => code_node(i), b'$' => latex_fragment_node(i), b'\\' => entity_node(i).or_else(|_| latex_fragment_node(i)), - b'^' if subscript_superscript::verify_pre(pre.s) => superscript_node(i), - b'_' if subscript_superscript::verify_pre(pre.s) => subscript_node(i), + b'^' if !input.c.use_sub_superscript.is_nil() + && subscript_superscript::verify_pre(pre.s) => + { + superscript_node(i) + } + b'_' if !input.c.use_sub_superscript.is_nil() + && subscript_superscript::verify_pre(pre.s) => + { + subscript_node(i) + } _ => Err(nom::Err::Error(())), }, input, diff --git a/src/syntax/subscript_superscript.rs b/src/syntax/subscript_superscript.rs index 17f544e..ce511a1 100644 --- a/src/syntax/subscript_superscript.rs +++ b/src/syntax/subscript_superscript.rs @@ -24,23 +24,16 @@ pub fn superscript_node(input: Input) -> IResult { let mut children = vec![caret]; - if let Ok((input, star)) = tag::<&str, Input, ()>("*")(input) { - children.push(star.text_token()); - Ok((input, node(SyntaxKind::SUPERSCRIPT, children))) - } else if let Ok((input, (l, contents, r))) = template1(input) { - children.push(l); - children.extend(standard_object_nodes(contents)); - children.push(r); - Ok((input, node(SyntaxKind::SUPERSCRIPT, children))) - } else if let Ok((input, (sign, contents))) = template2(input) { - if let Some(s) = sign { - children.push(s) - } - children.push(contents); - Ok((input, node(SyntaxKind::SUPERSCRIPT, children))) - } else { - Err(nom::Err::Error(())) + if input.c.use_sub_superscript.is_brace() { + let (input, rest) = template1(input)?; + children.extend(rest); + return Ok((input, node(SyntaxKind::SUPERSCRIPT, children))); } + + let (input, rest) = alt((template0, template1, template2))(input)?; + children.extend(rest); + + Ok((input, node(SyntaxKind::SUPERSCRIPT, children))) } pub fn subscript_node(input: Input) -> IResult { @@ -48,33 +41,35 @@ pub fn subscript_node(input: Input) -> IResult { let mut children = vec![underscore]; - if let Ok((input, star)) = tag::<&str, Input, ()>("*")(input) { - children.push(star.text_token()); - Ok((input, node(SyntaxKind::SUBSCRIPT, children))) - } else if let Ok((input, (l, contents, r))) = template1(input) { - children.push(l); - children.extend(standard_object_nodes(contents)); - children.push(r); - Ok((input, node(SyntaxKind::SUBSCRIPT, children))) - } else if let Ok((input, (sign, contents))) = template2(input) { - if let Some(s) = sign { - children.push(s) - } - children.push(contents); - Ok((input, node(SyntaxKind::SUBSCRIPT, children))) - } else { - Err(nom::Err::Error(())) + if input.c.use_sub_superscript.is_brace() { + let (input, rest) = template1(input)?; + children.extend(rest); + return Ok((input, node(SyntaxKind::SUBSCRIPT, children))); } + + let (input, rest) = alt((template0, template1, template2))(input)?; + children.extend(rest); + + Ok((input, node(SyntaxKind::SUBSCRIPT, children))) } -fn template1(input: Input) -> IResult { +fn template0(input: Input) -> IResult, ()> { + let (input, star) = tag("*")(input)?; + Ok((input, vec![star.text_token()])) +} + +fn template1(input: Input) -> IResult, ()> { let (input, l) = l_curly_token(input)?; let (input, contents) = balanced_brackets(input)?; let (input, r) = r_curly_token(input)?; - Ok((input, (l, contents, r))) + let mut children = vec![]; + children.push(l); + children.extend(standard_object_nodes(contents)); + children.push(r); + Ok((input, children)) } -fn template2(input: Input) -> IResult, GreenElement), ()> { +fn template2(input: Input) -> IResult, ()> { let (input, sign) = opt(alt((tag("+"), tag("-"))))(input)?; let (input, contents) = @@ -84,7 +79,15 @@ fn template2(input: Input) -> IResult, GreenElement return Err(nom::Err::Error(())); } - Ok((input, (sign.map(|x| x.text_token()), contents.text_token()))) + let mut children = vec![]; + + if let Some(s) = sign { + children.push(s.text_token()) + } + + children.push(contents.text_token()); + + Ok((input, children)) } fn balanced_brackets(input: Input) -> IResult { @@ -113,6 +116,7 @@ pub fn verify_pre(s: &str) -> bool { #[test] fn parse() { use crate::ast::Subscript; + use crate::config::{ParseConfig, UseSubSuperscript}; use crate::tests::to_ast; let to_subscript = to_ast::(subscript_node); @@ -158,4 +162,14 @@ fn parse() { TEXT@1..4 "abc" "### ); + + let with_brace = ParseConfig { + use_sub_superscript: UseSubSuperscript::Brace, + ..Default::default() + }; + + debug_assert!(subscript_node(("_*", &with_brace).into()).is_err()); + debug_assert!(subscript_node(("_abc", &with_brace).into()).is_err()); + debug_assert!(subscript_node(("_+123", &with_brace).into()).is_err()); + debug_assert!(subscript_node(("_{*bo\nld*}", &with_brace).into()).is_ok()); }