djot 0.1.4.1 → 0.1.4.2
raw patch · 6 files changed
+86/−17 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG.md +12/−0
- djot.cabal +1/−1
- src/Djot/Djot.hs +25/−8
- src/Djot/Html.hs +5/−4
- src/Djot/Inlines.hs +1/−2
- test/footnotes.test +42/−2
CHANGELOG.md view
@@ -1,5 +1,17 @@ # Revision history for djot +## 0.1.4.2 -- 2026-08-27++ * Djot renderer: emit raw blocks/inlines for formats other than djot (#18).++ * Djot renderer: Fix calculation of fence length. We needed to add+ one to the length of the biggest backtick string in the code.++ * Fix two bugs in footnote handling:++ - Allow spaces and newlines in footnote references, as with djot.js.+ - Don't put a duplicate id on a second reference to same note.+ ## 0.1.4.1 -- 2026-07-21 * Fix bug in verbatim parsing (#17). We were wrongly allowing
djot.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: djot-version: 0.1.4.1+version: 0.1.4.2 synopsis: Parser and renderer for djot light markup syntax. description: Djot (<https://djot.net>) is a light markup language. This package provides a data structure to represent
src/Djot/Djot.hs view
@@ -11,7 +11,7 @@ import Djot.AST import Djot.Options (RenderOptions(..))-import Data.Char (ord, chr)+import Data.Char (ord, chr, isSpace) import Djot.Parse (utf8ToStr) import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as B8@@ -230,11 +230,7 @@ then pure ">" else prefixed "> " <$> toLayout bls CodeBlock lang bs -> do- let longesttickline =- case B8.lines bs of- [] -> 0- ls -> maximum $ map (B8.length . B8.takeWhile (=='`')) ls- let numticks = max 3 longesttickline+ let numticks = getFenceLength bs let ticks = literal $ T.replicate numticks "`" let lang' = if lang == mempty then mempty@@ -251,7 +247,14 @@ pure $ body $+$ caption RawBlock (Format "djot") bs -> pure $ literal (fromUtf8 bs)- RawBlock _ _ -> pure mempty)+ RawBlock (Format f) bs+ | isSaneFormat f -> do+ let numticks = getFenceLength bs+ let ticks = literal $ T.replicate numticks "`"+ pure $ (ticks <> literal (fromUtf8 ("=" <> f)))+ $$ literal (fromUtf8 bs)+ $$ ticks+ | otherwise -> pure mempty) <* modify' (\st -> st{ afterSpace = True -- Handle case of one bullet list right after -- another; we need to change the bullet to@@ -419,7 +422,10 @@ EmailLink email -> pure $ "<" <> literal (fromUtf8 email) <> ">" UrlLink url -> pure $ "<" <> literal (fromUtf8 url) <> ">" RawInline (Format "djot") bs -> pure $ literal (fromUtf8 bs)- RawInline _ _ -> pure mempty+ RawInline (Format f) bs+ | isSaneFormat f ->+ pure $ toVerbatimSpan bs <> literal (fromUtf8 ("{=" <> f <> "}"))+ | otherwise -> pure mempty FootnoteReference label -> do order <- gets noteOrder case M.lookup label order of@@ -493,3 +499,14 @@ go (Node _pos _ (Div bls')) n = max (n + 1) (foldr go (n + 1) (unMany bls')) go _ n = n++getFenceLength :: ByteString -> Int+getFenceLength bs = max 3 (longesttickline + 1)+ where+ longesttickline =+ case B8.lines bs of+ [] -> 0+ ls -> maximum $ map (B8.length . B8.takeWhile (=='`')) ls++isSaneFormat :: ByteString -> Bool+isSaneFormat bs = not (B8.any (\c -> isSpace c || c == '}' || c == '`') bs)
src/Djot/Html.hs view
@@ -19,7 +19,7 @@ import Data.ByteString.Builder (Builder, byteString, word8, intDec) import qualified Data.Sequence as Seq import qualified Data.Map.Strict as M-import Data.Maybe (fromMaybe)+import Data.Maybe (fromMaybe, isNothing) import Data.List (sort) import Control.Monad.State import qualified Data.Foldable as F@@ -310,9 +310,10 @@ M.insert label rendered (renderedNotes st) } pure num let num' = B8.pack $ show num- pure $ inTags "a" pos (Attr [("id", "fnref" <> num'),- ("href", "#fn" <> num'),- ("role", "doc-noteref")] <> attr) $+ pure $ inTags "a" pos (Attr ([("id", "fnref" <> num')+ | isNothing (M.lookup label noterefs)] +++ [("href", "#fn" <> num'),+ ("role", "doc-noteref")]) <> attr) $ inTags "sup" pos mempty (escapeHtml num') {-# INLINE inTags #-}
src/Djot/Inlines.hs view
@@ -338,8 +338,7 @@ pFootnoteReference = do asciiChar '[' asciiChar '^'- label <- byteStringOf $ skipMany $- skipSatisfyByte (\c -> c /= ']' && not (isWs c))+ label <- byteStringOf $ skipMany $ skipSatisfyByte (\c -> c /= ']') asciiChar ']' pure $ footnoteReference label
test/footnotes.test view
@@ -13,7 +13,7 @@ another ref to the first note[^a]. . <p>test<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a> and another<a id="fnref2" href="#fn2" role="doc-noteref"><sup>2</sup></a>.</p>-<p>another ref to the first note<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a>.</p>+<p>another ref to the first note<a href="#fn1" role="doc-noteref"><sup>1</sup></a>.</p> <section role="doc-endnotes"> <hr> <ol>@@ -85,7 +85,47 @@ <p>very long footnote<a id="fnref2" href="#fn2" role="doc-noteref"><sup>2</sup></a><a href="#fnref1" role="doc-backlink">↩︎</a></p> </li> <li id="fn2">-<p>bla bla<a id="fnref2" href="#fn2" role="doc-noteref"><sup>2</sup></a><a href="#fnref2" role="doc-backlink">↩︎</a></p>+<p>bla bla<a href="#fn2" role="doc-noteref"><sup>2</sup></a><a href="#fnref2" role="doc-backlink">↩︎</a></p>+</li>+</ol>+</section>+```++Footnote references are normalized like reference labels, so consecutive+space/newlines are collapsed:+```+[^a+ b]++[^a b]:+ foo+.+<p><a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>+<section role="doc-endnotes">+<hr>+<ol>+<li id="fn1">+<p>foo<a href="#fnref1" role="doc-backlink">↩︎</a></p>+</li>+</ol>+</section>+```++Issue #146: Footnote labels can't contain line breaks (so this+is interpreted not as a footnote but as an inline footnote reference):++```+[^a+b]: + foo+.+<p><a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a>: +foo</p>+<section role="doc-endnotes">+<hr>+<ol>+<li id="fn1">+<p><a href="#fnref1" role="doc-backlink">↩︎</a></p> </li> </ol> </section>