use super::node::parse_nodes;
use crate::CosyParserExtension;
use crate::ast::{Block, BlockContent};
use crate::tokens::TABLE_PREFIX;
use winnow::Result as PResult;
use winnow::ascii::{line_ending, till_line_ending};
use winnow::combinator::opt;
use winnow::prelude::*;
pub fn parse_table<'s, E>(
input: &mut &'s str,
extension: &'s E,
indent: usize,
) -> PResult<Block<E::Output>>
where
E: CosyParserExtension,
{
let _ = { TABLE_PREFIX }.parse_next(input)?;
let name_line = till_line_ending.parse_next(input)?;
let name = name_line.trim().to_string();
let _ = opt(line_ending).parse_next(input)?;
let mut rows = Vec::new();
loop {
let current_indent = input.chars().take_while(|&c| c == ' ').count();
if current_indent <= indent {
break;
}
let _ = winnow::token::take(current_indent).parse_next(input)?;
let line = till_line_ending.parse_next(input)?;
let cells_str: Vec<&str> = line.split('\t').collect();
let mut row = Vec::new();
for mut cell_str in cells_str {
let nodes = parse_nodes(&mut cell_str, extension)?;
row.push(nodes);
}
rows.push(row);
if opt(line_ending).parse_next(input)?.is_none() {
break;
}
}
Ok(Block {
indent,
content: BlockContent::Table { name, rows },
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ast::*;
#[test]
fn parse_table_block() {
let input = "table:MyTable\n Cell1\tCell2\tCell3\n Data1\tData2\tData3\n";
let mut input_stream = input;
let result = parse_table(&mut input_stream, &(), 0);
assert!(result.is_ok());
let block = result.unwrap();
assert_eq!(block.indent, 0);
assert_eq!(
block.content,
BlockContent::Table {
name: "MyTable".to_string(),
rows: vec![
vec![
vec![Node::Text("Cell1".to_string())],
vec![Node::Text("Cell2".to_string())],
vec![Node::Text("Cell3".to_string())],
],
vec![
vec![Node::Text("Data1".to_string())],
vec![Node::Text("Data2".to_string())],
vec![Node::Text("Data3".to_string())],
],
],
}
);
}
#[test]
fn parse_table_without_name() {
let input = "table:\n A\tB\n 1\t2\n";
let mut input_stream = input;
let result = parse_table(&mut input_stream, &(), 0);
assert!(result.is_ok());
let block = result.unwrap();
assert_eq!(block.indent, 0);
assert_eq!(
block.content,
BlockContent::Table {
name: "".to_string(),
rows: vec![
vec![
vec![Node::Text("A".to_string())],
vec![Node::Text("B".to_string())],
],
vec![
vec![Node::Text("1".to_string())],
vec![Node::Text("2".to_string())],
],
],
}
);
}
}