From 6b7123b1ad43e5b012546aafb9e173e9a4ae0efc Mon Sep 17 00:00:00 2001 From: jutty Date: Mon, 16 Feb 2026 01:54:19 -0300 Subject: [PATCH] Handle table cell separator cases --- src/syntax/content/parser/context/table.rs | 72 ++++++++++++---------- src/syntax/content/parser/token/table.rs | 29 ++++++--- 2 files changed, 58 insertions(+), 43 deletions(-) diff --git a/src/syntax/content/parser/context/table.rs b/src/syntax/content/parser/context/table.rs index 0aa95d2..a4c3f8e 100644 --- a/src/syntax/content/parser/context/table.rs +++ b/src/syntax/content/parser/context/table.rs @@ -41,21 +41,14 @@ pub fn parse( if buffer.in_header { log!(VERBOSE, "Adding unterminated header: {lexeme}"); candidate.add_header(&parse_text(&buffer.cell)); - buffer.cell.clear(); - iterator.next(); - iterator.next(); - } else if buffer.in_cell { - log!(VERBOSE, "Adding unterminated cell: {lexeme}"); - candidate.add_cell(&parse_text(&buffer.cell)); - buffer.cell.clear(); - iterator.next(); - iterator.next(); } else { - log!(VERBOSE, "Adding undelimited cell: {lexeme}"); + let descriptor = if buffer.in_cell { + "unterminated" + } else { + "undelimited" + }; + log!(VERBOSE, "Adding {descriptor} cell: {lexeme}"); candidate.add_cell(&parse_text(&buffer.cell)); - buffer.cell.clear(); - iterator.next(); - iterator.next(); } tokens.push(Token::Table(candidate.clone())); @@ -63,42 +56,53 @@ pub fn parse( state.context.block = Block::None; *buffer = state::TableBuffer::default(); iterator.next(); - } else if lexeme.match_char('\n') { + } else if lexeme.match_char('\n') + || lexeme.match_char_triple(' ', '!', '\n') + || lexeme.match_char_triple(' ', '|', '\n') + { log!(VERBOSE, "Adding row: found newline on {lexeme}"); + if !buffer.cell.is_empty() { if buffer.in_header { log!(VERBOSE, "Adding unterminated header: {lexeme}"); candidate.add_header(&parse_text(&buffer.cell)); - buffer.cell.clear(); - iterator.next(); - iterator.next(); - } else if buffer.in_cell { - log!(VERBOSE, "Adding unterminated cell: {lexeme}"); - candidate.add_cell(&parse_text(&buffer.cell)); - buffer.cell.clear(); - iterator.next(); - iterator.next(); } else { - log!(VERBOSE, "Adding undelimited cell: {lexeme}"); + let descriptor = if buffer.in_cell { + "unterminated" + } else { + "undelimited" + }; + log!(VERBOSE, "Adding {descriptor} cell: {lexeme}"); candidate.add_cell(&parse_text(&buffer.cell)); - buffer.cell.clear(); - iterator.next(); - iterator.next(); } - + buffer.cell.clear(); } + + if lexeme.match_next_either_char('|', '!') { + iterator.next(); + } + + buffer.in_header = false; + buffer.in_cell = false; candidate.add_row(vec![]); + } else if lexeme.match_char_triple(' ', '!', ' ') { - log!(VERBOSE, "Adding header: found spaced ! on {lexeme}"); - candidate.add_header(&parse_text(&buffer.cell)); - buffer.cell.clear(); + buffer.in_header = true; + if !buffer.cell.trim().is_empty() { + log!(VERBOSE, "Adding header: found spaced ! on {lexeme}"); + candidate.add_header(&parse_text(&buffer.cell)); + buffer.cell.clear(); + } iterator.next(); iterator.next(); } else if lexeme.match_char_triple(' ', '|', ' ') { - log!(VERBOSE, "Adding cell: found spaced | on {lexeme}"); - candidate.add_cell(&parse_text(&buffer.cell)); - buffer.cell.clear(); + buffer.in_cell = true; + if !buffer.cell.trim().is_empty() { + log!(VERBOSE, "Adding cell: found spaced | on {lexeme}"); + candidate.add_cell(&parse_text(&buffer.cell)); + buffer.cell.clear(); + } iterator.next(); iterator.next(); } else { diff --git a/src/syntax/content/parser/token/table.rs b/src/syntax/content/parser/token/table.rs index 8d0b811..6b13f7a 100644 --- a/src/syntax/content/parser/token/table.rs +++ b/src/syntax/content/parser/token/table.rs @@ -24,11 +24,19 @@ impl Table { last.push(content.trim().to_string()); } } + + pub fn last_row_count(&self) -> usize { + if let Some(last) = self.contents.last() { + last.len() + } else { + 0 + } + } } impl Parseable for Table { fn probe(lexeme: &Lexeme) -> bool { - lexeme.match_char_triple('\n', '%', '\n') + lexeme.match_char_sequence('%', '\n') } fn lex(_lexeme: &Lexeme) -> Table { @@ -37,26 +45,29 @@ impl Parseable for Table { fn render(&self) -> String { let mut xml = String::from("\n\n"); + let tab = " "; if !self.headers.is_empty() { - xml.push_str("\n"); + xml.push_str(format!("{tab}\n").as_str()); for header in &self.headers { - xml.push_str(format!("\n").as_str()); + xml.push_str(format!("{tab}{tab}\n").as_str()); } - xml.push_str("\n\n"); + xml.push_str(format!("{tab}\n").as_str()); } for row in &self.contents { - if !row.is_empty() { - xml.push_str("\n"); + if !row.is_empty() && row.iter().any(|cell| !cell.is_empty()) { + xml.push_str(format!("{tab}\n").as_str()); for cell in row { - xml.push_str(format!("\n").as_str()); + xml.push_str( + format!("{tab}{tab}\n").as_str(), + ); } - xml.push_str("\n\n"); + xml.push_str(format!("{tab}\n").as_str()); } } - xml.push_str("\n
{header}{header}
{cell}{cell}
\n"); + xml.push_str("\n"); xml }