From 17ab8727d11193a0d58d3f68ae3cdbb99f137dd6 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 19 Apr 2023 20:59:58 -0400 Subject: [PATCH 01/19] Initial structure for tables. --- src/compare/diff.rs | 27 +++++++++++++++++++++++++++ src/parser/element.rs | 12 ++++++++++++ src/parser/greater_element.rs | 5 +++++ src/parser/mod.rs | 2 ++ src/parser/table.rs | 8 ++++++++ 5 files changed, 54 insertions(+) create mode 100644 src/parser/table.rs diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 4920fb3..b0b6210 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -14,6 +14,7 @@ use crate::parser::PlainList; use crate::parser::PlainListItem; use crate::parser::PropertyDrawer; use crate::parser::Section; +use crate::parser::Table; use crate::DynamicBlock; #[derive(Debug)] @@ -198,6 +199,7 @@ fn compare_element<'s>( Element::Comment(obj) => compare_comment(source, emacs, obj), Element::Drawer(obj) => compare_drawer(source, emacs, obj), Element::PropertyDrawer(obj) => compare_property_drawer(source, emacs, obj), + Element::Table(obj) => compare_table(source, emacs, obj), } } @@ -459,3 +461,28 @@ fn compare_property_drawer<'s>( children: child_status, }) } + +fn compare_table<'s>( + source: &'s str, + emacs: &'s Token<'s>, + rust: &'s Table<'s>, +) -> Result> { + let children = emacs.as_list()?; + let mut child_status = Vec::new(); + let mut this_status = DiffStatus::Good; + let emacs_name = "table"; + if assert_name(emacs, emacs_name).is_err() { + this_status = DiffStatus::Bad; + } + + if assert_bounds(source, emacs, rust).is_err() { + this_status = DiffStatus::Bad; + } + + Ok(DiffResult { + status: this_status, + name: emacs_name.to_owned(), + message: None, + children: child_status, + }) +} diff --git a/src/parser/element.rs b/src/parser/element.rs index e3a2c4e..9475c40 100644 --- a/src/parser/element.rs +++ b/src/parser/element.rs @@ -9,6 +9,7 @@ use super::greater_element::FootnoteDefinition; use super::greater_element::GreaterBlock; use super::greater_element::PlainList; use super::greater_element::PropertyDrawer; +use super::greater_element::Table; use super::lesser_element::Comment; use super::lesser_element::Paragraph; use super::paragraph::paragraph; @@ -18,6 +19,7 @@ use super::Context; use super::Drawer; use super::PlainListItem; use crate::parser::parser_with_context::parser_with_context; +use crate::parser::table::table; use nom::branch::alt; use nom::combinator::map; @@ -31,6 +33,7 @@ pub enum Element<'s> { Comment(Comment<'s>), Drawer(Drawer<'s>), PropertyDrawer(PropertyDrawer<'s>), + Table(Table<'s>), } impl<'s> Source<'s> for Element<'s> { @@ -44,6 +47,7 @@ impl<'s> Source<'s> for Element<'s> { Element::Comment(obj) => obj.source, Element::Drawer(obj) => obj.source, Element::PropertyDrawer(obj) => obj.source, + Element::Table(obj) => obj.source, } } } @@ -102,6 +106,12 @@ impl<'s> Source<'s> for PropertyDrawer<'s> { } } +impl<'s> Source<'s> for Table<'s> { + fn get_source(&'s self) -> &'s str { + self.source + } +} + #[tracing::instrument(ret, level = "debug")] pub fn element<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, Element<'s>> { let non_paragraph_matcher = parser_with_context!(non_paragraph_element)(context); @@ -123,6 +133,7 @@ pub fn non_paragraph_element<'r, 's>( let footnote_definition_matcher = parser_with_context!(footnote_definition)(context); let comment_matcher = parser_with_context!(comment)(context); let drawer_matcher = parser_with_context!(drawer)(context); + let table_matcher = parser_with_context!(table)(context); alt(( map(plain_list_matcher, Element::PlainList), map(greater_block_matcher, Element::GreaterBlock), @@ -130,5 +141,6 @@ pub fn non_paragraph_element<'r, 's>( map(footnote_definition_matcher, Element::FootnoteDefinition), map(comment_matcher, Element::Comment), map(drawer_matcher, Element::Drawer), + map(table_matcher, Element::Table), ))(input) } diff --git a/src/parser/greater_element.rs b/src/parser/greater_element.rs index 78b05c2..96ee656 100644 --- a/src/parser/greater_element.rs +++ b/src/parser/greater_element.rs @@ -55,3 +55,8 @@ pub struct NodeProperty<'s> { pub source: &'s str, pub value: Option<&'s str>, } + +#[derive(Debug)] +pub struct Table<'s> { + pub source: &'s str, +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 6359a5c..74ddbe1 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -18,6 +18,7 @@ mod plain_list; mod plain_text; mod property_drawer; mod source; +mod table; mod util; pub use document::document; pub use document::Document; @@ -32,6 +33,7 @@ pub use greater_element::GreaterBlock; pub use greater_element::PlainList; pub use greater_element::PlainListItem; pub use greater_element::PropertyDrawer; +pub use greater_element::Table; pub use lesser_element::Comment; pub use lesser_element::Paragraph; pub use source::Source; diff --git a/src/parser/table.rs b/src/parser/table.rs new file mode 100644 index 0000000..05cde93 --- /dev/null +++ b/src/parser/table.rs @@ -0,0 +1,8 @@ +use super::Context; +use crate::parser::error::Res; +use crate::parser::Table; + +#[tracing::instrument(ret, level = "debug")] +pub fn table<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, Table<'s>> { + todo!() +} From f3c1b47a8a5fd3f84789068c8696837ab7ac11c7 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 19 Apr 2023 21:19:49 -0400 Subject: [PATCH 02/19] First attempt at table parser. Table row not yet implemented. --- src/parser/element.rs | 5 +-- src/parser/greater_element.rs | 6 ++++ src/parser/table.rs | 63 ++++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/parser/element.rs b/src/parser/element.rs index 9475c40..9f9f97f 100644 --- a/src/parser/element.rs +++ b/src/parser/element.rs @@ -19,7 +19,8 @@ use super::Context; use super::Drawer; use super::PlainListItem; use crate::parser::parser_with_context::parser_with_context; -use crate::parser::table::table; +use crate::parser::table; +use crate::parser::table::org_mode_table; use nom::branch::alt; use nom::combinator::map; @@ -133,7 +134,7 @@ pub fn non_paragraph_element<'r, 's>( let footnote_definition_matcher = parser_with_context!(footnote_definition)(context); let comment_matcher = parser_with_context!(comment)(context); let drawer_matcher = parser_with_context!(drawer)(context); - let table_matcher = parser_with_context!(table)(context); + let table_matcher = parser_with_context!(org_mode_table)(context); alt(( map(plain_list_matcher, Element::PlainList), map(greater_block_matcher, Element::GreaterBlock), diff --git a/src/parser/greater_element.rs b/src/parser/greater_element.rs index 96ee656..3054f38 100644 --- a/src/parser/greater_element.rs +++ b/src/parser/greater_element.rs @@ -59,4 +59,10 @@ pub struct NodeProperty<'s> { #[derive(Debug)] pub struct Table<'s> { pub source: &'s str, + pub children: Vec>, +} + +#[derive(Debug)] +pub struct TableRow<'s> { + pub source: &'s str, } diff --git a/src/parser/table.rs b/src/parser/table.rs index 05cde93..d83a4bf 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -1,8 +1,69 @@ +use nom::bytes::complete::tag; +use nom::character::complete::space0; +use nom::combinator::not; +use nom::combinator::peek; +use nom::combinator::recognize; +use nom::multi::many_till; +use nom::sequence::tuple; + use super::Context; use crate::parser::error::Res; +use crate::parser::exiting::ExitClass; +use crate::parser::greater_element::TableRow; +use crate::parser::parser_context::ContextElement; +use crate::parser::parser_context::ExitMatcherNode; +use crate::parser::parser_with_context::parser_with_context; +use crate::parser::util::exit_matcher_parser; +use crate::parser::util::get_consumed; +use crate::parser::util::maybe_consume_trailing_whitespace_if_not_exiting; +use crate::parser::util::start_of_line; use crate::parser::Table; +/// Parse an org-mode-style table +/// +/// This is not the table.el style. #[tracing::instrument(ret, level = "debug")] -pub fn table<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, Table<'s>> { +pub fn org_mode_table<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, Table<'s>> { + start_of_line(context, input)?; + peek(tuple((space0, tag("|"))))(input)?; + + let parser_context = context + .with_additional_node(ContextElement::ConsumeTrailingWhitespace(true)) + .with_additional_node(ContextElement::Context("table")) + .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + class: ExitClass::Alpha, + exit_matcher: &table_end, + })); + + let org_mode_table_row_matcher = parser_with_context!(org_mode_table_row)(&parser_context); + let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); + + let (remaining, (children, _exit_contents)) = + many_till(org_mode_table_row_matcher, exit_matcher)(input)?; + + let (remaining, _trailing_ws) = + maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; + let source = get_consumed(input, remaining); + + Ok(( + remaining, + Table { + source, + children + } + )) +} + +#[tracing::instrument(ret, level = "debug")] +fn table_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { + start_of_line(context, input)?; + recognize(tuple((space0, not(tag("|")))))(input) +} + +#[tracing::instrument(ret, level = "debug")] +pub fn org_mode_table_row<'r, 's>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, TableRow<'s>> { todo!() } From 093edf5c6e3692e0b5407600b336d112e1a80197 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 19 Apr 2023 21:21:33 -0400 Subject: [PATCH 03/19] Add TODO. --- src/parser/table.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/parser/table.rs b/src/parser/table.rs index d83a4bf..baf1873 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -41,6 +41,7 @@ pub fn org_mode_table<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<& let (remaining, (children, _exit_contents)) = many_till(org_mode_table_row_matcher, exit_matcher)(input)?; + // TODO: Consume trailing formulas let (remaining, _trailing_ws) = maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; let source = get_consumed(input, remaining); From 9747e0ba119be0cf6030ecaa30667427ccf80a19 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 19 Apr 2023 21:28:35 -0400 Subject: [PATCH 04/19] Implement table row rule. --- src/parser/table.rs | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/parser/table.rs b/src/parser/table.rs index baf1873..89fe042 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -1,4 +1,7 @@ +use nom::branch::alt; +use nom::bytes::complete::is_not; use nom::bytes::complete::tag; +use nom::character::complete::line_ending; use nom::character::complete::space0; use nom::combinator::not; use nom::combinator::peek; @@ -46,13 +49,7 @@ pub fn org_mode_table<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<& maybe_consume_trailing_whitespace_if_not_exiting(context, remaining)?; let source = get_consumed(input, remaining); - Ok(( - remaining, - Table { - source, - children - } - )) + Ok((remaining, Table { source, children })) } #[tracing::instrument(ret, level = "debug")] @@ -65,6 +62,28 @@ fn table_end<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, & pub fn org_mode_table_row<'r, 's>( context: Context<'r, 's>, input: &'s str, +) -> Res<&'s str, TableRow<'s>> { + alt(( + parser_with_context!(org_mode_table_row_rule)(context), + parser_with_context!(org_mode_table_row_regular)(context), + ))(input) +} + +#[tracing::instrument(ret, level = "debug")] +pub fn org_mode_table_row_rule<'r, 's>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, TableRow<'s>> { + start_of_line(context, input)?; + let (remaining, _) = tuple((space0, tag("|-"), is_not("\r\n"), line_ending))(input)?; + let source = get_consumed(input, remaining); + Ok((remaining, TableRow { source })) +} + +#[tracing::instrument(ret, level = "debug")] +pub fn org_mode_table_row_regular<'r, 's>( + context: Context<'r, 's>, + input: &'s str, ) -> Res<&'s str, TableRow<'s>> { todo!() } From 55201e905afacc4d69c630dd22fd7bb62dc77025 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 19 Apr 2023 21:57:08 -0400 Subject: [PATCH 05/19] Starting to implement table cell. --- src/parser/greater_element.rs | 6 ++++++ src/parser/object.rs | 12 +++++++++++ src/parser/table.rs | 39 ++++++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/parser/greater_element.rs b/src/parser/greater_element.rs index 3054f38..0758c71 100644 --- a/src/parser/greater_element.rs +++ b/src/parser/greater_element.rs @@ -65,4 +65,10 @@ pub struct Table<'s> { #[derive(Debug)] pub struct TableRow<'s> { pub source: &'s str, + pub children: Vec>, +} + +#[derive(Debug)] +pub struct TableCell<'s> { + pub source: &'s str, } diff --git a/src/parser/object.rs b/src/parser/object.rs index 36162a6..98078c6 100644 --- a/src/parser/object.rs +++ b/src/parser/object.rs @@ -54,3 +54,15 @@ pub fn standard_set_object<'r, 's>( map(plain_text_matcher, Object::PlainText)(input) } + +#[tracing::instrument(ret, level = "debug")] +pub fn minimal_set_object<'r, 's>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, Object<'s>> { + not(|i| context.check_exit_matcher(i))(input)?; + + let plain_text_matcher = parser_with_context!(plain_text)(context); + + map(plain_text_matcher, Object::PlainText)(input) +} diff --git a/src/parser/table.rs b/src/parser/table.rs index 89fe042..e7681f6 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -6,13 +6,16 @@ use nom::character::complete::space0; use nom::combinator::not; use nom::combinator::peek; use nom::combinator::recognize; +use nom::multi::many1; use nom::multi::many_till; use nom::sequence::tuple; use super::Context; use crate::parser::error::Res; use crate::parser::exiting::ExitClass; +use crate::parser::greater_element::TableCell; use crate::parser::greater_element::TableRow; +use crate::parser::object::minimal_set_object; use crate::parser::parser_context::ContextElement; use crate::parser::parser_context::ExitMatcherNode; use crate::parser::parser_with_context::parser_with_context; @@ -77,7 +80,13 @@ pub fn org_mode_table_row_rule<'r, 's>( start_of_line(context, input)?; let (remaining, _) = tuple((space0, tag("|-"), is_not("\r\n"), line_ending))(input)?; let source = get_consumed(input, remaining); - Ok((remaining, TableRow { source })) + Ok(( + remaining, + TableRow { + source, + children: Vec::new(), + }, + )) } #[tracing::instrument(ret, level = "debug")] @@ -85,5 +94,33 @@ pub fn org_mode_table_row_regular<'r, 's>( context: Context<'r, 's>, input: &'s str, ) -> Res<&'s str, TableRow<'s>> { + start_of_line(context, input)?; + let (remaining, _) = tuple((space0, tag("|")))(input)?; + let (remaining, children) = + many1(parser_with_context!(org_mode_table_cell)(context))(remaining)?; + let source = get_consumed(input, remaining); + Ok((remaining, TableRow { source, children })) +} + +#[tracing::instrument(ret, level = "debug")] +pub fn org_mode_table_cell<'r, 's>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, TableCell<'s>> { + let parser_context = + context.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { + class: ExitClass::Beta, + exit_matcher: &org_mode_table_cell_end, + })); + let minimal_set_object_matcher = parser_with_context!(minimal_set_object)(&parser_context); + todo!() } + +#[tracing::instrument(ret, level = "debug")] +fn org_mode_table_cell_end<'r, 's>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, &'s str> { + recognize(tuple((space0, alt((tag("|"), peek(line_ending))))))(input) +} From 49f5b65acfe8bfd09eb7370e6475e7f971fa1e21 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 19 Apr 2023 22:09:53 -0400 Subject: [PATCH 06/19] Match objects in cells. --- src/parser/greater_element.rs | 6 +----- src/parser/lesser_element.rs | 9 ++++++++- src/parser/table.rs | 9 ++++++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/parser/greater_element.rs b/src/parser/greater_element.rs index 0758c71..8af70e4 100644 --- a/src/parser/greater_element.rs +++ b/src/parser/greater_element.rs @@ -1,4 +1,5 @@ use super::element::Element; +use super::lesser_element::TableCell; #[derive(Debug)] pub struct PlainList<'s> { @@ -67,8 +68,3 @@ pub struct TableRow<'s> { pub source: &'s str, pub children: Vec>, } - -#[derive(Debug)] -pub struct TableCell<'s> { - pub source: &'s str, -} diff --git a/src/parser/lesser_element.rs b/src/parser/lesser_element.rs index 6d041b4..44b4f44 100644 --- a/src/parser/lesser_element.rs +++ b/src/parser/lesser_element.rs @@ -1,4 +1,5 @@ -use super::object::{Object, TextMarkup}; +use super::object::Object; +use super::object::TextMarkup; #[derive(Debug)] pub struct Paragraph<'s> { @@ -11,6 +12,12 @@ pub struct Comment<'s> { pub source: &'s str, } +#[derive(Debug)] +pub struct TableCell<'s> { + pub source: &'s str, + pub children: Vec>, +} + impl<'s> Paragraph<'s> { pub fn of_text(input: &'s str) -> Self { let mut objects = Vec::with_capacity(1); diff --git a/src/parser/table.rs b/src/parser/table.rs index e7681f6..92d1649 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -6,6 +6,7 @@ use nom::character::complete::space0; use nom::combinator::not; use nom::combinator::peek; use nom::combinator::recognize; +use nom::combinator::verify; use nom::multi::many1; use nom::multi::many_till; use nom::sequence::tuple; @@ -13,8 +14,8 @@ use nom::sequence::tuple; use super::Context; use crate::parser::error::Res; use crate::parser::exiting::ExitClass; -use crate::parser::greater_element::TableCell; use crate::parser::greater_element::TableRow; +use crate::parser::lesser_element::TableCell; use crate::parser::object::minimal_set_object; use crate::parser::parser_context::ContextElement; use crate::parser::parser_context::ExitMatcherNode; @@ -113,6 +114,12 @@ pub fn org_mode_table_cell<'r, 's>( exit_matcher: &org_mode_table_cell_end, })); let minimal_set_object_matcher = parser_with_context!(minimal_set_object)(&parser_context); + let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); + let (remaining, (children, _exit_contents)) = verify( + many_till(minimal_set_object_matcher, exit_matcher), + |(children, _exit_contents)| !children.is_empty(), + )(input)?; + todo!() } From 633d6e421f2af1c26c6b6b12a14ed465b881a6da Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 20 Apr 2023 00:15:40 -0400 Subject: [PATCH 07/19] Allow empty cells if not last of line. --- src/parser/table.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parser/table.rs b/src/parser/table.rs index 92d1649..d475398 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -117,7 +117,7 @@ pub fn org_mode_table_cell<'r, 's>( let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); let (remaining, (children, _exit_contents)) = verify( many_till(minimal_set_object_matcher, exit_matcher), - |(children, _exit_contents)| !children.is_empty(), + |(children, exit_contents)| !children.is_empty() || *exit_contents == "|", )(input)?; @@ -129,5 +129,5 @@ fn org_mode_table_cell_end<'r, 's>( context: Context<'r, 's>, input: &'s str, ) -> Res<&'s str, &'s str> { - recognize(tuple((space0, alt((tag("|"), peek(line_ending))))))(input) + recognize(tuple((space0, alt((tag("|"), line_ending)))))(input) } From 3a174dd41b7380fd209e201c76ed0234d7e55d3e Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 20 Apr 2023 22:53:17 -0400 Subject: [PATCH 08/19] Only build musl binaries on linux. --- Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dfad1d3..0728dd8 100644 --- a/Makefile +++ b/Makefile @@ -6,9 +6,14 @@ MAKEFLAGS += --warn-undefined-variables MAKEFLAGS += --no-builtin-rules TESTJOBS := 4 OS:=$(shell uname -s) +RELEASEFLAGS := ifeq ($(OS),Linux) TESTJOBS:=$(shell nproc) + RELEASEFLAGS=--target x86_64-unknown-linux-musl +endif +ifeq ($(OS),FreeBSD) + TESTJOBS:=$(shell sysctl -n hw.ncpu) endif ifeq ($(origin .RECIPEPREFIX), undefined) @@ -22,7 +27,7 @@ build: .PHONY: release release: -> cargo build --release --target x86_64-unknown-linux-musl +> cargo build --release $(RELEASEFLAGS) .PHONY: clean clean: From c75f4ebcffe43d6402054dc32cbf1342c8d2c1b1 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 14:35:34 -0400 Subject: [PATCH 09/19] Format the code. --- src/lib.rs | 6 +++--- src/parser/comment.rs | 20 ++++++++++++-------- src/parser/parser_context.rs | 1 - src/parser/table.rs | 1 - 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fbcf791..bea65b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ #![feature(round_char_boundary)] #![feature(exit_status_error)] -mod parser; mod compare; -pub use parser::*; +mod parser; +pub use compare::compare_document; pub use compare::emacs_parse_org_document; pub use compare::sexp; -pub use compare::compare_document; +pub use parser::*; diff --git a/src/parser/comment.rs b/src/parser/comment.rs index 92f79f6..558af0b 100644 --- a/src/parser/comment.rs +++ b/src/parser/comment.rs @@ -49,8 +49,11 @@ pub fn comment<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, fn comment_line<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> { start_of_line(context, input)?; let (remaining, _indent) = space0(input)?; - let (remaining, (_hash, _leading_whitespace_and_content, _line_ending)) = - tuple((tag("#"), opt(tuple((space1, is_not("\r\n")))), alt((line_ending, eof))))(remaining)?; + let (remaining, (_hash, _leading_whitespace_and_content, _line_ending)) = tuple(( + tag("#"), + opt(tuple((space1, is_not("\r\n")))), + alt((line_ending, eof)), + ))(remaining)?; let source = get_consumed(input, remaining); Ok((remaining, source)) } @@ -71,12 +74,13 @@ mod tests { let initial_context: ContextTree<'_, '_> = ContextTree::new(); let document_context = initial_context.with_additional_node(ContextElement::DocumentRoot(input)); - let comment_matcher = - parser_with_context!(comment)(&document_context); - let (remaining, first_comment) = - comment_matcher(input).expect("Parse first comment"); - assert_eq!(remaining, r#"#not a comment -# Comment again"#); + let comment_matcher = parser_with_context!(comment)(&document_context); + let (remaining, first_comment) = comment_matcher(input).expect("Parse first comment"); + assert_eq!( + remaining, + r#"#not a comment +# Comment again"# + ); assert_eq!( first_comment.source, "# Comment line diff --git a/src/parser/parser_context.rs b/src/parser/parser_context.rs index e113d21..c97f666 100644 --- a/src/parser/parser_context.rs +++ b/src/parser/parser_context.rs @@ -89,7 +89,6 @@ impl<'r, 's> ContextTree<'r, 's> { return local_result; } } - } _ => {} }; diff --git a/src/parser/table.rs b/src/parser/table.rs index d475398..0b1f4a0 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -120,7 +120,6 @@ pub fn org_mode_table_cell<'r, 's>( |(children, exit_contents)| !children.is_empty() || *exit_contents == "|", )(input)?; - todo!() } From f1b0d7e6be5c65d4fe7770350877bd09a7a5e495 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 14:39:20 -0400 Subject: [PATCH 10/19] Add a simple test table org-mode document. --- org_mode_samples/table/simple.org | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 org_mode_samples/table/simple.org diff --git a/org_mode_samples/table/simple.org b/org_mode_samples/table/simple.org new file mode 100644 index 0000000..8f7fcaf --- /dev/null +++ b/org_mode_samples/table/simple.org @@ -0,0 +1,3 @@ +| foo | bar | +|-----+-------| +| baz | lorem | From c971148871b42fa9fbee971aa09ffe608e4a3602 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 14:54:29 -0400 Subject: [PATCH 11/19] Running into an error running the tracer. --- src/init_tracing.rs | 2 +- src/parser/table.rs | 6 ++++-- toy_language.txt | 28 +++------------------------- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/src/init_tracing.rs b/src/init_tracing.rs index 171de8d..3a5169b 100644 --- a/src/init_tracing.rs +++ b/src/init_tracing.rs @@ -3,7 +3,7 @@ use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::EnvFilter; pub fn init_telemetry() -> Result<(), Box> { - let env_filter = EnvFilter::try_from_default_env().unwrap_or(EnvFilter::new("WARN")); + let env_filter = EnvFilter::try_from_default_env().unwrap_or(EnvFilter::new("warn")); // let stdout = tracing_subscriber::fmt::Layer::new() // .pretty() diff --git a/src/parser/table.rs b/src/parser/table.rs index 0b1f4a0..ab856f5 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -117,10 +117,12 @@ pub fn org_mode_table_cell<'r, 's>( let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); let (remaining, (children, _exit_contents)) = verify( many_till(minimal_set_object_matcher, exit_matcher), - |(children, exit_contents)| !children.is_empty() || *exit_contents == "|", + |(children, exit_contents)| !children.is_empty() || exit_contents.ends_with("|"), )(input)?; - todo!() + let source = get_consumed(input, remaining); + + Ok((remaining, TableCell { source, children })) } #[tracing::instrument(ret, level = "debug")] diff --git a/toy_language.txt b/toy_language.txt index 2538054..8f7fcaf 100644 --- a/toy_language.txt +++ b/toy_language.txt @@ -1,25 +1,3 @@ - - - - -# Blank lines and comments can come before property drawers in the zeroth section -:PROPERTIES: -:FOO: bar -:END: - - - -* Spaces turn property drawers into regular drawers - -:PROPERTIES: -:FOO: bar -:END: -* Comments turn property drawers into regular drawers -# Comment -:PROPERTIES: -:FOO: bar -:END: -* Baseline -:PROPERTIES: -:FOO: bar -:END: +| foo | bar | +|-----+-------| +| baz | lorem | From 5225290156ea91ceef4eaae278b76e920cbb074a Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 15:25:19 -0400 Subject: [PATCH 12/19] Disable the env filter because I am running into errors. --- src/init_tracing.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init_tracing.rs b/src/init_tracing.rs index 3a5169b..3a89c49 100644 --- a/src/init_tracing.rs +++ b/src/init_tracing.rs @@ -3,7 +3,7 @@ use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::EnvFilter; pub fn init_telemetry() -> Result<(), Box> { - let env_filter = EnvFilter::try_from_default_env().unwrap_or(EnvFilter::new("warn")); + // let env_filter = EnvFilter::try_from_default_env().unwrap_or(EnvFilter::new("warn")); // let stdout = tracing_subscriber::fmt::Layer::new() // .pretty() @@ -20,7 +20,7 @@ pub fn init_telemetry() -> Result<(), Box> { let opentelemetry = tracing_opentelemetry::layer().with_tracer(tracer); tracing_subscriber::registry() - .with(env_filter) + // .with(env_filter) .with(opentelemetry) // .with(stdout) .try_init()?; From d2fe10043578b9a487ca2bd86e1297ccba33dcad Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 15:28:46 -0400 Subject: [PATCH 13/19] Change the binary to use the library. Mostly just hoping this make rust-analyzer happier. --- src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6201ac9..f82e263 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,8 @@ #![feature(round_char_boundary)] use crate::init_tracing::init_telemetry; use crate::init_tracing::shutdown_telemetry; -use crate::parser::document; +use ::organic::document; mod init_tracing; -mod parser; const TEST_DOC: &'static str = include_str!("../toy_language.txt"); From f0d2754955fcf70e0f466cd4b3891e8ce45cf92b Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 15:36:45 -0400 Subject: [PATCH 14/19] Consume the end of the cell. --- src/parser/table.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/parser/table.rs b/src/parser/table.rs index ab856f5..a2b61e6 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -120,6 +120,8 @@ pub fn org_mode_table_cell<'r, 's>( |(children, exit_contents)| !children.is_empty() || exit_contents.ends_with("|"), )(input)?; + let (remaining, _tail) = org_mode_table_cell_end(&parser_context, remaining)?; + let source = get_consumed(input, remaining); Ok((remaining, TableCell { source, children })) @@ -130,5 +132,5 @@ fn org_mode_table_cell_end<'r, 's>( context: Context<'r, 's>, input: &'s str, ) -> Res<&'s str, &'s str> { - recognize(tuple((space0, alt((tag("|"), line_ending)))))(input) + recognize(tuple((space0, alt((tag("|"), peek(line_ending))))))(input) } From a63d38e0ce54f8bd9f7cdfb637654f3445fa1ed6 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 15:38:42 -0400 Subject: [PATCH 15/19] Consume line endings at the end of table rows. --- src/parser/table.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/parser/table.rs b/src/parser/table.rs index a2b61e6..fd68c93 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -3,6 +3,7 @@ use nom::bytes::complete::is_not; use nom::bytes::complete::tag; use nom::character::complete::line_ending; use nom::character::complete::space0; +use nom::combinator::eof; use nom::combinator::not; use nom::combinator::peek; use nom::combinator::recognize; @@ -99,6 +100,7 @@ pub fn org_mode_table_row_regular<'r, 's>( let (remaining, _) = tuple((space0, tag("|")))(input)?; let (remaining, children) = many1(parser_with_context!(org_mode_table_cell)(context))(remaining)?; + let (remaining, _tail) = recognize(tuple((space0, alt((line_ending, eof)))))(remaining)?; let source = get_consumed(input, remaining); Ok((remaining, TableRow { source, children })) } From 27037926446c48da6ad531fbbb0dd632cad70631 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 15:40:47 -0400 Subject: [PATCH 16/19] Very simple table is parsing now. --- scripts/run_integration_test.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/run_integration_test.bash b/scripts/run_integration_test.bash index f1feb0f..9185c65 100755 --- a/scripts/run_integration_test.bash +++ b/scripts/run_integration_test.bash @@ -21,5 +21,5 @@ function get_test_names { } get_test_names "$@" | while read test; do - (cd "$DIR/../" && cargo test --no-fail-fast --test test_loader "$test") + (cd "$DIR/../" && cargo test --no-fail-fast --test test_loader "$test" -- --show-output) done From 0fcfdd5ff22a21b148354c4ffc04c6576424b950 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 15:45:35 -0400 Subject: [PATCH 17/19] Compare table row and table cell bounds. --- src/compare/diff.rs | 62 +++++++++++++++++++++++++++++++++++++++++++ src/parser/element.rs | 14 ++++++++++ src/parser/mod.rs | 2 ++ 3 files changed, 78 insertions(+) diff --git a/src/compare/diff.rs b/src/compare/diff.rs index b0b6210..11975d2 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -15,6 +15,8 @@ use crate::parser::PlainListItem; use crate::parser::PropertyDrawer; use crate::parser::Section; use crate::parser::Table; +use crate::parser::TableCell; +use crate::parser::TableRow; use crate::DynamicBlock; #[derive(Debug)] @@ -479,6 +481,66 @@ fn compare_table<'s>( this_status = DiffStatus::Bad; } + for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { + child_status.push(compare_table_row(source, emacs_child, rust_child)?); + } + + Ok(DiffResult { + status: this_status, + name: emacs_name.to_owned(), + message: None, + children: child_status, + }) +} + +fn compare_table_row<'s>( + source: &'s str, + emacs: &'s Token<'s>, + rust: &'s TableRow<'s>, +) -> Result> { + let children = emacs.as_list()?; + let mut child_status = Vec::new(); + let mut this_status = DiffStatus::Good; + let emacs_name = "table-row"; + if assert_name(emacs, emacs_name).is_err() { + this_status = DiffStatus::Bad; + } + + if assert_bounds(source, emacs, rust).is_err() { + this_status = DiffStatus::Bad; + } + + for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) { + child_status.push(compare_table_cell(source, emacs_child, rust_child)?); + } + + Ok(DiffResult { + status: this_status, + name: emacs_name.to_owned(), + message: None, + children: child_status, + }) +} + +fn compare_table_cell<'s>( + source: &'s str, + emacs: &'s Token<'s>, + rust: &'s TableCell<'s>, +) -> Result> { + let children = emacs.as_list()?; + let mut child_status = Vec::new(); + let mut this_status = DiffStatus::Good; + let emacs_name = "table-cell"; + if assert_name(emacs, emacs_name).is_err() { + this_status = DiffStatus::Bad; + } + + if assert_bounds(source, emacs, rust).is_err() { + this_status = DiffStatus::Bad; + } + + for (emacs_child, rust_child) in children.iter().skip(2).zip(rust.children.iter()) {} + Ok(DiffResult { status: this_status, name: emacs_name.to_owned(), diff --git a/src/parser/element.rs b/src/parser/element.rs index 9f9f97f..abfaf4b 100644 --- a/src/parser/element.rs +++ b/src/parser/element.rs @@ -10,8 +10,10 @@ use super::greater_element::GreaterBlock; use super::greater_element::PlainList; use super::greater_element::PropertyDrawer; use super::greater_element::Table; +use super::greater_element::TableRow; use super::lesser_element::Comment; use super::lesser_element::Paragraph; +use super::lesser_element::TableCell; use super::paragraph::paragraph; use super::plain_list::plain_list; use super::source::Source; @@ -113,6 +115,18 @@ impl<'s> Source<'s> for Table<'s> { } } +impl<'s> Source<'s> for TableRow<'s> { + fn get_source(&'s self) -> &'s str { + self.source + } +} + +impl<'s> Source<'s> for TableCell<'s> { + fn get_source(&'s self) -> &'s str { + self.source + } +} + #[tracing::instrument(ret, level = "debug")] pub fn element<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, Element<'s>> { let non_paragraph_matcher = parser_with_context!(non_paragraph_element)(context); diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 74ddbe1..33eb7de 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -34,7 +34,9 @@ pub use greater_element::PlainList; pub use greater_element::PlainListItem; pub use greater_element::PropertyDrawer; pub use greater_element::Table; +pub use greater_element::TableRow; pub use lesser_element::Comment; pub use lesser_element::Paragraph; +pub use lesser_element::TableCell; pub use source::Source; type Context<'r, 's> = &'r parser_context::ContextTree<'r, 's>; From 2dabe093f4bfb9aef2ff99a8733061a211b454be Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 15:49:39 -0400 Subject: [PATCH 18/19] Now that tables are implemented, re-enable one of the tests that depended on them. --- build.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 5994fbd..94c9502 100644 --- a/build.rs +++ b/build.rs @@ -76,8 +76,7 @@ fn is_expect_fail(name: &str) -> Option<&str> { "element_container_priority_footnote_definition_dynamic_block" => Some("Keyword needs to be implemented."), "element_container_priority_greater_block_dynamic_block" => Some("Keyword needs to be implemented."), "element_container_priority_section_dynamic_block" => Some("Keyword needs to be implemented."), - "exit_matcher_investigation_table_list" => Some("Table needs to be implemented."), - "element_container_priority_readme" => Some("Table needs to be implemented."), + "element_container_priority_readme" => Some("A lot needs to be implemented."), _ => None, } } From c2b6b5103a3f7a6ac4e4763e01e06f84add3a10c Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 21 Apr 2023 15:57:45 -0400 Subject: [PATCH 19/19] Add comments about the sets of objects that can exist. --- src/parser/object.rs | 2 ++ src/parser/table.rs | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/parser/object.rs b/src/parser/object.rs index 98078c6..7a493a1 100644 --- a/src/parser/object.rs +++ b/src/parser/object.rs @@ -48,6 +48,7 @@ pub fn standard_set_object<'r, 's>( context: Context<'r, 's>, input: &'s str, ) -> Res<&'s str, Object<'s>> { + // TODO: add entities, LaTeX fragments, export snippets, footnote references, citations (NOT citation references), inline babel calls, inline source blocks, line breaks, links, macros, targets and radio targets, statistics cookies, subscript and superscript, timestamps, and text markup. not(|i| context.check_exit_matcher(i))(input)?; let plain_text_matcher = parser_with_context!(plain_text)(context); @@ -60,6 +61,7 @@ pub fn minimal_set_object<'r, 's>( context: Context<'r, 's>, input: &'s str, ) -> Res<&'s str, Object<'s>> { + // TODO: add text markup, entities, LaTeX fragments, superscripts and subscripts not(|i| context.check_exit_matcher(i))(input)?; let plain_text_matcher = parser_with_context!(plain_text)(context); diff --git a/src/parser/table.rs b/src/parser/table.rs index fd68c93..44f9616 100644 --- a/src/parser/table.rs +++ b/src/parser/table.rs @@ -18,6 +18,7 @@ use crate::parser::exiting::ExitClass; use crate::parser::greater_element::TableRow; use crate::parser::lesser_element::TableCell; use crate::parser::object::minimal_set_object; +use crate::parser::object::Object; use crate::parser::parser_context::ContextElement; use crate::parser::parser_context::ExitMatcherNode; use crate::parser::parser_with_context::parser_with_context; @@ -115,10 +116,11 @@ pub fn org_mode_table_cell<'r, 's>( class: ExitClass::Beta, exit_matcher: &org_mode_table_cell_end, })); - let minimal_set_object_matcher = parser_with_context!(minimal_set_object)(&parser_context); + let table_cell_set_object_matcher = + parser_with_context!(table_cell_set_object)(&parser_context); let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); let (remaining, (children, _exit_contents)) = verify( - many_till(minimal_set_object_matcher, exit_matcher), + many_till(table_cell_set_object_matcher, exit_matcher), |(children, exit_contents)| !children.is_empty() || exit_contents.ends_with("|"), )(input)?; @@ -136,3 +138,14 @@ fn org_mode_table_cell_end<'r, 's>( ) -> Res<&'s str, &'s str> { recognize(tuple((space0, alt((tag("|"), peek(line_ending))))))(input) } + +#[tracing::instrument(ret, level = "debug")] +pub fn table_cell_set_object<'r, 's>( + context: Context<'r, 's>, + input: &'s str, +) -> Res<&'s str, Object<'s>> { + not(|i| context.check_exit_matcher(i))(input)?; + + parser_with_context!(minimal_set_object)(context)(input) + // TODO: add citations, export snippets, footnote references, links, macros, radio targets, targets, and timestamps. +}