From 50e596b7d7dce83bed2380e0dcae5600ef7a4749 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 21 Sep 2026 05:51:17 +0000 Subject: [PATCH] Shared: avoid Text -> String round-trips in htmlAttrs. Each attribute was rendered with `text . T.unpack`, converting the escaped Text to String and back. Use `literal . fromText` instead (free for Doc Text, which is what all callers use). This adds a FromText constraint to htmlAttrs and tagWithAttrs. Benchmark (30k-cell table with id/class/data attrs, json -> mediawiki): 2.15s -> 2.00s with ~70-char attribute values; no change with short values, where attribute text is a small fraction of the document. Co-Authored-By: Claude --- src/Text/Pandoc/Writers/Shared.hs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs index 7ebdce0b1..0d66f6d7e 100644 --- a/src/Text/Pandoc/Writers/Shared.hs +++ b/src/Text/Pandoc/Writers/Shared.hs @@ -196,24 +196,24 @@ getLang opts meta = _ -> Nothing -- | Produce an HTML tag with the given pandoc attributes. -tagWithAttrs :: HasChars a => a -> Attr -> Doc a +tagWithAttrs :: (HasChars a, FromText a) => a -> Attr -> Doc a tagWithAttrs tag attr = "<" <> literal tag <> (htmlAttrs attr) <> ">" -- | Produce HTML for the given pandoc attributes, to be used in HTML tags -htmlAttrs :: HasChars a => Attr -> Doc a +htmlAttrs :: (HasChars a, FromText a) => Attr -> Doc a htmlAttrs (ident, classes, kvs) = addSpaceIfNotEmpty (hsep [ if T.null ident then empty - else "id=" <> doubleQuotes (text $ T.unpack (escapeStringForXML ident)) + else "id=" <> doubleQuotes (literal $ fromText (escapeStringForXML ident)) ,if null classes then empty else "class=" <> doubleQuotes - (text $ T.unpack . escapeStringForXML $ T.unwords classes) + (literal $ fromText . escapeStringForXML $ T.unwords classes) ,hsep (map (\(k,v) -> formatKey k <> "=" <> - doubleQuotes (text $ T.unpack (escapeStringForXML v))) kvs) + doubleQuotes (literal $ fromText (escapeStringForXML v))) kvs) ]) where - formatKey x = text . T.unpack $ + formatKey x = literal . fromText $ if ((x `Set.member` html5Attributes || x `Set.member` rdfaAttributes) && x /= "label") -- #10048 || T.any (== ':') x -- e.g. epub: namespace