oxedyne/fe2o3/fe2o3_text/src/doc/djot/mod.rs
3.7 KiB, 1 run
created by r1870400018:14702, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | //! Djot -- a reader for the post-Markdown markup language, producing the neutral |
| 2 | //! [document tree](crate::doc). |
| 3 | //! |
| 4 | //! Djot is what a prose author reaches for when Markdown cannot name the thing they mean: a box around |
| 5 | //! an aside, a class on a span, an id on a heading. Its blocks and inlines carry [attributes](crate::doc::Attrs), |
| 6 | //! and a `:::` fence draws a [division](crate::doc::Block::Div) that Markdown has no way to write. What |
| 7 | //! this reader produces belongs to [`crate::doc`] and knows nothing of Djot, which is what lets a site |
| 8 | //! author the same page in either Djot or Markdown and reach the one tree. |
| 9 | //! |
| 10 | //! # Where Djot parts from Markdown |
| 11 | //! |
| 12 | //! The two front-ends agree on most of the tree, and part on a few points a reader of both should hold |
| 13 | //! in mind: |
| 14 | //! |
| 15 | //! - The emphasis markers are swapped and single. A single `_` is ordinary emphasis and a single `*` |
| 16 | //! is strong, where Markdown reads a single marker as ordinary and doubles it for strong. So `_it_` |
| 17 | //! is italic here and `*it*` is bold, and neither is doubled. |
| 18 | //! - Emphasis may fall inside a word, since Djot judges a marker by the whitespace against it and keeps |
| 19 | //! no intraword exception. |
| 20 | //! - There is no two-space hard break and no indented code block. A break the author asked for is a |
| 21 | //! backslash at the end of the line, and code is fenced. |
| 22 | //! - A `:::` fence draws a division, and a `{...}` group names attributes, on a division, on a span, or |
| 23 | //! on its own line to attach to the block below. These are the constructs Djot exists for. |
| 24 | //! |
| 25 | //! # A soft line break says a space |
| 26 | //! |
| 27 | //! A single newline within a paragraph is a soft break, and it contributes a space rather than a |
| 28 | //! newline. Where an author's editor wrapped a line is not where the author asked for a break, and |
| 29 | //! preserving it would freeze prose at the width it was typed at instead of reflowing to the width it |
| 30 | //! is read at. [`Inline::Break`](crate::doc::Inline::Break) is only ever a break the author did ask |
| 31 | //! for -- here, a backslash at the end of a line. |
| 32 | //! |
| 33 | //! # The dialect |
| 34 | //! |
| 35 | //! The subset read is what prose actually uses: headings, paragraphs, block quotations, fenced code, |
| 36 | //! ordered and unordered lists (nested), thematic breaks, pipe tables, divisions, standalone |
| 37 | //! attributes lines, and the inline run of ordinary and strong emphasis, verbatim spans, links |
| 38 | //! (inline and by reference), images, attributed spans and hard breaks. |
| 39 | //! |
| 40 | //! # Not yet read |
| 41 | //! |
| 42 | //! The following Djot constructs are not yet read, and their syntax survives as the literal text it is |
| 43 | //! written in rather than being interpreted: footnotes, inline and display maths (`$` and `$$`), |
| 44 | //! definition lists, superscript and subscript (`^` and `~`), inline symbols (`:name:`), smart |
| 45 | //! punctuation, raw inline and raw blocks, comments (`{% %}`), line blocks, and task lists. A document |
| 46 | //! that uses them is read without error; the marks simply stand as characters. |
| 47 | //! |
| 48 | //! # Usage |
| 49 | //! |
| 50 | //! ```ignore |
| 51 | //! use oxedyne_fe2o3_text::doc::djot; |
| 52 | //! |
| 53 | //! let tree = res!(djot::parse("# A heading\n\nA paragraph with *strength*.\n")); |
| 54 | //! ``` |
| 55 | |
| 56 | pub mod block; |
| 57 | pub mod inline; |
| 58 | |
| 59 | use crate::doc::Doc; |
| 60 | |
| 61 | use oxedyne_fe2o3_core::prelude::*; |
| 62 | |
| 63 | /// Reads Djot text and produces its document tree. |
| 64 | /// |
| 65 | /// Parsing does not fail on badly formed markup: Djot has no syntax errors, only text that means less |
| 66 | /// than the author hoped. An unclosed fence runs to the end, an unmatched bracket is literal text, and |
| 67 | /// a stray asterisk is an asterisk. The outcome is an error only when the input breaks a limit the |
| 68 | /// reader holds against a hostile document, such as nesting past [`block::DEPTH_LIMIT`]. |
| 69 | pub fn parse(src: &str) -> Outcome<Doc> { |
| 70 | let blocks = res!(block::parse(src)); |
| 71 | Ok(Doc { blocks }) |
| 72 | } |