feat: support formulas in org table

This commit is contained in:
PoiScript 2023-11-24 16:15:11 +08:00
parent 3c2c8b28fd
commit f8fd1306e2
No known key found for this signature in database
GPG key ID: 22C2B1249D99985E
3 changed files with 129 additions and 24 deletions

View file

@ -8,10 +8,9 @@ use nom::{
sequence::tuple,
IResult, InputLength, InputTake,
};
use rowan::GreenNode;
use super::{
combinator::{blank_lines, hash_plus_token, trim_line_end, GreenElement},
combinator::{blank_lines, hash_plus_token, node, trim_line_end, GreenElement},
input::Input,
SyntaxKind,
};
@ -19,18 +18,19 @@ use super::{
#[tracing::instrument(level = "debug", skip(input), fields(input = input.s))]
pub fn keyword_node(input: Input) -> IResult<Input, GreenElement, ()> {
fn f(input: Input) -> IResult<Input, GreenElement, ()> {
let (input, (key, mut nodes, post_blank)) = keyword_node_base(input)?;
let (input, (key, mut nodes)) = keyword_node_base(input)?;
let (input, post_blank) = blank_lines(input)?;
nodes.extend(post_blank);
Ok((
input,
GreenElement::Node(GreenNode::new(
node(
if key == "CALL" {
SyntaxKind::BABEL_CALL.into()
SyntaxKind::BABEL_CALL
} else {
SyntaxKind::KEYWORD.into()
SyntaxKind::KEYWORD
},
nodes,
)),
),
))
}
crate::lossless_parser!(f, input)
@ -44,10 +44,12 @@ pub fn affiliated_keyword_nodes(input: Input) -> IResult<Input, Vec<GreenElement
let mut i = input;
while !i.is_empty() {
let Ok((input_, (key, nodes, post_blank))) = keyword_node_base(i) else {
let Ok((input_, (key, nodes))) = keyword_node_base(i) else {
break;
};
let (input_, post_blank) = blank_lines(input_)?;
// affiliated keyword can not followed by blank lines or eof
if !post_blank.is_empty() || input_.is_empty() {
return Ok((input, vec![]));
@ -64,24 +66,44 @@ pub fn affiliated_keyword_nodes(input: Input) -> IResult<Input, Vec<GreenElement
input_.input_len()
);
i = input_;
children.push(GreenElement::Node(GreenNode::new(
SyntaxKind::AFFILIATED_KEYWORD.into(),
nodes,
)));
children.push(node(SyntaxKind::AFFILIATED_KEYWORD, nodes));
}
Ok((i, children))
}
fn keyword_node_base(
input: Input,
) -> IResult<Input, (&str, Vec<GreenElement>, Vec<GreenElement>), ()> {
pub fn tblfm_keyword_nodes(input: Input) -> IResult<Input, Vec<GreenElement>, ()> {
let mut children = vec![];
let mut i = input;
while !i.is_empty() {
let Ok((input, (key, nodes))) = keyword_node_base(i) else {
break;
};
if !key.eq_ignore_ascii_case("TBLFM") {
break;
}
debug_assert!(
i.input_len() > input.input_len(),
"{} > {}",
i.input_len(),
input.input_len()
);
i = input;
children.push(node(SyntaxKind::KEYWORD, nodes));
}
Ok((i, children))
}
fn keyword_node_base(input: Input) -> IResult<Input, (&str, Vec<GreenElement>), ()> {
let (input, (ws, hash_plus)) = tuple((space0, hash_plus_token))(input)?;
let (input, (key, optional, colon)) = alt((key_with_optional, key))(input)?;
let (input, (value, ws_, nl)) = trim_line_end(input)?;
let (input, post_blank) = blank_lines(input)?;
let mut children = vec![];
if !ws.is_empty() {
@ -103,7 +125,7 @@ fn keyword_node_base(
children.push(nl.nl_token());
}
Ok((input, (key.s, children, post_blank)))
Ok((input, (key.s, children)))
}
fn key(input: Input) -> IResult<Input, (Input, Option<(Input, Input, Input)>, Input), ()> {

View file

@ -9,6 +9,7 @@ use nom::{
use super::{
combinator::{blank_lines, line_ends_iter, node, pipe_token, GreenElement, NodeBuilder},
input::Input,
keyword::tblfm_keyword_nodes,
object::standard_object_nodes,
SyntaxKind::*,
};
@ -23,11 +24,7 @@ fn org_table_node_base(input: Input) -> IResult<Input, GreenElement, ()> {
// Org tables end at the first line not starting with a vertical bar.
if !trimmed.starts_with('|') {
if start == 0 {
return Err(nom::Err::Error(()));
} else {
break;
}
break;
}
if trimmed.starts_with("|-") {
@ -39,8 +36,17 @@ fn org_table_node_base(input: Input) -> IResult<Input, GreenElement, ()> {
start = i;
}
let (input, post_blank) = blank_lines(input.slice(start..))?;
if start == 0 {
return Err(nom::Err::Error(()));
}
let input = input.slice(start..);
let (input, tblfm) = tblfm_keyword_nodes(input)?;
let (input, post_blank) = blank_lines(input)?;
children.extend(tblfm);
children.extend(post_blank);
Ok((input, node(ORG_TABLE, children)))
@ -176,6 +182,52 @@ r#"|
WHITESPACE@19..20 "\n"
"###
);
insta::assert_debug_snapshot!(
to_org_table("| a |\n#+tblfm: test").syntax,
@r###"
ORG_TABLE@0..19
ORG_TABLE_STANDARD_ROW@0..6
PIPE@0..1 "|"
WHITESPACE@1..2 " "
ORG_TABLE_CELL@2..3
TEXT@2..3 "a"
WHITESPACE@3..4 " "
PIPE@4..5 "|"
WHITESPACE@5..6 "\n"
KEYWORD@6..19
HASH_PLUS@6..8 "#+"
TEXT@8..13 "tblfm"
COLON@13..14 ":"
TEXT@14..19 " test"
"###
);
insta::assert_debug_snapshot!(
to_org_table("| a |\n#+TBLFM: test1\n#+TBLFM: test2").syntax,
@r###"
ORG_TABLE@0..35
ORG_TABLE_STANDARD_ROW@0..6
PIPE@0..1 "|"
WHITESPACE@1..2 " "
ORG_TABLE_CELL@2..3
TEXT@2..3 "a"
WHITESPACE@3..4 " "
PIPE@4..5 "|"
WHITESPACE@5..6 "\n"
KEYWORD@6..21
HASH_PLUS@6..8 "#+"
TEXT@8..13 "TBLFM"
COLON@13..14 ":"
TEXT@14..20 " test1"
NEW_LINE@20..21 "\n"
KEYWORD@21..35
HASH_PLUS@21..23 "#+"
TEXT@23..28 "TBLFM"
COLON@28..29 ":"
TEXT@29..35 " test2"
"###
);
}
#[test]