feat: handle <thead> in html export

This commit is contained in:
PoiScript 2023-11-15 12:55:35 +08:00
parent 1362624083
commit db7fb70724
No known key found for this signature in database
GPG key ID: 22C2B1249D99985E
5 changed files with 300 additions and 14 deletions

View file

@ -1,6 +1,57 @@
use super::OrgTableRow;
use rowan::ast::AstNode;
use super::{OrgTable, OrgTableRow};
use crate::syntax::SyntaxKind;
impl OrgTable {
/// Returns `true` if this table has a header
///
/// A table has a header when it contains at least two row groups.
///
/// ```rust
/// use orgize::{Org, ast::OrgTable};
///
/// let org = Org::parse(r#"
/// | a | b |
/// |---+---|
/// | c | d |"#);
/// let table = org.first_node::<OrgTable>().unwrap();
/// assert!(table.has_header());
///
/// let org = Org::parse(r#"
/// | a | b |
/// | 0 | 1 |
/// |---+---|
/// | a | w |"#);
/// let table = org.first_node::<OrgTable>().unwrap();
/// assert!(table.has_header());
///
/// let org = Org::parse(r#"
/// | a | b |
/// | c | d |"#);
/// let table = org.first_node::<OrgTable>().unwrap();
/// assert!(!table.has_header());
///
/// let org = Org::parse(r#"
/// |---+---|
/// | a | b |
/// | c | d |
/// |---+---|"#);
/// let table = org.first_node::<OrgTable>().unwrap();
/// assert!(!table.has_header());
/// ```
pub fn has_header(&self) -> bool {
self.syntax
.children()
.filter_map(OrgTableRow::cast)
.skip_while(|row| row.is_rule())
.skip_while(|row| row.is_standard())
.skip_while(|row| row.is_rule())
.next()
.is_some()
}
}
impl OrgTableRow {
/// Returns `true` if this row is a rule
///

View file

@ -31,12 +31,12 @@
/// let level = title.headline().and_then(|h| h.level()).unwrap_or(1);
/// let level = min(level, 6);
/// let raw = title.syntax().to_string();
/// self.0.output += &format!("<h{level}><a id=\"{0}\" href=\"#{0}\">", slugify!(&raw));
/// self.0.push_str(format!("<h{level}><a id=\"{0}\" href=\"#{0}\">", slugify!(&raw)));
/// }
/// WalkEvent::Leave(title) => {
/// let level = title.headline().and_then(|h| h.level()).unwrap_or(1);
/// let level = min(level, 6);
/// self.0.output += &format!("</a></h{level}>");
/// self.0.push_str(format!("</a></h{level}>"));
/// }
/// }
/// }

View file

@ -47,11 +47,27 @@ impl<S: AsRef<str>> fmt::Display for HtmlEscape<S> {
#[derive(Default)]
pub struct HtmlExport {
pub output: String,
output: String,
in_descriptive_list: Vec<bool>,
table_row: TableRow,
}
#[derive(Default, PartialEq, Eq)]
enum TableRow {
#[default]
HeaderRule,
Header,
BodyRule,
Body,
}
impl HtmlExport {
pub fn push_str(&mut self, s: impl AsRef<str>) {
self.output += s.as_ref();
}
pub fn finish(self) -> String {
self.output
}
@ -306,10 +322,28 @@ impl Traverser for HtmlExport {
#[tracing::instrument(skip(self, _ctx))]
fn org_table(&mut self, event: WalkEvent<&OrgTable>, _ctx: &mut TraversalContext) {
self.output += match event {
WalkEvent::Enter(_) => "<table><tbody>",
WalkEvent::Leave(_) => "</tbody></table>",
};
match event {
WalkEvent::Enter(table) => {
self.output += "<table>";
self.table_row = if table.has_header() {
TableRow::HeaderRule
} else {
TableRow::BodyRule
}
}
WalkEvent::Leave(_) => {
match self.table_row {
TableRow::Body => {
self.output += "</tbody>";
}
TableRow::Header => {
self.output += "</thead>";
}
_ => {}
}
self.output += "</table>";
}
}
}
#[tracing::instrument(skip(self, ctx))]
@ -317,13 +351,39 @@ impl Traverser for HtmlExport {
if match event {
WalkEvent::Enter(n) | WalkEvent::Leave(n) => n.is_rule(),
} {
match self.table_row {
TableRow::Body => {
self.output += "</tbody>";
self.table_row = TableRow::BodyRule;
}
TableRow::Header => {
self.output += "</thead>";
self.table_row = TableRow::BodyRule;
}
_ => {}
}
return ctx.skip();
}
self.output += match event {
WalkEvent::Enter(_) => "<tr>",
WalkEvent::Leave(_) => "</tr>",
};
match event {
WalkEvent::Enter(_) => {
match self.table_row {
TableRow::HeaderRule => {
self.table_row = TableRow::Header;
self.output += "<thead>";
}
TableRow::BodyRule => {
self.table_row = TableRow::Body;
self.output += "<tbody>";
}
_ => {}
}
self.output += "<tr>";
}
WalkEvent::Leave(_) => {
self.output += "</tr>";
}
}
}
#[tracing::instrument(skip(self, _ctx))]