Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

### Added

- IR v2: footnotes (`[^1]`), definition lists (`Term` / `: definition`), task lists (`- [x]`),
figures with captions, table column alignment (`:---:`) and `colspan`/`rowspan` (laid out on a
grid; GFM has no spans). HTML maps GitHub and Pandoc footnote markup, `<dl>`, checkbox list items,
`<figure>`/`<figcaption>` and table spans/alignment. Row-header `<th>` cells in table bodies are
no longer dropped.
- `Document.ir_version` (`markkit::ir::IR_VERSION = 2`) is serialized with the IR JSON.

### Security

- `extract_url` (CLI, Python and Node `extract_url` too) now refuses non-public destinations by default:
Expand All @@ -18,6 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

### Changed

- **Breaking (IR API):** `Node`, `Document`, `ListItem` and the new IR structs are `#[non_exhaustive]`;
matches need a `_` arm and structs are built with constructors. `Node::Table` cells are now
`TableCell` (`children`, `colspan`, `rowspan`) with an `alignments` field. DOCX `gridSpan` is
carried as `colspan`.
- Design docs moved from `specs/` to an OKF v0.2 knowledge bundle in `knowledge/`, validated in CI.
- CI workflows declare read-only default permissions and do not persist checkout credentials.
- CI runs every example; `just bench` now runs the criterion benchmarks.
Expand Down
19 changes: 10 additions & 9 deletions crates/markkit/src/docx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::collections::HashMap;
use crate::archive::{ArchiveError, ZipGuard};
use crate::config::MarkkitBuilder;
use crate::error::Error;
use crate::ir::{Document, ListItem, Node};
use crate::ir::{Document, ListItem, Node, TableCell};
use crate::render::escape_table_cell;
use crate::xml::{self, Element, XmlError};

Expand Down Expand Up @@ -803,31 +803,32 @@ impl Ctx<'_> {
}

fn table(&self, tbl: &Element) -> Option<Node> {
let mut rows: Vec<Vec<Vec<Node>>> = Vec::new();
let mut rows: Vec<Vec<TableCell>> = Vec::new();
for tr in tbl.elements().filter(|e| e.name == "tr") {
let mut tcs = Vec::new();
self.row_cells(tr, &mut tcs);
let mut row = Vec::new();
for tc in tcs {
let mut content = Vec::new();
self.cell_content(tc, &mut content);
row.push(table_cell(content));
let span: usize = tc
let span: u32 = tc
.child("tcPr")
.and_then(|p| p.child_val("gridSpan"))
.and_then(|v| v.parse().ok())
.unwrap_or(1);
for _ in 1..span.min(64) {
row.push(Vec::new());
}
row.push(TableCell::new(table_cell(content)).with_span(span.min(64), 1));
}
rows.push(row);
}
if rows.iter().all(|r| r.iter().all(|c| is_blank(c))) {
if rows.iter().all(|r| r.iter().all(|c| is_blank(&c.children))) {
return None;
}
let headers = rows.remove(0);
Some(Node::Table { headers, rows })
Some(Node::Table {
alignments: Vec::new(),
headers,
rows,
})
}
}

Expand Down
Loading
Loading