Merge branch 'table'
This commit is contained in:
commit
bcf5f5a9c8
7
Makefile
7
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:
|
||||
|
3
build.rs
3
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,
|
||||
}
|
||||
}
|
||||
|
3
org_mode_samples/table/simple.org
Normal file
3
org_mode_samples/table/simple.org
Normal file
@ -0,0 +1,3 @@
|
||||
| foo | bar |
|
||||
|-----+-------|
|
||||
| baz | lorem |
|
@ -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
|
||||
|
@ -14,6 +14,9 @@ use crate::parser::PlainList;
|
||||
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)]
|
||||
@ -198,6 +201,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 +463,88 @@ fn compare_property_drawer<'s>(
|
||||
children: child_status,
|
||||
})
|
||||
}
|
||||
|
||||
fn compare_table<'s>(
|
||||
source: &'s str,
|
||||
emacs: &'s Token<'s>,
|
||||
rust: &'s Table<'s>,
|
||||
) -> Result<DiffResult, Box<dyn std::error::Error>> {
|
||||
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;
|
||||
}
|
||||
|
||||
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<DiffResult, Box<dyn std::error::Error>> {
|
||||
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<DiffResult, Box<dyn std::error::Error>> {
|
||||
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(),
|
||||
message: None,
|
||||
children: child_status,
|
||||
})
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use tracing_subscriber::util::SubscriberInitExt;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
pub fn init_telemetry() -> Result<(), Box<dyn std::error::Error>> {
|
||||
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<dyn std::error::Error>> {
|
||||
let opentelemetry = tracing_opentelemetry::layer().with_tracer(tracer);
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(env_filter)
|
||||
// .with(env_filter)
|
||||
.with(opentelemetry)
|
||||
// .with(stdout)
|
||||
.try_init()?;
|
||||
|
@ -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::*;
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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
|
||||
|
@ -9,8 +9,11 @@ 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::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;
|
||||
@ -18,6 +21,8 @@ use super::Context;
|
||||
use super::Drawer;
|
||||
use super::PlainListItem;
|
||||
use crate::parser::parser_with_context::parser_with_context;
|
||||
use crate::parser::table;
|
||||
use crate::parser::table::org_mode_table;
|
||||
use nom::branch::alt;
|
||||
use nom::combinator::map;
|
||||
|
||||
@ -31,6 +36,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 +50,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 +109,24 @@ impl<'s> Source<'s> for PropertyDrawer<'s> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s> Source<'s> for Table<'s> {
|
||||
fn get_source(&'s self) -> &'s str {
|
||||
self.source
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -123,6 +148,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!(org_mode_table)(context);
|
||||
alt((
|
||||
map(plain_list_matcher, Element::PlainList),
|
||||
map(greater_block_matcher, Element::GreaterBlock),
|
||||
@ -130,5 +156,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)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::element::Element;
|
||||
use super::lesser_element::TableCell;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PlainList<'s> {
|
||||
@ -55,3 +56,15 @@ pub struct NodeProperty<'s> {
|
||||
pub source: &'s str,
|
||||
pub value: Option<&'s str>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Table<'s> {
|
||||
pub source: &'s str,
|
||||
pub children: Vec<TableRow<'s>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TableRow<'s> {
|
||||
pub source: &'s str,
|
||||
pub children: Vec<TableCell<'s>>,
|
||||
}
|
||||
|
@ -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<Object<'s>>,
|
||||
}
|
||||
|
||||
impl<'s> Paragraph<'s> {
|
||||
pub fn of_text(input: &'s str) -> Self {
|
||||
let mut objects = Vec::with_capacity(1);
|
||||
|
@ -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,7 +33,10 @@ 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 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>;
|
||||
|
@ -48,6 +48,20 @@ 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);
|
||||
|
||||
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>> {
|
||||
// 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);
|
||||
|
@ -89,7 +89,6 @@ impl<'r, 's> ContextTree<'r, 's> {
|
||||
return local_result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
151
src/parser/table.rs
Normal file
151
src/parser/table.rs
Normal file
@ -0,0 +1,151 @@
|
||||
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::eof;
|
||||
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;
|
||||
|
||||
use super::Context;
|
||||
use crate::parser::error::Res;
|
||||
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;
|
||||
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 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)?;
|
||||
|
||||
// TODO: Consume trailing formulas
|
||||
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>> {
|
||||
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,
|
||||
children: Vec::new(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[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>> {
|
||||
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 (remaining, _tail) = recognize(tuple((space0, alt((line_ending, eof)))))(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 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(table_cell_set_object_matcher, exit_matcher),
|
||||
|(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 }))
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
|
||||
#[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.
|
||||
}
|
@ -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 |
|
||||
|
Loading…
x
Reference in New Issue
Block a user