diff options
Diffstat (limited to 'dlang/README.md')
| -rw-r--r-- | dlang/README.md | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/dlang/README.md b/dlang/README.md new file mode 100644 index 0000000..e3a41b6 --- /dev/null +++ b/dlang/README.md @@ -0,0 +1,85 @@ +# ocda-write, in D + +Sample writers over the abstraction: + + ocda-write --text|--md|--html|--epub|--typst <file> [lang] + ocda-write --md <file> [lang] [--image-prefix <path>] + +writes a document out, from any serialisation of its abstraction. + +## Modules + +| | | +|---|---| +| `write.text` | the model -> spine's plain text, byte for byte | +| `write.html` | the model -> one self-contained, valid html5 file | +| `write.epub` | the model -> an epub3, one file per segment | +| `write.markdown` | the model -> CommonMark, object numbers and all | +| `write.typst` | the model -> typst markup, for a pdf | +| `write.zip` | writing a zip, stored only, with no timestamps | +| `write.rgx` | the internal markup, as regular expressions | +| `main` | the program: which format, which file, which language | + +`write.text` takes an `OcdaDocument` and returns a string. It is given no +file, no path and no option: a writer is a function from the model to bytes, +and everything it needs is in the model. + +## Build and run + +```sh +nix build --override-input ocda-lib path:../../sisudoc-ocda-lib +./result/bin/ocda-write --text <doc>.ssp +./result/bin/ocda-write --html <doc>.ocda.db de +./result/bin/ocda-write --html <doc>.sisupod +./result/bin/ocda-write --md <doc>.ssp +./result/bin/ocda-write --epub <doc>.ocda.db en --out <doc>.epub +./result/bin/ocda-write --typst <doc>.ocda.db en --out out/<doc>.typ +typst compile --root out out/<doc>.typ out/<doc>.pdf +``` + +`--epub` writes a zip, so it takes `--out` rather than stdout. `--typst` goes +to stdout too, but with `--out` it also writes the `image/` directory the +`.typ` names. + +`nix build .#ocda-write-dmd` builds with dmd instead of ldc. + +The library's modules are compiled alongside these rather than linked as a +separate product; for five modules a second build step buys nothing. + +## The checks + +`--text` and `--md` are checked against the html writer's objects, word for +word, and against each other language's writer, byte for byte: **36 of 36 on +every count.** Byte identity with `spine --text` was the first oracle and is +no longer the target; see the repository README. + +`--html` is checked harder still: it parses, every `href="#x"` +resolves, no id appears twice, no heading falls outside `h1`..`h6`, and the +objects' visible text equals spine's scroll html exactly. **36 of 36 on each, +and byte identical to the Gleam writer.** See the repository README for what +it does differently from spine and why. + +`--epub` is judged by `epubcheck`, and `--typst` by typst: a link to a label +that does not exist is a compile error, so a silent compile means every +internal link in the document resolves. **36 of 36 on each, and byte +identical to the Gleam writer.** + +## Where it is faithful rather than sensible + +The *text* writer reproduces spine's output exactly, which means reproducing +what would not be chosen from scratch. The comments say so at each point. +The three worth knowing before reading the code: + +- **the table layout strips trailing whitespace from the whole accumulated + table after every cell**, not once per row, so a row ending in an empty + cell loses the newline before it; +- **a column's width is the widest cell in bytes and the padding is counted + in codepoints**, so a cell holding `©` is padded one place further than one + holding `c`; +- **the section sequence is spine's `scroll` sequence**, not its `text` one: + head, toc, body, then each trailing section *that has more than one + object*, and no `tail` unless an html or epub output was also asked for. + +The *html* writer takes none of these as given. What it takes from the model +and what it declines to take from spine is set out in its own comments, at +the point where each choice is made. |
