use std::borrow::Cow;
use nom::{
error::{make_error, ErrorKind},
Err, IResult,
};
use crate::parse::combinators::{blank_lines_count, line, lines_while};
#[derive(Debug, Clone)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
#[cfg_attr(feature = "ser", serde(tag = "table_type"))]
pub enum Table<'a> {
#[cfg_attr(feature = "ser", serde(rename = "org"))]
Org {
#[cfg_attr(feature = "ser", serde(skip_serializing_if = "Option::is_none"))]
tblfm: Option<Cow<'a, str>>,
post_blank: usize,
has_header: bool,
},
#[cfg_attr(feature = "ser", serde(rename = "table.el"))]
TableEl {
value: Cow<'a, str>,
post_blank: usize,
},
}
impl Table<'_> {
pub fn parse_table_el(input: &str) -> Option<(&str, Table)> {
Self::parse_table_el_internal(input).ok()
}
fn parse_table_el_internal(input: &str) -> IResult<&str, Table, ()> {
let (_, first_line) = line(input)?;
let first_line = first_line.trim();
if !first_line.starts_with("+-")
|| first_line
.as_bytes()
.iter()
.any(|&c| c != b'+' && c != b'-')
{
return Err(Err::Error(make_error(input, ErrorKind::Many0)));
}
let (input, content) = lines_while(|line| {
let line = line.trim_start();
line.starts_with('|') || line.starts_with('+')
})(input)?;
let (input, post_blank) = blank_lines_count(input)?;
Ok((
input,
Table::TableEl {
value: content.into(),
post_blank,
},
))
}
pub fn into_owned(self) -> Table<'static> {
match self {
Table::Org {
tblfm,
post_blank,
has_header,
} => Table::Org {
tblfm: tblfm.map(Into::into).map(Cow::Owned),
post_blank,
has_header,
},
Table::TableEl { value, post_blank } => Table::TableEl {
value: value.into_owned().into(),
post_blank,
},
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
#[cfg_attr(feature = "ser", serde(tag = "table_row_type"))]
#[cfg_attr(feature = "ser", serde(rename_all = "kebab-case"))]
pub enum TableRow {
Header,
Body,
HeaderRule,
BodyRule,
}
#[derive(Debug, Clone)]
#[cfg_attr(test, derive(PartialEq))]
#[cfg_attr(feature = "ser", derive(serde::Serialize))]
#[cfg_attr(feature = "ser", serde(tag = "table_cell_type"))]
#[cfg_attr(feature = "ser", serde(rename_all = "kebab-case"))]
pub enum TableCell {
Header,
Body,
}
#[test]
fn parse_table_el_() {
assert_eq!(
Table::parse_table_el(
r#" +---+
| |
+---+
"#
),
Some((
"",
Table::TableEl {
value: r#" +---+
| |
+---+
"#
.into(),
post_blank: 1
}
))
);
assert!(Table::parse_table_el("").is_none());
assert!(Table::parse_table_el("+----|---").is_none());
}