[
  {
    "path": ".gitignore",
    "content": "14882\ndist\ntags\nnode_modules\n.stack-work/\n"
  },
  {
    "path": "14882.css",
    "content": "body {\n\tfont-family: 'Noto Serif';\n\thyphens: auto;\n\tline-height: 1.5;\n\tmargin-left: 20mm;\n\tmargin-right: 16mm;\n\tmargin-top: 12mm;\n\tmargin-bottom: 12mm;\n\tfont-size: 10pt;\n}\n\ndiv {\n\tbackground: inherit;\n}\n\ndiv.wrapper {\n\tmax-width: 20cm;\n\tmargin: auto;\n}\n\ndiv.texpara {\n\ttext-align: justify;\n\tmargin-top: 3pt;\n\tmargin-bottom: 3pt;\n}\n\ntable div.texpara {\n\tmargin-top: 0;\n\tmargin-bottom: 0;\n}\n\ntable.enumerate div.texpara {\n\tmargin-top: 3pt;\n\tmargin-bottom: 3pt;\n}\n\nul {\n\tlist-style-type: none;\n\tpadding-left: 9mm;\n\tmargin-top: 0;\n\tmargin-bottom: 0;\n}\n\nol {\n\tmargin-top: 0;\n\tmargin-bottom: 0;\n}\n\na { text-decoration: none; }\n\na.hidden_link {\n\ttext-decoration: none;\n\tcolor: inherit;\n}\n\nli {\n\tmargin-top: 3pt;\n\tmargin-bottom: 3pt;\n}\n\nh1 {\n\tline-height: 1;\n\tfont-size: 20pt;\n\tmargin-top: 10pt;\n\tmargin-bottom: 10pt;\n}\n\nh2 {\n\tline-height: 1;\n\tfont-size: 16pt;\n\tmargin-top: 10pt;\n\tmargin-bottom: 10pt;\n}\n\nh2::after {\n    content: \"\";\n    clear: both;\n    display: table;\n}\n\nh3 {\n\tline-height: 1;\n\tfont-size: 12pt;\n\tmargin-top: 10pt;\n\tmargin-bottom: 10pt;\n}\n\nh3::after {\n    content: \"\";\n    clear: both;\n    display: table;\n}\n\nh4 {\n\tline-height: 1;\n\tfont-size: 11pt;\n\tmargin-top: 10pt;\n\tmargin-bottom: 10pt;\n}\n\nh4::after {\n    content: \"\";\n    clear: both;\n    display: table;\n}\n\nul > li:before {\n\tcontent: \"\\2014\";\n\tposition: absolute;\n\tmargin-left: -1.5em; \n}\n\n.shy:before {\n\tcontent: \"\\00ad\";\n\t/* This is U+00AD SOFT HYPHEN, same as &shy, but we put it in :before\n\tto stop it from being included when the text is copied to the clipboard\n\twith Firefox, which is especially annoying when copying to a terminal,\n\twhere the hyphen characters will show up. */\n}\n\n:target { background-color: #C9FBC9; }\n:target .codeblock { background-color: #C9FBC9; }\n:target ul { background-color: #C9FBC9; }\n\n.abbr_ref { float: right; }\n\n.folded_abbr_ref { float: right; }\n:target .folded_abbr_ref { display: none; }\n\n:target .unfolded_abbr_ref { float: right; display: inherit; }\n.unfolded_abbr_ref { display: none; }\n\n.secnum { display: inline-block; min-width: 35pt; }\n.annexnum { display: block; }\n\ndiv.sourceLinkParent {\n\tfloat: right;\n}\n\na.sourceLink {\n\tposition: absolute;\n\topacity: 0;\n\tmargin-left: 10pt;\n}\n\na.sourceLink:hover {\n\topacity: 1;\n}\n\na.itemDeclLink {\n\tposition: absolute;\n\tfont-size: 75%;\n\ttext-align: right;\n\twidth: 5em;\n\topacity: 0;\n}\na.itemDeclLink:hover { opacity: 1; }\n\ndiv.marginalizedparent {\n\tposition: relative;\n\ttext-align: left;\n\tleft: -18mm;\n}\n\na.marginalized {\n\twidth: 15mm;\n\tposition: absolute;\n\ttop: 0.4mm;\n\tfont-size: 7pt;\n\ttext-align: right;\n}\n\na.enumerated_item_num {\n\tdisplay: block;\n\tmargin-top: 3pt;\n\tmargin-bottom: 3pt;\n\tmargin-right: 6pt;\n}\n\ndiv.para {\n\tposition: relative;\n\tleft: -14mm;\n\tpadding-left: 14mm;\n\twidth: 100%;\n\tmargin-bottom: 6pt;\n\tmargin-top: 6pt;\n\ttext-align: justify;\n\tmin-height: 1.2em;\n}\n\ndiv.section { text-align: justify; }\ndiv.sentence { display: inline; }\n\na.index {\n\tposition: relative;\n\tfloat: right;\n\tright: -1em;\n\tdisplay: none;\n}\n\na.index:before {\n\tposition: absolute;\n\tcontent: \"⟵\";\n\tbackground-color: #C9FBC9;\n}\n\na.index:target {\n\tdisplay: inline;\n}\n\n.indexitems {\n\tmargin-left: 2em;\n\ttext-indent: -2em;\n}\n\ndiv.itemdescr {\n\tmargin-left: 12mm;\n}\n\n.bnf {\n\tfont-family: 'Noto Sans';\n\tfont-size: 10pt;\n\tfont-style: italic;\n\tmargin-left: 25pt;\n\tmargin-right: -15mm;\n\tmargin-top: 0.5em;\n\tmargin-bottom: 0.5em;\n\ttext-indent: -3em;\n\tpadding-left: 3em;\n\tline-height: 1.5;\n}\n\ndiv.bnf span.texttt { font-family: 'Noto Sans Mono'; font-style: normal; }\n\n.rebnf {\n\tfont-family: 'Noto Serif';\n\tfont-style: italic;\n\tmargin-top: 0.5em;\n\tmargin-bottom: 0.5em;\n\tmargin-left: 30pt;\n\ttext-indent: -3em;\n\tpadding-left: 3em;\n\tline-height: 1.5;\n}\n\n.simplebnf {\n\tfont-family: 'Noto Serif';\n\tfont-style: italic;\n\tfont-size: 10pt;\n\tmargin-top: 0.5em;\n\tmargin-bottom: 0.5em;\n\tmargin-left: 30pt;\n\tline-height: 1.5;\n}\n\nspan.textnormal {\n\tfont-style: normal;\n\tfont-family: 'Noto Serif';\n\tfont-size: 10pt;\n\twhite-space: normal;\n}\n\n.bnf span.textnormal {\n\tfont-style: normal;\n\tfont-family: 'Noto Serif';\n\tfont-size: 10pt;\n\twhite-space: normal;\n}\n\np {\n\tmargin-top: 4pt;\n\tmargin-bottom: 4pt;\n}\n\nspan.rlap {\n    display: inline-block;\n    width: 0px;\n    text-indent: 0;\n}\n\nspan.terminal {\n\tfont-family: 'Noto Sans Mono';\n\tfont-style: normal;\n\tfont-size: 9pt;\n\twhite-space: pre-wrap;\n}\n\nspan.noncxxterminal {\n\tfont-family: 'Noto Sans Mono';\n\tfont-style: normal;\n\tfont-size: 9pt;\n}\n\nspan.term { font-style: italic; }\nspan.tcode { font-family: 'Noto Sans Mono'; font-style: normal; }\nspan.textbf { font-weight: bold; }\nspan.textsf { font-family: 'Noto Sans'; font-size: 10pt; }\ndiv.footnote span.textsf { font-family: 'Noto Sans'; font-size: 8pt; }\n.bnf span.textsf { font-family: 'Noto Sans'; font-size: 10pt; }\n.simplebnf span.textsf { font-family: 'Noto Sans'; font-size: 10pt; }\n.example span.textsf { font-family: 'Noto Sans'; font-size: 10pt; }\nspan.textsc { font-variant: small-caps; }\nspan.nontermdef { font-style: italic; font-family: 'Noto Sans'; font-size: 10pt; }\nspan.emph { font-style: italic; }\nspan.techterm { font-style: italic; }\nspan.mathit { font-style: italic; }\nspan.mathsf { font-family: 'Noto Sans'; }\nspan.mathrm { font-family: 'Noto Serif'; font-style: normal; }\nspan.textrm { font-family: 'Noto Serif'; font-size: 10pt; }\nspan.textsl { font-style: italic; }\nspan.mathtt { font-family: 'Noto Sans Mono'; font-style: normal; }\nspan.mbox { font-family: 'Noto Serif'; font-style: normal; }\nspan.ungap { display: inline-block; width: 2pt; }\nspan.texttt { font-family: 'Noto Sans Mono'; }\nspan.textit { font-style: italic; }\ndiv.footnote span.texttt { font-family: 'Noto Sans Mono'; }\nspan.tcode_in_codeblock { font-family: 'Noto Sans Mono'; font-style: normal; font-size: 9pt; }\n\nspan.phantom { color: white; }\n\t/* Unfortunately, this way the text is still selectable. Another\n\toption is display:none, but then we lose the nice layout.\n\tTodo: find proper solution. */\n\nspan.math {\n\tfont-style: normal;\n\tfont-family: 'Noto Serif';\n\tfont-size: 10pt;\n}\n\nspan.mathblock {\n\tdisplay: block;\n\tmargin-left: auto;\n\tmargin-right: auto;\n\tmargin-top: 1.2em;\n\tmargin-bottom: 1.2em;\n\ttext-align: center;\n}\n\nspan.mathalpha {\n\tfont-style: italic;\n}\n\nspan.synopsis {\n\tfont-weight: bold;\n\tmargin-top: 0.5em;\n\tdisplay: block;\n}\n\nspan.definition {\n\tfont-weight: bold;\n\tdisplay: block;\n}\n\n.codeblock {\n\tfont-family: 'Noto Sans Mono';\n\tmargin-left: 1.2em;\n\tline-height: 1.5;\n\tfont-size: 9pt;\n\twhite-space: pre;\n\tdisplay: block;\n\tmargin-top: 3pt;\n\tmargin-bottom: 3pt;\n\toverflow: auto;\n\tmargin-right: -15mm;\n}\n\ntable .codeblock { margin-right: 0; }\n\n.outputblock {\n\tmargin-left: 1.2em;\n\tline-height: 1.5;\n\tfont-family: 'Noto Sans Mono';\n\tfont-size: 9pt;\n}\n\ncode {\n\tfont-family: 'Noto Sans Mono';\n\tfont-style: normal;\n}\n\ndiv.itemdecl {\n\tmargin-top: 2ex;\n}\n\ncode.itemdeclcode {\n\twhite-space: pre;\n\tfont-family: 'Noto Sans Mono';\n\tfont-size: 9pt;\n\tdisplay: block;\n\toverflow: auto;\n\tmargin-right: -15mm;\n}\n\n.comment { color: green; font-style: italic; font-family: 'Noto Serif'; font-size: 10pt; }\n.footnote .comment { color: green; font-style: italic; font-family: 'Noto Serif'; font-size: 8pt; }\n.example .comment { color: green; font-style: italic; font-family: 'Noto Serif'; font-size: 9pt; }\n.note .comment { color: green; font-style: italic; font-family: 'Noto Serif'; font-size: 9pt; }\n\nspan.keyword { color: #00607c; font-style: normal; }\nspan.parenthesis { color: #af1915; }\nspan.curlybracket { color: #af1915; }\nspan.squarebracket { color: #af1915; }\nspan.literal { color: #9F6807; }\nspan.literalterminal { color: #9F6807; font-family: 'Noto Sans Mono'; font-style: normal; }\nspan.operator { color: #570057; }\nspan.anglebracket { color: #570057; }\nspan.preprocessordirective { color: #6F4E37; }\n\nspan.textsuperscript {\n\tvertical-align: super;\n\tfont-size: smaller;\n\tline-height: 0;\n}\n\n.footnoteref {\n\tvertical-align: super;\n\tfont-size: smaller;\n\tline-height: 0;\n}\n\n.footnote {\n\tfont-size: 8pt;\n}\n\n.footnote .math {\n\tfont-size: 8pt;\n}\n\n.footnotenum {\n\tdisplay: inline-block;\n\ttext-align: right;\n\tmargin-right: 1mm;\n\twidth: 4ch;\n}\n\n.footnoteBacklink {\n\tdisplay: none;\n}\n\n:target .footnoteBacklink {\n\tdisplay: inline-block;\n\ttext-align: right;\n\tmargin-right: 1mm;\n\twidth: 4ch;\n}\n\n:target .footnotenum {\n\tdisplay: none;\n}\n\n.footnoteSeparator {\n\tbackground: black;\n\tmargin-top: 5mm;\n\theight: 1px;\n\twidth: 6cm;\n}\n\ndiv.minipage {\n\tdisplay: inline-block;\n\tmargin-right: 3em;\n}\n\ndiv.numberedTable {\n\ttext-align: center;\n\tmargin-left: 1em;\n\tmargin-right: 1em;\n\tmargin-bottom: 12pt;\n\tmargin-top: 8pt;\n}\n\ndiv.figure {\n\ttext-align: center;\n\tmargin-left: 2em;\n\tmargin-right: 2em;\n\tmargin-bottom: 12pt;\n\tmargin-top: 3pt;\n}\n\ntable {\n\tborder: 1px solid black;\n\tborder-collapse: collapse;\n\tmargin-left: auto;\n\tmargin-right: auto;\n\tmargin-top: 7pt;\n\ttext-align: left;\n}\n\ntd, th {\n\tpadding-left: 8pt;\n\tpadding-right: 8pt;\n\tvertical-align: top;\n}\n\ntd.empty {\n    padding: 0px;\n    padding-left: 1px;\n}\n\ntd.left {\n\ttext-align: left;\n}\n\ntd.hidden {\n\tpadding: 0;\n\twidth: 0;\n}\n\ntd.right {\n\ttext-align: right;\n}\n\ntd.center {\n\ttext-align: center;\n}\n\ntd.justify {\n\ttext-align: justify;\n}\n\ntd.border {\n\tborder-left: 1px solid black;\n}\n\ntr.rowsep, td.cline {\n\tborder-top: 1px solid black;\n}\n\ntr.capsep {\n\tborder-top: 3px solid black;\n\tborder-top-style: double;\n}\n\nth {\n\tborder-bottom: 1px solid black;\n}\n\nspan.centry {\n\tfont-weight: bold;\n}\n\ndiv.table {\n\tdisplay: block;\n\tmargin-left: auto;\n\tmargin-right: auto;\n\ttext-align: center;\n\twidth: 90%;\n}\n\nspan.indented {\n\tbackground: inherit;\n\tdisplay: block;\n\tmargin-left: 2em;\n\tmargin-bottom: 1em;\n\tmargin-top: 1em;\n}\n\nspan.uppercase {\n\ttext-transform: uppercase;\n}\n\nspan.ucode {\n\tfont-variant: small-caps;\n\ttext-transform: uppercase;\n\tfont-size: 90%;\n}\n\nspan.uname {\n\tfont-variant: small-caps;\n\ttext-transform: uppercase;\n\tfont-size: 90%;\n}\n\ntable.enumerate {\n\tborder: 0;\n\tmargin: 0;\n}\n\ntable.enumerate td {\n\tpadding: 0;\n}\n\ntable.enumerate td:first-child {\n\twidth: 1cm;\n\ttext-align: right;\n}\n\n@media (prefers-color-scheme: dark) {\n    body {\n        background-color: #171717;\n        color: #e0e0e0;\n    }\n\n    span.mjx-mstyle { color: #e0e0e0 !important }\n\n    a:link { color: #74bdff; }\n    a:visited { color: #c38aff; }\n\n    a.hidden_link {\n        text-decoration: none;\n        color: inherit;\n    }\n\n    span.phantom { color: #171717; }\n\n    a.index:before { color: #e0e0e0; background-color: #4b6353; }\n\n    .comment { color: #40f040; }\n    .footnote .comment { color: #60ff60; }\n    .example .comment { color: #60ff60; }\n    .note .comment { color: #60ff60; }\n\n    span.keyword { color: #32eade; }\n    span.parenthesis { color: #ff7070; }\n    span.curlybracket { color: #ff7070; }\n    span.squarebracket { color: #ff7070; }\n    span.literal { color: #ffd867; }\n    span.literalterminal { color: #ffd867; }\n    span.operator { color: #dac6d9; }\n    span.anglebracket { color: #dac6d9; }\n    span.preprocessordirective { color: #c28c68; }\n\n    table { border-color: #e0e0e0; }\n    td.border { border-color: #e0e0e0; }\n    td.border { border-left-color: #e0e0e0; }\n    tr.rowsep, td.cline { border-top-color: #e0e0e0; }\n    tr.capsep { border-top-color: #e0e0e0; }\n    th { border-bottom-color: #e0e0e0; }\n\n    .footnoteSeparator { background-color: #e0e0e0; }\n\n    text { fill: #e0e0e0; }\n    path { stroke: #e0e0e0; }\n    polygon { stroke: #e0e0e0; fill: #e0e0e0; }\n    ellipse { stroke: #e0e0e0; }\n\n    :target { background-color: #4b6345; color: #ffffff; }\n    :target .codeblock { background-color: #4b6345; }\n    :target ul { background-color: #4b6345; }\n    :target a:link { color: #9fcdff; }\n    :target a:visited { color: #d39aff; }\n    :target a.hidden_link { text-decoration: none; color: inherit; }\n    :target span.keyword { color: #52faee; }\n    :target span.parenthesis { color: #ff4060; font-weight: bold; }\n    :target span.curlybracket { color: #ff4060; font-weight: bold; }\n    :target span.squarebracket { color: #ff4060; font-weight: bold; }\n    :target span.literal { color: #ffe070; }\n    :target span.literalterminal { color: #ffe070; }\n    :target span.operator { color: #ffffff; }\n    :target span.anglebracket { color: #ffffff; }\n    :target span.preprocessordirective { color: #e0968f; }\n    :target .comment { color: #75ff20; }\n    :target .footnote .comment { color: #75ff20; }\n    :target .example .comment { color: #75ff20; }\n    :target .note .comment { color: #75ff20; }\n}\n"
  },
  {
    "path": "CxxParser.hs",
    "content": "{-# OPTIONS_GHC -fno-warn-tabs #-}\n{-# LANGUAGE\n\tOverloadedStrings,\n\tRecordWildCards,\n\tTupleSections,\n\tViewPatterns,\n\tLambdaCase,\n\tTypeSynonymInstances,\n\tFlexibleInstances #-}\n\nmodule CxxParser (parseLiteral, parseComment, parseCppDirective) where\n\nimport LaTeXBase (LaTeX, LaTeXUnit(..), ArgKind(..), concatRaws,\n    texStripPrefix, texStripAnyPrefix, texStripInfix, texSpan, unconsRaw)\nimport qualified Data.Text as Text\nimport Data.Char (isAlpha, isSpace, isAlphaNum, isDigit)\nimport Control.Arrow (first)\nimport Prelude hiding ((.), (++))\nimport Util ((.), (++), Text)\n\ntexStripHash :: LaTeX -> Maybe LaTeX\ntexStripHash x\n    | Just x' <- texStripPrefix \"#\" x = Just x'\n    | TeXComm \"#\" _ [] : x' <- x = Just x'\n    | otherwise = Nothing\n\ncppDirectives :: [Text]\ncppDirectives = Text.words \"include define elifndef elifdef ifndef endif ifdef pragma error undef line elif warning else if embed\"\n\nspanLiteralChars :: String -> (String, String {- rest without the closing ' -})\nspanLiteralChars [] = ([], [])\nspanLiteralChars ('\\\\' : '\\'' : rest) = first (\"\\\\'\"++) (spanLiteralChars rest)\nspanLiteralChars ('\\\\' : '\\\\' : rest) = first (\"\\\\\\\\\"++) (spanLiteralChars rest)\nspanLiteralChars ('\\'' : x) = ([], x)\nspanLiteralChars (c : rest) = first (c :) (spanLiteralChars rest)\n\nparseLiteralChars :: LaTeX -> (LaTeX, LaTeX)\nparseLiteralChars [] = ([], [])\nparseLiteralChars (TeXRaw s : rest) = case spanLiteralChars (Text.unpack s) of\n    (x, []) -> first (TeXRaw (Text.pack x) :) (parseLiteralChars rest)\n    (x, more) -> ([TeXRaw (Text.pack x)], TeXRaw (Text.pack more) : rest)\nparseLiteralChars (x : rest) = first (x :) (parseLiteralChars rest)\n\nparseCharLiteral :: LaTeX -> Maybe (LaTeX, LaTeX {- rest -})\nparseCharLiteral x\n    | Just (pre, x') <- texStripAnyPrefix [\"'\", \"u'\", \"L'\", \"U'\", \"u8'\"] x\n    , (before, x'') <- parseLiteralChars x'\n    , (suffix, x''') <- texSpan (\\c -> isAlphaNum c || c == '_') x''\n        = Just ([TeXRaw pre] ++ before ++ [TeXRaw $ \"'\" ++ suffix], x''')\n    | otherwise = Nothing\n\nparseCppDirective :: LaTeX -> Maybe (LaTeX, LaTeX {- rest -})\nparseCppDirective x\n    | Just x'' <- texStripHash x\n    , (spaces, x''') <- texSpan isSpace x''\n    , Just (directive, x'''') <- texStripAnyPrefix cppDirectives x'''\n        = Just ([TeXRaw (\"#\" ++ spaces ++ directive)], x'''')\n    | otherwise = Nothing\n\nparseSingleLineComment :: LaTeX -> Maybe (LaTeX {- comment -}, LaTeX {- subsequent lines -})\nparseSingleLineComment x\n    | Just x' <- texStripPrefix \"//\" x = Just $ case texStripInfix \"\\n\" x' of\n        Just (commentLine, moreLines) -> (TeXRaw \"//\" : commentLine, TeXRaw \"\\n\" : moreLines)\n        Nothing -> (x, [])\n    | rlap@(TeXComm \"rlap\" _ [(FixArg, [TeXComm \"textnormal\" _ [(FixArg,[TeXComm \"textit\" _ [(FixArg,[TeXRaw \"//\"])]])]])]) : more <- x\n    , Just (commentLine, moreLines) <- texStripInfix \"\\n\" more\n        = Just ([rlap, TeXComm \"tcode\" \"\" [(FixArg, commentLine)]], TeXRaw \"\\n\" : moreLines)\n    | TeXComm \"comment\" _ [(FixArg, c)] : x' <- x = Just (c, x')\n    | otherwise = Nothing\n\nfromTeXRaw :: LaTeXUnit -> Text\nfromTeXRaw (TeXRaw x) = x\nfromTeXRaw x = error $ \"fromTeXRaw (\" ++ show x ++ \")\"\n\nparseStringLiteral :: LaTeX -> Maybe (LaTeX, LaTeX {- rest -})\nparseStringLiteral x\n    -- raw:\n    | Just (pre, x') <- texStripAnyPrefix [\"R\\\"\", \"u8R\\\"\", \"uR\\\"\", \"UR\\\"\", \"LR\\\"\"] x\n    , Just (delim, x'') <- texStripInfix \"(\" x'\n    , Just (body, x''') <- texStripInfix (\")\" ++ Text.concat (map fromTeXRaw delim) ++ \"\\\"\") (concatRaws $ f x'')\n    , (suffix, x'''') <- texSpan (\\c -> isAlphaNum c || c == '_') x'''\n        = Just ([TeXRaw pre] ++ delim ++ [TeXRaw \"(\"] ++ body ++ [TeXRaw \")\"] ++ delim ++ [TeXRaw $ \"\\\"\" ++ suffix], x'''')\n    -- normal:\n    | Just (pre, x') <- texStripAnyPrefix [\"\\\"\", \"u\\\"\", \"U\\\"\", \"L\\\"\", \"u8\\\"\"] x\n    , Just (body, x'') <- parseBody x'\n    , (suffix, x''') <- texSpan (\\c -> isAlphaNum c || c == '_') x''\n        = Just ([TeXRaw pre] ++ body ++ [TeXRaw $ \"\\\"\" ++ suffix], x''')\n    | otherwise = Nothing\n    where\n        f :: LaTeX -> LaTeX\n        f [] = []\n        f (TeXComm \"~\" _ [] : more) = TeXRaw \"~\" : f more\n        f (TeXBraces [] : more) = f more\n        f (hd : t) = hd : f t\n        parseBody :: LaTeX -> Maybe (LaTeX, LaTeX {- rest -})\n        parseBody [] = Nothing\n        parseBody (TeXComm \"textbackslash\" _ [] : more) = parseBody $ concatRaws $ TeXRaw \"\\\\\" : more\n        parseBody (TeXRaw (Text.unpack -> raw) : more)\n            | '\\\\':'\"':t <- raw = first (TeXRaw \"\\\\\\\"\" :) . parseBody (TeXRaw (Text.pack t) : more)\n            | \"\\\"\" <- raw = Just ([], more)\n            | '\"':t <- raw = Just ([], TeXRaw (Text.pack t) : more)\n            | raw == \"\" = parseBody more\n            | hd:t <- raw = first (TeXRaw (Text.pack [hd]) :) . parseBody (TeXRaw (Text.pack t) : more)\n        parseBody (TeXComm \"%\" ws [] : more) = first (TeXComm \"%\" ws [] :) . parseBody more\n        parseBody (y : more) = first (y :) . parseBody more\n\nparseNumber :: LaTeX -> Maybe (Text, LaTeX)\nparseNumber x\n    | (raw, more) <- unconsRaw x\n    , Just (n, rest) <- (parseStart `parseSeq` (\\t -> Just (parseMany parseSuffix t))) raw\n        = Just (n, TeXRaw rest : more)\n    | otherwise = Nothing\n    where\n        parseDigit = parseChar isDigit\n        parseNonDigit = parseChar (\\c -> isAlpha c || c == '_')\n        parseStart :: Text -> Maybe (Text, Text)\n        parseStart = parseFirstOf [parseChar (== '.') `parseSeq` parseDigit, parseDigit]\n        parseSign :: Text -> Maybe (Text, Text)\n        parseSign = parseChar (\\c -> c == '-' || c == '+')\n        parseSuffix :: Text -> Maybe (Text, Text)\n        parseSuffix = parseFirstOf\n            [ parseDigit\n            , parseChar (== '\\'') `parseSeq` parseDigit\n            , parseChar (== '\\'') `parseSeq` parseNonDigit\n            , parseChar (`elem` (\"eEpP\"::String)) `parseSeq` parseSign\n            , parseChar (== '.')\n            , parseNonDigit\n            ]\n\nparseLiteral :: LaTeX -> Maybe (LaTeX, LaTeX)\nparseLiteral x\n    | Just (number, x') <- parseNumber x = Just ([TeXRaw number], x')\n    | Just (lit, x') <- parseCharLiteral x = Just (lit, x')\n    | Just (lit, x') <- parseStringLiteral x = Just (lit, x')\n    | otherwise = Nothing\n\nparseComment :: LaTeX -> Maybe (LaTeX, LaTeX)\nparseComment x\n    | Just x' <- texStripPrefix \"/*\" x, Just (comment, x'') <- texStripInfix \"*/\" x'\n        = Just ([TeXRaw \"/*\"] ++ comment ++ [TeXRaw \"*/\"], x'')\n    | Just x' <- texStripPrefix \"/*\" x\n        = Just ([TeXRaw \"/*\"], x')\n    | Just x' <- texStripPrefix \"*/\" x\n        = Just ([TeXRaw \"*/\"], x')\n    | Just (comment, x') <- parseSingleLineComment x\n        = Just (comment, x')\n    | otherwise = Nothing\n\nparseChar :: (Char -> Bool) -> Text -> Maybe (Text, Text)\nparseChar p t\n    | t /= \"\", p (Text.head t) = Just (Text.take 1 t, Text.drop 1 t)\n    | otherwise = Nothing\n\nparseSeq :: (Text -> Maybe (Text, Text)) -> (Text -> Maybe (Text, Text)) -> Text -> Maybe (Text, Text)\nparseSeq p q t\n    | Just (x, t') <- p t\n    , Just (y, t'') <- q t' = Just (x ++ y, t'')\n    | otherwise = Nothing\n\nparseFirstOf :: [Text -> Maybe (a, Text)] -> Text -> Maybe (a, Text)\nparseFirstOf [] _ = Nothing\nparseFirstOf (p:pp) t\n    | Just r <- p t = Just r\n    | otherwise = parseFirstOf pp t\n\nparseMany :: (Text -> Maybe (Text, Text)) -> Text -> (Text, Text)\nparseMany p t = case p t of\n    Nothing -> (\"\", t)\n    Just (x, t') -> first (x++) (parseMany p t')\n"
  },
  {
    "path": "Document.hs",
    "content": "{-# OPTIONS_GHC -fno-warn-tabs #-}\n{-# LANGUAGE OverloadedStrings, RecordWildCards, ViewPatterns #-}\n\nmodule Document (\n\tCellSpan(..), Cell(..), RowSepKind(..), Row(..), Element(..), Paragraph(..),\n\tSection(..), Chapter(..), Draft(..), Table(..), Figure(..), Item(..), Footnote(..),\n\tIndexPath, IndexComponent(..), IndexCategory, Index, IndexTree, IndexNode(..),\n\tColumnSpec(..), TextAlignment(..), normative, Formula(..), chapterOfSection,\n\tIndexEntry(..), IndexKind(..), Note(..), Example(..), TeXPara(..), Sentence(..),\n\ttexParaTex, texParaElems, XrefDelta, sectionByAbbr, isDefinitionSection, Abbreviation,\n\tindexKeyContent, indexCatName, Sections(sections), SectionKind(..), mergeIndices, SourceLocation(..),\n\tfigures, tables, tableByAbbr, figureByAbbr, formulaByAbbr, elemTex, footnotes, allElements,\n\tLaTeX, makeAbbrMap, formulas) where\n\nimport LaTeXBase (LaTeXUnit(..), LaTeX, MathType(Dollar))\nimport Data.Text (Text, replace)\nimport qualified Data.Text as Text\nimport qualified Data.List as List\nimport Data.IntMap (IntMap)\nimport Prelude hiding (take, (.), takeWhile, (++), lookup, readFile)\nimport Data.Map (Map)\nimport qualified Data.Map as Map\nimport Data.String (IsString)\nimport Util ((.), (++), greekAlphabet)\n\n-- Document structure:\n\ndata CellSpan = Normal | Multicolumn { width :: Int, colspec :: ColumnSpec } deriving (Eq, Show)\ndata Cell a = Cell { cellSpan :: CellSpan, content :: a } deriving (Eq, Show)\ndata RowSepKind = RowSep | CapSep | Clines [(Int, Int)] | NoSep deriving (Eq, Show)\ndata Row a = Row { rowSep :: RowSepKind, cells :: [Cell a] } deriving (Eq, Show)\n\ndata TextAlignment = AlignLeft | AlignRight | AlignCenter | Justify\n\tderiving Eq\n\ninstance Show TextAlignment where\n\tshow AlignLeft = \"left\"\n\tshow AlignRight = \"right\"\n\tshow AlignCenter = \"center\"\n\tshow Justify = \"justify\"\n\ndata ColumnSpec = ColumnSpec\n\t{ columnAlignment :: TextAlignment\n\t, columnBorder :: Bool\n\t, columnWidth :: Maybe Text}\n\tderiving (Eq, Show)\n\ndata Table = Table\n\t{ tableNumber :: Int\n\t, tableCaption :: LaTeX\n\t, columnSpec :: [ColumnSpec]\n\t, tableAbbr :: Abbreviation\n\t, tableBody :: [Row [TeXPara]]\n\t, tableSection :: Section }\n\ninstance Show Table where\n\tshow _ = \"<table>\"\n\ndata Figure = Figure\n\t{ figureNumber :: Int\n\t, figureName :: LaTeX\n\t, figureAbbr :: Abbreviation\n\t, figureSvg :: Text\n\t, figureSection :: Section }\n\ninstance Show Figure where\n\tshow _ = \"<figure>\"\n\ndata Formula = Formula\n    { formulaNumber :: Int\n    , formulaAbbr :: Abbreviation\n    , formulaContent :: LaTeX\n    , formulaSection :: Section }\n\ninstance Show Formula where\n    show _ = \"<formula>\"\n\ndata Item = Item\n\t{ itemNumber :: Maybe [String]\n\t, itemLabel :: Maybe LaTeX\n\t, itemInlineContent :: [Element]\n\t, itemBlockContent :: [TeXPara] }\n\tderiving Show\n\nitemElements :: Item -> [Element]\nitemElements Item{..} = itemInlineContent ++ allElements itemBlockContent\n\ndata Footnote = Footnote\n\t{ footnoteNumber :: Int\n\t, footnoteContent :: [TeXPara] }\n\tderiving Show\n\ndata Note = Note { noteNumber :: Int, noteLabel :: Text, noteContent :: [TeXPara] }\n\tderiving Show\n\ndata Example = Example { exampleNumber :: Int, exampleContent :: [TeXPara] }\n\tderiving Show\n\ndata Sentence = Sentence { sentenceNumber :: Maybe Int, sentenceElems :: [Element] }\n\tderiving Show\n\nnewtype TeXPara = TeXPara { sentences :: [Sentence] }\n\tderiving Show\n\ndata Element\n\t= LatexElement LaTeXUnit\n\t| Enumerated { enumCmd :: String, enumItems :: [Item] }\n\t| Bnf String LaTeX\n\t| TableElement Table\n\t| Tabbing LaTeX\n\t| FigureElement Figure\n\t| FormulaElement Formula\n\t| Codeblock LaTeXUnit\n\t| Itemdescr [TeXPara] -- needed because there can be notes in itemdescr envs\n\t| NoteElement Note\n\t| ExampleElement Example\n\t| HtmlElement Text\n\tderiving Show\n\nnormative :: Element -> Bool\nnormative (NoteElement _) = False\nnormative (ExampleElement _) = False\nnormative (LatexElement (TeXComm \"index\" _ _)) = False\nnormative _ = True\n\ndata SectionKind\n\t= NormalSection { _level :: Int }\n\t| DefinitionSection { _level :: Int }\n\t| InformativeAnnexSection\n\t| NormativeAnnexSection\n\tderiving (Eq, Show)\n\nisDefinitionSection :: SectionKind -> Bool\nisDefinitionSection (DefinitionSection _) = True\nisDefinitionSection _ = False\n\ndata Chapter = NormalChapter | InformativeAnnex | NormativeAnnex\n\tderiving (Eq, Show)\n\ndata SourceLocation = SourceLocation\n\t{ sourceFile :: FilePath\n\t, sourceLine :: Int }\n\tderiving (Eq, Show)\n\ndata Paragraph = Paragraph\n\t{ paraNumber :: Maybe Int\n\t, paraInItemdescr :: Bool\n\t, paraElems :: [TeXPara]\n\t, paraSection :: Section\n\t, paraSourceLoc :: Maybe SourceLocation\n\t, allParaElems :: [Element] } -- derivable but stored for efficiency\n\tderiving Show\n\ntype Abbreviation = Text -- of a section, figure, or table\n\ndata Section = Section\n\t{ abbreviation :: Abbreviation\n\t, sectionName :: LaTeX\n\t, paragraphs :: [Paragraph]\n\t, sectionFootnotes :: [Footnote]\n\t, subsections :: [Section]\n\t, sectionNumber :: Int\n\t, chapter :: Chapter\n\t, parents :: [Section] -- if empty, this is the chapter\n\t, sectionKind :: SectionKind\n\t, secIndexEntries :: IntMap IndexEntry\n\t, secIndexEntriesByPath :: Map IndexPath [(Int, IndexEntry)]\n\t}\n\tderiving Show\n\nchapterOfSection :: Section -> Section\nchapterOfSection s@Section{..}\n    | null parents = s\n    | otherwise = last parents\n\ninstance Eq Section where\n\tx == y = abbreviation x == abbreviation y\n\ntype XrefDelta = [(Abbreviation, [LaTeX])]\n\ndata StablyNamedItem\n\t= StablyNamedTable Table\n\t| StablyNamedSection Section\n\t| StablyNamedFigure Figure\n\t| StablyNamedFormula Formula\n\ndata Draft = Draft\n\t{ commitUrl :: Text\n\t, chapters  :: [Section]\n\t, index     :: Index\n\t, indexEntryMap :: IntMap IndexEntry\n\t, indexEntriesByPath :: Map IndexPath [(Int, IndexEntry)]\n\t, xrefDelta :: XrefDelta\n\t, abbrMap :: Abbreviation -> Maybe StablyNamedItem\n\t, labels :: Map Text Section }\n\n-- (The index entry maps are derivable but stored for efficiency.)\n\nstablyNamedItems :: Draft -> [(Abbreviation, StablyNamedItem)]\nstablyNamedItems d =\n\t[(abbreviation s, StablyNamedSection s) | s <- sections d] ++\n\t[(tableAbbr t, StablyNamedTable t) | p <- allParagraphs d, TableElement t <- allParaElems p] ++\n\t[(formulaAbbr f, StablyNamedFormula f) | p <- allParagraphs d, FormulaElement f <- allParaElems p] ++\n\t[(figureAbbr f, StablyNamedFigure f) | p <- allParagraphs d, FigureElement f <- allParaElems p]\n\nmakeAbbrMap :: Draft -> Abbreviation -> Maybe StablyNamedItem\nmakeAbbrMap = flip Map.lookup . Map.fromList . stablyNamedItems\n\n-- Indices:\n\ndata IndexComponent = IndexComponent { distinctIndexSortKey, indexKey :: LaTeX }\n\tderiving (Ord, Show)\n\ninstance Eq IndexComponent where\n\tx == y =\n\t\tdistinctIndexSortKey x == distinctIndexSortKey y &&\n\t\tindexKeyContent (indexKey x) == indexKeyContent (indexKey y)\n\ntype IndexPath = [IndexComponent]\n\ndata IndexKind = See { _also :: Bool, _ref :: LaTeX } | IndexOpen | IndexClose | DefinitionIndexEntry\n\tderiving (Eq, Show)\n\ntype IndexCategory = Text\n\ntype Index = Map IndexCategory IndexTree\n\ninstance Show IndexEntry where\n\tshow IndexEntry{..} =\n\t\t\"IndexEntry\"\n\t\t++ \"{indexSection=\" ++ show indexEntrySection\n\t\t++ \",indexCategory=\" ++ show indexCategory\n\t\t++ \",indexPath=\" ++ show indexPath\n\t\t++ \",indexEntryKind=\" ++ show indexEntryKind\n\t\t++ \"}\"\n\ndata IndexEntry = IndexEntry\n\t{ indexEntrySection :: Abbreviation\n\t, indexEntryKind :: Maybe IndexKind\n\t, indexPath :: IndexPath\n\t, indexEntryNr :: Maybe Int\n\t, indexCategory :: Text\n\t}\n\ntype IndexTree = Map IndexComponent IndexNode\n\ndata IndexNode = IndexNode\n\t{ indexEntries :: [IndexEntry]\n\t, indexSubnodes :: IndexTree }\n\nmergeIndices :: [Index] -> Index\nmergeIndices = Map.unionsWith (Map.unionWith mergeIndexNodes)\n\nmergeIndexNodes :: IndexNode -> IndexNode -> IndexNode\nmergeIndexNodes x y = IndexNode\n\t{ indexEntries = indexEntries x ++ indexEntries y\n\t, indexSubnodes = Map.unionWith mergeIndexNodes (indexSubnodes x) (indexSubnodes y) }\n\nindexKeyContent :: LaTeX -> Text\nindexKeyContent = mconcat . map ikc\n\twhere\n\t\tikc :: LaTeXUnit -> Text\n\t\tikc (TeXRaw t) = replace \"\\n\" \" \" t\n\t\tikc (TeXComm \"tcode\" _ [(_, x)]) = indexKeyContent x\n\t\tikc (TeXComm \"idxcode\" _ [(_, x)]) = indexKeyContent x\n\t\tikc (TeXComm \"noncxxtcode\" _ [(_, x)]) = indexKeyContent x\n\t\tikc (TeXComm \"indexedspan\" _ [(_, x), _]) = indexKeyContent x\n\t\tikc (TeXComm \"text\" _ [(_, x)]) = indexKeyContent x\n\t\tikc (TeXComm \"texttt\" _ [(_, x)]) = indexKeyContent x\n\t\tikc (TeXComm \"textit\" _ [(_, x)]) = indexKeyContent x\n\t\tikc (TeXComm \"textsc\" _ [(_, x)]) = indexKeyContent x\n\t\tikc (TeXComm \"mathsf\" _ [(_, x)]) = indexKeyContent x\n\t\tikc (TeXComm \"textsf\" _ [(_, x)]) = indexKeyContent x\n\t\tikc (TeXComm \"textcolor\" _ [_, (_, x)]) = indexKeyContent x\n\t\tikc (TeXComm \"xspace\" _ []) = \"_\"\n\t\tikc (TeXComm \"Cpp\" _ []) = \"C++\"\n\t\tikc (TeXComm \"&\" _ []) = \"&\"\n\t\tikc (TeXComm \"%\" _ []) = \"%\"\n\t\tikc (TeXComm \"-\" _ []) = \"\"\n\t\tikc (TeXComm \"ell\" _ []) = \"ℓ\"\n\t\tikc (TeXComm \"~\" _ []) = \"~\"\n\t\tikc (TeXComm \"#\" _ []) = \"#\"\n\t\tikc (TeXComm \"{\" _ []) = \"{\"\n\t\tikc (TeXComm \"}\" _ []) = \"}\"\n\t\tikc (TeXComm \"protect\" _ []) = \"\"\n\t\tikc (TeXComm \"frenchspacing\" _ []) = \"\"\n\t\tikc (TeXComm \"caret\" _ []) = \"^\"\n\t\tikc (TeXComm \"tilde\" _ []) = \"~\"\n\t\tikc (TeXComm \"^\" _ []) = \"^\"\n\t\tikc (TeXComm \"\\\"\" _ []) = \"\\\"\"\n\t\tikc (TeXComm \"\" _ []) = \"\"\n\t\tikc (TeXComm \"x\" _ []) = \"TODO\"\n\t\tikc (TeXComm \"textbackslash\" _ []) = \"\\\\\"\n\t\tikc (TeXComm \"textunderscore\" _ []) = \"_\"\n\t\tikc (TeXComm \"discretionary\" _ _) = \"\"\n\t\tikc (TeXComm \"texorpdfstring\" _ [_, (_, x)]) = indexKeyContent x\n\t\tikc (TeXComm s _ [])\n\t\t\t| Just c <- List.lookup s greekAlphabet = Text.pack [c]\n\t\tikc (TeXBraces x) = indexKeyContent x\n\t\tikc (TeXMath Dollar x) = indexKeyContent x\n\t\tikc (TeXComm \"index\" _ _) = \"\"\n\t\tikc (TeXComm \"indexlink\" _ ((_, x):_)) = indexKeyContent x\n\t\tikc (TeXComm \"hiddenindexlink\" _ ((_, x):_)) = indexKeyContent x\n\t\tikc x = error $ \"indexKeyContent: unexpected: \" ++ show x\n\nindexCatName :: (Eq b, Show b, IsString a, IsString b) => b -> a\nindexCatName \"impldefindex\" = \"Index of implementation-defined behavior\"\nindexCatName \"libraryindex\" = \"Index of library names\"\nindexCatName \"headerindex\" = \"Index of library headers\"\nindexCatName \"generalindex\" = \"Index\"\nindexCatName \"grammarindex\" = \"Index of grammar productions\"\nindexCatName \"conceptindex\" = \"Index of library concepts\"\nindexCatName \"bibliography\" = \"Bibliography\"\nindexCatName x = error $ \"indexCatName: \" ++ show x\n\n-- Gathering entities:\n\nclass Sections a where sections :: a -> [Section]\n\ninstance Sections Section where sections s = s : (subsections s >>= sections)\ninstance Sections Draft where sections = concatMap sections . chapters\ninstance Sections a => Sections (Maybe a) where sections = maybe [] sections\n\nallParagraphs :: Sections a => a -> [Paragraph]\nallParagraphs = (>>= paragraphs) . sections\n\ntables :: Sections a => a -> [(Paragraph, Table)]\ntables x = [(p, t) | p <- allParagraphs x, TableElement t <- allParaElems p]\n\nfigures :: Sections a => a -> [(Paragraph, Figure)]\nfigures x = [(p, f) | p <- allParagraphs x, FigureElement f <- allParaElems p]\n\nformulas :: Sections a => a -> [(Paragraph, Formula)]\nformulas x = [(p, f) | p <- allParagraphs x, FormulaElement f <- allParaElems p]\n\nfootnotes :: Sections a => a -> [(Section, Footnote)]\nfootnotes x = [(s, f) | s <- sections x, f <- sectionFootnotes s]\n\nallElements :: [TeXPara] -> [Element]\nallElements x = x >>= sentences >>= sentenceElems >>= f\n\twhere\n\t\tf :: Element -> [Element]\n\t\tf e = e : case e of\n\t\t\tEnumerated {..} -> enumItems >>= itemElements\n\t\t\tTableElement Table{..} -> allElements $ tableBody >>= cells >>= content\n\t\t\tNoteElement Note{..} -> allElements noteContent\n\t\t\tCodeblock y -> [LatexElement y]\n\t\t\tExampleElement Example{..} -> allElements exampleContent\n\t\t\tTabbing y -> LatexElement . y\n\t\t\tBnf _ y -> LatexElement . y\n\t\t\t_ -> []\n\n-- Misc:\n\ntexParaElems :: TeXPara -> [Element]\ntexParaElems = (>>= sentenceElems) . sentences\n\ntexParaTex :: TeXPara -> LaTeX\ntexParaTex = (>>= elemTex) . texParaElems\n\nitemTex :: Item -> LaTeX\nitemTex Item{..} = (itemInlineContent >>= elemTex) ++ (itemBlockContent >>= texParaTex)\n\nelemTex :: Element -> LaTeX\nelemTex (NoteElement n) = noteContent n >>= texParaTex\nelemTex (ExampleElement x) = exampleContent x >>= texParaTex\nelemTex (LatexElement l) = [l]\nelemTex (Enumerated _ e) = e >>= itemTex\nelemTex (Bnf _ l) = l\nelemTex (Tabbing t) = t\nelemTex (Codeblock t) = [t]\nelemTex (Itemdescr t) = t >>= texParaTex\nelemTex (TableElement Table{..}) = tableCaption ++ (tableBody >>= rowTex)\n\twhere\n\t\trowTex :: Row [TeXPara] -> LaTeX\n\t\trowTex r = content . cells r >>= (>>= texParaTex)\nelemTex (FigureElement _) = []\nelemTex (FormulaElement f) = formulaContent f\nelemTex (HtmlElement _) = []\n\ntableByAbbr :: Draft -> Abbreviation -> Maybe Table\n\t-- only returns Maybe because some of our tables are broken\ntableByAbbr d a = case abbrMap d a of\n\tJust (StablyNamedTable t) -> Just t\n\t_ -> Nothing\n\nfigureByAbbr :: Draft -> Abbreviation -> Figure\nfigureByAbbr d a = case abbrMap d a of\n\tJust (StablyNamedFigure f) -> f\n\t_ -> error $ \"figureByAbbr: \" ++ show a\n\nformulaByAbbr :: Draft -> Abbreviation -> Formula\nformulaByAbbr d a = case abbrMap d a of\n\tJust (StablyNamedFormula f) -> f\n\t_ -> error $ \"formulaByAbbr: \" ++ show a\n\nsectionByAbbr :: Draft -> Abbreviation -> Maybe Section\nsectionByAbbr d a = case abbrMap d a of\n\tJust (StablyNamedSection s) -> Just s\n\t_ -> Nothing\n"
  },
  {
    "path": "LICENSE",
    "content": "All authors involved in the creation of the contents of this package have agreed to release their respective contributions into the Public Domain.\n"
  },
  {
    "path": "LaTeXBase.hs",
    "content": "{-# LANGUAGE ViewPatterns, OverloadedStrings #-}\n\nmodule LaTeXBase\n ( MathType(..), LaTeXUnit(..), LaTeX, TeXArg, ArgKind(..), concatRaws, hasCommand, isJustRaw\n , matchCommand, lookForCommand, matchEnv, mapTeX, mapCommandName, renderLaTeX, mapTeXRaw, isTeXEnv, texSpan, unconsRaw\n , trim, trimr, triml, texStripInfix, isCodeblock, isMath, texStripPrefix, texStripAnyPrefix, AllUnits(..) ) where\n\nimport Data.String (fromString)\nimport Prelude hiding ((.), (++), writeFile, dropWhile)\nimport Data.Text (Text, pack)\nimport qualified Data.Text as Text\nimport Data.Char (isSpace)\nimport Util ((.), (++), textStripInfix)\nimport Control.Arrow (first, second)\n\ndata MathType = Parentheses | Square | Dollar\n\tderiving (Eq, Show, Ord)\n\ndata ArgKind = FixArg | OptArg\n\tderiving (Eq, Show, Ord)\n\ntype TeXArg = (ArgKind, LaTeX)\n\ndata LaTeXUnit\n\t= TeXRaw Text\n\t| TeXComm String String [TeXArg] -- first string is command name, second is trailing whitespace\n\t| TeXEnv String [TeXArg] LaTeX\n\t| TeXMath MathType LaTeX\n\t| TeXLineBreak\n\t| TeXBraces LaTeX\n\tderiving (Eq, Show, Ord)\n\nisTeXEnv :: String -> LaTeXUnit -> Bool\nisTeXEnv x (TeXEnv y _ _) = x == y\nisTeXEnv _ _ = False\n\ntype LaTeX = [LaTeXUnit]\n\nlookForCommand :: String -> LaTeX -> [[TeXArg]]\nlookForCommand n = (snd .) . matchCommand (n ==)\n\nclass AllUnits a where\n\tallUnits :: a -> [LaTeXUnit]\n\ninstance AllUnits LaTeXUnit where\n\tallUnits u = u : case u of\n\t\tTeXMath _ l -> allUnits l\n\t\tTeXBraces l -> allUnits l\n\t\tTeXComm _ _ a -> (snd . a) >>= allUnits\n\t\tTeXEnv _ a l -> (l : snd . a) >>= allUnits\n\t\t_ -> []\n\ninstance AllUnits a => AllUnits [a] where\n\tallUnits = concatMap allUnits\n\nmatchCommand :: AllUnits a => (String -> Bool) -> a -> [(String, [TeXArg])]\nmatchCommand f x = [(str, as) | TeXComm str _ as <- allUnits x, f str]\n\nhasCommand :: (String -> Bool) -> LaTeX -> Bool\nhasCommand f = not . null . matchCommand f\n\nmatchEnv :: AllUnits a => (String -> Bool) -> a -> [(String, [TeXArg], LaTeX)]\nmatchEnv f x = [(str, as, l) | TeXEnv str as l <- allUnits x, f str]\n\nmapTeX :: (LaTeXUnit -> Maybe LaTeX) -> LaTeX -> LaTeX\nmapTeX f = concatMap g\n\twhere\n\t\tg :: LaTeXUnit -> LaTeX\n\t\tg (f -> Just x) = x\n\t\tg (TeXComm c ws a) = [TeXComm c ws (h . a)]\n\t\tg (TeXBraces x) = [TeXBraces (mapTeX f x)]\n\t\tg (TeXMath t b) = [TeXMath t (mapTeX f b)]\n\t\tg (TeXEnv n a b) = [TeXEnv n (h . a) (mapTeX f b)]\n\t\tg x = [x]\n\t\th = second (mapTeX f)\n\nmapCommandName :: (String -> String) -> LaTeX -> LaTeX\nmapCommandName f = concatMap g\n\twhere\n\t\tg :: LaTeXUnit -> LaTeX\n\t\tg (TeXComm c ws a) = [TeXComm (f c) ws (h . a)]\n\t\tg (TeXBraces x) = [TeXBraces (mapCommandName f x)]\n\t\tg (TeXMath t b) = [TeXMath t (mapCommandName f b)]\n\t\tg (TeXEnv n a b) = [TeXEnv n (h . a) (mapCommandName f b)]\n\t\tg x = [x]\n\t\th = second (mapCommandName f)\n\nrenderLaTeX :: LaTeX -> Text\nrenderLaTeX = mconcat . (renderUnit .)\n\nrenderUnit :: LaTeXUnit -> Text\nrenderUnit (TeXRaw t) = t\nrenderUnit (TeXComm \"right\" _ [(FixArg, [TeXRaw \".\"])]) = \"\\\\right.\"\nrenderUnit (TeXComm name ws [])\n\t| name `elem` [\"left\", \"sum\", \"int\", \"sin\", \"cos\", \"right\", \"bigl\", \"bigr\", \"big\", \"small\", \"smaller\"] = pack $ \"\\\\\" <> name <> ws\n\t| otherwise = \"\\\\\" <> fromString name <> \"{}\"\nrenderUnit (TeXComm name ws args) = \"\\\\\" <> pack (fromString name) <> pack (fromString ws) <> renderArgs args\nrenderUnit (TeXEnv name args c) =\n\t\"\\\\begin{\" <> fromString name <> \"}\"\n\t<> renderArgs args\n\t<> renderLaTeX c\n\t<> \"\\\\end{\" <> fromString name <> \"}\"\nrenderUnit (TeXMath Dollar l) = \"$\" <> renderLaTeX l <> \"$\"\nrenderUnit (TeXMath Square l) = \"\\\\[\" <> renderLaTeX l <> \"\\\\]\"\nrenderUnit (TeXMath Parentheses l) = \"\\\\(\" <> renderLaTeX l <> \"\\\\)\"\nrenderUnit TeXLineBreak = \"\\\\\\\\\"\nrenderUnit (TeXBraces l) = \"{\" <> renderLaTeX l <> \"}\"\n\nrenderArgs :: [TeXArg] -> Text\nrenderArgs = mconcat . (renderArg .)\n\nrenderArg :: TeXArg -> Text\nrenderArg (FixArg, l) = \"{\" <> renderLaTeX l <> \"}\"\nrenderArg (OptArg, l) = \"[\" <> renderLaTeX l <> \"]\"\n\nmapTeXRaw :: (Text -> LaTeXUnit) -> (LaTeX -> LaTeX)\nmapTeXRaw f = map go\n\twhere\n\t\tgo :: LaTeXUnit -> LaTeXUnit\n\t\tgo (TeXRaw t) = f t\n\t\tgo (TeXComm s ws args) = TeXComm s ws (second (go .) . args)\n\t\tgo (TeXEnv s args body) = TeXEnv s (second (go .) . args) (go . body)\n\t\tgo (TeXBraces l) = TeXBraces $ go . l\n\t\tgo t@(TeXMath _ _) = t\n\t\tgo t@TeXLineBreak = t\n\nconcatRaws :: LaTeX -> LaTeX\nconcatRaws (TeXRaw a : TeXRaw b : more) = concatRaws (TeXRaw (a ++ b) : more)\nconcatRaws (TeXComm s ws args : more) = TeXComm s ws (second concatRaws . args) : concatRaws more\nconcatRaws (TeXEnv s args bd : more) = TeXEnv s (second concatRaws . args) (concatRaws bd) : concatRaws more\nconcatRaws (TeXBraces x : more) = TeXBraces (concatRaws x) : concatRaws more\nconcatRaws (x : more) = x : concatRaws more\nconcatRaws [] = []\n\nunconsRaw :: LaTeX -> (Text, LaTeX)\nunconsRaw (TeXRaw x : y) = first (x ++) (unconsRaw y)\nunconsRaw x = (\"\", x)\n\ntexStripPrefix :: Text -> LaTeX -> Maybe LaTeX\ntexStripPrefix t (TeXRaw s : y) = case Text.stripPrefix t s of\n\tJust \"\" -> Just y\n\tJust s' -> Just (TeXRaw s' : y)\n\tNothing -> Nothing\ntexStripPrefix _ _ = Nothing\n\ntexStripAnyPrefix :: [Text] -> LaTeX -> Maybe (Text, LaTeX)\ntexStripAnyPrefix [] _ = Nothing\ntexStripAnyPrefix (x:y) z\n    | Just a <- texStripPrefix x z = Just (x, a)\n    | otherwise = texStripAnyPrefix y z\n\ntexStripInfix :: Text -> LaTeX -> Maybe (LaTeX, LaTeX)\ntexStripInfix t = go\n\twhere\n\t\tgo [] = Nothing\n\t\tgo (x : rest)\n\t\t\t| TeXRaw s <- x\n\t\t\t, Just (y, z) <- textStripInfix t s\n\t\t\t\t= Just (h y, h z ++ rest)\n\t\t\t| otherwise = first (x :) . go rest\n\t\th \"\" = []\n\t\th x = [TeXRaw x]\n\ntexSpan :: (Char -> Bool) -> LaTeX -> (Text, LaTeX)\ntexSpan p (TeXRaw x : y) = case Text.span p x of\n    (stuff, \"\") ->  first (stuff ++) (texSpan p y)\n    (stuff, rest) -> (stuff, TeXRaw rest : y)\ntexSpan _ x = (\"\", x)\n\ninvisible :: LaTeXUnit -> Bool\ninvisible (TeXComm \"index\" _ _) = True\ninvisible _ = False\n\ndropWhileEnd :: (Char -> Bool) -> LaTeX -> LaTeX\ndropWhileEnd _ [] = []\ndropWhileEnd p x\n\t| invisible (last x) = dropWhileEnd p (init x) ++ [last x]\n\t| TeXRaw y <- last x = init x ++ case Text.dropWhileEnd p y of\n\t\t\"\" -> []\n\t\ta -> [TeXRaw a]\n\t| otherwise = x\n\ntrimr, trim :: LaTeX -> LaTeX\ntrimr = dropWhileEnd isSpace\ntrim = triml . trimr\n\ntriml :: LaTeX -> LaTeX\ntriml (TeXRaw x : y) = case Text.dropWhile isSpace x of\n\t\"\" -> triml y\n\tx' -> TeXRaw x' : y\ntriml x = x\n\nisMath :: LaTeXUnit -> Bool\nisMath (TeXMath _ _) = True\nisMath (TeXComm \"ensuremath\" _ _) = True\nisMath (TeXEnv \"eqnarray*\" _ _) = True\nisMath (TeXEnv \"equation*\" _ _) = True\nisMath _ = False\n\nisCodeblock :: LaTeXUnit -> Bool\nisCodeblock (TeXEnv \"codeblock\" _ _) = True\nisCodeblock (TeXEnv \"indexedcodeblock\" _ _) = True\nisCodeblock (TeXEnv \"codeblocktu\" _ _) = True\nisCodeblock (TeXEnv \"codeblockdigitsep\" _ _) = True\nisCodeblock _ = False\n\nisJustRaw :: LaTeX -> Maybe Text\nisJustRaw [TeXRaw x] = Just x\nisJustRaw _ = Nothing\n"
  },
  {
    "path": "LaTeXParser.hs",
    "content": "{-# OPTIONS_GHC -fno-warn-tabs #-}\n{-# LANGUAGE OverloadedStrings, RecordWildCards, ViewPatterns, TupleSections #-}\n\nmodule LaTeXParser (parseString,\n\tToken(Token), Context(..), defaultContext, Signature(..), Macros(..), Environment(..), Command(..), ParseResult(ParseResult),\n\tdefaultMacros,\n\tnullCmd, storeCmd, codeEnv, normalCmd,\n\tstoreEnv) where\n\nimport LaTeXBase (LaTeXUnit(..), LaTeX, TeXArg, ArgKind(..), MathType(..), concatRaws)\nimport Data.Text (Text)\nimport qualified Data.Text as Text\nimport Data.Char (isAlphaNum, isSpace, isAlpha)\nimport Data.Maybe (fromJust)\nimport Control.Arrow (first)\nimport Data.Map (Map)\nimport qualified Data.Map as Map\nimport Prelude hiding ((++), (.))\nimport Util ((.), (++), getDigit, stripInfix)\n\nnewtype Token = Token { tokenChars :: String }\n\tderiving (Eq, Show)\n\ndata Environment = Environment (Context -> [Token] -> ParseResult)\ndata Command = Command { runCommand :: Context -> String {- ws -} -> [Token] -> ParseResult }\n\ndata Macros = Macros\n\t{ commands :: Map Text Command\n\t, environments :: Map Text Environment\n\t, counters :: Map Text Int }\n\nnewCommand :: Bool {- overwrite -} -> (Text, Command) -> Macros -> Macros\nnewCommand True (name, cmd) Macros{..} = Macros{commands = Map.insert name cmd commands, ..}\nnewCommand False (name, cmd) Macros{..} = Macros{commands = Map.insertWith (\\_ y -> y) name cmd commands, ..}\n\ninstance Semigroup Macros where\n\tx <> y = Macros\n\t\t(commands x ++ commands y)\n\t\t(environments x ++ environments y)\n\t\t(counters x ++ counters y)\n\ninstance Monoid Macros where\n\tmempty = Macros mempty mempty mempty\n\ndata ParseResult = ParseResult\n\t{ content :: LaTeX\n\t, newMacros :: Macros\n\t, remainder :: [Token] }\n\ndata Signature = Signature\n\t{ nrFixArgs :: Int\n\t, defaultArg :: Maybe [Token] }\n\tderiving Show\n\ndata Context = Context\n\t{ commentsEnabled :: Bool\n\t, parsingOptArg :: Bool\n\t, macros :: Macros }\n\nprependContent :: LaTeX -> ParseResult -> ParseResult\nprependContent t p = p{content = t ++ content p}\n\ncombineMacros :: Bool {- left biased -} -> Macros -> Macros -> Macros\ncombineMacros b x y = if b then x ++ y else y ++ x\n\naddMacros :: Bool {- overwrite -} -> Macros -> ParseResult -> ParseResult\naddMacros b m p = p{newMacros = combineMacros b m (newMacros p)}\n\ndefaultEnvs :: [(Text, Environment)]\ndefaultEnvs = [outputblockEnv]\n\ncodeEnv :: Text -> Signature -> (Text, Environment)\ncodeEnv name sig = (name, Environment f)\n\twhere\n\t\tf :: Context -> [Token] -> ParseResult\n\t\tf ctx toks = ParseResult [env] mempty rest'\n\t\t\twhere\n\t\t\t\t(arguments, rest) = parseArgs sig toks\n\t\t\t\tJust (code, rest') = stripInfix [Token \"\\\\end\", Token \"{\", Token (Text.unpack name), Token \"}\"] rest\n\t\t\t\tenv = TeXEnv (Text.unpack name) (map ((FixArg, ) . fullParse ctx) arguments) (parseCode name ctx code)\n\noutputblockEnv :: (Text, Environment)\noutputblockEnv = (\"outputblock\", Environment f)\n\twhere\n\t\tf :: Context -> [Token] -> ParseResult\n\t\tf ctx toks = ParseResult [env] mempty rest\n\t\t\twhere\n\t\t\t\tJust (content, rest) = stripInfix [Token \"\\\\end\", Token \"{\", Token \"outputblock\", Token \"}\"] toks\n\t\t\t\tenv = TeXEnv \"outputblock\" [] (parseOutputBlock ctx content)\n\nparseOutputBlock :: Context -> [Token] -> LaTeX\nparseOutputBlock c = concatRaws . go\n\twhere\n\t\tgo :: [Token] -> LaTeX\n\t\tgo [] = []\n\t\tgo (Token \"@\" : rest) = fullParse c cmd ++ go rest'\n\t\t\twhere (cmd, Token \"@\" : rest') = break (== Token \"@\") rest\n\t\tgo s = TeXRaw (Text.pack $ concatMap tokenChars code) : go rest\n\t\t\twhere (code, rest) = break (== Token \"@\") s\n\nstoreEnv :: String -> Signature -> (Text, Environment)\nstoreEnv name sig = (Text.pack name, Environment act)\n\twhere\n\t\tact :: Context -> [Token] -> ParseResult\n\t\tact ctx toks = ParseResult [env] mempty afterend\n\t\t\twhere\n\t\t\t\t(arguments, rest) = parseArgs sig toks\n\t\t\t\tParseResult body _ afterend = parse ctx rest\n\t\t\t\tenv = TeXEnv name (map ((FixArg, ) . fullParse ctx) arguments) (concatRaws body)\n\t\t\t\t\t\t\t-- todo: not all fixargs\n\ndefaultCmds :: [(Text, Command)]\ndefaultCmds =\n\t[ (\"newcommand\", newCommandCommand)\n\t, (\"renewcommand\", newCommandCommand)\n\t, (\"DeclareMathOperator\", declareMathOperator)\n\t, (\"newcolumntype\", newColumnTypeCommand)\n\t, (\"newenvironment\", newEnvCommand)\n\t, (\"lstnewenvironment\", newEnvCommand)\n\t, (\"raisebox\", raiseBoxCommand)\n\t, (\"let\", Command $ \\ctx _ws rest -> parse ctx (drop 2 rest))\n\t, beginCommand\n\t, endCommand\n\t, oldDefCommand\n\t]\n\noldDefCommand :: (Text, Command)\noldDefCommand = (\"def\", Command pars)\n\twhere\n\t\tpars ctx@Context{..} _ws rest\n\t\t\t| (Token ('\\\\' : name) : rest') <- rest\n\t\t\t, Just (body, rest'') <- balanced ('{', '}') rest' =\n\t\t\t\tlet\n\t\t\t\t\tm = Macros (Map.fromList [defCmd (Text.pack name) (Signature 0 Nothing) body]) mempty mempty\n\t\t\t\t\tParseResult p mm r = parse ctx{macros=macros++m} rest''\n\t\t\t\tin\n\t\t\t\t\tParseResult p (m ++ mm) r\n\t\t\t| otherwise = parse ctx $ snd $ fromJust $ balanced ('{', '}') $ dropWhile (/= Token \"{\") rest\n\nendCommand :: (Text, Command)\nendCommand = (\"end\", Command $ \\c _ws rest ->\n\tlet Just (_, rest') = parseFixArg c rest in ParseResult mempty mempty rest')\n\nbeginCommand :: (Text, Command)\nbeginCommand = (\"begin\", normalCmd $ Command pars)\n\twhere\n\t\tpars c@Context{..} _ws rest\n\t\t\t| Just (Environment f) <- Map.lookup (envname) (environments macros) = f c rest'\n\t\t\t| otherwise = error $ \"undefined env: \" ++ Text.unpack envname\n\t\t\twhere\n\t\t\t\tJust (arg, rest') = parseFixArg c rest\n\t\t\t\t[TeXRaw envname] = concatRaws arg\n\nraiseBoxCommand :: Command\nraiseBoxCommand = normalCmd $ Command $ \\c@Context{..} _ws rest ->\n\tlet\n\t\tJust (a0, rest') = balanced ('{', '}') rest\n\t\t(a1, rest'') = case parseOptArg rest' of\n\t\t\tNothing -> (Nothing, rest')\n\t\t\tJust (x, y) -> (Just x, y)\n\t\tJust (a2, rest''') = balanced ('{', '}') rest''\n\t\targs = [(FixArg, fullParse c a0)]\n\t\t\t++ case a1 of\n\t\t\t\tNothing -> []\n\t\t\t\tJust x -> [(OptArg, fullParse c x)]\n\t\t\t++ [(FixArg, fullParse c a2)]\n\tin\n\t\tParseResult [TeXComm \"raisebox\" \"\" args] mempty rest'''\n\nnewCommandCommand :: Command\nnewCommandCommand = normalCmd $ Command $ \\Context{..} _ws (Token \"{\" : Token ('\\\\' : name) : Token \"}\" : rest) ->\n\tlet\n\t\t(sig, rest') = parseSignature rest\n\t\tJust (body, rest'') = balanced ('{', '}') rest'\n\t\tnewMacros = newCommand True (defCmd (Text.pack name) sig body) mempty\n\tin\n\t\tParseResult [] newMacros rest''\n\ndeclareMathOperator :: Command\ndeclareMathOperator = normalCmd $ Command $ \\Context{..} _ws (Token \"{\" : Token ('\\\\' : name) : Token \"}\" : rest) ->\n\tlet\n\t\tJust (body, rest') = balanced ('{', '}') rest\n\t\tnewBody = [Token \"\\\\operatorname\", Token \"{\"] ++ body ++ [Token \"}\"]\n\t\tnewMacros = newCommand True (defCmd (Text.pack name) (Signature 0 Nothing) newBody) mempty\n\tin\n\t\tParseResult [] newMacros rest'\n\nnewColumnTypeCommand :: Command\nnewColumnTypeCommand = normalCmd $ Command $ \\Context{..} _ws (Token \"{\" : Token _ : Token \"}\" : rest) ->\n\tlet\n\t\t(_, rest') = parseSignature rest\n\t\tJust (_, rest'') = balanced ('{', '}') rest'\n\tin\n\t\tParseResult [] mempty rest''\n\ndefaultMacros :: Macros\ndefaultMacros = Macros (Map.fromList defaultCmds) (Map.fromList defaultEnvs) mempty\n\ndefaultContext :: Context\ndefaultContext = Context\n\t{ commentsEnabled = True\n\t, parsingOptArg = False\n\t, macros = defaultMacros }\n\nrmLine :: [Token] -> [Token]\nrmLine s = case dropWhile (/= Token \"\\n\") s of\n\tToken \"\\n\" : x -> x\n\tx -> x\n\nparseOptArg :: [Token] -> Maybe ([Token], [Token])\nparseOptArg = balanced ('[', ']')\n\nparseOptArgs :: [Token] -> ([[Token]], [Token])\nparseOptArgs s\n\t| Just (r, s') <- parseOptArg s = first (r:) (parseOptArgs s')\n\t| otherwise = ([], s)\n\nparseFixArg :: Context -> [Token] -> Maybe (LaTeX, [Token])\nparseFixArg ctx (Token [c] : more) | isSpace c = parseFixArg ctx more\nparseFixArg ctx (Token \"{\" : more) =\n\tlet ParseResult t _macros s = parse ctx more in Just (t, s)\nparseFixArg _ _ = Nothing\n\nparseSignature :: [Token] -> (Signature, [Token])\nparseSignature t = case optArgs of\n\t[] -> (Signature 0 Nothing, t')\n\t[[Token a]] -> (Signature (read a) Nothing, t')\n\t[[Token a], deflt] -> (Signature (read a) (Just deflt), t')\n\t_ -> error \"unrecognized signature\"\n\twhere (optArgs, t') = parseOptArgs t\n\nbalanced :: (Char, Char) -> [Token] -> Maybe ([Token], [Token])\nbalanced (open, close) (dropWhile (all isSpace . tokenChars) -> (Token [o] : s))\n\t| o == open = Just $ go 0 s\n\twhere\n\t\tgo :: Int -> [Token] -> ([Token], [Token])\n\t\tgo 0 [] = ([], [])\n\t\tgo 0 (Token [c] : x) | c == close = ([], x)\n\t\tgo n (Token \"}\" : x) = first (Token \"}\" :) (go (n-1) x)\n\t\tgo n (Token \"{\" : x) = first (Token \"{\" :) (go (n+1) x)\n\t\tgo n (x:y) = first (x :) (go n y)\n\t\tgo n x = error $ \"\\n\\nbalanced: \" ++ show (n, x)\nbalanced oc (dropWhile (all isSpace. tokenChars) -> (Token \"%\" : x)) = balanced oc (dropWhile (/= Token \"\\n\") x)\nbalanced _ _ = Nothing\n\nbalanced_body :: Context -> String -> [Token] -> ([Token], [Token])\nbalanced_body ctx end = go 0\n\twhere\n\t\tgo :: Int -> [Token] -> ([Token], [Token])\n\t\tgo 0 [] = ([], [])\n\t\tgo 0 (Token \"\\\\end\" : Token \"{\" : e : Token \"}\" : x) | fullParse ctx [e] == [TeXRaw $ Text.pack end] = ([], x)\n\t\tgo n (Token \"}\" : x) = first (Token \"}\" :) (go (n-1) x)\n\t\tgo n (Token \"{\" : x) = first (Token \"{\" :) (go (n+1) x)\n\t\tgo n (x:y) = first (x :) (go n y)\n\t\tgo n s = error $ \"\\n\\nbalanced: \" ++ show (n, s)\n\nparseArgs :: Signature -> [Token] -> ([[Token]], [Token])\nparseArgs Signature{..} s = case defaultArg of\n\tNothing -> n_balanced ('{', '}') nrFixArgs s\n\tJust dfl -> case parseOptArg s of\n\t\tNothing ->\n\t\t\tfirst (dfl :) (n_balanced ('{', '}') (nrFixArgs - 1) s)\n\t\tJust (optArg, s') ->\n\t\t\tfirst (optArg :) (n_balanced ('{', '}') (nrFixArgs - 1) s')\n\nparseArgs2 :: Context -> Signature -> [Token] -> ([TeXArg], [Token])\nparseArgs2 c Signature{..} s\n\t| defaultArg == Nothing = first (map fa) (n_balanced ('{', '}') nrFixArgs s)\n\t| Just (optArg, s') <- parseOptArg s =\n\t\t\tfirst (\\a -> (OptArg, fullParse c optArg) : map fa a)\n\t\t\t(n_balanced ('{', '}') (nrFixArgs - 1) s')\n\t| otherwise = first (map fa) (n_balanced ('{', '}') (nrFixArgs - 1) s)\n\twhere\n\t\tfa = (FixArg, ) . fullParse c\n\n-- todo: clean up parseArgs/parseArgs2 above\n\nn_balanced :: (Char, Char) -> Int -> [Token] -> ([[Token]], [Token])\nn_balanced oc n s\n\t| n > 0, Just (x, s') <- balanced oc s = first (x:) $ n_balanced oc (n-1) s'\n\t| otherwise = ([], s)\n\nnewEnvCommand :: Command\nnewEnvCommand = normalCmd $ Command $ \\Context{..} _ws (Token \"{\" : (span (/= Token \"}\") -> (name, Token \"}\" : rest))) ->\n\tlet\n\t\tnameStr = concatMap tokenChars name\n\t\t(sig, rest') = parseSignature rest\n\t\tJust (begin, rest'') = balanced ('{', '}') rest'\n\t\tJust (end, rest''') = balanced ('{', '}') rest''\n\t\tpa :: Context -> [Token] -> ParseResult\n\t\tpa c' toks = ParseResult replaced mempty toks''\n\t\t\twhere\n\t\t\t\treplaced = fullParse c' $ replArgs args begin ++ body ++ end\n\t\t\t\t(args, toks') = parseArgs sig toks\n\t\t\t\t(body, toks'') = balanced_body c' nameStr toks'\n\t\tm = Macros mempty (Map.singleton (Text.pack nameStr) (Environment pa)) mempty\n\tin\n\t\tParseResult [] m rest'''\n\nparseString :: Context -> String -> (LaTeX, Macros, [Token])\nparseString c s = (concatRaws x, y, z)\n\twhere ParseResult x y z = parse c (tokenize s)\n\nliteral :: String\nliteral = \" @_{}&,%-#/~>!$;:^\"\n\nbreakComment :: [Token] -> ([Token], [Token])\nbreakComment x@(Token \"\\n\" : _) = ([], x)\nbreakComment (Token ('\\\\' : cmd) : xs)\n\t| (c, r@(_:_)) <- span (/= '\\n') cmd = ([Token ('\\\\':c)], Token r : xs)\nbreakComment (Token \"%\" : Token \"\\n\" : x) = first ((Token \"%\" :) . (Token \"\\n\" :)) (breakComment x)\nbreakComment (x : xs) = first (x:) (breakComment xs)\nbreakComment [] = ([], [])\n\ndata LiteralKind = StringLiteral | CharLiteral\n\nparseCode :: Text -> Context -> [Token] -> LaTeX\nparseCode envname c = concatRaws . go Nothing\n\twhere\n\t\tgo :: Maybe LiteralKind -> [Token] -> LaTeX\n\t\tgo _ [] = []\n\t\tgo b (Token \"@\" : rest) = fullParse c cmd ++ go b rest'\n\t\t\twhere (cmd, Token \"@\" : rest') = break (== Token \"@\") rest\n\t\tgo (Just StringLiteral) (Token \"\\\"\" : rest) = TeXRaw \"\\\"\" : go Nothing rest\n\t\tgo (Just CharLiteral) (Token \"'\" : rest) = TeXRaw \"'\" : go Nothing rest\n\t\tgo Nothing (Token \"\\\"\" : rest) = TeXRaw \"\\\"\" : (go (Just StringLiteral) lit ++ go Nothing rest')\n\t\t\twhere (lit, rest') = stringLiteral rest\n\t\tgo Nothing (Token \"'\" : rest)\n\t\t       | envname == \"codeblockdigitsep\" = TeXRaw \"'\" : go Nothing rest\n\t\t       | otherwise = TeXRaw \"'\" : (go (Just CharLiteral) lit ++ go Nothing rest')\n\t\t       where (lit, rest') = charLiteral rest\n\t\tgo Nothing (Token \"/\" : Token \"/\" : (breakComment -> (comment, rest')))\n\t\t\t= TeXComm \"comment\" \"\" [(FixArg, TeXRaw \"//\" : noncode comment)] : go Nothing rest'\n\t\tgo Nothing (Token \"/\" : Token \"*\" : rest)\n\t\t    | Just (comment, rest') <- stripInfix [Token \"*\", Token \"/\"] rest\n\t\t    = TeXComm \"comment\" \"\" [(FixArg, [TeXRaw \"/*\"] ++ noncode comment ++ [TeXRaw \"*/\"])] : go Nothing rest'\n\t\tgo b (Token \"/\" : rest) = TeXRaw \"/\" : go b rest\n\t\tgo b s = TeXRaw (Text.pack $ concatMap tokenChars code) : go b rest\n\t\t\twhere\n\t\t\t  breakToks = [Token \"@\", Token \"/\"] ++ \n\t\t\t    case b of\n\t\t\t      Nothing -> [Token \"\\\"\", Token \"'\"]\n\t\t\t      Just StringLiteral -> [Token \"\\\"\"]\n\t\t\t      Just CharLiteral -> [Token \"'\"]\n\t\t\t  (code, rest) = break (`elem` breakToks) s\n\t\tnoncode :: [Token] -> LaTeX\n\t\tnoncode toks =\n\t\t  fullParse c nc ++ case more of\n\t\t    [] -> []\n\t\t    Token \"@\" : (break (== Token \"@\") -> (code, _ : rest)) ->\n\t\t        TeXComm \"tcode\" \"\" [(FixArg, fullParse c code)] : noncode rest\n\t\t    _ -> error \"no\"\n\t\t    where (nc, more) = span (/= Token \"@\") toks\n\t\tstringLiteral :: [Token] -> ([Token], [Token])\n\t\tstringLiteral (Token \"\\\\\" : Token \"\\\"\" : x) = first (Token \"\\\\\\\"\" :) (stringLiteral x)\n\t\tstringLiteral (Token \"\\\\\" : Token \"\\\\\" : x) = first (Token \"\\\\\\\\\" :) (stringLiteral x)\n\t\tstringLiteral (Token \"\\\"\" : x) = ([Token \"\\\"\"], x)\n\t\tstringLiteral (y : x) = first (y :) (stringLiteral x)\n\t\tstringLiteral [] = ([], [])\n\t\tcharLiteral :: [Token] -> ([Token], [Token])\n\t\tcharLiteral (Token \"\\\\\" : Token \"'\" : x) = first (Token \"\\\\'\" :) (charLiteral x)\n\t\tcharLiteral (Token \"\\\\\" : Token \"\\\\\" : x) = first (Token \"\\\\\\\\\" :) (charLiteral x)\n\t\tcharLiteral (Token \"'\" : x) = ([Token \"'\"], x)\n\t\tcharLiteral (y : x) = first (y :) (charLiteral x)\n\t\tcharLiteral [] = ([], [])\n\nisCommandChar :: Char -> Bool\nisCommandChar c = isAlpha c || c == '*'\n\ntokenize :: String -> [Token]\ntokenize \"\" = []\ntokenize ('\\\\':'v':'e':'r':'b': delim : (break (== delim) -> (arg, _ : rest))) =\n\tToken (\"\\\\verb:\" ++ arg) : tokenize rest\ntokenize ('\\\\' : (span isCommandChar -> (cmd@(_:_), (span isSpace -> (ws, rest)))))\n\t= Token ('\\\\' : cmd ++ ws) : tokenize rest\ntokenize ('\\\\' : c : rest) = Token ['\\\\', c] : tokenize rest\ntokenize x@((isAlpha -> True): _) = let (a, b) = span isAlphaNum x in Token a : tokenize b\ntokenize (x:y) = Token [x] : tokenize y\n\n\t-- \\verb is handled in tokenize so that the 'balanced' function doesn't\n\t-- get confused by \\verb|{|\n\n\t-- Notice how the whitespace following a command like \\bla is included in the Token\n\t-- This lets the parser include it in the TeXComm/TeXCommS's command field, so that\n\t-- the whitespace is not lost when serializing back to text when sending to MathJax.\n\nreplArgs :: [[Token]] -> [Token] -> [Token]\nreplArgs args = go\n\twhere\n\t\tgo [] = []\n\t\tgo (Token \"%\" : (span (/= Token \"\\n\") -> (x, y))) = Token \"%\" : x ++ go y\n\t\tgo (Token \"#\" : Token \"#\" : y) = Token \"#\" : go y\n\t\tgo (Token \"#\" : Token [getDigit -> Just i] : y)\n\t\t\t| length args >= i = (args !! (i-1)) ++ go y\n\t\t\t| otherwise = error $ \"need more args than \" ++ show args ++ \" to replace in \" ++ show (concatMap tokenChars y)\n\t\tgo (x:y) = x : go y\n\nnullCmd :: Text -> Signature -> (Text, Command)\nnullCmd name sig = defCmd name sig []\n\nstoreCmd :: String -> Signature -> (Text, Command)\nstoreCmd name sig = (Text.pack name, normalCmd $ Command pars)\n\twhere\n\t\tpars context ws tokens = ParseResult [TeXComm name ws args] mempty rest\n\t\t\twhere (args, rest) = parseArgs2 context sig tokens\n\ndefCmd :: Text -> Signature -> [Token] -> (Text, Command)\ndefCmd name sig body = (name, normalCmd $ Command pars)\n\twhere\n\t\tpars context _ws tokens = ParseResult (fullParse context $ replArgs args body) mempty rest\n\t\t\twhere (args, rest) = parseArgs sig tokens\n\nnormalCmd :: Command -> Command\nnormalCmd (Command f) = Command $ \\ctx ws toks ->\n\tlet ParseResult content newMacros rest = f ctx ws toks\n\tin addMacros False newMacros (prependContent content (parse ctx{macros=macros ctx ++ newMacros} rest))\n\nconsumeMath :: [Token] -> ([Token], [Token])\nconsumeMath = f 0\n    where\n        f :: Integer -> [Token] -> ([Token], [Token])\n        f 0 (Token \"$\" : rest) = ([], rest)\n        f depth (Token \"{\" : rest) = first (Token \"{\" :) (f (depth + 1) rest)\n        f depth (Token \"}\" : rest) = first (Token \"}\" :) (f (depth - 1) rest)\n        f depth (tok : rest) = first (tok :) (f depth rest)\n        f _ [] = error \"unexpected end of math\"\n\nparse :: Context -> [Token] -> ParseResult\nparse c (Token \"$\" : (consumeMath -> (math, rest))) =\n\tprependContent [TeXMath Dollar (fullParse c math)] (parse c rest)\nparse c (Token \"\\\\[\" : (span (/= Token \"\\\\]\") -> (math, Token \"\\\\]\" : rest))) =\n\tprependContent [TeXMath Square (fullParse c math)] (parse c rest)\nparse c (Token \"]\" : x)\n\t| parsingOptArg c = ParseResult mempty mempty x\nparse _ (Token \"}\" : x) = ParseResult mempty mempty x\nparse c (Token \"{\" : x) = prependContent [TeXBraces y] $ parse c rest\n\twhere ParseResult y _ rest = parse c x\nparse c (Token \"%\" : x)\n\t| commentsEnabled c = parse c (rmLine x)\nparse _ [] = ParseResult mempty mempty mempty\nparse c (Token \"\\\\\\\\\" : x) = prependContent [TeXLineBreak] (parse c x)\nparse c (Token ['\\\\', ch] : x)\n\t| ch `elem` literal = prependContent [TeXComm [ch] \"\" []] (parse c x)\nparse c (Token ('\\\\':'v':'e':'r':'b':':':arg) : rest) =\n\tprependContent [TeXComm \"verb\" \"\" [(FixArg, [TeXRaw $ Text.pack arg])]] (parse c rest)\nparse c (Token \"\\\\rSec\" : Token [getDigit -> Just i] : s)\n\t\t= prependContent [TeXComm \"rSec\" \"\" args] $ parse c s''\n\twhere\n\t\tJust (a, s') = parseOptArg s\n\t\tJust (b, s'') = parseFixArg c s'\n\t\targs = [(FixArg, [TeXRaw $ Text.pack $ show i]), (FixArg, fullParse c a), (FixArg, b)]\nparse c@Context{..} (Token ('\\\\' : (span (not . isSpace) -> (nos, w))) : rest)\n\t| Just f <- Map.lookup (Text.pack cmd) (commands macros) = runCommand f c ws rest\n\t| otherwise = error $\n\t\t\"\\n\\nundefined command: \" ++ show cmd ++ \" at: \" ++ take 50 (concatMap tokenChars rest)\n\twhere (cmd, ws) | nos == \"\", (x : xx) <- w = ([x], xx)\n\t                | otherwise = (nos, w)\nparse ctx (Token c : rest)\n\t| all isAlphaNum c\n\t\t= prependContent [TeXRaw $ Text.pack c] $ parse ctx rest\nparse ctx (Token [c] : rest)\n\t\t= prependContent [TeXRaw $ Text.pack [c]] $ parse ctx rest\nparse _ s = error $ \"parse: unexpected: \" ++ take 100 (concatMap tokenChars s)\n\nfullParse :: Context -> [Token] -> LaTeX\nfullParse c t\n\t| all isSpace (concatMap tokenChars remainder) = concatRaws content\n\t| otherwise = error $ \"could not fully parse: \"\n\t\t++ concatMap tokenChars t\n\t\t++ \"\\n\\nremainder: \"\n\t\t++ concatMap tokenChars remainder\n\twhere ParseResult{..} = parse c t\n"
  },
  {
    "path": "Load14882.hs",
    "content": "{-# OPTIONS_GHC -fno-warn-tabs #-}\n{-# LANGUAGE\n\tOverloadedStrings,\n\tScopedTypeVariables,\n\tRecordWildCards,\n\tViewPatterns,\n\tLambdaCase,\n\tTupleSections,\n\tNamedFieldPuns,\n\tFlexibleInstances,\n\tFlexibleContexts,\n\tRankNTypes,\n\tMultiParamTypeClasses,\n\tFunctionalDependencies,\n\tUndecidableInstances,\n\tRecursiveDo #-}\n\nmodule Load14882 (parseIndex, load14882) where\n\nimport qualified LaTeXParser as Parser\nimport qualified Data.IntMap as IntMap\nimport qualified Data.List as List\nimport Data.IntMap (IntMap)\nimport LaTeXBase\n\t( LaTeXUnit(..), TeXArg, ArgKind(..), lookForCommand\n\t, mapTeX, mapTeXRaw, concatRaws, texStripInfix, allUnits)\nimport Data.Text (Text, replace, isPrefixOf)\nimport Data.Text.IO (readFile)\nimport Text.Regex (mkRegex, matchRegexAll)\nimport qualified Data.Text as Text\nimport Control.Monad (forM, when)\nimport Prelude hiding (take, (.), takeWhile, (++), lookup, readFile)\nimport Data.Char (isAlpha)\nimport Control.Arrow (first)\nimport Data.Map (Map)\nimport Data.Maybe (isJust, fromJust)\nimport qualified Data.Map as Map\nimport Data.List (unfoldr, (\\\\), takeWhile)\nimport System.Process (readProcess)\nimport System.IO.Unsafe (unsafePerformIO)\nimport Control.Monad.Fix (MonadFix)\nimport Control.Monad.State (MonadState, evalState, get, put, liftM2, modify)\nimport Util ((.), (++), mapLast, stripInfix, measure, textStripInfix)\nimport RawDocument\nimport Sentences (splitIntoSentences, isActualSentence, breakSentence)\nimport Document\n\ngetCommitUrl :: IO Text\ngetCommitUrl = do\n\turl <- gitGetRemoteUrl\n\tcommit <- gitGetCommitRef\n\treturn $\n\t\t( Text.replace \"git@github.com:\" \"http://github.com/\"\n\t\t$ Text.replace \".git\" \"/commit/\" url)\n\t\t++ commit\n\ngitGetRemoteUrl :: IO Text\ngitGetRemoteUrl = do\n\tx <- readProcess \"git\" [\"ls-remote\", \"--get-url\"] \"\"\n\treturn $ Text.strip $ Text.pack x\n\ngitGetCommitRef :: IO Text\ngitGetCommitRef = do\n\tx <- readProcess \"git\" [\"rev-parse\", \"HEAD\"] \"\"\n\treturn $ Text.strip $ Text.pack $ x\n\n-- In the LaTeX sources, \\definition is often preceded by corresponding \\indexdefns.\n-- Since we treat definitions like sections (and generate pages for them), we need\n-- to move the \\indexdefns inside (after) the \\definition, so that the index entries\n-- don't link to the page for the preceding section.\n\nmoveIndexEntriesIntoDefs :: [Text] -> [Text]\nmoveIndexEntriesIntoDefs [] = []\nmoveIndexEntriesIntoDefs (x:xs)\n\t| \"\\\\indexdefn{\" `isPrefixOf` x = case moveIndexEntriesIntoDefs xs of\n\t\t[] -> [x]\n\t\ty:ys\n\t\t\t| \"\\\\definition{\" `isPrefixOf` y -> y : x : ys\n\t\t\t| otherwise -> x : y : ys\n\t| otherwise = x : moveIndexEntriesIntoDefs xs\n\nmoveIndexEntriesIntoSecs :: [Text] -> [Text]\nmoveIndexEntriesIntoSecs = go []\n\twhere\n\t\tgo x [] = x\n\t\tgo x (h:t)\n\t\t    | \"\\\\indextext{\" `isPrefixOf` h = go (h : x) t\n\t\t    | \"\\\\rSec\" `isPrefixOf` h = h : reverse x ++ go [] t\n\t\t    | otherwise = reverse x ++ [h] ++ go [] t\n\n{- The document has a ton of:\n\n  \\indexlibraryglobal{bla}%\n  \\begin{itemdecl}\n  void bla();\n  \\end{itemdecl}\n\nTo highlight the whole itemdecl, indexItemDecls converts this to:\n\n  \\begin{indexeditemdecl}{\n  \\indexlibraryglobal{bla}%\n  }\n  void bla();\n  \\end{indexeditemdecl}\n-}\n\nindexCodeEnvs :: [Text] -> [Text] -> [Text]\nindexCodeEnvs envs = go []\n\twhere\n\t\tgo collected [] = collected\n\t\tgo collected (x:xs)\n\t\t\t| \"\\\\index\" `isPrefixOf` x = go (collected ++ [x]) xs\n\t\t\t| [e] <- [e | e <- envs, (\"\\\\begin{\" ++ e ++ \"}\") `isPrefixOf` x] =\n\t\t\t\tlet (code, _ : rest) = span (not . ((\"\\\\end{\" ++ e ++ \"}\") `isPrefixOf`)) xs\n\t\t\t\tin (if null collected then\n\t\t\t\t\t\t[\"\\\\begin{\" ++ e ++ \"}\"]\n\t\t\t\t\t\t++ code\n\t\t\t\t\t\t++ [\"\\\\end{\" ++ e ++ \"}\"]\n\t\t\t\t\telse\n\t\t\t\t\t\t[\"\\\\begin{indexed\" ++ e ++ \"}{\"] ++ collected ++ [\"}\"]\n\t\t\t\t\t\t++ code\n\t\t\t\t\t\t++ [\"\\\\end{indexed\" ++ e ++ \"}\"])\n\t\t\t\t \t++ go [] rest\n\t\t\t| otherwise = collected ++ (x : go [] xs)\n\ndata Numbers = Numbers\n\t{ tableNr, figureNr, footnoteRefNr, footnoteNr, itemDeclNr\n\t, nextIndexEntryNr, noteNr, exampleNr, nextSentenceNr, formulaNr :: Int }\n\nclass AssignNumbers a b | a -> b where\n\tassignNumbers :: forall m . (Functor m, MonadFix m, MonadState Numbers m) => Section -> a -> m b\n\ninstance AssignNumbers TeXArg TeXArg where\n\tassignNumbers s (y, x) = (y, ) . assignNumbers s x\n\ninstance AssignNumbers LaTeXUnit LaTeXUnit where\n\tassignNumbers s (TeXEnv \"itemdecl\" [] x) = do\n\t\tn <- get\n\t\tput n{itemDeclNr = itemDeclNr n + 1}\n\t\tTeXEnv \"itemdecl\" [(FixArg, [TeXRaw $ Text.pack $ show $ itemDeclNr n])] . assignNumbers s x\n\tassignNumbers s (TeXEnv \"indexeditemdecl\" indices x) = do\n\t\tn <- get\n\t\tput n{itemDeclNr = itemDeclNr n + 1}\n\t\tliftM2 (TeXEnv \"indexeditemdecl\") (assignNumbers s indices) (assignNumbers s x)\n\tassignNumbers s (TeXEnv x y z) = liftM2 (TeXEnv x) (assignNumbers s y) (assignNumbers s z)\n\tassignNumbers _ (TeXComm \"index\" ws args) = do\n\t\tn <- get\n\t\tput n{nextIndexEntryNr = nextIndexEntryNr n + 1}\n\t\treturn $ TeXComm \"index\" ws $ (FixArg, [TeXRaw $ Text.pack $ show $ nextIndexEntryNr n]) : args\n\tassignNumbers _ (TeXComm \"defnx\" ws args) = do\n\t\tn <- get\n\t\tput n{nextIndexEntryNr = nextIndexEntryNr n + 1}\n\t\treturn $ TeXComm \"defnx\" ws $ (FixArg, [TeXRaw $ Text.pack $ show $ nextIndexEntryNr n]) : args\n\tassignNumbers _ (TeXComm \"footnoteref\" ws []) = do\n\t\tNumbers{..} <- get\n\t\tput Numbers{footnoteRefNr = footnoteRefNr+1, ..}\n\t\treturn $ TeXComm \"footnoteref\" ws [(FixArg, [TeXRaw $ Text.pack $ show footnoteRefNr])]\n\tassignNumbers s (TeXComm x ws args) = TeXComm x ws . assignNumbers s args\n\tassignNumbers _ x = return x\n\ninstance AssignNumbers a b => AssignNumbers (Cell a) (Cell b) where\n\tassignNumbers s x@Cell{..} = do\n\t\tn <- get\n\t\tput n{nextSentenceNr=1}\n\t\tcontent' <- assignNumbers s content\n\t\tmodify $ \\m -> m{nextSentenceNr = nextSentenceNr n}\n\t\treturn x{content=content'}\n\ninstance AssignNumbers a b => AssignNumbers (Row a) (Row b) where\n\tassignNumbers s x@Row{..} = do\n\t\tcells' <- assignNumbers s cells\n\t\treturn x{cells=cells'}\n\ninstance AssignNumbers RawTexPara TeXPara where\n\tassignNumbers s (RawTexPara (splitIntoSentences -> x)) = TeXPara . f x\n\t\twhere\n\t\t\tf [] = return []\n\t\t\tf (h:t) = do\n\t\t\t\th' <- assignNumbers s h\n\t\t\t\tlet actual = isActualSentence h\n\t\t\t\tn <- get\n\t\t\t\tput n{nextSentenceNr = nextSentenceNr n + (if actual then 1 else 0)}\n\t\t\t\t(Sentence (if actual then Just (nextSentenceNr n) else Nothing) h' :) . f t\n\nassignNonInlineItem :: (MonadState Numbers m, MonadFix m) => Section -> RawItem -> m Item\nassignNonInlineItem s (RawItem label content) = do\n\tn <- get\n\tput n{nextSentenceNr = 1}\n\tItem Nothing (if null label then Nothing else Just label) [] . assignNumbers s content\n\nbreakFirstSentence :: [TeXPara] -> (Sentence, [TeXPara])\nbreakFirstSentence (TeXPara [x] : z) = (x, z)\nbreakFirstSentence (TeXPara (x:y) : z) = (x, TeXPara y : z)\nbreakFirstSentence x = error $ \"breakFirstSentence: \" ++ show x\n\nassignInlineItem :: (MonadState Numbers m, MonadFix m) => Section -> RawItem -> m Item\nassignInlineItem s (RawItem label content) = do\n\tn <- get\n\tput n{nextSentenceNr = 1}\n\tcontent' <- assignNumbers s content\n\tlet (Sentence _ x, y) = breakFirstSentence content'\n\treturn $ Item Nothing (if null label then Nothing else Just label) x y\n\nendsWithFullStop :: [RawElement] -> Bool\nendsWithFullStop = isJust . breakSentence\n\ninstance AssignNumbers RawElement Element where\n\tassignNumbers section RawFigure{..} = do\n\t\tNumbers{..} <- get\n\t\tput Numbers{figureNr = figureNr+1, ..}\n\t\treturn $ FigureElement Figure\n\t\t\t{ figureNumber  = figureNr\n\t\t\t, figureName    = rawFigureName\n\t\t\t, figureAbbr    = \"fig:\" ++ rawFigureAbbr\n\t\t\t, figureSvg     = rawFigureSvg\n\t\t\t, figureSection = section }\n\tassignNumbers section RawFormula{..} = do\n\t    Numbers{..} <- get\n\t    put Numbers{formulaNr = formulaNr + 1, ..}\n\t    return $ FormulaElement Formula\n\t        { formulaNumber = formulaNr\n\t        , formulaAbbr = \"eq:\" ++ rawFormulaAbbr\n\t        , formulaContent = rawFormulaContent\n\t        , formulaSection = section }\n\tassignNumbers s RawTable{..} = do\n\t\tNumbers{..} <- get\n\t\tput Numbers{tableNr = tableNr+1, ..}\n\t\ttableCaption <- assignNumbers s rawTableCaption\n\t\ttableBody <- assignNumbers s rawTableBody\n\t\treturn $ TableElement Table\n\t\t\t{ tableNumber  = tableNr\n\t\t\t, columnSpec   = rawColumnSpec\n\t\t\t, tableAbbr   = rawTableAbbr\n\t\t\t, tableCaption = tableCaption\n\t\t\t, tableSection = s\n\t\t\t, .. }\n\tassignNumbers s (RawEnumerated x p) = do\n\t\torigNum <- nextSentenceNr . get\n\t\tlet c = length (filter (any (endsWithFullStop . rawTexParaElems) . rawItemContent) p)\n\t\tr <- mapM (if c > 1 then assignNonInlineItem s else assignInlineItem s) p\n\t\tmodify $ \\y -> y{nextSentenceNr = origNum}\n\t\treturn $ Enumerated x r\n\tassignNumbers s (RawLatexElement x) = LatexElement . assignNumbers s x\n\tassignNumbers s (RawBnf x y) = Bnf x . assignNumbers s y\n\tassignNumbers _ (RawTabbing x) = return $ Tabbing x\n\tassignNumbers s (RawCodeblock x) = Codeblock . assignNumbers s x\n\tassignNumbers s (RawItemdescr x) = Itemdescr . assignNumbers s x\n\tassignNumbers s (RawNote label x) = do\n\t\tNumbers{..} <- get\n\t\tput Numbers{noteNr = noteNr+1, ..}\n\t\tx' <- assignNumbers s x\n\t\treturn $ NoteElement $ Note noteNr label x'\n\tassignNumbers s (RawExample x) = do\n\t\tNumbers{..} <- get\n\t\tput Numbers{exampleNr = exampleNr+1, ..}\n\t\tx' <- assignNumbers s x\n\t\treturn $ ExampleElement $ Example exampleNr x'\n\ninstance AssignNumbers RawFootnote Footnote where\n\tassignNumbers s (RawFootnote t) = do\n\t\tNumbers{..} <- get\n\t\tput Numbers{footnoteNr = footnoteNr+1, nextSentenceNr = 1, ..}\n\t\tt' <- assignNumbers s t\n\t\treturn $ Footnote{footnoteNumber=footnoteNr,footnoteContent=t'}\n\nlsectionLevel :: LinearSection -> Int\nlsectionLevel (lsectionKind -> NormalSection l) = l\nlsectionLevel (lsectionKind -> DefinitionSection l) = l\nlsectionLevel _ = 0\n\nparaNumbers :: [Bool] -> [Maybe Int]\nparaNumbers = f 1\n\twhere\n\t\tf _ [] = []\n\t\tf i (True : x) = Just i : f (i + 1) x\n\t\tf i (False : x) = Nothing : f i x\n\ntreeizeChapters :: forall m . (Functor m, MonadFix m, MonadState Numbers m) =>\n\tBool -> Int -> [LinearSection] -> m [Section]\ntreeizeChapters _ _ [] = return []\ntreeizeChapters annexes secNumber (LinearSection{..} : more) = mdo\n\t\tnums <- get\n\t\tput nums{formulaNr = 1}\n\t\tsectionFootnotes <- assignNumbers newSec lsectionFootnotes\n\t\tlet\n\t\t\tie = rawIndexEntriesForSec newSec\n\t\t\tnewSec = Section{sectionKind=lsectionKind, secIndexEntries=ie, secIndexEntriesByPath=reverseIndexEntryMap ie, ..}\n\t\tlet pn = paraNumbers $ paraNumbered . lsectionParagraphs\n\t\tparagraphs <- forM (zip pn lsectionParagraphs) $ assignNumbers newSec\n\t\tsubsections <- treeizeSections 1 chapter [newSec] lsubsections\n\t\t(newSec :) . treeizeChapters annexes' (sectionNumber + 1) more'\n\twhere\n\t\tsectionNumber = if annexes' /= annexes then 0 else secNumber\n\t\tannexes' = chapter /= NormalChapter\n\t\tparents = []\n\t\tchapter\n\t\t\t| lsectionKind == InformativeAnnexSection = InformativeAnnex\n\t\t\t| lsectionKind == NormativeAnnexSection = NormativeAnnex\n\t\t\t| otherwise = NormalChapter\n\t\tabbreviation = lsectionAbbreviation\n\t\tsectionName = lsectionName\n\t\t(lsubsections, more') = span ((> 0) . lsectionLevel) more\n\nrawIndexEntriesForSec :: Section -> IntMap IndexEntry\nrawIndexEntriesForSec s = IntMap.fromList\n\t[(n, e) | e@IndexEntry{indexEntryNr=Just n} <- sectionIndexEntries s]\n\nreverseIndexEntryMap :: IntMap IndexEntry -> Map IndexPath [(Int, IndexEntry)]\nreverseIndexEntryMap m = Map.fromListWith (++) [(indexPath x, [(i, x)])  | (i, x) <- IntMap.assocs m]\n\nassignItemNumbers :: Paragraph -> Paragraph\nassignItemNumbers p\n\t| Just n <- paraNumber p = p{ paraElems = fst $ goParas [n, 1] $ paraElems p }\n\t| otherwise = p\n\twhere\n\n\t\tgoParas :: [Int] -> [TeXPara] -> ([TeXPara], [Int])\n\t\tgoParas nn [] = ([], nn)\n\t\tgoParas nn (TeXPara e : pp) = first (TeXPara e' :) (goParas nn' pp)\n\t\t\twhere (e', nn') = goSentences nn e\n\n\t\tgoSentences :: [Int] -> [Sentence] -> ([Sentence], [Int])\n\t\tgoSentences nn [] = ([], nn)\n\t\tgoSentences nn (Sentence m e : ss) = first (Sentence m e' :) (goSentences nn' ss)\n\t\t\twhere (e', nn') = goElems nn e\n\n\t\tgoElems :: [Int] -> [Element] -> ([Element], [Int])\n\t\tgoElems nn [] = ([], nn)\n\t\tgoElems nn (e:ee) = first (e' :) (goElems nn' ee)\n\t\t\twhere (e', nn') = goElem nn e\n\n\t\tgoElem :: [Int] -> Element -> (Element, [Int])\n\t\tgoElem nn Enumerated{..} = (Enumerated enumCmd items', mapLast (+ length enumItems) nn)\n\t\t\twhere\n\t\t\t\titems' = map (\\(i, Item{..}) ->\n\t\t\t\t\tItem\n\t\t\t\t\t\t(Just (map show $ mapLast (+i) nn))\n\t\t\t\t\t\titemLabel\n\t\t\t\t\t\t(fst $ goElems (mapLast (+i) nn ++ [1]) itemInlineContent)\n\t\t\t\t\t\t(fst $ goParas (mapLast (+i) nn ++ [1]) itemBlockContent)\n\t\t\t\t\t) (zip [0..] enumItems)\n\t\tgoElem nn (NoteElement (Note nr label paras)) = (NoteElement (Note nr label paras'), nn')\n\t\t\twhere (paras', nn') = goParas nn paras\n\t\tgoElem nn (ExampleElement (Example nr paras)) = (ExampleElement (Example nr paras'), nn')\n\t\t\twhere (paras', nn') = goParas nn paras\n\t\tgoElem nn x = (x, nn)\n\ninstance AssignNumbers (Maybe Int, RawParagraph) Paragraph where\n\tassignNumbers paraSection (paraNumber, RawParagraph{..}) = do\n\t\tnums <- get\n\t\tput nums{nextSentenceNr=if paraNumbered then 1 else nextSentenceNr nums}\n\t\tparaElems <- assignNumbers paraSection rawParaElems\n\t\twhen paraNumbered $ modify $ \\newnums -> newnums{nextSentenceNr = nextSentenceNr nums}\n\t\treturn $ assignItemNumbers Paragraph\n\t\t  { paraInItemdescr = rawParaInItemdescr\n\t\t  , paraSourceLoc = rawParaSourceLoc\n\t\t  , allParaElems = allElements paraElems\n\t\t  , .. }\n\ntreeizeSections :: forall m . (Functor m, MonadFix m, MonadState Numbers m) =>\n\tInt -> Chapter -> [Section] -> [LinearSection] -> m [Section]\ntreeizeSections _ _ _ [] = return []\ntreeizeSections sectionNumber chapter parents\n\t(s@LinearSection{..} : (span ((> lsectionLevel s) . lsectionLevel) -> (lsubsections, more'))) = mdo\n\t\tlet\n\t\t  ie = rawIndexEntriesForSec newSec\n\t\t  newSec = Section\n\t\t\t{ sectionKind = lsectionKind\n\t\t\t, secIndexEntries = ie\n\t\t\t, secIndexEntriesByPath = reverseIndexEntryMap ie\n\t\t\t, sectionName = lsectionName\n\t\t\t, abbreviation = lsectionAbbreviation\n\t\t\t, .. }\n\t\tlet pn = paraNumbers $ paraNumbered . lsectionParagraphs\n\t\tnums <- get\n\t\tput nums{noteNr=1, exampleNr=1, itemDeclNr=1}\n\t\tsectionFootnotes <- assignNumbers newSec lsectionFootnotes\n\t\tmodify $ \\n -> n{nextSentenceNr=1}\n\t\tparagraphs <- forM (zip pn lsectionParagraphs) $ assignNumbers newSec\n\t\tsubsections <- treeizeSections 1 chapter (newSec : parents) lsubsections\n\t\t(newSec :) . treeizeSections (sectionNumber + 1) chapter parents more'\n\ninstance AssignNumbers a b => AssignNumbers [a] [b] where\n\tassignNumbers s = mapM (assignNumbers s)\n\nresolveGrammarterms :: Parser.Macros -> [Text] -> LinearSection -> LinearSection\nresolveGrammarterms macros links LinearSection{..} =\n\tLinearSection{lsectionParagraphs = map resolve lsectionParagraphs, ..}\n\twhere\n\t\tresolveTexPara :: RawTexPara -> RawTexPara\n\t\tresolveTexPara RawTexPara{..} = RawTexPara{rawTexParaElems = map resolveRawElem rawTexParaElems, ..}\n\t\tresolveRawElem :: RawElement -> RawElement\n\t\tresolveRawElem (RawBnf s tex) = RawBnf s (bnfGrammarterms macros links tex)\n\t\tresolveRawElem (RawEnumerated s items) = RawEnumerated s (map resolveItem items)\n\t\tresolveRawElem y = y\n\t\tresolveItem :: RawItem -> RawItem\n\t\tresolveItem (RawItem label content) = RawItem label (map resolveTexPara content)\n\t\tresolve :: RawParagraph -> RawParagraph\n\t\tresolve RawParagraph{..} = RawParagraph{rawParaElems = map resolveTexPara rawParaElems, ..}\n\nbnfGrammarterms :: Parser.Macros -> [Text] -> LaTeX -> LaTeX\nbnfGrammarterms macros links = mapTeX go . mapTeX wordify\n\twhere\n\t\twordify :: LaTeXUnit -> Maybe LaTeX\n\t\twordify (TeXRaw stuff) = Just $ map TeXRaw $ unfoldr f stuff\n\t\t\twhere\n\t\t\t\tf s | Text.null s = Nothing\n\t\t\t\tf s | isName $ Text.head s = Just $ Text.span isName s\n\t\t\t\tf s = Just $ Text.break isName s\n\n\t\t\t\tisName c = isAlpha c || c `elem` ['-', '_']\n\t\twordify _ = Nothing\n\n\t\tgo :: LaTeXUnit -> Maybe LaTeX\n\t\tgo d@(TeXComm cmd _ _) | cmd `elem` [\"tcode\", \"index\", \"textnormal\", \"indexlink\", \"hiddenindexlink\", \"indexedspan\", \"terminal\", \"literalterminal\", \"noncxxterminal\"] = Just [d]\n\t\tgo (TeXRaw name)\n\t\t\t| name `elem` links = Just $ fst $ RawDocument.doParse macros $ \"\\\\grammarterm{\" ++ name ++ \"}\"\n\t\tgo _ = Nothing\n\nparseIndex :: LaTeX -> (IndexPath, Maybe IndexKind)\nparseIndex = go . mapTeXRaw unescapeIndexPath . concatRaws\n\twhere\n\t\tgo (texStripInfix \"|seealso\" -> Just (x, [TeXBraces y])) = (parseIndexPath x, Just $ See True y)\n\t\tgo (texStripInfix \"|see \" -> Just (x, [TeXBraces y])) = (parseIndexPath x, Just $ See False y)\n\t\tgo (texStripInfix \"|see\" -> Just (x, [TeXBraces y])) = (parseIndexPath x, Just $ See False y)\n\t\tgo (texStripInfix \"|see\" -> Just (x, [TeXBraces y, TeXRaw \"|idxbfpage\"])) = (parseIndexPath x, Just $ See False y)\n\t\tgo (texStripInfix \"|(\" -> Just (t, _)) = (parseIndexPath t, Just IndexOpen)\n\t\tgo (texStripInfix \"|)\" -> Just (t, _)) = (parseIndexPath t, Just IndexClose)\n\t\tgo (texStripInfix \"|idxbfpage\" -> Just (t, _)) = (parseIndexPath t, Just DefinitionIndexEntry)\n\t\tgo t = (parseIndexPath t, Nothing)\n\n\t\tunescapeIndexPath :: Text -> LaTeXUnit\n\t\tunescapeIndexPath = TeXRaw\n\t\t\t. replace \"\\5\" \"\\\"\"\n\n\t\t\t. replace \"\\2\" \"!\"\n\t\t\t. replace \"!\" \"\\1\"\n\t\t\t. replace \"\\\"!\" \"\\2\"\n\n\t\t\t. replace \"\\4\" \"@\"\n\t\t\t. replace \"@\" \"\\3\"\n\t\t\t. replace \"\\\"@\" \"\\4\"\n\n\t\t\t. replace \"\\\"|\" \"|\"\n\t\t\t. replace \"\\\"\\\"\" \"\\5\"\n\n\t\t\t. (!! 10) . iterate (replace \"  \" \" \")\n\t\t\t. replace \"\\n\" \" \"\n\n\t\tparseIndexPath :: LaTeX -> IndexPath\n\t\tparseIndexPath (texStripInfix \"\\1\" -> Just (x, y)) = parseIndexPath x ++ parseIndexPath y\n\t\tparseIndexPath (texStripInfix \"\\3\" -> Just (x, y)) = [IndexComponent x y]\n\t\tparseIndexPath t = [IndexComponent [] t]\n\nsectionTexParas :: Section -> [TeXPara]\nsectionTexParas s = (paragraphs s >>= paraElems) ++ (sectionFootnotes s >>= footnoteContent)\n\nsectionTex :: Section -> LaTeX\nsectionTex s = sectionTexParas s >>= texParaTex\n\nsectionIndexEntries :: Section -> [IndexEntry]\nsectionIndexEntries s =\n\t[ IndexEntry{indexEntrySection=abbreviation sec, ..}\n\t| sec <- sections s\n\t, [ (FixArg, [TeXRaw (Text.unpack -> read -> Just -> indexEntryNr)])\n\t  , (OptArg, [TeXRaw indexCategory]), (FixArg, (parseIndex -> (indexPath, indexEntryKind)))\n\t  ] <- lookForCommand \"index\" (sectionTex sec)]\n\nsectionLabels :: Section -> [(Text, Section)]\nsectionLabels s =\n\t[ (label, sec) | sec <- sections s\n\t, [ (FixArg, [TeXRaw label]) ] <- lookForCommand \"label\" (sectionTex sec)]\n\ntoIndex :: IndexEntry -> Index\ntoIndex IndexEntry{..} = Map.singleton indexCategory $ go indexPath\n\twhere\n\t\tgo :: [IndexComponent] -> IndexTree\n\t\tgo [c] = Map.singleton c (IndexNode [IndexEntry indexEntrySection indexEntryKind indexPath indexEntryNr indexCategory] Map.empty)\n\t\tgo (c:cs) = Map.singleton c $ IndexNode [] $ go cs\n\t\tgo _ = error \"toIndex\"\n\ntrackPnums :: FilePath -> Text -> Text\n\t-- Replaces \\pnum with \\pnum{file}{line}\ntrackPnums file = Text.pack . unlines . map (uncurry f) . zip [1..] . lines . Text.unpack\n\twhere\n\t\tf :: Integer -> String -> String\n\t\tf lineNr line\n\t\t\t| Just (pre, post) <- stripInfix \"\\\\pnum\" line\n\t\t\t\t= pre ++ \"\\\\pnum{\" ++ file ++ \"}{\" ++ show lineNr ++ \"}\" ++ (if null post then \"%\" else post)\n\t\t\t| otherwise = line\n\ngetFileList :: IO [FilePath]\ngetFileList =\n\t(\\\\ [\"front\", \"back\"]) .\n\tmap (Text.unpack . Text.dropEnd 1 . Text.drop (Text.length pre)) .\n\tfilter (pre `isPrefixOf`) .\n\tText.lines . readFile \"std.tex\"\n  where pre = \"\\\\include{\"\n\ngrabBnf :: [String] -> [String]\ngrabBnf [] = []\ngrabBnf (line : rest)\n    | \"\\\\begin{bnf}\" `List.isPrefixOf` line =\n        let (x, end : more) = break (\"\\\\end{bnf}\" `List.isPrefixOf`) rest\n        in [\"\", line] ++ x ++ [end] ++ grabBnf more\n    | \"\\\\gramSec\" `List.isPrefixOf` line = [\"\", line] ++ grabBnf rest\n    | otherwise = grabBnf rest\n\ngenerateStdGramExt :: [FilePath] -> IO Text\ngenerateStdGramExt files =\n    Text.pack . unlines . grabBnf . lines . Text.unpack .\n    Text.concat . mapM readFile ((++ \".tex\") . files)\n\nimportExampleFile :: FilePath -> IO Text\nimportExampleFile =\n    (Text.strip .\n     Text.unlines .\n     takeWhile (/= \"\\\\end{document}\") .\n     tail .\n     dropWhile (/= \"\\\\begin{document}\") .\n     Text.lines .) .\n    readFile\n\nimportExamples :: Text -> Text\nimportExamples x = case matchRegexAll r (Text.unpack x) of\n        Nothing -> x\n        Just (before, _match, after, subs) ->\n            Text.pack before ++\n            unsafePerformIO (importExampleFile $ \"assets/\" ++ (subs !! 1) ++ \".tex\") ++\n            importExamples (Text.pack after)\n    where r = mkRegex \"\\\\\\\\importexample(\\\\[[0-9a-zA-Z.-]*\\\\])?{([a-zA-Z0-9_-]*)}\"\n\nparseFiles :: Parser.Macros -> IO ([LinearSection], Parser.Macros)\nparseFiles m = do\n\tfiles <- getFileList\n\tstdGramExt <- generateStdGramExt files\n\tlet\n\t\tgo [] macros = return ([], macros)\n\t\tgo (c:cc) macros = do\n\t\t\tlet p = c ++ \".tex\"\n\n\t\t\tstuff <-\n\t\t\t\timportExamples .\n\t\t\t\treplace \"multicolfloattable\" \"floattable\" .\n\t\t\t\treplace \"\\\\indeximpldef{\" \"\\\\index[impldefindex]{\" .\n\t\t\t\tText.unlines .\n\t\t\t\t\tindexCodeEnvs [\"codeblock\", \"itemdecl\"] .\n\t\t\t\t\tmoveIndexEntriesIntoSecs .\n\t\t\t\t\tmoveIndexEntriesIntoDefs .\n\t\t\t\tText.lines .\n\t\t\t\ttrackPnums p .\n\t\t\t\treplace \"\\\\nodiffref\\n\\\\change\" \"\\n\\\\pnum\\\\textbf{Change:}\\\\space\" .\n\t\t\t\treplace \"\\n\\\\diffref\" \"\\n\\\\pnum\\\\nopnumdiffref\" .\n\t\t\t\t\t-- Done here because (1) the real \\nodiffref is defined with \\def in a way\n\t\t\t\t\t-- we don't support yet, and (2) this way a source link is generated for the pnum.\n\t\t\t\treadFile p\n\n\t\t\tlet extra = if c /= \"grammar\" then \"\" else replace \"\\\\gramSec\" \"\\\\rSec1\" stdGramExt\n\t\t\tlet (r, macros') = parseFile macros (stuff ++ extra)\n\t\t\tif length r == 0 then undefined else\n\t\t\t\tfirst (r ++) . go cc (macros ++ macros')\n\t\n\tbib <- fst . parseFile m .\n\t       fst . fromJust .\n\t       textStripInfix \"\\\\clearpage\" .\n\t       (\"\\\\rSec0[bibliography]{Bibliography}\\n\" ++) .\n\t       readFile \"back.tex\"\n\n\tfirst (++ bib) . go files m\n\nload14882 :: Text -> IO Draft\nload14882 extraMacros = do\n\n\tcommitUrl <- getCommitUrl\n\n\t(macros@Parser.Macros{..}, took) <- measure (loadMacros extraMacros)\n\tputStrLn $ \"Loaded macros in \" ++ show (took * 1000) ++ \"ms.\"\n\n\t(secs :: [LinearSection], took2) <- measure $ fst . parseFiles macros\n\tputStrLn $ \"Parsed LaTeX in \" ++ show (took2 * 1000) ++ \"ms.\"\n\n\txrefDelta <- loadXrefDelta\n\n\t(r, took3) <- measure $ if length (show secs) == 0 then undefined else do\n\t\t-- force eval before we leave the dir\n\t\tlet\n\t\t\tgrammarNames = [n |\n\t\t\t\tTeXComm \"index\" _ [\n\t\t\t\t\t(OptArg, [TeXRaw \"grammarindex\"]) ,\n\t\t\t\t\t(FixArg, [TeXRaw _\n\t\t\t\t\t ,TeXComm \"textcolor\" \"\" [(FixArg,[TeXRaw \"grammar-gray\"]),(FixArg,[TeXComm \"textsf\" _ [(FixArg,[TeXComm \"textit\" \"\" [(FixArg,[TeXRaw n])]])]])]\n\t\t\t\t\t ,TeXRaw \"|idxbfpage\"]\n\t\t\t\t\t)] <- allUnits secs]\n\n\t\t\tsecs' = map (resolveGrammarterms macros grammarNames) secs\n\t\t\tchapters = evalState (treeizeChapters False 1 secs') (Numbers 1 1 1 1 0 0 1 1 1 1)\n\t\t\tallEntries :: [IndexEntry]\n\t\t\tallEntries = chapters >>= sectionIndexEntries\n\t\t\tindex = mergeIndices $ map toIndex allEntries\n\t\t\tindexEntryMap = IntMap.fromList [(n, e) | e@IndexEntry{indexEntryNr=Just n} <- allEntries]\n\t\t\tindexEntriesByPath = reverseIndexEntryMap indexEntryMap\n\t\t\tlabels = Map.fromList $ chapters >>= sectionLabels\n\t\n\t\t\tabbrMap = makeAbbrMap dr\n\t\t\tdr = Draft{..}\n\t\treturn dr\n\t\n\tputStrLn $ \"Processed in \" ++ show (took3 * 1000) ++ \"ms.\"\n\treturn r\n"
  },
  {
    "path": "MathJax.hs",
    "content": "{-# LANGUAGE OverloadedStrings, ViewPatterns #-}\n\nmodule MathJax (render) where\n\nimport Control.Concurrent.MVar (takeMVar, putMVar, newMVar)\nimport Data.Text (Text)\nimport qualified Data.Text as Text\nimport System.IO.Unsafe (unsafePerformIO)\nimport System.Process (shell, CreateProcess(..), createProcess, StdStream(CreatePipe))\nimport System.IO (BufferMode(..), hGetLine, hPutStrLn, hSetBuffering)\nimport Text.Regex (mkRegex, subRegex)\nimport Prelude hiding ((++))\nimport Util ((++))\nimport qualified Data.Map as Map\nimport Data.Map (Map)\n\nrmTrailingNewline :: Text -> Text\nrmTrailingNewline (Text.stripSuffix \"\\n\" -> Just x) = x\nrmTrailingNewline x = x\n\ntype Renderer = String {- formula -} -> Bool {- inline -} -> Text\n\ndata Input = Input { _formula :: String, _inline :: Bool }\n    deriving (Eq, Ord)\n\nmakeRenderer :: IO Renderer\nmakeRenderer = do\n\n    (Just stdinPipe, Just stdoutPipe, _, _) <- createProcess (shell \"./mathjax-batch\")\n            {std_in = CreatePipe, std_out = CreatePipe}\n\n    hSetBuffering stdinPipe LineBuffering\n    hSetBuffering stdoutPipe LineBuffering\n\n    let\n      rm r s = subRegex (mkRegex r) s \"\"\n      readResult = do\n        line <- hGetLine stdoutPipe\n        if line == \"DONE\"\n          then return \"\"\n          else do\n            more <- readResult\n            return $ line ++ \"\\n\" ++ more\n\n    mutex <- newMVar (Map.empty :: Map Input Text)\n\n    return $ \\formula inline -> unsafePerformIO $ do\n        let input = Input formula inline\n        cache <- takeMVar mutex\n        (result, cache') <- case Map.lookup input cache of\n            Just output -> return (output, cache)\n            Nothing -> do\n                hPutStrLn stdinPipe formula\n                hPutStrLn stdinPipe (if inline then \"INLINE\" else \"NONINLINE\")\n                rawResult <- readResult\n                let\n                  output\n                    = Text.replace \" focusable=\\\"false\\\"\" \"\"\n                    $ rmTrailingNewline -- Prevents artifacts in [rand.adapt.ibits]#4\n                    $ Text.pack\n                    $ rm \" id=\\\"(MJXc|MathJax)-[0-9A-Za-z-]+\\\"\"\n                    $ rm \" style=\\\"\\\"\"\n                    $ rawResult\n                return (output, Map.insert input output cache)\n        putMVar mutex cache'\n        return result\n\nrender :: Renderer\nrender = unsafePerformIO $ makeRenderer\n"
  },
  {
    "path": "Pages.hs",
    "content": "{-# LANGUAGE OverloadedStrings, RecordWildCards, ViewPatterns #-}\n\nmodule Pages (fileContent, pageContent, pagePath, writePage, applyPageStyle, Link(..), outputDir, PageStyle(..)) where\n\nimport Prelude hiding ((++), (.), writeFile)\nimport System.Directory (createDirectoryIfMissing)\nimport Control.Monad (when)\nimport qualified Data.Text as Text\nimport qualified Data.Text.Lazy as LazyText\nimport qualified Data.Text.Lazy.Builder as TextBuilder\nimport Util ((++), (.), Text, writeFile)\n\noutputDir :: FilePath\noutputDir = \"14882/\"\n\ndata PageStyle = Bare | WithExtension | InSubdir\n    deriving (Eq, Read)\n\nfileContent :: TextBuilder.Builder -> TextBuilder.Builder -> TextBuilder.Builder -> TextBuilder.Builder -> TextBuilder.Builder\nfileContent pathHome title extraHead body =\n    \"<!DOCTYPE html>\" ++\n    \"<html lang='en'>\" ++\n        \"<head>\" ++\n            \"<title>\" ++ title ++ \"</title>\" ++\n            \"<meta charset='UTF-8'>\" ++\n            \"<link rel='stylesheet' type='text/css' href='\" ++ pathHome ++ \"14882.css'>\" ++\n            \"<link rel='stylesheet' type='text/css' href='https://fonts.googleapis.com/css2?family=Noto+Serif'>\" ++\n            \"<link rel='stylesheet' type='text/css' href='https://fonts.googleapis.com/css2?family=Noto+Sans'>\" ++\n            \"<link rel='stylesheet' type='text/css' href='https://fonts.googleapis.com/css2?family=Noto+Sans+Mono'>\" ++\n            \"<link rel='icon' href='icon-light.png' media='(prefers-color-scheme: light)'>\" ++\n            \"<link rel='icon' href='icon-dark.png' media='(prefers-color-scheme: dark)'>\" ++\n            extraHead ++\n        \"</head>\" ++\n        \"<body><div class='wrapper'>\" ++ body ++ \"</div></body>\" ++\n    \"</html>\"\n\ndata Link = TocToSection | SectionToToc | SectionToSection\n\tderiving Show\n\ndoLink :: PageStyle -> Link -> Text -> Text\ndoLink sfs l = LazyText.toStrict . TextBuilder.toLazyText . go . Text.splitOn (Text.pack (show l) ++ \"/\")\n\twhere\n\t\tgo :: [Text] -> TextBuilder.Builder\n\t\tgo (x : (Text.break (`elem` (\"'#\" :: String)) -> (a, b)) : z) = TextBuilder.fromText x ++ f (TextBuilder.fromText a) ++ go (b : z)\n\t\tgo [x] = TextBuilder.fromText x\n\t\tgo _ = undefined\n\t\tf :: TextBuilder.Builder -> TextBuilder.Builder\n\t\tf = case (sfs, l) of\n\t\t\t(Bare, SectionToToc) -> (\"./#\" ++)\n\t\t\t(Bare, TocToSection) -> id\n\t\t\t(Bare, SectionToSection) -> id\n\t\t\t(InSubdir, SectionToToc) -> (\"../#\" ++)\n\t\t\t(InSubdir, TocToSection) -> (++ \"/\")\n\t\t\t(InSubdir, SectionToSection) -> (\"../\" ++)\n\t\t\t(WithExtension, SectionToToc) -> (\"index.html#\" ++)\n\t\t\t(WithExtension, TocToSection) -> (++ \".html\")\n\t\t\t(WithExtension, SectionToSection) -> (++ \".html\")\n\napplyPageStyle :: PageStyle -> Text -> Text\napplyPageStyle sfs =\n\tdoLink sfs SectionToSection\n\t. doLink sfs SectionToToc\n\t. doLink sfs TocToSection\n\npagePath :: FilePath -> PageStyle -> String\npagePath n Bare = outputDir ++ n\npagePath n WithExtension = outputDir ++ n ++ \".html\"\npagePath n InSubdir = outputDir ++ n ++ \"/index.html\"\n\npageContent :: PageStyle -> TextBuilder.Builder -> Text\npageContent sfs content = applyPageStyle sfs $ LazyText.toStrict $ TextBuilder.toLazyText $ content\n\nwritePage :: FilePath -> PageStyle -> Text -> IO ()\nwritePage n sfs content = do\n    when (sfs == InSubdir) $ createDirectoryIfMissing True (outputDir ++ n)\n    writeFile (pagePath n sfs) content\n"
  },
  {
    "path": "README",
    "content": "Introduction\n\n  cxxdraft-htmlgen parses the LaTeX sources of the draft,\n  and generates static HTML pages from them.\n\nPrerequisites\n\n  - Git\n  - The Haskell Platform (https://www.haskell.org/platform/)\n  - Graphviz\n  - Node.js\n  - The 'split' NPM package\n  - mathjax-node-cli (https://github.com/mathjax/mathjax-node-cli/)\n\nUsage\n\n  Do:\n    git clone https://github.com/Eelis/cxxdraft-htmlgen.git\n    cd cxxdraft-htmlgen\n    cabal build\n    dist/build/cxxdraft-htmlgen/cxxdraft-htmlgen path/to/draft [sectionfilestyle]\n\n  Or with stack:\n    stack build\n    stack exec cxxdraft-htmlgen path/to/draft [sectionfilestyle]\n\n  The sectionfilestyle parameter is one of:\n\n    Bare            (to generate e.g. intro.execution)\n    WithExtension   (to generate e.g. intro.execution.html)\n    InSubdir        (to generate e.g. intro.execution/index.html)\n\n  The default is WithExtension, since this is suitable\n  for direct browsing on a filesystem without a web server.\n\n  Bare may be used in conjunction with web server configuration\n  specifying a default text/html mime type for the directory\n  containing the section pages, to get URLs such as:\n\n    temp.res#temp.dep\n    temp.dep#3\n\n  InSubdir only requires defaulting to index.html, to give:\n\n    temp.res/#temp.dep\n    temp.dep/#3\n\nCustom draft branch\n\n  While cxxdraft-htmlgen works with the official draft sources as-is,\n  better results can be obtained by using the following branch:\n\n    https://github.com/Eelis/draft/tree/cxxdraft-htmlgen-fixes\n\n  This branch tracks the official draft sources, but makes some changes to:\n    - improve syntax highlighting\n    - clean up hyperlinks\n    - work around MathJax limitations\n    - work around cxxdraft-htmlgen limitations\n\nOutput\n\n  The following will be created in ./14882/ :\n\n  - index.html    A table of contents with links to...\n\n  - ~2300 interlinked section pages\n\n    These are named after the section abbreviation, which for\n    the Bare section file style look like:\n\n      stmt.goto\n      class.member.lookup\n      cpp\n      iterator.requirements.general\n      locale.moneypunct.virtuals\n\n    Since sections nest, content is duplicated at every level.\n    This allows one to specify more or less context for a given\n    citation. For example, one can link to:\n\n      basic.scope.hiding   (section 6.4.10 \"Name hiding\" on\n                            a page of its own)\n\n      basic.scope#hiding   (the same section highlighted on\n                            the page for section 6.4 \"Scope\")\n\n      basic#scope.hiding   (the same section highlighted on\n                            the page for chapter 6 \"Basics\")\n\n  - full         The entire document (~24 mbyte, or ~2 mbyte compressed).\n\n  - 14882.css    Used by all of the above.\n\nHidden links\n\n  On any page:\n\n  - defined terms/concepts/nonterminals are links that select themselves;\n\n  - a full stop at the end of a sentence is a link that selects the sentence;\n\n  - moving the mouse over the right margin of a numbered paragraph reveals a link\n    to the LaTeX source for that paragraph;\n\n  - moving the mouse over the left margin of an itemdecl or table row reveals a link\n    that selects it.\n"
  },
  {
    "path": "RawDocument.hs",
    "content": "{-# LANGUAGE\n\tOverloadedStrings,\n\tRecordWildCards,\n\tViewPatterns,\n\tLambdaCase,\n\tTupleSections,\n\tNamedFieldPuns,\n\tFlexibleInstances,\n\tFlexibleContexts,\n\tRankNTypes,\n\tMultiParamTypeClasses,\n\tFunctionalDependencies,\n\tUndecidableInstances,\n\tRecursiveDo #-}\n\nmodule RawDocument\n\t( RawElement(..), RawTexPara(..), RawFootnote(..), RawParagraph(..), LinearSection(..), RawItem(..)\n\t, loadMacros, parseFile, loadXrefDelta, doParse) where\n\nimport qualified LaTeXParser as Parser\nimport qualified Data.Text as Text\nimport Data.Text (Text, replace)\nimport Document (Row(..), SourceLocation(..), RowSepKind(..), SectionKind(..), Cell(..), CellSpan(..), XrefDelta, Abbreviation, ColumnSpec(..), TextAlignment(..))\nimport Data.Maybe (isJust, fromJust)\nimport LaTeXParser (Macros(..), Signature(..), nullCmd, storeCmd, storeEnv, Environment(..), Command(..), codeEnv, Token(..), normalCmd, ParseResult(..))\nimport Data.Text.IO (readFile)\nimport Text.Regex (mkRegex)\nimport qualified Data.Map as Map\nimport Data.Map (Map)\nimport Data.List (transpose, take, isPrefixOf)\nimport Util ((.), (++), mapHead, textStripInfix, textSubRegex, splitOn)\nimport Prelude hiding (take, (.), takeWhile, (++), lookup, readFile)\nimport System.IO.Unsafe (unsafePerformIO)\nimport System.Process (readProcess)\nimport Control.Arrow (first)\nimport Data.Char (isSpace, isDigit)\nimport LaTeXBase\n\ndata RawItem = RawItem\n\t{ rawItemLabel :: LaTeX\n\t, rawItemContent :: [RawTexPara] }\n\tderiving (Eq, Show)\n\ndata RawElement\n\t= RawLatexElement LaTeXUnit\n\t| RawEnumerated String [RawItem]\n\t| RawCodeblock LaTeXUnit\n\t| RawExample [RawTexPara]\n\t| RawNote Text [RawTexPara]\n\t| RawItemdescr [RawTexPara]\n\t| RawBnf String LaTeX\n\t| RawTable\n\t\t{ rawTableCaption :: LaTeX\n\t\t, rawColumnSpec :: [ColumnSpec]\n\t\t, rawTableAbbr :: Abbreviation\n\t\t, rawTableBody :: [Row [RawTexPara]] }\n\t| RawTabbing LaTeX\n\t| RawFormula { rawFormulaAbbr :: Abbreviation, rawFormulaContent :: LaTeX }\n\t| RawFigure { rawFigureName :: LaTeX, rawFigureAbbr :: Abbreviation, rawFigureSvg :: Text }\n\tderiving (Eq, Show)\n\nnewtype RawTexPara = RawTexPara { rawTexParaElems :: [RawElement] }\n\tderiving (Eq, Show)\n\nnewtype RawFootnote = RawFootnote [RawTexPara]\n\tderiving Show\n\ndata RawParagraph = RawParagraph\n\t{ paraNumbered :: Bool\n\t, rawParaInItemdescr :: Bool\n\t, rawParaElems :: [RawTexPara]\n\t, rawParaSourceLoc :: Maybe SourceLocation }\n\tderiving Show\n\ndata LinearSection = LinearSection\n\t{ lsectionAbbreviation :: Abbreviation\n\t, lsectionKind :: SectionKind\n\t, lsectionName :: LaTeX\n\t, lsectionParagraphs :: [RawParagraph]\n\t, lsectionFootnotes :: [RawFootnote] }\n\tderiving Show\n\ninstance AllUnits RawElement where\n\tallUnits (RawLatexElement x) = allUnits x\n\tallUnits (RawBnf _ x) = allUnits x\n\tallUnits (RawTabbing x) = allUnits x\n\tallUnits (RawNote _ x) = allUnits x\n\tallUnits (RawExample x) = allUnits x\n\tallUnits (RawCodeblock x) = allUnits x\n\tallUnits (RawItemdescr x) = allUnits x\n\tallUnits (RawEnumerated _ x) = allUnits x\n\tallUnits (RawFormula _ x) = allUnits x\n\tallUnits RawFigure{} = []\n\tallUnits RawTable{..} = allUnits rawTableCaption ++ concatMap (allUnits . concat . map content) (map cells rawTableBody)\n\ninstance AllUnits RawTexPara where\n\tallUnits = allUnits . rawTexParaElems\n\ninstance AllUnits RawItem where\n\tallUnits RawItem{..} = allUnits rawItemLabel ++ allUnits rawItemContent\n\ninstance AllUnits LinearSection where\n\tallUnits LinearSection{..} = allUnits lsectionName ++ allUnits lsectionParagraphs ++ allUnits lsectionFootnotes\n\ninstance AllUnits RawParagraph where\n\tallUnits RawParagraph{..} = allUnits rawParaElems\n\ninstance AllUnits RawFootnote where\n\tallUnits (RawFootnote x) = allUnits x\n\nbnfEnvs :: [String]\nbnfEnvs = [\"bnf\", \"ncbnf\", \"bnfkeywordtab\", \"simplebnf\", \"ncsimplebnf\", \"ncrebnf\"]\n\nisBnf :: LaTeXUnit -> Bool\nisBnf (TeXEnv s _ _)\n\t| s `elem` bnfEnvs = True\nisBnf _ = False\n\nisTable, isTabbing, isFigure :: LaTeXUnit -> Bool\nisTable x = isTeXEnv \"floattablebasex\" x || isTeXEnv \"htmlTable\" x\nisTabbing = isTeXEnv \"tabbing\"\nisFigure = isTeXEnv \"importgraphic\"\n\nisEnumerate :: LaTeXUnit -> Maybe String\nisEnumerate (TeXEnv s _ _)\n\t| s `elem` [\"enumerate\", \"itemize\", \"description\", \"thebibliography\"] = Just s\nisEnumerate _ = Nothing\n\nisParaEnd :: LaTeXUnit -> Bool\nisParaEnd (TeXEnv \"itemdecl\" _ _) = True\nisParaEnd (TeXEnv \"indexeditemdecl\" _ _) = True\nisParaEnd (TeXEnv \"itemdescr\" _ _) = True\nisParaEnd (TeXComm \"pnum\" _ _) = True\nisParaEnd x = isParasEnd x\n\nisParasEnd :: LaTeXUnit -> Bool\nisParasEnd (TeXComm \"definition\" _ _) = True\nisParasEnd (TeXComm \"rSec\" _ _) = True\nisParasEnd (TeXComm \"infannex\" _ _) = True\nisParasEnd (TeXComm \"normannex\" _ _) = True\nisParasEnd _ = False\n\nisJunk :: LaTeXUnit -> Bool\nisJunk (TeXRaw x) = all isSpace (Text.unpack x)\nisJunk (TeXComm \"index\" _ _) = True\nisJunk (TeXComm \"setlength\" _ _) = True\nisJunk _ = False\n\nisItem :: LaTeXUnit -> Maybe LaTeX\nisItem (TeXComm \"item\" _ []) = Just []\nisItem (TeXComm \"item\" _ [(_, label)]) = Just label\nisItem (TeXComm \"bibitem\" _ [(_, [TeXRaw label])]) = Just [TeXRaw $ \"bib:\" ++ label]\nisItem _ = Nothing\n\nparseItems :: LaTeX -> [RawItem]\nparseItems [] = []\nparseItems (x : rest)\n\t| isJunk x = mapHead (mapItemContent (mapHead addJunk)) (parseItems rest)\n\t| Just label <- isItem x, (item, rest') <- break (isJust . isItem) rest =\n\t\tRawItem label (parsePara item) : parseItems rest'\n\twhere\n\t\tmapItemContent f (RawItem l c) = RawItem l (f c)\n\t\taddJunk :: RawTexPara -> RawTexPara\n\t\taddJunk (RawTexPara z) = RawTexPara (dropWhile isOnlySpace $ RawLatexElement x : z)\nparseItems _ = error \"need items or nothing\"\n\ndoParse :: Macros -> Text -> (LaTeX, Macros)\ndoParse m t = (x, y)\n\twhere\n\t\t(x, y, []) = Parser.parseString ctx (Text.unpack t)\n\t\tctx = initialContext{Parser.macros=m}\n\nnullCmds :: [(Int, String)]\nnullCmds =\n\t[ (0, \"clearpage kill rmfamily hfill vfill nocorr small larger noindent itcorrwidth itletterwidth global bigskip begingroup endgroup\")\n\t, (1, \"enlargethispage lstset newsavebox vspace input thispagestyle\")\n\t, (2, \"glossary settowidth addtolength copypagestyle\")\n\t, (3, \"definecolor makeheadrule\")\n\t, (4, \"makeoddhead\")\n\t]\n\nstoreCmds :: [(Int, String)]\nstoreCmds =\n\t[ (0, \"today def makeatletter bottomline makeatother Sec bmod mod long prime \" ++\n\t\t\t\"chapter section paragraph subparagraph fi otextup linebreak newpage log \" ++\n\t\t\t\"textup edef x BnfIndent par leq bot perp Sigma \" ++\n\t\t\t\"leftmargini BnfInc BnfRest protect caret sum \" ++\n\t\t\t\"xspace onelineskip textlangle textrangle tilde raggedright = \" ++\n\t\t\t\"space copyright textregistered textbackslash hsize br Gamma \" ++\n\t\t\t\"frenchspacing list leftmargin listparindent itemindent itshape relax \" ++\n\t\t\t\"nonfrenchspacing endlist upshape ttfamily baselineskip nobreak \" ++\n\t\t\t\"endfirsthead quad qquad cdot cdots dotsc bnfindentinc footnotemark ldots capsep max min \" ++\n\t\t\t\"continuedcaption hline endhead footnotesize le times dotsb rightarrow to equiv \" ++\n\t\t\t\"lfloor rfloor pi geq neq ge lceil rceil ell alpha bigl bigr mu lambda beta \" ++\n\t\t\t\"tabularnewline exp sigma big delta rho Pi nu infty displaystyle lim sin cos \" ++\n\t\t\t\"phi int theta zeta FlushAndPrintGrammar break backslash centering \" ++\n\t\t\t\"normalbaselineskip land lor mapsto normalfont textmu tablerefname figurerefname newline \" ++\n\t\t\t\"obeyspaces bnfindent vdots tabcolsep columnbreak emergencystretch commentellip \" ++\n\t\t\t\"gamma widowpenalties sffamily parskip left right `\")\n\t, (1, \"hspace footnote textit textrm textnormal texttt textbf ensuremath ref ref* mbox bibitem mathop \" ++\n\t\t\t\"terminal literalterminal noncxxterminal textsl textsc textsf text term overline \" ++\n\t\t\t\"tcode noncxxtcode literaltcode footnotetext microtypesetup cline mathtt mathit mathrm mathsf \" ++\n\t\t\t\"label newlength uline value newcounter mathscr c uppercase iref operatorname textlarger \" ++\n\t\t\t\"phantom hphantom sqrt ln emph minipage url indexescape changeglossnumformat textasciitilde \" ++\n\t\t\t\"removedxref deprxref textsuperscript rlap mathrel mathbin nopnumdiffref color ucode uname\")\n\t, (2, \"pnum definition addtocounter setcounter frac \" ++\n\t\t\t\"binom infannex normannex parbox link weblink indexedspan movedxref movedxrefs \" ++\n\t\t\t\"equal setlength textcolor providecommand\")\n\t, (3, \"multicolumn discretionary movedxrefii ifthenelse PackageError NewEnviron\")\n\t, (4, \"movedxrefiii indexlink hiddenindexlink\")\n\t]\n\ninitialCmds :: Map Text Command\ninitialCmds = Map.fromList $\n\t[ storeCmd \"item\" (Signature 0 (Just []))\n\t, storeCmd \"caption\" (Signature 2 (Just []))\n\t, storeCmd \"index\" (Signature 2 (Just []))\n\t, storeCmd \"hyperref\" (Signature 2 (Just []))\n\t, nullCmd \"makebox\" (Signature 2 (Just []))\n\t, storeCmd \"\\n\" (Signature 0 Nothing)\n\t, storeCmd \"nolinebreak\" (Signature 0 (Just []))\n\t, storeCmd \"textsmaller\" (Signature 2 (Just []))\n\t, nullCmd \"gramSec\" (Signature 2 (Just []))\n\t, (\"kern\", normalCmd $ Command $ \\_ctx _ws -> ParseResult [] mempty . snd . parseDimen)\n\t]\n\t++ [storeCmd c (Signature a Nothing) | (a, l) <- storeCmds, c <- words l]\n\t++ [nullCmd (Text.pack c) (Signature a Nothing) | (a, l) <- nullCmds, c <- words l]\n\nparseDimen :: [Token] -> ([Token], [Token])\nparseDimen toks\n    | t@(Token txt) : more <- toks, txt `elem` [\".\", \"pt\", \"-\", \"em\"] || all isDigit txt = first (t :) (parseDimen more)\n    | otherwise = ([], toks)\n\ninitialEnvs :: Map Text Environment\ninitialEnvs = Map.fromList $\n\t[ (storeEnv e (Signature 0 Nothing))\n\t| e <- bnfEnvs ++\n\t       words \"indented description itemize center tabbing defnote enumerate eqnarray* equation* itemdescr footnote matrix\"\n\t] ++\n\t[ storeEnv \"example\" (Signature 1 (Just []))\n\t, storeEnv \"tailexample\" (Signature 1 (Just []))\n\t, storeEnv \"note\" (Signature 0 (Just [Token \"Note\"]))\n\t, storeEnv \"tailnote\" (Signature 0 (Just [Token \"Note\"]))\n\t, storeEnv \"table\" (Signature 1 Nothing)\n\t, storeEnv \"tabular\" (Signature 1 Nothing)\n\t, storeEnv \"longtable\" (Signature 1 Nothing)\n\t, storeEnv \"importgraphic\" (Signature 3 Nothing)\n\t, storeEnv \"formula\" (Signature 1 Nothing)\n\t, storeEnv \"minipage\" (Signature 1 Nothing)\n\t, storeEnv \"thebibliography\" (Signature 1 Nothing)\n\t, codeEnv \"indexeditemdecl\" (Signature 1 Nothing)\n\t, codeEnv \"itemdecl\" (Signature 0 Nothing)\n\t, codeEnv \"indexedcodeblock\" (Signature 1 Nothing)\n\t, codeEnv \"codeblock\" (Signature 0 Nothing)\n\t, codeEnv \"codeblockdigitsep\" (Signature 0 Nothing)\n\t, codeEnv \"codeblocktu\" (Signature 1 Nothing)\n\t, storeEnv \"array\" (Signature 1 Nothing)\n\t, storeEnv \"floattablebasex\" (Signature 4 Nothing)\n\t, storeEnv \"htmlTable\" (Signature 3 Nothing)\n\t]\n\ninitialMacros :: Parser.Macros\ninitialMacros = Parser.defaultMacros ++ mempty{Parser.commands=initialCmds, Parser.environments=initialEnvs}\n\ninitialContext :: Parser.Context\ninitialContext = Parser.defaultContext{Parser.macros=initialMacros}\n\nparseFile :: Macros -> Text -> ([LinearSection], Macros)\nparseFile macros =\n\tfirst (parseSections 0)\n\t. doParse macros\n\t. replace \"$$\" \"$\"\n\t. replace \"\\\\hspace*\" \"\\\\hspace\"\n\t. replace \"``\" \"“\"\n\t. textSubRegex (mkRegex \"(\\\\grammarterm\\\\{[A-Za-z-]*\\\\})(\\\\{s\\\\}|s)\") \"\\\\1\\\\textit{s}\"\n\t\t-- Mixing italic and upright looks okay in the PDF, but looks bad in browsers,\n\t\t-- and our linkification makes clear enough that the plural 's' is not part\n\t\t-- of the grammarterm.\n\nloadFigure :: Text -> Text\nloadFigure f = unsafePerformIO $ do\n\t\tdot <- readFile $ \"assets/\" ++ p\n\t\tsvg <- readProcess \"dot\" [\"-Tsvg\",\n\t\t\t\"-Gbgcolor=transparent\",\n\t\t\t\"-Gsize=8\",\n\t\t\t\"-Nfontsize=10\",\n\t\t\t\"-Gfontsize=10\",\n\t\t\t\"-Efontsize=10\",\n\t\t\t\"-Nfontname=Noto Serif\",\n\t\t\t\"-Efontname=Noto Serif\",\n\t\t\t\"-Gfontname=Noto Serif\"] (Text.unpack $ Text.replace \"Courier New\" \"Noto Sans Mono\" $ Text.replace \", fontsize=24\" \"\" dot)\n\t\treturn $ rmIds $ snd $ Text.breakOn \"<svg\" $ Text.pack svg\n\twhere\n\t\tp = Text.unpack $ Text.replace \".pdf\" \".dot\" f\n\t\tr = mkRegex \"<g id=\\\"[^\\\"]*\\\"\" \n\t\trmIds = textSubRegex r \"<g\"\n\t\t\t-- Without rmIds, if a page has more than one figure, it will\n\t\t\t-- have duplicate 'graph1', 'node1', 'edge1' etc ids.\n\nisOnlySpace :: RawElement -> Bool\nisOnlySpace (RawLatexElement x) = triml [x] == []\nisOnlySpace _ = False\n\nparsePara :: LaTeX -> [RawTexPara]\nparsePara u = RawTexPara . dropWhile isOnlySpace . fmap f . splitElems (trim (filter (not . kill) u))\n\twhere\n\t\tkill (TeXComm \"hline\" _ []) = True\n\t\tkill (TeXComm \"capsep\" _ []) = True\n\t\tkill (TeXComm \"endhead\" _ _) = True\n\t\tkill _ = False\n\t\tf :: LaTeXUnit -> RawElement\n\t\tf e@(TeXEnv k a stuff)\n\t\t\t| isFigure e\n\t\t\t, [(FixArg, rawFigureName), (FixArg, [TeXRaw rawFigureAbbr]), (FixArg, [TeXRaw figureFile])] <- a\n\t\t\t\t= RawFigure{rawFigureSvg=loadFigure figureFile, ..}\n\t\t\t| k == \"formula\", [(FixArg, [TeXRaw rawFormulaAbbr])] <- a = RawFormula{rawFormulaContent = stuff, ..}\n\t\t\t| isTable e\n\t\t\t, ((_, cap) : (_, [TeXRaw abbr]) : (_, y) : _) <- a\n\t\t\t\t= RawTable\n\t\t\t\t{ rawTableCaption = cap\n\t\t\t\t, rawColumnSpec = parseColspec y\n\t\t\t\t, rawTableAbbr = \"tab:\" ++ abbr\n\t\t\t\t, rawTableBody = breakMultiCols $ parseTable stuff }\n\t\t\t| isTable e = error $ \"other table: \" ++ show e\n\t\t\t| isTabbing e = RawTabbing stuff\n\t\t\t| isBnf e = RawBnf (if \"nc\" `isPrefixOf` k then drop 2 k else k) stuff\n\t\t\t| Just ek <- isEnumerate e = RawEnumerated ek (parseItems stuff)\n\t\t\t| isCodeblock e = RawCodeblock e\n\t\t\t| k `elem` [\"note\", \"defnote\", \"tailnote\"] =\n\t\t\t    let label = case a of [(FixArg, [TeXRaw x])] -> x; _ -> \"Note\"\n\t\t\t    in RawNote label $ parsePara stuff\n\t\t\t| k `elem` [\"example\", \"tailexample\"] = RawExample $ parsePara stuff\n\t\t\t| k == \"itemdecl\" || k == \"minipage\" || k == \"indexeditemdecl\" = RawLatexElement e\n\t\t\t| k == \"itemdescr\" = RawItemdescr $ parsePara stuff\n\t\tf x = RawLatexElement x\n\t\tsplitElems :: LaTeX -> [LaTeX]\n\t\tsplitElems [] = []\n\t\tsplitElems (x:xs)\n\t\t\t| TeXRaw (textStripInfix \"\\n\\n\" -> Just (a, (Text.stripStart -> b))) <- x =\n\t\t\t\t(if a == \"\" then ([] :) else ([TeXRaw a] :)) $\n\t\t\t\t\tsplitElems (if b == \"\" then xs else TeXRaw b : xs)\n\t\t\t| otherwise = case splitElems xs of\n\t\t\t\t[] -> [[x]]\n\t\t\t\ta:b -> ((x:a):b)\n\nclass ExtractFootnotes a where extractFootnotes :: a -> (a, [RawFootnote])\n\ninstance ExtractFootnotes LaTeX where\n\textractFootnotes [] = ([], [])\n\textractFootnotes (TeXRaw x : t@(TeXEnv \"footnote\" _ _ : _))\n\t\t= (TeXRaw (Text.stripEnd x) : t', ft)\n\t\twhere (t', ft) = extractFootnotes t\n\t\t\t-- stripEnd here implements the footnote's \\unskip\n\textractFootnotes (h:t) = (h' : t', fh ++ ft)\n\t\twhere\n\t\t\t(h', fh) = extractFootnotes h\n\t\t\t(t', ft) = extractFootnotes t\n\ninstance ExtractFootnotes LaTeXUnit where\n\textractFootnotes (TeXEnv \"footnote\" [] content) =\n\t\t(TeXComm \"footnoteref\" \"\" [], [RawFootnote $ parsePara content])\n\textractFootnotes (TeXComm \"footnotemark\" _ []) =\n\t\t(TeXComm \"footnoteref\" \"\" [], [])\n\textractFootnotes (TeXComm \"footnotetext\" _ [(_, content)]) =\n\t\t(TeXRaw \"\" {- todo.. -}, [RawFootnote $ parsePara content])\n\textractFootnotes (TeXComm a ws [(FixArg, content)]) =\n\t\tfirst (\\c -> TeXComm a ws [(FixArg, c)]) (extractFootnotes content)\n\textractFootnotes (TeXEnv env args content) = first (TeXEnv env args) (extractFootnotes content)\n\textractFootnotes other = (other, [])\n\nparseParas :: LaTeX -> ([RawParagraph], [RawFootnote], LaTeX {- rest -})\nparseParas (break isParasEnd -> (extractFootnotes -> (stuff, fs), rest))\n\t\t= (collectParas stuff, fs, rest)\n\twhere\n\t\tcollectParas :: LaTeX -> [RawParagraph]\n\t\tcollectParas (t@(TeXEnv \"indexeditemdecl\" _ _) : more) =\n\t\t\tRawParagraph False False (parsePara [t]) Nothing : collectParas more\n\t\tcollectParas (t@(TeXEnv \"itemdecl\" _ _) : more) =\n\t\t\tRawParagraph False False (parsePara [t]) Nothing : collectParas more\n\t\tcollectParas (TeXEnv \"itemdescr\" _ desc : more) =\n\t\t\tmap (\\p -> p{rawParaInItemdescr=True}) (collectParas desc)\n\t\t\t++ collectParas more\n\t\tcollectParas (TeXComm \"pnum\" _\n\t\t\t[ (FixArg, [TeXRaw (Text.unpack -> file)])\n\t\t\t, (FixArg, [TeXRaw (Text.unpack -> read -> lineNr)])] : more) =\n\t\t\t\t(\\(p : x) -> p{paraNumbered=True, rawParaSourceLoc=Just (SourceLocation file lineNr)} : x)\n\t\t\t\t(collectParas more)\n\t\tcollectParas (TeXComm \"pnum\" _ [] : more) =\n\t\t\t\t(\\(p : x) -> p{paraNumbered=True, rawParaSourceLoc=Nothing} : x)\n\t\t\t\t(collectParas more)\n\t\tcollectParas [] = []\n\t\tcollectParas x = (if null p then id else (RawParagraph False False p Nothing :)) (collectParas more)\n\t\t\twhere (parsePara -> p, more) = break isParaEnd x\n\nparseSections :: Int -> LaTeX -> [LinearSection]\nparseSections level (TeXComm \"textlarger\" _ _ : more) = parseSections level more\nparseSections level\n\t(TeXComm c _ args : (parseParas -> (lsectionParagraphs, lsectionFootnotes, more)))\n\t| ((FixArg, isJustRaw -> fromJust -> lsectionAbbreviation), (FixArg, lsectionName), lsectionKind, level') <- case (c, args) of\n\t\t(\"normannex\", [abbr, name]) -> (abbr, name, NormativeAnnexSection, level)\n\t\t(\"infannex\", [abbr, name]) -> (abbr, name, InformativeAnnexSection, level)\n\t\t(\"definition\", [name, abbr]) -> (abbr, name, DefinitionSection (level + 1), level)\n\t\t(\"rSec\", [(FixArg, [TeXRaw (Text.unpack -> read -> l)]), abbr, name]) ->\n\t\t\t(abbr, name, NormalSection l, l)\n\t\t_ -> error $ \"not a section command: \" ++ show (c, args)\n\t= LinearSection{..} : parseSections level' more\nparseSections _ [] = []\nparseSections l (x:xx)\n\t| TeXRaw t <- x, all isSpace (Text.unpack t) = parseSections l xx\n\t| otherwise = error $ \"parseSections: \" ++ show x\n\nparseTable :: LaTeX -> [Row [RawTexPara]]\nparseTable latex\n\t| triml latex == [] = []\n\t| triml row == [] = parseTable $ tail rest\n\t| hasCommand (== \"endfirsthead\") row = parseTable $ findEndHead rest\n\t| hasCommand (`elem` [\"caption\", \"bottomline\"]) row = parseTable rest\n\t| otherwise = makeRow row : parseTable rest\n\twhere\n\t\t(row, rest) = break (== TeXLineBreak) latex\n\t\tfindEndHead l\n\t\t\t| row' == [] = findEndHead $ tail rest'\n\t\t\t| hasCommand (== \"endhead\") row' = l\n\t\t\t| otherwise = findEndHead rest'\n\t\t\twhere\n\t\t\t\t(row', rest') = break (== TeXLineBreak) l\n\ncolumnBreakCell :: Cell [RawTexPara]\ncolumnBreakCell = Cell Normal [RawTexPara [RawLatexElement (TeXComm \"columnbreak\" \"\" [])]]\nisColumnBreakCell :: Cell [RawTexPara] -> Bool\nisColumnBreakCell (Cell Normal [RawTexPara [RawLatexElement (TeXComm \"columnbreak\" _ [])]]) = True\nisColumnBreakCell _ = False\n\nmakeRectangular :: a -> [[a]] -> [[a]]\nmakeRectangular filler rows = (take numCols . (++ repeat filler)) . rows\n    where numCols = maximum (length . rows)\n        -- Todo: Remove this when the bugs in Chrome's collapsed border rendering are fixed.\n\nbreakMultiCols :: [Row [RawTexPara]] -> [Row [RawTexPara]]\n    -- implements the multicolfloattable environment's \\columnbreak, which is left intact by parseTable\nbreakMultiCols rows\n    | all (\\Row{..} -> length cells == 1 && rowSep == NoSep) rows =\n        Row NoSep . makeRectangular (Cell Normal []) (transpose $ splitOn isColumnBreakCell $ separateColumnBreaks $ (head . cells) . rows)\n    | otherwise = rows\n    where\n        separateColumnBreaks :: [Cell [RawTexPara]] -> [Cell [RawTexPara]]\n        separateColumnBreaks = concatMap f\n            where\n                f :: Cell [RawTexPara] -> [Cell [RawTexPara]]\n                f c@Cell{..} | [RawTexPara (RawLatexElement (TeXComm \"columnbreak\" _ []) : rest)] <- content =\n                        [columnBreakCell, c{content = [RawTexPara rest]}]\n                    | otherwise = [c]\n\nmakeRow :: LaTeX -> Row [RawTexPara]\nmakeRow l = Row sep $ makeRowCells l\n\twhere\n\t\tsep\n\t\t\t| hasCommand (== \"hline\") l = RowSep\n\t\t\t| hasCommand (== \"capsep\") l = CapSep\n\t\t\t| hasCommand (== \"cline\") l = Clines $ clines $ lookForCommand \"cline\" l\n\t\t\t| otherwise = NoSep\n\n\t\tclines [] = []\n\t\tclines (([(FixArg, [TeXRaw c])]) : rest) = (begin, end) : clines rest\n\t\t\twhere\n\t\t\t\t(begin', end') = Text.breakOn \"-\" c\n\t\t\t\tbegin = read $ Text.unpack begin' :: Int\n\t\t\t\tend = read $ Text.unpack $ Text.tail end' :: Int\n\t\tclines other = error $ \"Unexpected \\\\clines syntax: \" ++ show other\n\nparseWidth :: LaTeX -> (Maybe Text, LaTeX)\nparseWidth (TeXRaw \"\" : x) = parseWidth x\nparseWidth (TeXBraces [TeXRaw x] : rest) = (Just x, rest)\nparseWidth (TeXBraces [TeXRaw x, TeXComm \"hsize\" \"\" []] : rest) =\n\t(Just $ Text.pack (show (round ((read (\"0\" ++ Text.unpack x) :: Double) * 100) :: Int)) ++ \"%\", rest)\nparseWidth (TeXBraces _ : rest) = (Nothing, rest) -- remaining cases unsupported for now\nparseWidth x = (Nothing, x)\n\nparseColspec :: LaTeX -> [ColumnSpec]\nparseColspec = \\x -> case x of\n\t\t[] -> []\n\t\tTeXRaw (Text.unpack -> '|' : z) : y -> go (TeXRaw (Text.pack z) : y)\n\t\t_ -> go x\n\twhere\n\t\tgo :: LaTeX -> [ColumnSpec]\n\t\tgo [] = []\n\t\tgo [TeXRaw \"|\"] = []\n\t\tgo (TeXRaw \"@\" : TeXBraces _ : x) = go x -- unimplemented\n\t\tgo (TeXRaw \">\" : TeXBraces _ : x) = go x -- unimplemented\n\t\tgo (TeXRaw \"\" : y) = go y\n\t\tgo (TeXRaw (Text.uncons -> Just (letter, rest)) : y)\n\t\t    | letter == ' ' = go (TeXRaw rest : y)\n\t\t    | letter == '|' = mapHead (\\(ColumnSpec x _ z) -> ColumnSpec x True z) $ go (TeXRaw rest : y)\n\t\t    | otherwise =\n\t\t    \tlet (w, rest') = parseWidth (TeXRaw rest : y)\n\t\t    \tin ColumnSpec (colClass letter) False w : go rest'\n\t\tgo x = error (\"parseColspec: \" ++ show x)\n\t\t\n\t\tcolClass :: Char -> TextAlignment\n\t\tcolClass x | x `elem` ['l', 'm', 'x'] = AlignLeft\n\t\tcolClass 'p' = Justify\n\t\tcolClass 'r' = AlignRight\n\t\tcolClass 'c' = AlignCenter\n\t\tcolClass other = error $ \"Unexpected column type \" ++ (other : [])\n\nmakeRowCells :: LaTeX -> [Cell [RawTexPara]]\nmakeRowCells [] = []\nmakeRowCells latex =\n\tcase rest of\n\t\t[] -> [makeCell cell]\n\t\t_ : r ->\n\t\t\t(makeCell $ cell <> [TeXRaw cell']) : makeRowCells (TeXRaw rest'' : r)\n\twhere\n\t\t(cell, rest) = break isColEnd latex\n\t\tisColEnd (TeXRaw c) = isJust $ Text.find (== '&') c\n\t\tisColEnd _ = False\n\n\t\t(cell', rest') = Text.break (== '&') $ getText rest\n\t\trest'' = Text.drop 1 rest'\n\t\tgetText (TeXRaw s : _) = s\n\t\tgetText other = error $ \"Didn't expect \" ++ show other\n\n\t\tmakeCell content\n\t\t\t| [[(FixArg, [TeXRaw w]), (FixArg, cs), (FixArg, content')]] <- lookForCommand \"multicolumn\" content =\n\t\t\t\tCell (Multicolumn (read $ Text.unpack w) (head $ parseColspec cs)) $ parsePara content'\n\t\t\t| otherwise =\n\t\t\t\tCell Normal $ parsePara content\n\nrmExplSyntax :: Text -> Text\nrmExplSyntax = Text.unlines . f . Text.lines\n    where\n        f [] = []\n        f (\"\\\\ExplSyntaxOn\" : (dropWhile (/= \"\\\\ExplSyntaxOff\") -> (_ : x))) = f x\n        f (h : t) = h : f t\n\nloadMacros :: Text -> IO Macros\nloadMacros extraMacros =\n\t(initialMacros ++)\n\t. snd\n\t. doParse initialMacros\n\t. replace \"\\\\indeximpldef{\" \"\\\\index[impldefindex]{\"\n\t. textSubRegex (mkRegex \"\\\\\\\\penalty[0-9]+{}\") \"\"\n\t. textSubRegex (mkRegex \"\\\\\\\\verbtocs{[\\\\a-zA-Z]*}\\\\|[^|]*\\\\|\") \"\"\n\t. rmExplSyntax\n\t. (++ extraMacros)\n\t. mconcat\n\t. mapM readFile\n\t[\"config.tex\", \"macros.tex\", \"tables.tex\"]\n\nloadXrefDelta :: IO XrefDelta\nloadXrefDelta = do\n\t(tex, _, _) <- Parser.parseString initialContext . Text.unpack . readFile \"xrefdelta.tex\"\n\tlet lfc c = lookForCommand c tex\n\treturn $\n\t\t[ (fromJust $ isJustRaw $ snd from, [snd to])\n\t\t\t| [from, to] <- lfc \"movedxrefs\" ] ++\n\t\t[ (fromJust $ isJustRaw $ snd from, (:[]) . TeXComm \"ref\" \"\" . (:[]) . tos)\n\t\t\t| from : tos <- lfc \"movedxref\" ++ lfc \"movedxrefii\" ++ lfc \"movedxrefiii\" ] ++\n\t\t[ (abbr, [])\n\t\t\t| [(_, [TeXRaw abbr])] <- lfc \"removedxref\" ] ++\n\t\t[ (abbr, [[TeXComm \"ref\" \"\" [(FixArg, [TeXRaw (\"depr.\" ++ abbr)])]]])\n\t\t\t| [(_, [TeXRaw abbr])] <- lfc \"deprxref\" ]\n"
  },
  {
    "path": "Render.hs",
    "content": "{-# OPTIONS_GHC -fno-warn-tabs #-}\n{-# LANGUAGE\n\tOverloadedStrings,\n\tRecordWildCards,\n\tTupleSections,\n\tViewPatterns,\n\tNamedFieldPuns,\n\tLambdaCase,\n\tTypeSynonymInstances,\n\tFlexibleInstances #-}\n\nmodule Render (\n\tRender(render), concatRender, renderTab, renderFig, renderIndex, simpleRender, simpleRender2, squareAbbr,\n\tlinkToSection, secnum, Page(..), parentLink, abbrHref,\n\tdefaultRenderContext, isSectionPage,\n\tRenderContext(..), renderLatexParas\n\t) where\n\nimport Load14882 (parseIndex) -- todo: bad\nimport Document (\n\tCellSpan(..), Cell(..), RowSepKind(..), Row(..), Element(..), Draft(..), Footnote(..),\n\tTeXPara(..), Sentence(..), Abbreviation, sectionByAbbr, footnotes, ColumnSpec(..),\n\tSection(..), Chapter(..), Table(..), Figure(..), Sections(..), figures, formulas, tables, Item(..),\n\tIndexComponent(..), IndexTree, IndexNode(..), IndexKind(..), IndexEntry(..), Formula(..),\n\tIndexPath, indexKeyContent, tableByAbbr, figureByAbbr, formulaByAbbr, Paragraph(..), Note(..), Example(..),\n\tchapterOfSection)\nimport LaTeXBase (LaTeX, LaTeXUnit(..), ArgKind(..), MathType(..), lookForCommand, concatRaws,\n    renderLaTeX, trim, isMath, isCodeblock, texStripPrefix, texSpan, mapTeX, mapCommandName)\nimport qualified Data.IntMap as IntMap\nimport Data.Text (isPrefixOf)\nimport qualified Data.Text.Lazy.Builder as TextBuilder\nimport Debug.Trace (trace)\nimport qualified Data.Text as Text\nimport qualified Data.Text.Lazy as LazyText\nimport qualified Text.HTML.TagSoup as Soup\nimport Data.Char (isAlpha, isSpace, isAlphaNum, toLower, isUpper, ord, isDigit, toUpper)\nimport Control.Arrow (second)\nimport qualified Prelude ()\nimport qualified MathJax\nimport Prelude hiding (take, (.), (++), writeFile)\nimport Data.List (find, nub, intersperse, (\\\\), sortOn, dropWhileEnd)\nimport qualified Data.Map as Map\nimport Data.Maybe (isJust, fromJust)\nimport Pages (Link(..))\nimport Sentences (linkifyFullStop)\nimport Util ((.), (++), replace, Text, xml, spanTag, anchor, Anchor(..), greekAlphabet,\n    urlChars, intercalateBuilders, replaceXmlChars, spanJust, h, partitionBy, mapHead)\nimport CxxParser (parseCppDirective, parseLiteral, parseComment)\n\nkill, literal :: [String]\nkill = words $\n\t\"clearpage renewcommand newcommand enlargethispage noindent indent vfill pagebreak setlength \" ++\n\t\"caption capsep continuedcaption bottomline hline rowsep hspace endlist cline \" ++\n\t\"hfill nocorr small endhead kill footnotesize rmfamily microtypesetup nobreak nolinebreak \" ++\n\t\"topline FlushAndPrintGrammar left right protect = ! @ - xspace obeyspaces\"\nliteral = [\"#\", \"{\", \"}\", \"~\", \"%\", \"\"]\n\nsimpleMacros :: [(String, Text)]\nsimpleMacros =\n\t[ (\",\"              , \"<span style='white-space:nowrap'>&thinsp;</span>\")\n\t                           -- thin, non-breaking, non-stretching space\n\t, (\"\\\"\"             , \"\\\"\")\n\t, (\"`\"              , \"`\")\n\t, (\"prime\"          , \"'\")\n\t, (\"caret\"          , \"^\")\n\t, (\"copyright\"      , \"&copy;\")\n\t, (\"textregistered\" , \"&reg;\")\n\t, (\"Cpp\"            , \"C++\")\n\t, (\"sum\"            , \"∑\")\n\t, (\"bot\"            , \"⊥\")\n\t, (\"perp\"           , \"⊥\")\n\t, (\"ell\"            , \"ℓ\")\n\t, (\"shr\"            , \">>\")\n\t, (\"cv\"             , \"cv\")\n\t, (\"shl\"            , \"&lt;&lt;\")\n\t, (\"br\"             , \"<br/>\")\n\t, (\"linebreak\"      , \"<br/>\")\n\t, (\"sim\"            , \"~\")\n\t, (\"quad\"           , \"&emsp;&ensp;\")\n\t, (\"qquad\"          , \"&emsp;&emsp;\")\n\t, (\"indent\"         , \"&emsp;\")\n\t, (\"unun\"           , \"__\")\n\t, (\"^\"              , \"^\")\n\t, (\"ldots\"          , \"&hellip;\")\n\t, (\"vdots\"          , \"&#8942;\")\n\t, (\"dotsc\"          , \"&hellip;\")\n\t, (\"times\"          , \"&times;\")\n\t, (\"&\"              , \"&amp;\")\n\t, (\"$\"              , \"&#36;\")\n\t, (\"backslash\"      , \"\\\\\")\n\t, (\"textbackslash\"  , \"\\\\\")\n\t, (\"colcol\"         , \"::\")\n\t, (\"tilde\"          , \"~\")\n\t, (\"textasciitilde\" , \"~\")\n\t, (\"hspace\"         , \" \")\n\t, (\"space\"          , \" \")\n\t, (\"equiv\"          , \"&equiv;\")\n\t, (\"le\"             , \"&ensp;≤&ensp;\")\n\t, (\"leq\"            , \"&ensp;≤&ensp;\")\n\t, (\"ge\"             , \"&ensp;≥&ensp;\")\n\t, (\"geq\"            , \"&ensp;≥&ensp;\")\n\t, (\"neq\"            , \"&ensp;≠&ensp;\")\n\t, (\"land\"           , \"&ensp;∧&ensp;\")\n\t, (\"lor\"            , \"&ensp;∨&ensp;\")\n\t, (\"cdot\"           , \"·\")\n\t, (\"cdots\"          , \"⋯\")\n\t, (\"to\"             , \"→\")\n\t, (\"rightarrow\"     , \"→\")\n\t, (\"mapsto\"         , \"↦\")\n\t, (\"sqrt\"           , \"√\")\n\t, (\"lfloor\"         , \"⌊\")\n\t, (\"rfloor\"         , \"⌋\")\n\t, (\"lceil\"          , \"⌈\")\n\t, (\"rceil\"          , \"⌉\")\n\t, (\";\"              , \" \")\n\t, (\"min\"            , \"<span class=\\\"mathrm\\\">min</span>\")\n\t, (\"max\"            , \"<span class=\\\"mathrm\\\">max</span>\")\n\t, (\"bmod\"           , \"<span class=\\\"mathrm\\\">mod</span>\")\n\t, (\"exp\"            , \"<span class=\\\"mathrm\\\">exp</span>\")\n\t, (\"ln\"             , \"<span class=\\\"mathrm\\\">ln</span>\")\n\t, (\"log\"            , \"<span class=\\\"mathrm\\\">log</span>\")\n\t, (\"opt\"            , \"<sub><small>opt</small></sub>\")\n\t, (\"rightshift\"     , \"<span class=\\\"mathsf\\\">rshift</span>\")\n\t, (\"textlangle\"     , \"&langle;\")\n\t, (\"textrangle\"     , \"&rangle;\")\n\t, (\"textmu\"         , \"μ\")\n\t, (\"tablerefname\"   , \"Table\")\n\t, (\"figurerefname\"  , \"Figure\")\n\t, (\"newline\"        , \"<br>\")\n\t, (\">\"              , \"&#9;\")\n\t, (\"bnfindent\"      , \"&emsp;&emsp;&emsp;\")\n\t, (\"\\n\"             , \"\\n\")\n\t]\n\t++ [(n, Text.pack [c]) | (n, c) <- greekAlphabet]\n\nzwsp :: Text\nzwsp = \"&#x200b;\" -- U+200B ZERO WIDTH SPACE\n\nmakeSpan, makeDiv :: [String]\nmakeSpan = words \"center mbox mathsf emph textsc phantom term mathtt textnormal textrm descr textsl textit mathit indented\"\nmakeDiv = words \"definition cvqual emph exitnote footnote mathit paras ttfamily TableBase table tabular longtable\"\n\nindexPathString :: IndexPath -> Text\nindexPathString =\n\treplace \" \" \"_\" . -- HTML forbids space.\n\tText.intercalate \",\" .\n\tmap (indexKeyContent . indexKey)\n\nindexShortName :: Text -> Maybe IndexKind -> Text\nindexShortName \"grammarindex\" (Just DefinitionIndexEntry) = \"nt\"\nindexShortName \"grammarindex\" Nothing = \"ntref\"\nindexShortName \"conceptindex\" (Just DefinitionIndexEntry) = \"concept\"\nindexShortName \"conceptindex\" Nothing = \"conceptref\"\nindexShortName \"headerindex\" (Just DefinitionIndexEntry) = \"header\"\nindexShortName \"headerindex\" Nothing = \"headerref\"\nindexShortName \"generalindex\" (Just DefinitionIndexEntry) = \"def\"\nindexShortName \"generalindex\" _ = \"\"\nindexShortName \"libraryindex\" _ = \"lib\"\nindexShortName \"impldefindex\" _ = \"\"\nindexShortName \"bibliography\" _ = \"bib\"\nindexShortName cat _ = error $ \"indexShortName: unrecognized category: \" ++ Text.unpack cat\n\nindexPathId :: Text -> Maybe IndexKind -> IndexPath -> Text\nindexPathId category kind =\n\t(indexShortName category kind ++) .\n\t(\":\" ++) .\n\treplace \" \"  \"%20\" .\n\treplace \"'\" \"&#39;\" .\n\treplace \"&\" \"&amp;\" .\n\tindexPathString\n\nindexPathId2 :: RenderContext -> Int -> Text -> IndexPath -> Maybe IndexKind -> Text\nindexPathId2 ctx entryNr cat path kind = indexPathId cat kind path ++ indexOccurrenceSuffix ctx entryNr\n\nindexPathId3 :: RenderContext -> LaTeX -> Text\nindexPathId3 ctx indices = indexPathId2 ctx inum icat ipath ikind\n\twhere (icat, ipath, inum, ikind) : _ = indexPaths indices\n\nindexPathHref :: Text -> Maybe IndexKind -> IndexPath -> Text\nindexPathHref cat kind = ((\"#\" ++ indexShortName cat kind ++ \":\") ++) . urlChars . replace \"&\" \"&amp;\" . indexPathString\n\nasId :: LaTeX -> Text\nasId = mconcat . map f\n\twhere\n\t\tf :: LaTeXUnit -> Text\n\t\tf (TeXRaw t) = replace \"\\n\" \"_\" $ replace \" \" \"_\" t\n\t\tf (TeXComm \"tcode\" _ [(_, x)]) = asId x\n\t\tf (TeXComm \"noncxxtcode\" _ [(_, x)]) = asId x\n\t\tf (TeXComm \"texttt\" _ [(_, x)]) = asId x\n\t\tf (TeXComm \"textit\" _ [(_, x)]) = asId x\n\t\tf (TeXComm \"mathsf\" _ [(_, x)]) = asId x\n\t\tf (TeXComm \"xspace\" _ []) = \"_\"\n\t\tf (TeXBraces x) = asId x\n\t\tf (TeXMath Dollar x) = asId x\n\t\tf (TeXComm \"texorpdfstring\" _ [_, (_, x)]) = asId x\n\t\tf x = error $ \"asId: unexpected: \" ++ show x\n\ninstance Render Anchor where\n\trender Anchor{..} _ =\n\t\txml \"a\" ([(\"class\", aClass) | aClass /= \"\"] ++\n\t\t         [(\"href\" , aHref ) | aHref  /= \"\"] ++\n\t\t         [(\"id\"   , aId   ) | aId    /= \"\"] ++\n\t\t         [(\"title\", aTitle) | aTitle /= \"\"] ++\n\t\t         [(\"style\", aStyle) | aStyle /= \"\"]) aText\n\nclass Render a where render :: a -> RenderContext -> TextBuilder.Builder\n\nconcatRender :: Render a => [a] -> RenderContext -> TextBuilder.Builder\nconcatRender x c = mconcat $ map (\\y -> render y c) x\n\ninstance Render Char where render c _ = TextBuilder.singleton c\n\ninstance (Render a, Render b) => Render (a, b) where\n\trender (x, y) = render x ++ render y\n\nrenderCodeblock :: String -> [(ArgKind, LaTeX)] -> LaTeX -> RenderContext -> TextBuilder.Builder\nrenderCodeblock env args code ctx =\n    (case (env, args) of\n      (\"codeblocktu\", [(FixArg, title)]) -> ((\"<p>\" ++ render title ctx ++ \":\") ++)\n      (\"indexedcodeblock\", [(FixArg, indices)]) ->\n      \tlet\n      \t\tlink = anchor\n      \t\t\t{ aClass = \"itemDeclLink\"\n      \t\t\t, aHref = \"#\" ++ urlChars (indexPathId3 ctx indices)\n      \t\t\t, aText = \"🔗\" }\n      \tin\trenderIndexed ctx \"span\" indices .\n      \t\t(xml \"div\" [(\"class\", \"marginalizedparent\")] (render link ctx) ++)\n      _ -> id) $\n    xml \"span\" [(\"class\", \"codeblock\")] (\n        highlightLines ctx{rawTilde=True, rawHyphens=True, rawSpace=True, inCodeBlock=True} $\n        concatRaws $ expandTcode (dropInitialNewline code))\n  where\n    dropInitialNewline :: LaTeX -> LaTeX\n    dropInitialNewline (TeXRaw (Text.uncons -> Just ('\\n', rest)) : more) = TeXRaw rest : more\n    dropInitialNewline x = x\n    expandTcode :: LaTeX -> LaTeX\n    expandTcode [] = []\n    expandTcode (TeXComm \"tcode\" _ [(FixArg, x)] : y) = expandTcode (x ++ y)\n    expandTcode (x : y) = x : expandTcode y\n\nrenderOutputblock :: LaTeX -> RenderContext -> TextBuilder.Builder\nrenderOutputblock code ctx = xml \"pre\" [(\"class\", \"outputblock\")] $\n    render code ctx{rawTilde=True, rawHyphens=True, rawSpace=True}\n\nsameIdNamespace :: Maybe IndexKind -> Maybe IndexKind -> Bool\nsameIdNamespace Nothing (Just IndexOpen) = True\nsameIdNamespace (Just IndexOpen) Nothing = True\nsameIdNamespace x y = x == y\n\nisFullPage :: Page -> Bool\nisFullPage FullPage = True\nisFullPage _ = False\n\nabbrIsOnPage :: Abbreviation -> Page -> Bool\nabbrIsOnPage _ FullPage = True\nabbrIsOnPage abbr TablesPage = \"tab:\" `isPrefixOf` abbr\nabbrIsOnPage abbr FiguresPage = \"fig:\" `isPrefixOf` abbr\nabbrIsOnPage abbr (FigurePage Figure{..}) = abbr == figureAbbr\nabbrIsOnPage abbr (TablePage Table{..}) = abbr == tableAbbr\nabbrIsOnPage abbr (SectionPage sec)\n\t| \"fig:\" `isPrefixOf` abbr = abbr `elem` (figureAbbr . snd . figures sec)\n\t| \"eq:\" `isPrefixOf` abbr = abbr `elem` (formulaAbbr . snd . formulas sec)\n\t| \"tab:\" `isPrefixOf` abbr = abbr `elem` (tableAbbr . snd . tables sec)\n\t| otherwise = abbr `elem` (abbreviation . sections sec)\nabbrIsOnPage _ _ = False\n\npageIndexEntries :: RenderContext -> IntMap.IntMap IndexEntry\npageIndexEntries c\n    | SectionPage s <- page c = secIndexEntries s\n    | otherwise = indexEntryMap (draft c)\n\nindexOccurrenceSuffix :: RenderContext -> Int -> Text\n\t-- Returns the _ that distinguishes expr#def:object_expression from\n\t-- expr#def:object_expression_ ([expr] has two definitions of 'object expression',\n\t-- one for E1.E2 and one for E1.*E2.)\nindexOccurrenceSuffix c indexNum = underscores\n\twhere\n\t\tJust theEntry = IntMap.lookup indexNum (pageIndexEntries c)\n\t\ties\n\t\t\t| SectionPage s <- page c = secIndexEntriesByPath s\n\t\t\t| otherwise = indexEntriesByPath (draft c)\n\t\tunderscores = Text.pack\n\t\t\t[ '_' | (i, e) <- fromJust (Map.lookup (indexPath theEntry) ies)\n\t\t\t     , indexCategory e == indexCategory theEntry\n\t\t\t     , sameIdNamespace (indexEntryKind e) (indexEntryKind theEntry)\n\t\t\t     , i < indexNum ]\n\ninstance Render LaTeX where\n\trender (TeXComm \"textbackslash\" _ [] : y)\n\t\t| (TeXRaw s : rest) <- y  = \\sec -> \"\\\\\" ++ render (TeXRaw $ if rawSpace sec then s else unspace s) sec ++ render rest sec\n\t\twhere\n\t\t\tunspace s\n\t\t\t\t| Just (c, cc) <- Text.uncons s, isSpace c = cc\n\t\t\t\t| otherwise = s\n\trender (TeXComm \"itshape\" _ [] : x) = (\"<i>\" ++) . (++ \"</i>\") . render x\n\trender (x : y) = render x ++ render y\n\trender [] = return \"\"\n\nkeywords :: [Text]\nkeywords = map Text.pack $ words $\n    \"char8_t char16_t char32_t namespace struct void operator friend template typedef long short class double public extern \" ++\n    \"using char new union unsigned sizeof alignas typename virtual this return const_cast delete noexcept static_cast \" ++\n    \"reinterpret_cast mutable bool private protected inline constexpr consteval final volatile default explicit enum export asm \" ++\n    \"typeid dynamic_cast throw if else for do while goto auto concept requires decltype try catch static_assert wchar_t \" ++\n    \"case switch alignof break continue signed audit axiom override const register thread_local int float static module import \" ++\n    \"co_return co_await co_yield constinit contract_assert\"\n    -- todo: read the real keyword table instead\n\nhighlightLines :: RenderContext -> LaTeX -> TextBuilder.Builder\nhighlightLines ctx x\n    | (spaces, x') <- texSpan (== ' ') x, spaces /= \"\" = TextBuilder.fromText spaces ++ highlightLines ctx x'\n    | Just (directive, x') <- parseCppDirective x = spanTag \"preprocessordirective\" (render directive ctx) ++ highlight ctx x'\n    | TeXComm (Text.pack -> c) _ [(FixArg, y)] : more <- x, c `elem` [\"terminal\"] = spanTag c (highlightLines ctx y) ++ highlight ctx more\n    | i@(TeXComm cmd _ _) : more <- x, cmd `elem` [\"index\", \"obeyspaces\"] = render i ctx ++ highlightLines ctx more\n    | otherwise = highlight ctx x\n\nhighlightUnit :: RenderContext -> LaTeXUnit -> TextBuilder.Builder\nhighlightUnit ctx x = case x of\n    TeXComm \"rlap\" _ [(FixArg, text)] ->\n        spanTag \"rlap\" (highlight ctx text)\n    TeXComm \"indexedspan\" _ [(FixArg, text), (FixArg, indices)] ->\n        renderIndexed ctx \"span\" indices (highlight ctx text)\n    TeXComm \"terminal\" _ [(FixArg, y)] ->\n        spanTag \"terminal\" (highlight ctx y)\n    TeXComm c _ []\n        | c `elem` [\"%\", \"&\", \"caret\", \"~\"] -> spanTag \"operator\" (render x ctx)\n        | c == \"#\" -> spanTag \"preprocessordirective\" (render x ctx)\n        | c `elem` [\"{\", \"}\"] -> spanTag \"curlybracket\" (render x ctx)\n    TeXBraces y -> highlight ctx y\n    _ -> render x ctx\n\nhighlight :: RenderContext -> LaTeX -> TextBuilder.Builder\nhighlight ctx (TeXRaw kwd : TeXComm \"-\" \"\" [] : x)\n    | kwd `elem` keywords = TextBuilder.fromText kwd ++ highlight ctx x\nhighlight ctx (TeXRaw kwd : rest@(TeXComm \"textit\" _ [(FixArg, (TeXRaw (Text.uncons -> Just (isAlphaNum -> True, _)) : _))] : _))\n    | kwd `elem` keywords = TextBuilder.fromText kwd ++ highlight ctx rest\nhighlight ctx x\n    | Just x' <- texStripPrefix \"\\n\" x = \"\\n\" ++ highlightLines ctx x'\n    | (TeXRaw \"\" : t) <- x = highlight ctx t\n    | Just (lit, x') <- parseLiteral x = spanTag \"literal\" (render lit ctx) ++ highlight ctx x'\n    | Just (comment, x') <- parseComment x = spanTag \"comment\" (render comment ctx{inComment=True, rawTilde=False}) ++ highlightLines ctx x'\n    | Just x' <- texStripPrefix \"<new>\" x = spanTag \"operator\"\"<\" ++ \"new\" ++ spanTag \"operator\" \">\" ++ highlight ctx x'\n    -- keywords\n    | (a, x') <- texSpan p x, a /= \"\" = (case () of\n        _ | a `elem` keywords -> spanTag \"keyword\"\n        _ | a `elem` [\"defined\", \"__has_include\", \"__has_embed\", \"__has_cpp_attribute\", \"_Pragma\"] -> spanTag \"preprocessordirective\"\n        _ | a `elem` [\"nullptr\", \"true\", \"false\"] -> spanTag \"literal\"\n        _ | otherwise -> id) (render (TeXRaw a) ctx) ++ highlight ctx x'\n    where p c = isAlphaNum c || c == '_'\nhighlight ctx (TeXRaw x : more)\n    | Text.head x `elem` (\"'\\\"\" :: String) = render (TeXRaw $ Text.take 1 x) ctx ++ highlight ctx (TeXRaw (Text.tail x) : more)\n    | Text.head x `elem` (\"()\"::String) = spanTag \"parenthesis\" (render (TeXRaw $ Text.take 1 x) ctx) ++ highlight ctx (TeXRaw (Text.tail x) : more)\n    | Text.head x `elem` (\"{}\"::String) = spanTag \"curlybracket\" (render (TeXRaw $ Text.take 1 x) ctx) ++ highlight ctx (TeXRaw (Text.tail x) : more)\n    | Text.head x `elem` (\"[]\"::String) = spanTag \"squarebracket\" (render (TeXRaw $ Text.take 1 x) ctx) ++ highlight ctx (TeXRaw (Text.tail x) : more)\n    | Text.head x `elem` (\"<>\"::String) = spanTag \"anglebracket\" (render (TeXRaw $ Text.take 1 x) ctx) ++ highlight ctx (TeXRaw (Text.tail x) : more)\n    | Text.head x == '#' = spanTag \"preprocessordirective\" \"#\" ++ highlight ctx (TeXRaw (Text.tail x) : more)\n    | Text.take 2 x == \"::\"\n        = spanTag \"operator\" (render (TeXRaw \"::\") ctx) ++ highlight ctx (TeXRaw (Text.drop 2 x) : more)\n    | Text.head x `elem` (\"*&^.-+/!=|:?%~#\"::String)\n        = spanTag \"operator\" (render (TeXRaw (Text.take 1 x)) ctx) ++ highlight ctx (TeXRaw (Text.tail x) : more)\n    | (a, x') <- Text.span (\\c -> not (isAlphaNum c || c `elem` (\"#%_(){}[]<>.*:?'\\\"+=-/|&!^~\\n\" :: String))) x, a /= \"\"\n        = render (TeXRaw a) ctx ++ highlight ctx (TeXRaw x' : more)\n    | otherwise = error (\"shit: \" ++ show x)\nhighlight ctx (x : more) = highlightUnit ctx x ++ highlight ctx more\nhighlight _ [] = \"\"\n\nindexPaths :: LaTeX -> [(Text, IndexPath, Int, Maybe IndexKind)]\nindexPaths indices =\n\t[ (cat, path, entryNr, kind)\n\t| [ (FixArg, [TeXRaw (Text.unpack -> read -> entryNr)])\n\t   , (OptArg, [TeXRaw cat])\n\t   , (FixArg, (parseIndex -> (path, kind))) ] <- lookForCommand \"index\" indices]\n\nrenderIndexed :: RenderContext -> Text -> LaTeX -> TextBuilder.Builder -> TextBuilder.Builder\nrenderIndexed ctx thing indices body = foldl f body (indexPaths indices)\n\twhere f t (cat, path, entryNr, kind) = xml thing [(\"id\", indexPathId2 ctx entryNr cat path kind)] t\n\ncommasAnd :: [TextBuilder.Builder] -> TextBuilder.Builder\ncommasAnd [] = undefined\ncommasAnd [x] = x\ncommasAnd [x, y] = x ++ \" and \" ++ y\ncommasAnd [x, y, z] = x ++ \", \" ++ y ++ \", and \" ++ z\ncommasAnd (x : y) = x ++ \", \" ++ commasAnd y\n\nabbrTitle :: Text -> Bool -> RenderContext -> Text\nabbrTitle \"bibliography\" _ _ = \"Bibliography\"\nabbrTitle abbr includeAbbr ctx\n\t| \"tab:\" `isPrefixOf` abbr\n\t, Just Table{..} <- tableByAbbr (draft ctx) abbr =\n\t\t\t\"Table \" ++ Text.pack (show tableNumber) ++ \": \" ++\n\t\t\tLazyText.toStrict (TextBuilder.toLazyText $ render tableCaption ctx{noTags=True})\n\t| Just sec@Section{..} <- sectionByAbbr (draft ctx) abbr =\n\t\tLazyText.toStrict $ TextBuilder.toLazyText $\n\t\t\tsecnumText sec ++ \"&emsp;\" ++\n\t\t\trender sectionName ctx{noTags=True} ++\n\t\t\tTextBuilder.fromText (if includeAbbr then \"&emsp;[\" ++ abbr ++ \"]\" else \"\")\n\t| otherwise = \"\"\n\nrenderBreak :: RenderContext -> TextBuilder.Builder\nrenderBreak ctx = if noTags ctx then \"\\n\" else \"<br>\"\n\nrenderIndexLink :: String -> [(ArgKind, [LaTeXUnit])] -> RenderContext -> TextBuilder.Builder\nrenderIndexLink cmd [(FixArg, txt), (FixArg, [TeXRaw cat]), (FixArg, rawIndexPath), (FixArg, abbr_arg)] ctx\n\t| not (noTags ctx)\n\t, Just abbr <- mabbr = render anchor\n\t\t{ aText = render txt ctx{inLink=True}\n\t\t, aHref = (if abbrIsOnPage abbr (page ctx) then \"\" else linkToSectionHref SectionToSection abbr)\n\t\t\t++ indexPathHref cat kind p\n\t\t, aTitle = abbrTitle abbr True ctx\n\t\t, aClass = if cmd == \"hiddenindexlink\" then \"hidden_link\" else \"\"\n\t\t} ctx\n\t| otherwise = render txt ctx\n\twhere\n\t\t(p, kind) = parseIndex rawIndexPath\n\t\tresolved :: Maybe Text\n\t\tresolved = case Map.lookup p $ indexEntriesByPath (draft ctx) of\n\t\t\t\tJust entries\n\t\t\t\t\t| (hd:_) <- [ abbreviation\n\t\t\t\t\t            | (_, IndexEntry{indexEntrySection=abbreviation, indexEntryKind}) <- entries\n\t\t\t\t\t            , indexEntryKind == kind\n\t\t\t\t\t            , not (\"gram.\" `isPrefixOf` abbreviation) ] -> Just hd\n\t\t\t\t_ -> Nothing\n\t\ttraceIfBad\n\t\t\t| resolved == Nothing, cat /= \"grammarindex\", cat /= \"bibliography\" =\n\t\t\t\ttrace $ \"\\nbad index link: \" ++ show (cat, rawIndexPath)\n\t\t\t\t\t++ \"\\nlookup result: \" ++ show (Map.lookup p $ indexEntriesByPath (draft ctx))\n\t\t\t| otherwise = id\n\t\tmabbr = traceIfBad $ case abbr_arg of\n\t\t\t\t[] -> resolved\n\t\t\t\t[TeXRaw x] -> Just x\n\t\t\t\ty -> error $ \"bad indexlink arg: \" ++ show y\nrenderIndexLink _ _ _ = error \"bad indexlink\"\n\ninstance Render LaTeXUnit where\n\trender (TeXRaw x                 ) = \\RenderContext{..} -> TextBuilder.fromText\n\t    $ (if rawHyphens then id else replace \"--\" \"–\" . replace \"---\" \"—\")\n\t    $ (if not inCodeBlock then replace \"''\" \"”\" else id)\n\t    $ (if rawTilde then id else replace \"~\" \" \")\n\t    $ (if not insertBreaks then id else\n\t    \treplace \"::\" (zwsp ++ \"::\" ++ zwsp) .\n\t    \treplace \"\\1\" \"__\" .\n\t    \treplace \"_\" (if noTags then \"_&shy;\" else \"_<span class='shy'></span>\") .\n\t    \treplace \"__\" \"\\1\")\n\t    $ (if replXmlChars then replaceXmlChars else id)\n\t    $ x\n\trender (TeXComm \"br\" _ _         ) = renderBreak\n\trender  TeXLineBreak               = renderBreak\n\trender (TeXComm \"break\" _ []     ) = renderBreak\n\trender (TeXBraces t              ) = render t\n\trender m@(TeXMath _ _            ) = renderMath [m]\n\trender (TeXComm \"commentellip\" _ []) = const $ spanTag \"comment\" \"/* ... */\"\n\trender (TeXComm \"ensuremath\" _ [(FixArg, x)]) = renderMath x\n\trender (TeXComm \"hyperref\" _ [_, (FixArg, x)]) = render x\n\trender (TeXComm \"label\" _ [(FixArg, [TeXRaw x])]) = render anchor{aId = x, aClass = \"index\"}\n\trender (TeXComm \"ref*\" x y) = render (TeXComm \"ref\" x y)\n\trender (TeXComm \"ref\" _ [(FixArg, concatRaws -> [TeXRaw abbr])]) = \\ctx@RenderContext{..} ->\n\t\tlet\n\t\t\tlinkText :: TextBuilder.Builder\n\t\t\tlinkText\n\t\t\t\t| \"tab:\" `isPrefixOf` abbr\n\t\t\t\t, Just Table{..} <- tableByAbbr draft abbr = TextBuilder.fromString $ show tableNumber\n\t\t\t\t| \"fig:\" `isPrefixOf` abbr\n\t\t\t\t, Figure{..} <- figureByAbbr draft abbr = TextBuilder.fromString $ show figureNumber\n\t\t\t\t| \"eq:\" `isPrefixOf` abbr\n\t\t\t\t, f@Formula{..} <- formulaByAbbr draft abbr = TextBuilder.fromText $ fullFormulaNumber f\n\t\t\t\t| otherwise = squareAbbr (not noTags) abbr\n\t\t\trenderLabelRef sec =\n\t\t\t   simpleRender2 anchor{\n\t\t\t     aHref = abbrHref (abbreviation sec) ctx ++ \"#\" ++ abbr,\n\t\t\t     aText = squareAbbr (not noTags) (abbreviation sec),\n\t\t\t     aTitle = abbrTitle (abbreviation sec) False ctx }\n\t\t\trenderSectionRef =\n\t\t\t  simpleRender2 anchor{\n\t\t\t    aHref = abbrHref abbr ctx,\n\t\t\t    aText = linkText,\n\t\t\t    aTitle = abbrTitle abbr False ctx }\n\t    in if noTags then linkText else\n\t        case Map.lookup abbr (labels draft) of\n\t            Just sec -> renderLabelRef sec\n\t            Nothing\n\t                | SectionPage pageSec <- page, abbreviation pageSec == abbr -> linkText\n\t                | otherwise -> renderSectionRef\n\trender (TeXComm \"iref\" _ [(FixArg, [TeXRaw abbrs])]) = \\ctx ->\n\t    let renderAbbr abbr = render (TeXComm \"ref\" \"\" [(FixArg, [TeXRaw abbr])]) ctx\n\t    in \" (\" ++ mconcat (intersperse \", \" $ map (renderAbbr . Text.strip) $ Text.splitOn \",\" abbrs) ++ \")\"\n\trender (TeXComm \"nopnumdiffref\" _ [(FixArg, [TeXRaw (Text.splitOn \",\" -> abbrs)])]) = \\ctx ->\n\t    let f abbr = simpleRender2 anchor{aHref = abbrHref abbr ctx, aText = squareAbbr True abbr}\n\t    in \"<b>Affected \" ++ (if length abbrs == 1 then \"subclause\" else \"subclauses\") ++ \":</b> \"\n\t        ++ commasAnd (map f abbrs)\n\trender (TeXComm \"weblink\" _ [(FixArg, text), (FixArg, href)])\n\t\t= render anchor\n\t\t\t{ aText = simpleRender2 text\n\t\t\t, aHref = simpleRender href}\n\trender (TeXComm \"url\" _ [(FixArg, u)])\n\t\t= render anchor\n\t\t\t{ aText = simpleRender2 u\n\t\t\t, aHref = simpleRender u }\n\trender (TeXComm \"link\" _ [(FixArg, txt), (FixArg, [TeXRaw abbr])])\n\t\t= \\ctx -> if noTags ctx then render txt ctx else render anchor{\n\t\t\taHref = abbrHref abbr ctx,\n\t\t\taText = render txt ctx{inLink=True},\n\t\t\taTitle = abbrTitle abbr True ctx} ctx\n\trender (TeXComm c _ l) | c `elem` [\"indexlink\", \"hiddenindexlink\"] = renderIndexLink c l\n\trender (TeXComm \"color\" _ _) = const \"\"\n\trender (TeXComm \"textcolor\" _ [_, (FixArg, x)]) = render x\n\trender (TeXComm \"textsmaller\" _ [_, (FixArg, x)]) = render x\n\trender (TeXComm \"terminal\" _ [(FixArg, x)]) = spanTag \"terminal\" . flip highlightLines x\n\trender (TeXComm \"texttt\" _ [(FixArg, x)]) = \\ctx ->\n\t\t(if noTags ctx then id else spanTag \"texttt\") $ render x ctx{rawHyphens = True, insertBreaks = True}\n\trender (TeXComm \"literaltcode\" _ [(FixArg, x)]) = spanTag \"literal\" . spanTag \"texttt\" . render x\n\trender (TeXComm cmd _ [(FixArg, x)])\n\t\t| cmd `elem` [\"tcode\"] = \\ctx ->\n\t\tif noTags ctx then render x ctx{rawHyphens=True, insertBreaks=True}\n\t\telse spanTag (if inCodeBlock ctx then \"tcode_in_codeblock\" else \"texttt\") $\n\t\t\tif not (inComment ctx) && not (inLink ctx) && not (inSectionTitle ctx)\n\t\t\tthen highlightLines ctx{rawHyphens=True, insertBreaks=True} x\n\t\t\telse render x ctx{rawHyphens=True, insertBreaks=True}\n\trender (TeXComm \"noncxxtcode\" _ [(FixArg, x)]) = \\ctx ->\n\t\tspanTag (if inCodeBlock ctx then \"tcode_in_codeblock\" else \"texttt\") $\n\t\t    render x ctx{rawHyphens=True, insertBreaks=True}\n\trender (TeXComm \"textbf\" _ [(FixArg, x)]) = (\"<b>\" ++) . (++ \"</b>\") . render x\n\trender (TeXComm \"index\" _\n\t\t\t[ (FixArg, [TeXRaw (Text.unpack -> read -> entryNr)])\n\t\t\t, (OptArg, [TeXRaw category])\n\t\t\t, (FixArg, (parseIndex -> (p, kind)))\n\t\t\t])\n\t\t= \\ctx -> if noTags ctx then \"\" else case kind of\n\t\t\tJust IndexClose -> \"\"\n\t\t\tJust (See _ _) -> \"\"\n\t\t\t_ -> render anchor\n\t\t\t\t\t\t{ aId = indexPathId2 ctx entryNr category p kind\n\t\t\t\t\t\t, aClass = \"index\"} ctx\n\trender (TeXComm \"indexedspan\" _ [(FixArg, text), (FixArg, indices)]) =\n\t\t\\ctx -> (if noTags ctx then id else renderIndexed ctx \"span\" indices) $ render text ctx\n\trender (TeXEnv \"indexeditemdecl\" [(FixArg, indices)] t) = \\ctx ->\n\t\tlet\n\t\t\tlink = anchor\n\t\t\t\t{ aClass = \"itemDeclLink\"\n\t\t\t\t, aHref = \"#\" ++ urlChars (indexPathId3 ctx indices)\n\t\t\t\t, aText = \"🔗\" }\n\t\tin\n\t\t\trenderIndexed ctx \"div\" indices $\n\t\t\txml \"div\" [(\"class\", \"itemdecl\")] $\n\t\t\txml \"div\" [(\"class\", \"marginalizedparent\")] (render link ctx) ++\n\t\t\txml \"code\" [(\"class\", \"itemdeclcode\")] (TextBuilder.fromText $ Text.dropWhile (== '\\n') $ LazyText.toStrict $ TextBuilder.toLazyText $ highlightLines ctx{rawTilde=True, rawHyphens=True} t)\n\trender (TeXComm \"discretionary\" _ _) = const (TextBuilder.fromText zwsp)\n\trender (TeXComm \"ifthenelse\" _ [_, _, (FixArg, x)]) = render x\n\trender (TeXComm \"multicolumn\" _ [(FixArg, [TeXRaw n]), _, (FixArg, content)]) = xml \"td\" [(\"colspan\", n)] . render content\n\trender (TeXComm \"leftshift\" _ [(FixArg, content)]) =\n\t\t(spanTag \"mathsf\" \"lshift\" ++) . xml \"sub\" [(\"class\", \"math\")] . render content\n\trender (TeXComm \"verb\" _ [(FixArg, a)]) = \\c -> xml \"code\" [] $ render a c{rawTilde=True, rawHyphens=True}\n\trender (TeXComm \"footnoteref\" _ [(FixArg, [TeXRaw n])]) = \\ctx -> flip render ctx $ anchor\n\t\t{ aClass = \"footnoteref\"\n\t\t, aText  = TextBuilder.fromText n\n\t\t, aId    = \"footnoteref-\" ++ n\n\t\t, aTitle = (!! 3) $ iterate (Text.replace \"  \" \" \")\n\t\t\t\t $ Text.replace \"\\n\" \" \"\n\t\t\t\t $ Text.replace \"'\" \"&apos;\"\n\t\t\t\t $ LazyText.toStrict $ TextBuilder.toLazyText\n\t\t\t\t $ mconcat $ map (flip render ctx{noTags = True})\n\t\t\t\t $ footnoteContent $ snd\n\t\t\t\t $ footnotes (draft ctx) !! ((read (Text.unpack n) :: Int) - 1)\n\t\t, aHref  =\n\t\t\t(if isFullPage (page ctx) || isSectionPage (page ctx) then \"\" else \"SectionToSection/\" ++ paraUrl ctx)\n\t\t\t++ \"#footnote-\" ++ n }\n\trender (TeXComm \"raisebox\" _ args)\n\t\t| (FixArg, concatRaws -> [TeXRaw d]) <- head args\n\t\t, (FixArg, content) <- Prelude.last args =\n\t\t\tlet neg s\n\t\t\t\t| Text.head s == '-' = Text.tail s\n\t\t\t\t| otherwise = \"-\" ++ s\n\t\t\tin xml \"span\" [(\"style\", \"position: relative; top: \" ++ neg d)] . render content\n\trender (TeXComm \"parbox\" _ [_, (FixArg, x)]) = render x\n\trender (TeXComm \"term\" _ [(FixArg, x)]) =\n\t\t\\sec ->\n\t\t\tlet\n\t\t\t\ti = \"def:\" ++ asId x\n\t\t\t\t-- It's tempting to use 'term:' instead of 'def:' here, but if we do that,\n\t\t\t\t-- URLs break when upstream promotes a \\term to a \\defn.\n\t\t\tin render anchor\n\t\t\t\t{ aText  = \"<i>\" ++ render x sec ++ \"</i>\"\n\t\t\t\t, aId    = i\n\t\t\t\t, aHref  = \"#\" ++ urlChars i\n\t\t\t\t, aClass = \"hidden_link\" } sec\n\trender (TeXComm \"texorpdfstring\" _ [_, (FixArg, x)]) = render x\n\trender (TeXComm \" \" _ [])            = return \"&nbsp;\"\n\trender (TeXComm \"\\n\" _ [])           = return \"\\n\"\n\trender (TeXComm \"textit\" _ [(FixArg, x)]) = \\c -> (if noTags c then id else xml \"i\" []) $ render x c{rawTilde = False}\n\trender (TeXComm \"c\" _ [(FixArg, [TeXRaw \"t\"])]) = return \"ţ\"\n\trender (TeXComm s _ [])\n\t    | s == \"caret\"                 = return \"^\"\n\t    | s `elem` literal             = return $ TextBuilder.fromString s\n\t    | Just x <-\n\t       lookup s simpleMacros       = return $ TextBuilder.fromText x\n\t    | s `elem` kill                = return \"\"\n\t    | otherwise                    = return $ spanTag (Text.pack s) \"\"\n\trender (TeXComm \"class\" _ [(FixArg, [TeXRaw cls]), (FixArg, [TeXComm \"href\" _ [(FixArg, [TeXRaw href]), (FixArg, text)]])])\n\t    = \\ctx -> render anchor{aHref=href, aText=render text ctx, aClass=cls} ctx\n\trender (TeXComm \"class\" _ [(FixArg, [TeXRaw cls]), (FixArg, x)])\n\t    = \\ctx -> spanTag cls $ render x ctx\n\trender (TeXComm \"href\" _ [(FixArg, [TeXRaw href]), (FixArg, text)])\n\t    = \\ctx -> render anchor{aHref=href, aText=render text ctx} ctx\n\trender (TeXComm \"ucode\" _ [(FixArg, code)]) = spanTag \"ucode\" . render (TeXRaw \"U+\" : code)\n\trender (TeXComm x _ s)\n\t    | x `elem` kill                = return \"\"\n\t    | null s, Just y <-\n\t       lookup x simpleMacros       = return $ TextBuilder.fromText y\n\t    | [(FixArg, z)] <- s, Just y <-\n\t       lookup x simpleMacros       = (TextBuilder.fromText y ++) . render z\n\t    | otherwise                    = \\ctx -> (if noTags ctx then id else spanTag (Text.pack x)) $ render (s >>= snd) ctx\n\trender (TeXEnv \"itemdecl\" [(FixArg, [TeXRaw num])] t) = \\c ->\n\t\tlet\n\t\t\ti = case [(icat, ipath) | (icat, ipath, _inum, Just DefinitionIndexEntry) <- indexPaths t] of\n\t\t\t\t[(icat, ipath)] -> indexPathId icat (Just DefinitionIndexEntry) ipath\n\t\t\t\t_ -> mconcat (idPrefixes c) ++ \"itemdecl:\" ++ num\n\t\t\tlink = anchor{aClass=\"itemDeclLink\", aHref=\"#\" ++ urlChars i, aText=\"🔗\"}\n\t\tin\n\t\t\txml \"div\" [(\"class\", \"itemdecl\"), (\"id\", i)] $\n\t\t\txml \"div\" [(\"class\", \"marginalizedparent\")] (render link c) ++\n\t\t\txml \"code\" [(\"class\", \"itemdeclcode\")] (TextBuilder.fromText $ Text.dropWhile (== '\\n') $ LazyText.toStrict $ TextBuilder.toLazyText $ highlightLines c{rawTilde=True, rawHyphens=True} t)\n\trender env@(TeXEnv e args t)\n\t    | e `elem` makeSpan            = \\ctx -> (if noTags ctx then id else spanTag (Text.pack e)) (render t ctx)\n\t    | e `elem` makeDiv             = xml \"div\" [(\"class\", Text.pack e)] . render t\n\t    | isMath env && hasComplexMath True [env] = renderComplexMath [env]\n\t    | isCodeblock env              = renderCodeblock e args t\n\t\t| e == \"minipage\", [e2@(TeXEnv _ _ cb)] <- trim t, isCodeblock e2 =\n\t\t\txml \"div\" [(\"class\", \"minipage\")] . renderCodeblock \"codeblock\" [] cb\n\t\t| e == \"outputblock\"           = renderOutputblock t\n\t\t| e == \"itemdescr\"             = render t\n\t\t| e == \"thebibliography\"       = render t\n\t    | otherwise                    = error $ \"render: unexpected \" ++ show env\n\ninstance Render Int where render = return . TextBuilder.fromString . show\n\ninstance Render IndexComponent where\n\trender IndexComponent{..} = render indexKey\n\ninstance Render IndexEntry where\n\trender IndexEntry{indexEntryKind=Just (See also x), ..} = \\ctx ->\n\t\t\"<i>\" ++ (if also then \"see also\" else \"see\") ++ \"</i> \" ++\n\t\t\t render (anchor\n\t\t\t\t { aHref = \"#:\" ++\n\t\t\t\t (urlChars $\n\t\t\t\t  replace \" \" \"_\" $\n\t\t\t\t  replace \", \" \",\" $\n\t\t\t\t  indexKeyContent x)\n\t\t\t\t , aText = render x ctx}) ctx\n\trender IndexEntry{indexEntryKind=Just IndexClose} = return \"\"\n\trender IndexEntry{..} =\n\t\treturn $ simpleRender2 anchor\n\t\t\t{ aHref = \"SectionToSection/\" ++ urlChars indexEntrySection\n\t\t\t\t++ indexPathHref indexCategory indexEntryKind indexPath\n\t\t\t, aText = (if indexEntryKind == Just DefinitionIndexEntry then xml \"b\" [] else id) $ squareAbbr True indexEntrySection }\n\nindexDisplayOrder :: IndexComponent -> (([(Int, Int)], Int), ([(Int, Int)], Int))\nindexDisplayOrder y = (f (indexSortKey y), f (indexKey y))\n\twhere\n\t\tg :: Char -> (Int, Int)\n\t\tg c\n\t\t\t| isDigit c = (1, ord c)\n\t\t\t| isAlpha c = (2, ord (toLower c))\n\t\t\t| otherwise = (0, ord c)\n\t\the :: String -> ([(Int, Int)], Int)\n\t\the x = (map g x, if isUpper (head x) then 0 else 1)\n\t\tf = he . Text.unpack . indexKeyContent\n\ninstance Render [(IndexComponent, IndexNode)] where\n\trender tree ctx = go [] tree\n\t\twhere\n\t\t\tIndexPage cat = page ctx\n\t\t\tgo :: IndexPath -> [(IndexComponent, IndexNode)] -> TextBuilder.Builder\n\t\t\tgo up x = mconcat $ f up . (sortOn (indexDisplayOrder . fst) x)\n\n\t\t\tf :: IndexPath -> (IndexComponent, IndexNode) -> TextBuilder.Builder\n\t\t\tf up (comp, IndexNode{..}) =\n\t\t\t\tlet\n\t\t\t\t\tup' = up ++ [comp]\n\t\t\t\tin\n\t\t\t\t\txml \"div\" [(\"id\", indexPathId cat Nothing up')] $\n\t\t\t\t\txml \"div\" [(\"class\", \"indexitems\")] $\n\t\t\t\t\tTextBuilder.fromText (\n\t\t\t\t\tText.intercalate \", \" (nub $ filter (/= \"\") $ map (LazyText.toStrict . TextBuilder.toLazyText) $ render comp ctx : flip render ctx . indexEntries)) ++\n\t\t\t\t\tgo up' (Map.toList indexSubnodes)\n\ndata IndexHeading = Symbols | Numbers | Letter Char\n\tderiving (Eq, Ord)\n\ninstance Show IndexHeading where\n\tshow Symbols = \"Symbols\"\n\tshow Numbers = \"Numbers\"\n\tshow (Letter c) = [c]\n\nindexHeading :: IndexComponent -> IndexHeading\nindexHeading (indexSortKey -> indexKeyContent -> Text.head -> c)\n\t| isDigit c = Numbers\n\t| isAlpha c = Letter (toUpper c)\n\t| otherwise = Symbols\n\nindexSortKey :: IndexComponent -> LaTeX\nindexSortKey IndexComponent{..}\n\t| distinctIndexSortKey /= [] = distinctIndexSortKey\n\t| otherwise = indexKey\n\nrenderIndex :: RenderContext -> IndexTree -> TextBuilder.Builder\nrenderIndex ctx tree\n\t| name `elem` [\"generalindex\", \"libraryindex\"] = mconcat $ [\"<hr>\"] ++ linklines ++ [\"<hr>\"] ++ map sub p\n\t| otherwise = render (Map.toList tree) ctx\n\twhere\n\t\tIndexPage name = page ctx\n\t\tp = partitionBy (indexHeading . fst) $ Map.toList tree\n\t\tsub (n, ii) = h 2 (render anchor{aText=TextBuilder.fromText $ Text.pack (show n), aId=Text.pack (show n)} ctx) ++ render ii ctx\n\t\t(symnum, rest) = splitAt 2 p\n\t\tlinklines = map (h 2 . mconcat . intersperse \" \" . map (li . fst)) [symnum, rest]\n\t\tli n = render anchor{aText = TextBuilder.fromText $ Text.pack (show n), aHref = \"#\" ++ Text.pack (show n)} ctx\n\nrenderTab :: Bool -> Table -> Text -> Bool -> Bool -> RenderContext -> TextBuilder.Builder\nrenderTab stripTab Table{..} href boldCaption linkifyTableNum ctx =\n\txml \"div\" [(\"class\", \"numberedTable\"), (\"id\", id_)] $ -- todo: multiple abbrs?\n\t\t(if boldCaption then \"<b>\" else \"\") ++\n\t\t\"Table \" ++ tableNumF (render tableNumber ctx) ++ \" &mdash; \" ++\n\t\trender tableCaption ctx ++\n\t\t\"&emsp;\" ++\n\t\trender anchor{aText=\"[\" ++ TextBuilder.fromText tableAbbr ++ \"]\", aHref=href} ctx ++\n\t\t(if boldCaption then \"</b>\" else \"\") ++\n\t\t\"<br>\" ++\n\t\trenderTable columnSpec tableBody ctx\n\twhere\n\t\ttableNumF = if linkifyTableNum then linkify anchor{aHref = \"#\" ++ id_} ctx else id\n\t\tid_ = (if stripTab then replace \"tab:\" \"\" else id) tableAbbr\n\nlinkify :: Anchor -> RenderContext -> TextBuilder.Builder -> TextBuilder.Builder\nlinkify a ctx txt = render a{aText=txt} ctx\n\nrenderFig :: Bool -> Figure -> Text -> Bool -> Bool -> RenderContext -> TextBuilder.Builder\nrenderFig stripFig Figure{..} href boldCaption linkifyFigureNum ctx =\n\txml \"div\" [(\"class\", \"figure\"), (\"id\", id_)] $\n\t\tTextBuilder.fromText figureSvg ++ \"<br>\" ++\n\t\t(if boldCaption then \"<b>\" else \"\") ++\n\t\t\"Figure \" ++ figureNumF (render figureNumber ctx) ++ \" &mdash; \" ++\n\t\trender figureName ctx ++ \"&emsp;&ensp;\" ++\n\t\trender anchor{aText=squareAbbr False figureAbbr, aHref=href} ctx ++\n\t\t(if boldCaption then \"</b>\" else \"\")\n\twhere\n\t\tfigureNumF = if linkifyFigureNum then linkify anchor{aHref=\"#\" ++ id_} ctx else id\n\t\tid_ = (if stripFig then replace \"fig:\" \"\" else id) figureAbbr\n\ndata RenderItem = RenderItem { listOrdered :: Bool, item :: Item }\n\nspacedJoin :: TextBuilder.Builder -> TextBuilder.Builder -> TextBuilder.Builder\nspacedJoin x y\n\t| TextBuilder.toLazyText x == \"\" = y\n\t| TextBuilder.toLazyText y == \"\" = x\n\t| otherwise = x ++ \" \" ++ y\n\ninstance Render RenderItem where\n\trender RenderItem{item=Item Nothing mlabel elems paras} ctx\n\t\t= xml \"li\" attrs $ render elems ctx ++ renderLatexParas paras ctx\n\t\t\twhere\n\t\t\t    attrs\n\t\t\t        | Just [TeXRaw l] <- mlabel = [(\"id\", l)]\n\t\t\t        | otherwise = []\n\n\trender RenderItem{item=Item (Just nn) mlabel elems paras, ..} ctx\n\t\t| listOrdered =\n\t\t\txml \"tr\" [(\"id\", thisId)] $\n\t\t\t\t(xml \"td\" [] (case mlabel of\n\t\t\t\t\tNothing -> render link ctx'\n\t\t\t\t\tJust label -> render anchor{aHref = linkHref, aText=simpleRender2 label} ctx' ++ \" \")) ++\n\t\t\t\t(xml \"td\" [] content)\n\t\t| otherwise =\n\t\t\txml \"li\" [(\"id\", thisId)] $ case mlabel of\n\t\t\t\tNothing -> xml \"div\" [(\"class\", \"marginalizedparent\"), (\"style\", \"left:\" ++ left)] (render link ctx') ++ content\n\t\t\t\tJust label ->\n\t\t\t\t\trender anchor{aHref = linkHref, aText=simpleRender2 label} ctx'\n\t\t\t\t\t++ \" \" ++ content\n\t\twhere\n\t\t\tcontent = spacedJoin (render elems ctx') (renderLatexParas paras ctx')\n\t\t\tleft\n\t\t\t\t| listOrdered = \"-4.5em\"\n\t\t\t\t| otherwise = simpleRender (-marginalizedParentLeft - ulPaddingLeft * (length nn - 1) - extraIndentation ctx) ++ \"mm\"\n\t\t\tulPaddingLeft = 9\n\t\t\tmarginalizedParentLeft = 18\n\t\t\tthisId = mconcat (idPrefixes ctx) ++ Text.pack (Prelude.last nn)\n\t\t\tctx' = ctx{ idPrefixes = idPrefixes ctx ++ [Text.pack (Prelude.last nn) ++ \".\"] }\n\t\t\tdottedNumber = Text.intercalate \".\" (Text.pack . nn)\n\t\t\tlinkText\n\t\t\t\t| listOrdered =\n\t\t\t\t\tlet\n\t\t\t\t\t\ts = Prelude.last nn\n\t\t\t\t\t\tpunct\n\t\t\t\t\t\t\t| isAlpha (head s) = \")\"\n\t\t\t\t\t\t\t| otherwise = \".\"\n\t\t\t\t\tin\n\t\t\t\t\t\tText.pack $ s ++ punct\n\t\t\t\t| otherwise = \"(\" ++ dottedNumber ++ \")\"\n\t\t\tlinkClass\n\t\t\t\t| listOrdered = \"enumerated_item_num\"\n\t\t\t\t| otherwise = \"marginalized\"\n\t\t\tlinkHref = \"#\" ++ thisId\n\t\t\tlink = anchor{aClass=linkClass, aHref=linkHref, aText=TextBuilder.fromText linkText}\n\nparaUrl :: RenderContext -> Text\nparaUrl RenderContext{..} = urlChars $ abbreviation $ case nearestEnclosing of\n\tLeft p -> paraSection p\n\tRight s -> s\n\nprependSentence :: Sentence -> TeXPara -> TeXPara\nprependSentence s (TeXPara ss) = TeXPara (s : ss)\n\ninstance Render Footnote where\n\trender (Footnote n content) ctx =\n\t\t\txml \"div\" [(\"class\", \"footnote\"), (\"id\", i)] $\n\t\t\trenderParas (mapHead (prependSentence footnoteNum) content)\n\t\twhere\n\t\t\tfootnoteNum = Sentence Nothing [HtmlElement (LazyText.toStrict $ TextBuilder.toLazyText $ render (link, backlink) ctx)]\n\t\t\tctx' = ctx{idPrefixes = [i ++ \".\"]}\n\t\t\tbacklink = anchor{aText = linkText, aHref = \"#footnoteref-\" ++ num, aClass = \"footnoteBacklink\"}\n\t\t\trenderParas [] = \"\"\n\t\t\trenderParas (p:pp) = xml \"div\" [(\"class\", \"texpara\")] (render p ctx') ++ renderParas pp\n\t\t\tnum = Text.pack $ show n\n\t\t\ti = \"footnote-\" ++ num\n\t\t\tfootnoteIsOnPage = isFullPage (page ctx) || isSectionPage (page ctx)\n\t\t\tlinkText = TextBuilder.fromText $ num ++ \")\"\n\t\t\tlink = anchor\n\t\t\t\t{ aText = linkText\n\t\t\t\t, aClass = \"footnotenum\"\n\t\t\t\t, aHref =\n\t\t\t\t\t(if footnoteIsOnPage then \"\" else \"SectionToSection/\" ++ paraUrl ctx)\n\t\t\t\t\t++ \"#\" ++ i }\n\nnoWrapSpace :: TextBuilder.Builder\nnoWrapSpace = \"&nbsp;\"\n\ninstance Render Note where\n\trender Note{..} ctx = xml \"div\" [(\"id\", i), (\"class\", \"note\")] (renderParas True noteContent)\n\t\twhere\n\t\t\tprefix = \"[<i>\" ++ TextBuilder.fromText noteLabel ++ \"&nbsp;\" ++ render link ctx ++ \"</i>:&ensp;\"\n\t\t\tsuffix = \" —\" ++ noWrapSpace ++ \"<i>end note</i>]\"\n\t\t\trenderParas _ [] = \"\"\n\t\t\trenderParas isFirst (p:pp) = xml \"div\" [(\"class\", \"texpara\")] ((if isFirst then prefix else \"\") ++ render p ctx ++ (if null pp then suffix else \"\")) ++ renderParas False pp\n\t\t\ti = mconcat (dropWhileEnd (isDigit . Text.head) (idPrefixes ctx)) ++ \"note-\" ++ noteNum\n\t\t\tnoteNum = Text.pack $ show noteNumber\n\t\t\tlink = anchor{aHref = \"#\" ++ i, aText = TextBuilder.fromText noteNum }\n\ninstance Render Example where\n\trender Example{..} ctx\n\t\t| noTags ctx =\n\t\t\t\"[Example: \"\n\t\t\t++ renderLatexParas exampleContent ctx\n\t\t\t++ \" —&nbsp;end&nbsp;example] \"\n\t\t| otherwise = xml \"div\" [(\"id\", i), (\"class\", \"example\")] (renderParas True exampleContent)\n\t\twhere\n\t\t\tprefix = \"[<i>Example&nbsp;\" ++ render link ctx ++ \"</i>:&ensp;\"\n\t\t\tsuffix = \" —\" ++ noWrapSpace ++ \"<i>end example</i>]\"\n\t\t\trenderParas _ [] = \"\"\n\t\t\trenderParas isFirst (p:pp) = xml \"div\" [(\"class\", \"texpara\")] ((if isFirst then prefix else \"\") ++ render p ctx ++ (if null pp then suffix else \"\")) ++ renderParas False pp\n\t\t\ti = mconcat (dropWhileEnd (isDigit . Text.head) (idPrefixes ctx)) ++ \"example-\" ++ exNum\n\t\t\texNum = Text.pack $ show exampleNumber\n\t\t\tlink = anchor{aHref = \"#\" ++ i, aText = TextBuilder.fromText exNum }\n\ninstance Render Formula where\n    render f@Formula{..} ctx =\n            xml \"div\" [(\"class\", \"formula\"), (\"id\", formulaAbbr)] $\n                doRenderComplexMath [TeXMath Square ([tag] ++ formulaContent)] ctx\n        where tag = TeXComm \"tag\" \"\" [(FixArg, [TeXRaw (fullFormulaNumber f)])]\n\nfullFormulaNumber :: Formula -> Text\nfullFormulaNumber Formula{..} = Text.pack $ show chapterNum ++ \".\" ++ show formulaNumber\n  where chapterNum = sectionNumber $ chapterOfSection formulaSection\n\nnontermDef :: LaTeX -> Maybe Text\nnontermDef t\n\t| [n] <- [n | (\"grammarindex\", [IndexComponent{distinctIndexSortKey=[TeXRaw n]}], _inum, Just DefinitionIndexEntry) <- indexPaths t] = Just n\n\t| otherwise = Nothing\n\t\t\ninstance Render Element where\n\trender (HtmlElement html) = const $ TextBuilder.fromText html\n\trender (LatexElement x) = render x\n\trender (Codeblock x) = render x\n\trender (Itemdescr x) = xml \"div\" [(\"class\", \"itemdescr\")] . renderLatexParas x\n\trender (NoteElement x) = render x\n\trender (ExampleElement x) = render x\n\trender (Bnf e t) = xml \"div\" ([(\"class\", Text.pack e)] ++ idattr) . render t\n\t\twhere\n\t\t\tidattr\n\t\t\t\t| Just nt <- nontermDef t = [(\"id\", \"nt:\" ++ nt)]\n\t\t\t\t| otherwise = []\n\trender (TableElement t) = \\ctx ->\n\t\t\trenderTab False t (\"./SectionToSection/\" ++ tableAbbr t) False True ctx{idPrefixes=[tableAbbr t++\"-\"]}\n\trender (FigureElement f) = renderFig False f (\"./SectionToSection/\" ++ figureAbbr f) False True\n\trender (FormulaElement f) = render f\n\trender (Tabbing t) =\n\t\txml \"pre\" [] . TextBuilder.fromText . htmlTabs . LazyText.toStrict . TextBuilder.toLazyText . render (preprocessPre t) -- todo: this is horrible\n\trender Enumerated{..} = xml t [(\"class\", Text.pack enumCmd)] .\n\t\t\tconcatRender (RenderItem (enumCmd == \"enumerate\") . enumItems)\n\t\twhere\n\t\t\tt = case enumCmd of\n\t\t\t\t\"enumerate\" -> \"table\"\n\t\t\t\t\"itemize\" -> \"ul\"\n\t\t\t\t\"description\" -> \"ul\"\n\t\t\t\t\"thebibliography\" -> \"ul\"\n\t\t\t\t_ -> undefined\n\nclass HasComplexMath a where\n    hasComplexMath :: Bool -> a -> Bool\n\ninstance HasComplexMath LaTeXUnit where\n    hasComplexMath mathMode (TeXRaw x) = mathMode && Text.any (`elem` (\"+-*/^_=' \" :: String)) (Text.strip x)\n    hasComplexMath m (TeXComm c _ args)\n        | c `elem` words \"frac sum binom int sqrt lfloor rfloor lceil rceil log mathscr mapsto cdot bmod\" = True\n        | c `elem` words \"tcode\" = hasComplexMath False (map snd args)\n        | otherwise = hasComplexMath m (map snd args)\n    hasComplexMath _ (TeXMath _ x) = hasComplexMath True x\n    hasComplexMath m (TeXBraces x) = hasComplexMath m x\n    hasComplexMath m (TeXEnv e _ args)\n        | e `elem` [\"array\", \"eqnarray\"] = True\n        | otherwise = hasComplexMath m args\n    hasComplexMath _ TeXLineBreak = False\n\ninstance HasComplexMath a => HasComplexMath [a] where\n    hasComplexMath m = any (hasComplexMath m)\n\ndata Page\n\t= SectionPage Section\n\t| TablePage Table\n\t| FigurePage Figure\n\t| FullPage\n\t| IndexPage Text {- category -}\n\t| XrefDeltaPage\n\t| FootnotesPage\n\t| TablesPage\n\t| FiguresPage\n\t| TocPage\n\t| ExpandedTocPage\n\nisSectionPage :: Page -> Bool\nisSectionPage (SectionPage _) = True\nisSectionPage _ = False\n\ndata RenderContext = RenderContext\n\t{ page :: Page\n\t, draft :: Draft\n\t, nearestEnclosing :: Either Paragraph Section\n\t, rawHyphens :: Bool -- in real code envs /and/ in \\texttt\n\t, rawTilde :: Bool   -- in real code envs but not in \\texttt\n\t, rawSpace :: Bool\n\t, insertBreaks :: Bool\n\t, inLink :: Bool -- so as not to linkify grammarterms that appear as part of a defined/linkified term/phrase\n\t, inCodeBlock :: Bool -- in codeblocks, some commands like \\tcode have a different meaning\n\t, inComment :: Bool -- in comments, \\tcode should not be highlighted\n\t, inSectionTitle :: Bool -- in section titles, there should be no highlighting\n\t, replXmlChars :: Bool -- replace < with &lt;, etc\n\t, noTags :: Bool -- means we're rendering the contents of e.g. a \"title\" attribute which cannot contain tags/elements\n\t, extraIndentation :: Int -- in em\n\t, idPrefixes :: [Text] }\n\ndefaultRenderContext :: RenderContext\ndefaultRenderContext = RenderContext\n\t{ page = error \"no page\"\n\t, draft = error \"no draft\"\n\t, nearestEnclosing = error \"no para/sec\"\n\t, rawHyphens = False\n\t, rawTilde = False\n\t, rawSpace = False\n\t, insertBreaks = False\n\t, inLink = False\n\t, inCodeBlock = False\n\t, inComment = False\n\t, inSectionTitle = False\n\t, replXmlChars = True\n\t, noTags = False\n\t, extraIndentation = 0\n\t, idPrefixes = [] }\n\nsquareAbbr :: Bool -> Abbreviation -> TextBuilder.Builder\nsquareAbbr softHyphens =\n\t(\"[\" ++) . (++ \"]\") .\n\tTextBuilder.fromText .\n\t(if softHyphens then Text.replace \".\" \".<span class='shy'></span>\" else id)\n\nparentLink :: Section -> Abbreviation -> Text\nparentLink parent child\n\t| Just sub <- Text.stripPrefix (abbreviation parent ++ \".\") child = sub\n\t| otherwise = child\n\nabbrHref :: Abbreviation -> RenderContext -> Text\nabbrHref abbr RenderContext{..}\n\t| SectionPage sec <- page, abbreviation sec == abbr = \"#\"\n\t| abbrIsOnPage abbr page = \"#\" ++ case page of\n\t    SectionPage sec -> urlChars (parentLink sec abbr)\n\t    TablesPage | Just abbr' <- Text.stripPrefix \"tab:\" abbr -> urlChars abbr'\n\t    _ -> urlChars abbr\n\t| \"fig:\" `isPrefixOf` abbr =\n\t\tlet Figure{figureSection=Section{..}, ..} = figureByAbbr draft abbr\n\t\tin \"SectionToSection/\" ++ urlChars abbr ++ \"#\" ++ urlChars figureAbbr\n\t| \"eq:\" `isPrefixOf` abbr =\n\t\tlet Formula{formulaSection=Section{..}, ..} = formulaByAbbr draft abbr\n\t\tin \"SectionToSection/\" ++ urlChars abbr ++ \"#\" ++ urlChars formulaAbbr\n\t| \"tab:\" `isPrefixOf` abbr =\n\t\tcase tableByAbbr draft abbr of\n\t\t\tJust Table{tableSection=Section{..}, ..} -> \"SectionToSection/\" ++ urlChars abbreviation ++ \"#\" ++ urlChars tableAbbr\n\t\t\t_ -> \"#\" ++ urlChars abbr\n\t| otherwise = linkToSectionHref SectionToSection abbr\n\nprepMath :: LaTeX -> String\nprepMath = Text.unpack . renderLaTeX . (>>= cleanup) . replaceTcode\n  where\n    replaceTcode = mapCommandName (\\x -> if x == \"tcode\" then \"texttt\" else x)\n    cleanupText :: LaTeX -> LaTeX -- MathJax does not support \\, in \\text\n    cleanupText [] = []\n    cleanupText (TeXComm \",\" _ [] : x) = TeXRaw \" \" : cleanupText x\n    cleanupText (x : y) = cleanup x ++ cleanupText y\n    cleanup :: LaTeXUnit -> LaTeX\n    cleanup (TeXComm \"texttt\" _ [(FixArg, TeXComm \"texttt\" \"\" [(FixArg, x)] : y)]) =\n            cleanup (TeXComm \"texttt\" \"\" [(FixArg, x ++ y)])\n    cleanup (TeXComm \"texttt\" _ [(FixArg, TeXRaw x : y)]) =\n            TeXComm \"texttt\" \"\" [(FixArg, [TeXRaw x])] : cleanup (TeXComm \"texttt\" \"\" [(FixArg, y)])\n    cleanup (TeXComm \"texttt\" _ [(FixArg, TeXComm \"textit\" \"\" x : y)]) =\n        [TeXComm \"class\" \"\" [(FixArg, [TeXRaw \"textit\"]), (FixArg, [TeXComm \"texttt\" \"\" x])]]\n        ++ cleanup (TeXComm \"texttt\" \"\" [(FixArg, y)])\n        -- \\texttt{\\textit{x}y} -> \\class{textit}{\\texttt{x}}\\texttt{y}\n        -- MathJax does not support \\textit inside \\texttt\n    cleanup (TeXComm \"nontcode\" _ x) = [TeXComm \"texttt\" \"\" (map (second (>>= cleanup)) x)]\n    cleanup (TeXComm \"ensuremath\" _ [(FixArg, x)]) = x >>= cleanup\n    cleanup (TeXComm \"discretionary\" _ _) = []\n    cleanup (TeXComm \"hfill\" _ []) = []\n    cleanup (TeXComm \"text\" ws [(FixArg, x)]) = [TeXComm \"text\" ws [(FixArg, cleanupText x)]]\n    cleanup (TeXComm \"break\" _ []) = []\n    cleanup (TeXComm \"br\" _ []) = []\n    cleanup (TeXComm \"-\" _ []) = []\n    cleanup (TeXComm \"quad\" _ []) = [TeXRaw \" \"] -- because MathJax does not support \\quad\n    cleanup (TeXComm x ws y) = [TeXComm x ws (map (second (>>= cleanup)) y)]\n    cleanup x@(TeXRaw _) = [x]\n    cleanup (TeXBraces x) = [TeXBraces (x >>= cleanup)]\n    cleanup (TeXEnv x y z) = [TeXEnv x (map (second (>>= cleanup)) y) (z >>= cleanup)]\n    cleanup (TeXMath Dollar [c@(TeXComm \"text\" _ _)]) = cleanup c\n        -- because the draft sources have \\bigoh{$\\text{bla}$}, which MathJax doesn't support\n    cleanup (TeXMath x y) = [TeXMath x (y >>= cleanup)]\n    cleanup x@TeXLineBreak = [x]\n\nrenderMath :: LaTeX -> RenderContext -> TextBuilder.Builder\nrenderMath [TeXMath Dollar (c@(TeXComm \"noncxxtcode\" _ _) : more)] ctx =\n  render c ctx ++ renderMath [TeXMath Dollar more] ctx\nrenderMath m ctx\n\t| noTags ctx = renderSimpleMath m ctx\n\t| hasComplexMath True m = renderComplexMath (mapTeX replaceNonCxxTcode m) ctx\n\t| otherwise = spanTag (mathKind m) $ renderSimpleMath m ctx\n\twhere\n\t\tmathKind [TeXMath Square _] = \"mathblock\"\n\t\tmathKind _ = \"math\"\n\t\treplaceNonCxxTcode :: LaTeXUnit -> Maybe LaTeX\n\t\treplaceNonCxxTcode (TeXComm \"noncxxtcode\" _ args) = Just [TeXComm \"tcode\" \"\" args]\n\t\treplaceNonCxxTcode _ = Nothing\n\nrenderSimpleMath :: LaTeX -> RenderContext -> TextBuilder.Builder\nrenderSimpleMath [] _ = \"\"\nrenderSimpleMath (TeXRaw s : rest) sec\n\t| tlast `elem` [\"^\", \"_\"] = if noTags sec then \"�\" else\n\t\trenderSimpleMathUnit (TeXRaw $ Text.reverse $ Text.drop 1 s') sec\n\t\t++ xml tag [] (renderSimpleMath content sec)\n\t\t++ renderSimpleMath rest' sec\n\t| otherwise = renderSimpleMathUnit (TeXRaw s) sec ++ renderSimpleMath rest sec\n\twhere\n\t\ts' = Text.reverse s\n\t\ttlast = Text.take 1 s'\n\t\ttag = case tlast of\n\t\t\t\"^\" -> \"sup\"\n\t\t\t\"_\" -> \"sub\"\n\t\t\t_ -> error \"\"\n\t\t(content, rest') = case rest of\n\t\t\t(a : b) -> ([a], b)\n\t\t\tother -> (other, [])\nrenderSimpleMath (TeXComm \"frac\" _ [(FixArg, num)] : rest) sec =\n\t\"[\" ++ renderSimpleMath num sec ++ \"] / [\" ++ renderSimpleMath den sec ++ \"]\" ++ renderSimpleMath rest' sec\n\twhere\n\t\t(den, rest') = findDenum rest\n\t\tfindDenum (TeXBraces d : r) = (d, r)\n\t\tfindDenum (_ : r) = findDenum r\n\t\tfindDenum r = (r, [])\nrenderSimpleMath (x : y) ctx = renderSimpleMathUnit x ctx ++ renderSimpleMath y ctx\n\nrenderSimpleMathUnit :: LaTeXUnit -> RenderContext -> TextBuilder.Builder\nrenderSimpleMathUnit (TeXRaw s) sec =\n\tcase suffix of\n\t\tJust ('^', rest) -> if noTags sec then \"�\" else italicise prefix ++ output \"sup\" rest\n\t\tJust ('_', rest) -> if noTags sec then \"�\" else italicise prefix ++ output \"sub\" rest\n\t\t_ -> italicise s\n\twhere\n\t\t(prefix, suffix') = Text.break (`elem` ['^', '_']) s\n\t\tsuffix = Text.uncons suffix'\n\n\t\toutput :: Text -> Text -> TextBuilder.Builder\n\t\toutput tag rest =\n\t\t\tcase Text.uncons rest of\n\t\t\t\tJust (c, rest') -> xml tag [] (italicise $ Text.singleton c) ++ (renderSimpleMathUnit (TeXRaw rest') sec)\n\t\t\t\tNothing -> error \"Malformed math\"\n\n\t\titalicise :: Text -> TextBuilder.Builder\n\t\titalicise t = if noTags sec then TextBuilder.fromText t else\n\t\t\tcase Text.span isAlpha t of\n\t\t\t\t(\"\", \"\") -> TextBuilder.fromString \"\"\n\t\t\t\t(\"\", rest) ->\n\t\t\t\t\tcase Text.uncons rest of\n\t\t\t\t\t\tJust (c, rest') -> entities c ++ italicise rest'\n\t\t\t\t\t\tNothing -> error \"\"\n\t\t\t\t(alpha, rest) -> spanTag \"mathalpha\" (TextBuilder.fromText alpha) ++ italicise rest\n\n\t\tentities :: Char -> TextBuilder.Builder\n\t\tentities '<' = \"&lt;\"\n\t\tentities '>' = \"&gt;\"\n\t\tentities c = TextBuilder.singleton c\nrenderSimpleMathUnit (TeXComm \"mathtt\" _ [(FixArg, x)]) ctx = spanTag \"mathtt\" (highlight ctx x)\nrenderSimpleMathUnit (TeXBraces x) sec = renderSimpleMath x sec\nrenderSimpleMathUnit (TeXMath Dollar m) sec = renderSimpleMath (trim m) sec\nrenderSimpleMathUnit (TeXMath _ m) sec = renderSimpleMath m sec\nrenderSimpleMathUnit other sec = render other sec\n\nmathKey :: LaTeX -> (String, Bool)\nmathKey m = case m of\n\t\t[TeXMath kind t] -> (prepMath t, kind == Dollar)\n\t\t[TeXEnv \"eqnarray*\" [] _] -> (prepMath m, False)\n\t\t[TeXEnv \"equation*\" [] _] -> (prepMath m, False)\n\t\t_ -> (prepMath m, True)\n\nhighlightCodeInMath :: RenderContext -> [Soup.Tag Text] -> TextBuilder.Builder\nhighlightCodeInMath ctx\n    ( open@(Soup.TagOpen \"span\" ((\"class\", cls) : _))\n    : Soup.TagText code\n    : close@(Soup.TagClose \"span\")\n    : more )\n      | cls `elem` [\"mjx-char MJXc-TeX-type-R\", \"mjx-charbox MJXc-TeX-type-R\"]\n        = TextBuilder.fromText (Soup.renderTags [open])\n        ++ highlight ctx [TeXRaw code]\n        ++ TextBuilder.fromText (Soup.renderTags [close])\n        ++ highlightCodeInMath ctx more\nhighlightCodeInMath ctx (a:b) = TextBuilder.fromText (Soup.renderTags [a]) ++ highlightCodeInMath ctx b\nhighlightCodeInMath _ [] = \"\"\n\n{- Unfortunately, for:    \\class{hidden_link}{\\href{url}{bla}}\nMathJax generates:        <a href=\"url\"><span class=\"yada hidden_link\">bla</span></a>\n\nBut CSS does not let you say \"apply the following style to 'a' elements that have a 'span' child with class 'hidden_link'\".\n\nSo fixHiddenLinks moves the \"hidden_link\" class from the span to the a... -}\n\nfixHiddenLinks :: [Soup.Tag Text] -> [Soup.Tag Text]\nfixHiddenLinks (Soup.TagOpen \"a\" attrs : Soup.TagOpen \"span\" [(\"class\", Text.words -> cls)] : rest)\n    | \"hidden_link\" `elem` cls\n        = Soup.TagOpen \"a\" ((\"class\", \"hidden_link\") : attrs) :\n          Soup.TagOpen \"span\" [(\"class\", Text.unwords $ cls \\\\ [\"hidden_link\"])] : rest\nfixHiddenLinks (x:y) = x : fixHiddenLinks y\nfixHiddenLinks [] = []\n\nremoveAriaLabel :: Soup.Tag Text -> Soup.Tag Text\nremoveAriaLabel (Soup.TagOpen x attrs) = Soup.TagOpen x (filter ((/= \"aria-label\") . fst) attrs)\nremoveAriaLabel x = x\n\ndoRenderComplexMath :: LaTeX -> RenderContext -> TextBuilder.Builder\ndoRenderComplexMath math ctx =\n        (if inComment ctx then TextBuilder.fromText . Soup.renderTags else highlightCodeInMath ctx) $\n          fixHiddenLinks $ map removeAriaLabel $ Soup.parseTags $ MathJax.render formula inline\n    where (formula, inline) = mathKey math\n\nrenderComplexMath :: LaTeX -> RenderContext -> TextBuilder.Builder\nrenderComplexMath math ctx = (if inline then \"\" else \"<br>\") ++ spanTag \"math\" (doRenderComplexMath math ctx)\n    where (_, inline) = mathKey math\n\ncssClasses :: ColumnSpec -> Text\ncssClasses (ColumnSpec alignment border _) =\n\t(if border then \"border \" else \"\") ++ Text.pack (show alignment)\n\ncssStyle :: ColumnSpec -> Maybe Text\ncssStyle (ColumnSpec _ _ (Just w)) = Just $ \"width:\" ++ w\ncssStyle _ = Nothing\n\nrenderTable :: [ColumnSpec] -> [Row [TeXPara]] -> RenderContext -> TextBuilder.Builder\nrenderTable colspec a = \\ctx -> xml \"table\" [] $ mconcat (renderRow ctx . zip [1..] a)\n\twhere\n\t\tcombine (ColumnSpec x False w) (ColumnSpec _ True _) = ColumnSpec x True w\n\t\tcombine x _ = x\n\n\t\trenderRow :: RenderContext -> (Integer, Row [TeXPara]) -> TextBuilder.Builder\n\t\trenderRow ctx (rowNum, Row{..}) =\n\t\t\txml \"tr\" ([(\"id\", rowId)] ++ cls) (renderCols ctx' rowId colspec 1 clines cells)\n\t\t\twhere\n\t\t\t\trowId = mconcat (idPrefixes ctx) ++ \"row-\" ++ Text.pack (show rowNum)\n\t\t\t\tctx' = ctx{idPrefixes = idPrefixes ctx ++ [\"row-\" ++ Text.pack (show rowNum) ++ \"-\"]}\n\t\t\t\tcls | RowSep <- rowSep = [(\"class\", \"rowsep\")]\n\t\t\t\t    | CapSep <- rowSep = [(\"class\", \"capsep\")]\n\t\t\t\t    | otherwise = []\n\t\t\t\tclines\n\t\t\t\t\t| Clines clns <- rowSep = clns\n\t\t\t\t\t| otherwise = []\n\n\t\trenderCols :: RenderContext -> Text -> [ColumnSpec] -> Int -> [(Int, Int)] -> [Cell [TeXPara]] -> TextBuilder.Builder\n\t\trenderCols _ _ _ _ _ [] = \"\"\n\t\trenderCols ctx rowId (c : cs) colnum clines (Cell{..} : rest)\n\t\t\t| length cs < length rest = undefined\n\t\t\t| Multicolumn w cs' <- cellSpan =\n\t\t\t\tlet\n\t\t\t\t\tcs'' = combine cs' c\n\t\t\t\t\tcolspan\n\t\t\t\t\t\t| null rest = length cs + 1\n\t\t\t\t\t\t| otherwise = w\n\t\t\t\tin\n\t\t\t\t\trenderCell colspan (cssClasses cs'' ++ clineClass colnum clines) (cssStyle cs'') cnt\n\t\t\t\t\t++ renderCols ctx rowId (drop (colspan - 1) cs) (colnum + colspan) clines rest\n\t\t\t| otherwise =\n\t\t\t\trenderCell 1 (cssClasses c ++ clineClass colnum clines) (cssStyle c) cnt\n\t\t\t\t++ renderCols ctx rowId cs (colnum + 1) clines rest\n\t\t\twhere\n\t\t\t\tmarginalizedLink = xml \"div\" [(\"class\", \"marginalizedparent\")] (render link ctx)\n\t\t\t\tlink = anchor{aClass=\"itemDeclLink\", aHref=\"#\" ++ urlChars rowId, aText=\"🔗\"}\n\t\t\t\tcnt = (if colnum == 1 then marginalizedLink else \"\") ++ renderLatexParas content ctx'\n\t\t\t\tctx' = ctx{idPrefixes = idPrefixes ctx ++ [\"column-\" ++ Text.pack (show colnum) ++ \"-\"]}\n\t\trenderCols _ _ [] _ _ (_ : _) = error \"Too many columns\"\n\n\t\tclineClass n clines\n\t\t\t| isJust $ find (\\(begin, end) -> begin <= n && n <= end) clines =\n\t\t\t\t\" cline\"\n\t\t\t| otherwise = \"\"\n\nrenderCell :: Int -> Text -> Maybe Text -> TextBuilder.Builder -> TextBuilder.Builder\nrenderCell colspan classes style content = xml \"td\" attrs content\n    where\n        classes' = if TextBuilder.toLazyText content == \"\" then \"empty \" ++ classes else classes\n        attrs = [(\"colspan\", Text.pack $ show colspan) | colspan /= 1]\n            ++ [(\"class\", classes')]\n            ++ [(\"style\", s) | Just s <- [style]]\n\ninstance Render TeXPara where\n\trender = (mconcat .) . (intersperse \" \" .) . mapM render . sentences\n\ninstance Render [Element] where\n    render l@(LatexElement _ : _) ctx = render (spanJust l p) ctx\n        where\n            p (LatexElement e) = Just e\n            p _ = Nothing\n    render (x : y) ctx = render x ctx ++ render y ctx\n    render [] _ = \"\"\n\ninstance Render Sentence where\n\trender Sentence{..} ctx\n\t\t\t| (Enumerated _ _ : _) <- sentenceElems = render sentenceElems ctx -- not a real sentence\n\t\t\t| not (noTags ctx), Just v <- i\n\t\t\t\t= xml \"div\" [(\"id\", v), (\"class\", \"sentence\")] $\n\t\t\t\t\trender (case linkifyFullStop link sentenceElems of Just x -> x; Nothing -> sentenceElems) ctx\n\t\t\t| otherwise = render sentenceElems ctx\n\t\twhere\n\t\t\ti = case sentenceNumber of\n\t\t\t\tJust v -> Just $ mconcat (idPrefixes ctx) ++ \"sentence-\" ++ Text.pack (show v)\n\t\t\t\tNothing -> Nothing\n\t\t\tlink = TeXComm \"class\" \"\"\n\t\t\t    [ (FixArg, [TeXRaw \"hidden_link\"])\n\t\t\t    , (FixArg, [TeXComm \"href\" \"\" [(FixArg, [TeXRaw (\"#\" ++ fromJust i)]), (FixArg, [TeXRaw \".\"])]])\n\t\t\t    ] -- in math, \\class and \\href are recognized by mathjax\n\nrenderLatexParas :: [TeXPara] -> RenderContext -> TextBuilder.Builder\nrenderLatexParas pp ctx = mconcat $ map (xml \"div\" [(\"class\", \"texpara\")] . flip render ctx) pp\n\n-- Explicit <br/>'s are redundant in <pre>, so strip them.\npreprocessPre :: LaTeX -> LaTeX\npreprocessPre = concatMap f\n\twhere\n\t\tf TeXLineBreak = []\n\t\tf (TeXComm \"br\" _ []) = []\n\t\tf (TeXEnv e a c) = [TeXEnv e a (preprocessPre c)]\n\t\tf x = [x]\n\nhtmlTabs :: Text -> Text\nhtmlTabs = replace \"\\t\" \"&#9;\" -- todo: still necessary?\n\nlinkToSectionHref :: Link -> Abbreviation -> Text\nlinkToSectionHref link abbr = Text.pack (show link) ++ \"/\" ++ urlChars abbr\n\nlinkToSection :: Link -> Abbreviation -> Anchor\nlinkToSection link abbr = anchor{ aHref = linkToSectionHref link abbr, aText = squareAbbr True abbr }\n\n--url :: Text -> Text\n--url = urlChars . LazyText.toStrict . TextBuilder.toLazyText . flip render defaultRenderContext{replXmlChars = False}\n\nsimpleRender :: Render a => a -> Text\nsimpleRender = LazyText.toStrict . TextBuilder.toLazyText . simpleRender2\n\nsimpleRender2 :: Render a => a -> TextBuilder.Builder\nsimpleRender2 = flip render defaultRenderContext\n\nsecnum :: Int -> Text -> Section -> TextBuilder.Builder\nsecnum reduceIndent href se@Section{..} =\n\tsimpleRender2 (anchor{aClass=c, aHref=href, aText=secnumText se, aStyle=Text.pack style})\n\twhere\n\t\tstyle = \"min-width:\" ++ show (50 + (length parents - reduceIndent) * 15) ++ \"pt\"\n\t\tc\t| chapter /= NormalChapter, null parents = \"annexnum\"\n\t\t\t| otherwise = \"secnum\"\n\nsecnumText :: Section -> TextBuilder.Builder\nsecnumText Section{sectionNumber=n,..}\n\t| chapter == InformativeAnnex, null parents = \"Annex \" ++ chap ++ \"&emsp;(informative)\"\n\t| chapter == NormativeAnnex, null parents = \"Annex \" ++ chap ++ \"&emsp;(normative)\"\n\t| otherwise = intercalateBuilders \".\" (chap : simpleRender2 . tail ns)\n\twhere\n\t\tns = reverse $ n : sectionNumber . parents\n\t\tchap :: TextBuilder.Builder\n\t\tchap\n\t\t\t| chapter == NormalChapter = simpleRender2 (head ns)\n\t\t\t| otherwise = TextBuilder.singleton $ ['A'..] !! head ns\n"
  },
  {
    "path": "SectionPages.hs",
    "content": "{-# OPTIONS_GHC -fno-warn-tabs #-}\n{-# LANGUAGE OverloadedStrings, RecordWildCards, TupleSections, ViewPatterns, NamedFieldPuns #-}\n\nmodule SectionPages\n\t( writeSectionFiles\n\t, writeSingleSectionFile\n\t, writeFiguresFile\n\t, writeFigureFiles\n\t, writeTablesFile\n\t, writeTableFiles\n\t, writeIndexFiles\n\t, writeFootnotesFile\n\t, writeCssFile\n\t, writeXrefDeltaFiles\n\t) where\n\nimport Prelude hiding ((++), (.), writeFile)\nimport System.Directory (createDirectoryIfMissing)\nimport Control.Monad (when, forM_)\nimport Control.Arrow (first)\nimport Data.Maybe (fromJust)\nimport System.Process (readProcess)\nimport qualified Data.Map as Map\nimport qualified Data.Text as Text\nimport qualified Data.Text.Lazy.Builder as TextBuilder\nimport LaTeXBase (LaTeXUnit(..))\nimport Pages (writePage, pageContent, pagePath, PageStyle(..), fileContent, outputDir, Link(..))\nimport Render (render, concatRender, simpleRender2, renderFig, abbrHref,\n\tdefaultRenderContext, renderTab, RenderContext(..), Page(..),linkToSection, squareAbbr,\n\tsecnum, renderLatexParas, isSectionPage, parentLink, renderIndex)\nimport Document\nimport Util (urlChars, (++), (.), h, anchor, xml, Anchor(..), Text, writeFile, intercalateBuilders)\n\nrenderParagraph :: RenderContext -> TextBuilder.Builder\nrenderParagraph ctx@RenderContext{nearestEnclosing=Left Paragraph{..}, draft=Draft{..}} =\n\t\t(case paraNumber of\n\t\t\tJust i -> renderNumbered (Text.pack $ show i)\n\t\t\tNothing -> id)\n\t\t$ (if paraInItemdescr then xml \"div\" [(\"class\", \"itemdescr\")] else id)\n\t\t$ (sourceLink\n\t\t  ++ renderLatexParas paraElems ctx'{extraIndentation=if paraInItemdescr then 12 else 0})\n\t\t\t-- the 12 here must match div.itemdescr's margin-left value in mm\n\twhere\n\t\turlBase = Text.replace \"/commit/\" \"/tree/\" commitUrl ++ \"/source/\"\n\t\tsourceLink :: TextBuilder.Builder\n\t\tsourceLink\n\t\t\t| Just SourceLocation{..} <- paraSourceLoc =\n\t\t\t\txml \"div\" [(\"class\", \"sourceLinkParent\")]\n\t\t\t\t$ simpleRender2 $ anchor\n\t\t\t\t\t{ aClass = \"sourceLink\"\n\t\t\t\t\t, aText = \"#\"\n\t\t\t\t\t, aHref = urlBase ++ Text.pack (sourceFile ++ \"#L\" ++ show sourceLine) }\n\t\t\t| otherwise = \"\"\n\n\t\trenderNumbered :: Text -> TextBuilder.Builder -> TextBuilder.Builder\n\t\trenderNumbered n =\n\t\t\tlet\n\t\t\t\tidTag = if isSectionPage (page ctx) then [(\"id\", mconcat (idPrefixes ctx) ++ n)] else []\n\t\t\t\ta = anchor\n\t\t\t\t\t{ aClass = \"marginalized\"\n\t\t\t\t\t, aHref  =\n\t\t\t\t\t\tif isSectionPage (page ctx)\n\t\t\t\t\t\t\tthen \"#\" ++ urlChars (mconcat (idPrefixes ctx)) ++ n\n\t\t\t\t\t\t\telse \"SectionToSection/\" ++ urlChars (abbreviation paraSection) ++ \"#\" ++ n\n\t\t\t\t\t, aText  = TextBuilder.fromText n }\n\t\t\t\tclasses = \"para\" ++\n\t\t\t\t\t(if all (not . normative) (paraElems >>= sentences >>= sentenceElems)\n\t\t\t\t\t\tthen \" nonNormativeOnly\"\n\t\t\t\t\t\telse \"\")\n\t\t\tin\n\t\t\t\txml \"div\" ((\"class\", classes) : idTag) .\n\t\t\t\t(xml \"div\" [(\"class\", \"marginalizedparent\")] (render a ctx') ++)\n\t\tctx' = case paraNumber of\n\t\t\tJust n -> ctx{ idPrefixes = idPrefixes ctx ++ [Text.pack (show n) ++ \".\"] }\n\t\t\tNothing -> ctx\nrenderParagraph _ = undefined\n\ntocSection :: RenderContext -> Section -> TextBuilder.Builder\ntocSection _ Section{sectionKind=DefinitionSection _} = \"\"\ntocSection ctx s@Section{..} = header ++ mconcat (tocSection ctx . subsections)\n  where\n    header = h (min 4 $ 1 + length parents) $\n        secnum 0 \"\" s ++ \" \"\n        ++ render ( sectionName ++ [TeXRaw \" \"]\n                  , anchor{ aHref = abbrHref abbreviation ctx, aText = squareAbbr True abbreviation, aClass=\"abbr_ref\" })\n                  ctx{ inSectionTitle = True }\n        ++ \"<div style='clear:right'></div>\"\n\nrenderSection :: RenderContext -> Maybe Section -> Bool -> Section -> (TextBuilder.Builder, Bool)\nrenderSection context specific parasEmitted s@Section{abbreviation, subsections, sectionFootnotes, paragraphs}\n\t| full = (, True) $\n\t\tidDiv header ++\n\t\t(if specific == Just s && any (not . isDefinitionSection . sectionKind) subsections then toc else \"\") ++\n\t\tmconcat (map\n\t\t\t(\\p -> renderParagraph (context{nearestEnclosing=Left p,idPrefixes=if parasEmitted then [secOnPage ++ \"-\"] else []}))\n\t\t\tparagraphs) ++\n\t\t(if null sectionFootnotes then \"\" else \"<div class='footnoteSeparator'></div>\") ++\n\t\tconcatRender sectionFootnotes context{nearestEnclosing=Right s} ++\n\t\tmconcat (fst . renderSection context Nothing True . subsections)\n\t| not anysubcontent = (\"\", False)\n\t| otherwise =\n\t\t( header ++\n\t\t  mconcat (fst . renderSection context specific False . subsections)\n\t\t, anysubcontent )\n\twhere\n\t\tidDiv\n\t\t\t| specific == Just s = id\n\t\t\t| otherwise = xml \"div\" [(\"id\", secOnPage), (\"class\", \"section\")]\n\t\tsecOnPage :: Text\n\t\tsecOnPage = case page context of\n\t\t\tSectionPage parent -> parentLink parent abbreviation\n\t\t\t_ -> abbreviation\n\t\tfull = specific == Nothing || specific == Just s\n\t\treduceHeaderIndent = case page context of\n\t\t    SectionPage p | specific == Nothing -> length (parents p) + 1\n\t\t    _ -> 0\n\t\theader = sectionHeader reduceHeaderIndent (min 4 $ 1 + length (parents s)) s\n\t\t\t(if specific == Nothing && isSectionPage (page context) then \"#\" ++ urlChars secOnPage else \"\")\n\t\t\tabbr context\n\t\ttoc = \"<hr>\" ++ mconcat (tocSection context . subsections) ++ \"<hr>\"\n\t\tabbr\n\t\t\t| specific == Just s && not (null (parents s))\n\t\t\t\t= anchor\n\t\t\t| Just sp <- specific, sp /= s, not (null (parents s))\n\t\t\t\t= anchor{aHref = \"SectionToSection/\" ++ urlChars abbreviation ++ \"#\" ++ parentLink s (Document.abbreviation sp)}\n\t\t\t| otherwise = linkToSection\n\t\t\t\t\t(if null (parents s) then SectionToToc else SectionToSection)\n\t\t\t\t\tabbreviation\n\t\tanysubcontent =\n\t\t\tor $ map (snd . renderSection context specific True)\n\t\t\t   $ subsections\n\nsectionFileContent :: PageStyle -> TextBuilder.Builder -> TextBuilder.Builder -> Text\nsectionFileContent sfs title body = pageContent sfs $ fileContent pathHome title sectionPageCss body\n  where\n    pathHome = if sfs == InSubdir then \"../\" else \"\"\n    sectionPageCss =\n        \"<link rel='stylesheet' type='text/css' href='\" ++ pathHome ++ \"expanded.css' title='Normal'>\" ++\n        \"<link rel='alternate stylesheet' type='text/css' href='\" ++ pathHome ++ \"colored.css' title='Notes and examples colored'>\" ++\n        \"<link rel='alternate stylesheet' type='text/css' href='\" ++ pathHome ++ \"normative-only.css' title='Notes and examples hidden'>\"\n\nwriteSectionFile :: FilePath -> PageStyle -> TextBuilder.Builder -> TextBuilder.Builder -> IO ()\nwriteSectionFile n sfs title body = writePage n sfs (sectionFileContent sfs title body)\n\nsectionHeader :: Int -> Int -> Section -> Text -> Anchor -> RenderContext -> TextBuilder.Builder\nsectionHeader reduceIndent hLevel s@Section{..} secnumHref abbr_ref ctx\n    | isDef = xml \"h4\" [(\"style\", \"margin-bottom:3pt\")] $ num ++ abbrR ++ name\n    | abbreviation == \"bibliography\" = h hLevel name\n    | otherwise = h hLevel $ num ++ \" \" ++ name ++ \" \" ++ abbrR\n  where\n    num = secnum reduceIndent secnumHref s\n    abbrR = simpleRender2 abbr_ref{aClass = \"abbr_ref\", aText = squareAbbr False abbreviation}\n    name = render sectionName ctx{inSectionTitle=True}\n    isDef = isDefinitionSection sectionKind\n\nwriteFiguresFile :: PageStyle -> Draft -> IO ()\nwriteFiguresFile sfs draft = writeSectionFile \"fig\" sfs \"14882: Figures\" $\n\t\"<h1>Figures <a href='SectionToToc/fig' class='abbr_ref'>[fig]</a></h1>\"\n\t++ mconcat (uncurry r . figures draft)\n\twhere\n\t\tr :: Paragraph -> Figure -> TextBuilder.Builder\n\t\tr p f@Figure{..} =\n\t\t\trenderFig True f (\"./SectionToSection/\" ++ urlChars figureAbbr) False True ctx\n\t\t\twhere ctx = defaultRenderContext{draft=draft, nearestEnclosing=Left p, page=FiguresPage}\n\nwriteTablesFile :: PageStyle -> Draft -> IO ()\nwriteTablesFile sfs draft = writeSectionFile \"tab\" sfs \"14882: Tables\" $\n\t\"<h1>Tables <a href='SectionToToc/tab' class='abbr_ref'>[tab]</a></h1>\"\n\t++ mconcat (uncurry r . tables draft)\n\twhere\n\t\tr :: Paragraph -> Table -> TextBuilder.Builder\n\t\tr p t@Table{tableSection=Section{..}, ..} =\n\t\t\trenderTab True t (\"./SectionToSection/\" ++ urlChars tableAbbr) False True ctx\n\t\t\twhere ctx = defaultRenderContext{\n\t\t\t\tdraft = draft,\n\t\t\t\tnearestEnclosing = Left p,\n\t\t\t\tpage = TablesPage,\n\t\t\t\tidPrefixes = [fromJust (Text.stripPrefix \"tab:\" tableAbbr) ++ \"-\"]}\n\nwriteFootnotesFile :: PageStyle -> Draft -> IO ()\nwriteFootnotesFile sfs draft = writeSectionFile \"footnotes\" sfs \"14882: Footnotes\" $\n\t\"<h1>List of Footnotes</h1>\"\n\t++ mconcat (uncurry r . footnotes draft)\n\twhere\n\t\tr :: Section -> Footnote -> TextBuilder.Builder\n\t\tr s fn = render fn defaultRenderContext{draft=draft, nearestEnclosing = Right s, page=FootnotesPage}\n\nwriteSingleSectionFile :: PageStyle -> Draft -> String -> IO ()\nwriteSingleSectionFile sfs draft abbr = do\n\tlet Just section@Section{..} = Document.sectionByAbbr draft (Text.pack abbr)\n\tlet baseFilename = Text.unpack abbreviation\n\twriteSectionFile baseFilename sfs (squareAbbr False abbreviation) $ mconcat $ fst . renderSection (defaultRenderContext{draft=draft,page=SectionPage section}) (Just section) False . chapters draft\n\tputStrLn $ \"  \" ++ baseFilename\n\nwriteTableFiles :: PageStyle -> Draft -> IO ()\nwriteTableFiles sfs draft =\n\tforM_ (snd . tables draft) $ \\tab@Table{..} -> do\n\t\tlet\n\t\t\tcontext = defaultRenderContext{draft=draft, page=TablePage tab, nearestEnclosing=Right tableSection}\n\t\t\theader :: Section -> TextBuilder.Builder\n\t\t\theader sec = sectionHeader 0 (min 4 $ 1 + length (parents sec)) sec \"\" anchor{aHref=href} context\n\t\t\t\twhere href=\"SectionToSection/\" ++ urlChars (abbreviation sec) ++ \"#\" ++ urlChars tableAbbr\n\t\t\theaders = mconcat $ map header $ reverse $ tableSection : parents tableSection\n\t\twriteSectionFile (Text.unpack tableAbbr) sfs (TextBuilder.fromText $ \"[\" ++ tableAbbr ++ \"]\") $\n\t\t\theaders ++ renderTab True tab \"\" True False context\n\nwriteFigureFiles :: PageStyle -> Draft -> IO ()\nwriteFigureFiles sfs draft =\n\tforM_ (snd . figures draft) $ \\fig@Figure{..} -> do\n\t\tlet\n\t\t\tcontext = defaultRenderContext{draft=draft, page=FigurePage fig, nearestEnclosing=Right figureSection}\n\t\t\theader :: Section -> TextBuilder.Builder\n\t\t\theader sec = sectionHeader 0 (min 4 $ 1 + length (parents sec)) sec \"\" anchor{aHref=href} context\n\t\t\t\twhere href=\"SectionToSection/\" ++ urlChars (abbreviation sec) ++ \"#\" ++ urlChars figureAbbr\n\t\t\theaders = mconcat $ map header $ reverse $ figureSection : parents figureSection\n\t\twriteSectionFile (Text.unpack figureAbbr) sfs (TextBuilder.fromText $ \"[\" ++ figureAbbr ++ \"]\") $\n\t\t\theaders ++ renderFig True fig \"\" True False context\n\nwriteSectionFiles :: PageStyle -> Draft -> [IO ()]\nwriteSectionFiles sfs draft = flip map (zip names contents) $ \\(n, content) -> do\n\t\twhen (sfs == InSubdir) $ createDirectoryIfMissing True (outputDir ++ n)\n\t\twriteFile (pagePath n sfs) content\n\twhere\n\t\tsecs = Document.sections draft\n\t\trenSec section@Section{..} = (Text.unpack abbreviation, sectionFileContent sfs title body)\n\t\t  where\n\t\t\ttitle = squareAbbr False abbreviation\n\t\t\tbody = mconcat $ fst . renderSection (defaultRenderContext{draft=draft,page=SectionPage section}) (Just section) False . chapters draft\n\t\tfullbody = mconcat $ fst . renderSection defaultRenderContext{draft=draft, page=FullPage} Nothing True . chapters draft\n\t\tfullfile = (\"full\", sectionFileContent sfs \"14882\" fullbody)\n\t\tfiles = fullfile : map renSec secs\n\t\tnames = fst . files\n\t\tcontents = snd . files\n\nwriteIndexFile :: PageStyle -> Draft -> String -> IndexTree -> IO ()\nwriteIndexFile sfs draft cat index =\n\twriteSectionFile cat sfs (\"14882: \" ++ indexCatName cat) $\n\t\th 1 (indexCatName cat) ++ renderIndex defaultRenderContext{page=IndexPage (Text.pack cat), draft=draft} index\n\nwriteIndexFiles :: PageStyle -> Draft -> Index -> [IO ()]\nwriteIndexFiles sfs draft index = flip map (Map.toList index) $ uncurry (writeIndexFile sfs draft) . first Text.unpack\n\nwriteCssFile :: IO ()\nwriteCssFile = do\n\tbase <- Text.pack . readFile \"14882.css\"\n\tlet\n\t\treplaceFonts =\n\t\t\tText.replace\n\t\t\t\t\".MJXc-TeX-sans-R {font-family: MJXc-TeX-sans-R,MJXc-TeX-sans-Rw}\"\n\t\t\t\t\".MJXc-TeX-sans-R {font-family: 'Noto Sans'; font-size: 10pt; }\" .\n\t\t\tText.replace\n\t\t\t\t\".MJXc-TeX-type-R {font-family: MJXc-TeX-type-R,MJXc-TeX-type-Rw}\"\n\t\t\t\t\".MJXc-TeX-type-R {font-family: 'Noto Sans Mono'; font-size: 10pt; }\" .\n\t\t\tText.replace\n\t\t\t\t\".MJXc-TeX-main-R {font-family: MJXc-TeX-main-R,MJXc-TeX-main-Rw}\"\n\t\t\t\t\".MJXc-TeX-main-R {}\" .\n\t\t\tText.replace\n\t\t\t\t\".MJXc-TeX-math-I {font-family: MJXc-TeX-math-I,MJXc-TeX-math-Ix,MJXc-TeX-math-Iw}\"\n\t\t\t\t\".MJXc-TeX-math-I {font-style: italic}\" .\n\t\t\tText.replace\n\t\t\t\t\".MJXc-TeX-main-I {font-family: MJXc-TeX-main-I,MJXc-TeX-main-Ix,MJXc-TeX-main-Iw}\"\n\t\t\t\t\".MJXc-TeX-main-I {font-style: italic}\"\n\t\t-- Replace fonts to make sure code in formulas matches code in code blocks, etc.\n\tmjx <- Text.replace \"display: block\" \"display: block;background:inherit\" . replaceFonts . Text.pack .\n\t\treadProcess \"tex2html\" [\"--css\", \"\"] \"\"\n\twriteFile (outputDir ++ \"/14882.css\") (base ++ mjx)\n\nwriteXrefDeltaFiles :: PageStyle -> Draft -> [IO ()]\nwriteXrefDeltaFiles sfs draft = flip map (xrefDelta draft) $ \\(from, to) ->\n\twriteSectionFile (Text.unpack from) sfs (squareAbbr False from) $\n\t\tif to == []\n\t\t\tthen \"Subclause \" ++ squareAbbr False from ++ \" was removed.\"\n\t\t\telse \"See \" ++ intercalateBuilders \", \" (flip render ctx . to) ++ \".\"\n\twhere ctx = defaultRenderContext{draft=draft, page=XrefDeltaPage}\n"
  },
  {
    "path": "Sentences.hs",
    "content": "{-# LANGUAGE OverloadedStrings, ViewPatterns, LambdaCase, TypeSynonymInstances, FlexibleInstances #-}\n\nmodule Sentences (splitIntoSentences, isActualSentence, linkifyFullStop, breakSentence) where\n\nimport LaTeXBase (LaTeXUnit(..), triml, ArgKind(FixArg))\nimport Data.Text (isPrefixOf, isSuffixOf, stripPrefix, Text)\nimport qualified Data.Text as Text\nimport Prelude hiding (take, (.), takeWhile, (++), lookup, readFile)\nimport Data.Char (isSpace, isDigit, isAlphaNum, isUpper, isLower)\nimport Control.Arrow (first)\nimport Data.Maybe (isNothing)\nimport Util ((++), textStripInfix, dropTrailingWs, (.))\nimport RawDocument\nimport Document\n\nstartsSentence :: RawElement -> Bool\nstartsSentence (RawLatexElement e) | [TeXRaw x] <- triml [e], x /= \"\" = isUpper (Text.head x)\nstartsSentence _ = False\n\nunitContinuesSentence :: LaTeXUnit -> Bool\nunitContinuesSentence (TeXComm \" \" _ []) = True\nunitContinuesSentence (TeXRaw txt) = \",\" `isPrefixOf` txt\nunitContinuesSentence _ = False\n\nelemContinuesSentence :: RawElement -> Bool\nelemContinuesSentence (RawLatexElement u) = unitContinuesSentence u\nelemContinuesSentence _ = False\n\nelemsContinueSentence :: [RawElement] -> Bool\nelemsContinueSentence (RawLatexElement (TeXRaw \"\") : more) = elemsContinueSentence more\nelemsContinueSentence (x : _) = elemContinuesSentence x\nelemsContinueSentence _ = False\n\nsimpleHead :: [RawElement] -> Maybe Char\nsimpleHead [] = Nothing\nsimpleHead (RawLatexElement (TeXRaw x) : more)\n\t| x == \"\" = simpleHead more\n\t| otherwise = Just (Text.head x)\nsimpleHead (RawLatexElement (TeXComm \" \" \"\" []) : _) = Just ' '\nsimpleHead (RawLatexElement (TeXComm \"tcode\" _ [(_, x)]) : more) = simpleHead (map RawLatexElement x ++ more)\nsimpleHead (RawLatexElement (TeXComm \"index\" _ _) : more) = simpleHead more\nsimpleHead (RawLatexElement (TeXComm \"footnoteref\" _ _) : _) = Nothing -- hmm\nsimpleHead (RawLatexElement TeXLineBreak : _) = Nothing\nsimpleHead (RawLatexElement (TeXComm \"br\" _ _) : _) = Nothing\nsimpleHead (RawLatexElement (TeXComm \"linebreak\" _ _) : _) = Nothing\nsimpleHead (RawLatexElement (TeXComm \"newline\" _ _) : _) = Nothing\nsimpleHead (RawLatexElement (TeXComm \"par\" _ _) : _) = Nothing\nsimpleHead (RawLatexElement (TeXComm \"nolinebreak\" _ _) : _) = Nothing\nsimpleHead (RawLatexElement (TeXComm \"iref\" _ _) : _) = Nothing\nsimpleHead (RawLatexElement (TeXComm \",\" _ _) : _) = Just ','\nsimpleHead x = error $ \"simpleHead: \" ++ show x\n\nsplitIntoSentences :: [RawElement] -> [[RawElement]]\nsplitIntoSentences = go []\n\twhere\n\t\tgo [] [] = []\n\t\tgo [] (RawLatexElement (TeXRaw \"\\n\") : y) = go [] y\n\t\tgo [] (x@(RawExample _) : y) = [x] : go [] y\n\t\tgo [] (x@(RawNote _ _) : y) = [x] : go [] y\n\t\tgo partial (x@(RawCodeblock _) : y) | z : _ <- rmIndices y, startsSentence z = (partial ++ [x]) : go [] y\n\t\tgo x [] = [x]\n\t\tgo x z@(e : y)\n\t\t\t| Just (s, rest) <- breakSentence z = (x ++ s) : go [] rest\n\t\t\t| otherwise = go (x ++ [e]) y\n\t\trmIndices (RawLatexElement (TeXRaw \"\\n\") : RawLatexElement (TeXComm \"index\" _ _) : x) = rmIndices x\n\t\trmIndices x = x\n\nbreakSentence :: [RawElement] -> Maybe ([RawElement] {- sentence -}, [RawElement] {- remainder -})\nbreakSentence (e@(RawLatexElement (TeXMath _ math)) : more)\n    | f (reverse math) = Just ([e], more)\n    | otherwise = first (e :) . breakSentence more\n    where\n        f :: LaTeX -> Bool\n        f (TeXRaw y : z) | all isSpace (Text.unpack y) = f z\n        f (TeXComm \"text\" _ [(FixArg, a)] : _) = f (reverse a)\n        f (TeXComm \"mbox\" _ [(FixArg, a)] : _) = f (reverse a)\n        f (TeXRaw \".\\n\" : TeXComm \"right\" \"\" [] : y) = f y\n        f (TeXRaw y : _) = \".\" `isSuffixOf` (Text.pack $ dropTrailingWs $ Text.unpack y)\n        f _ = False\nbreakSentence (b@(RawLatexElement TeXLineBreak) : more) = Just ([b], more)\nbreakSentence (RawLatexElement (TeXBraces x) : more) = breakSentence (map RawLatexElement x ++ more)\nbreakSentence (e@(RawLatexElement (TeXEnv \"eqnarray*\" _ _)) : more) = first (e :) . breakSentence more\nbreakSentence (b@(RawLatexElement (TeXComm cmd _ _)) : more) =\n\tif cmd `elem` [\"break\"]\n\t\tthen Just ([b], more)\n\t\telse (first (b :)) . breakSentence more\nbreakSentence (e@(RawLatexElement (TeXRaw (textStripInfix \".\" -> (Just ((++ \".\") -> pr, po))))) : more)\n    = f pr po\n  where\n   f :: Text -> Text -> Maybe ([RawElement], [RawElement])\n   f pre post\n    | \"''\" `isPrefixOf` post = f (pre ++ \"''\") (Text.drop 2 post)\n    | not ((\"(.\" `isSuffixOf` pre) && (\")\" `isPrefixOf` post))\n    , not (\"\" == post && maybe False (\\c -> isLower c || isDigit c) (simpleHead more))\n    , not (\"\" == post && length more /= 0 && head more == RawLatexElement (TeXComm \" \" \"\" []))\n    , not (Text.length post > 0 && ((Text.head post == '.')\n                                    || isLower (Text.head post)\n                                    || isDigit (Text.head post)))\n    , not (Text.length pre > 1 && Text.length post > 0 && isAlphaNum (Text.last $ Text.init pre) && isDigit (Text.head post))\n    , not (elemsContinueSentence (RawLatexElement (TeXRaw post) : more))\n    , not (Text.length pre >= 2 && (\".\" `isSuffixOf` pre) && isUpper (Text.last $ Text.init pre))\n    , not (\"e.g.\" `isSuffixOf` pre)\n    , not (\"i.e.\" `isSuffixOf` pre) =\n        let\n            post' = Text.stripStart post\n            (pre', post'') = case stripPrefix \")\" post' of\n                Just z -> (pre ++ \")\" , Text.stripStart z)\n                Nothing -> (pre, post')\n            more' = if post'' == \"\" then more else RawLatexElement (TeXRaw post'') : more\n            (maybefootnote, more'') = case more' of\n                fn@(RawLatexElement (TeXComm \"footnoteref\" _ _)) : z -> ([fn], z)\n                _ -> ([], more')\n            sentence = [RawLatexElement (TeXRaw pre')] ++ maybefootnote\n        in\n            Just (sentence, more'')\n    | Just ((++ \".\") -> pre', post') <- textStripInfix \".\" post = f (pre ++ pre') post'\n    | otherwise = first (e :) . breakSentence more\nbreakSentence (e@(RawLatexElement (TeXRaw _)) : more) = first (e :) . breakSentence more\nbreakSentence (enum@(RawEnumerated _ (last -> rawItemContent -> (_ : _ : _))) : more)\n    = Just ([enum], more)\nbreakSentence (enum@(RawEnumerated _ (last -> rawItemContent -> [RawTexPara y])) : more)\n    | Just _ <- breakSentence y = Just ([enum], more)\nbreakSentence _ = Nothing\n\nisActualSentence :: [RawElement] -> Bool\nisActualSentence (RawEnumerated _ _ : _) = False\nisActualSentence l = any p l\n\twhere\n\t\tyes = words $\n\t\t\t\"link tcode noncxxtcode textit ref grammarterm indexedspan \" ++\n\t\t\t\"defnx textbf textrm textsl textsc indexlink hiddenindexlink\"\n\n\t\tq :: LaTeXUnit -> Bool\n\t\tq (TeXRaw s) = not $ all isSpace $ Text.unpack s\n\t\tq (TeXComm c _ _) | c `elem` yes = True\n\t\tq (TeXEnv c _ _) | c `elem` yes = True\n\t\tq (TeXEnv \"indexed\" _ body) = any q body\n\t\tq (TeXBraces body) = any q body\n\t\tq _ = False\n\n\t\tp :: RawElement -> Bool\n\t\tp (RawLatexElement u) = q u\n\t\tp RawEnumerated{} = True\n\t\tp _ = False\n\nclass LinkifyFullStop a where\n    linkifyFullStop :: LaTeXUnit -> a -> Maybe a\n\ninstance LinkifyFullStop LaTeX where\n    linkifyFullStop link l = reverse . f (reverse l)\n      where\n        f [] = Nothing\n        f (x@(TeXRaw \".\\n\") : y@(TeXComm \"right\" _ _) : more) = ([x, y] ++) . f more\n        f (u : uu)\n            | Just u' <- inUnit u = Just (reverse u' ++ uu)\n            | otherwise = (u :) . f uu\n        inUnit :: LaTeXUnit -> Maybe LaTeX -- returns content in regular order\n        inUnit (TeXEnv \"array\" args body)\n            | Just body' <- linkifyFullStop link body = Just [TeXEnv \"array\" args body']\n        inUnit (TeXEnv \"indented\" [] body)\n            | Just body' <- linkifyFullStop link body = Just [TeXEnv \"indented\" [] body']\n        inUnit (TeXComm \"text\" ws [(FixArg, x)])\n            | Just x' <- linkifyFullStop link x = Just (moveStuffOutsideText (TeXComm \"text\" ws [(FixArg, x')]))\n            | otherwise = Nothing\n        inUnit (TeXComm \"mbox\" ws [(FixArg, x)])\n            | Just x' <- linkifyFullStop link x = Just (moveStuffOutsideText (TeXComm \"mbox\" ws [(FixArg, x')]))\n            | otherwise = Nothing\n        inUnit (TeXMath kind m)\n            | Just m' <- linkifyFullStop link m = Just [TeXMath kind m']\n        inUnit (TeXRaw (Text.dropWhileEnd (=='\\n') -> Text.stripSuffix \".\" -> Just s)) = Just [TeXRaw s, link]\n        inUnit (TeXRaw (Text.stripSuffix \".)\" -> Just s)) = Just [TeXRaw s, link, TeXRaw \")\"]\n        inUnit (TeXRaw (Text.stripSuffix \".''\" -> Just s)) = Just [TeXRaw s, link, TeXRaw \"''\"]\n        inUnit _ = Nothing\n\ninstance LinkifyFullStop Item where\n    linkifyFullStop link it@Item{itemInlineContent=e}\n        | Just y <- linkifyFullStop link e\n            = Just it{itemInlineContent=y}\n    linkifyFullStop _ _ = Nothing\n\ninstance LinkifyFullStop [Element] where\n    linkifyFullStop link = (reverse .) . f . reverse\n      where\n        f :: [Element] -> Maybe [Element]\n        f (Enumerated cmd (reverse -> (lastItem : moreItems)) : more)\n            | all (isNothing . linkifyFullStop link) moreItems\n            , Just lastItem' <- linkifyFullStop link lastItem\n            = Just $ Enumerated cmd (reverse (lastItem' : moreItems)) : more\n        f (LatexElement u : more)\n            | Just u' <- linkifyFullStop link [u] = Just $ map LatexElement (reverse u') ++ more\n            | otherwise = (LatexElement u :) . f more\n        f _ = Nothing\n\nmoveStuffOutsideText :: LaTeXUnit -> LaTeX\n    -- Turns \\text{ \\class{bla} } into \\text{ }\\class{\\text{bla}}\\text{ }, and similar for \\href,\n    -- because MathJax does not support \\class and \\href in \\text.\nmoveStuffOutsideText (TeXComm parent pws [(FixArg, [TeXComm nested nws [x, y]])])\n    | parent `elem` [\"text\", \"mbox\"]\n    , nested `elem` [\"class\", \"href\"] = [TeXComm nested nws [x, (FixArg, moveStuffOutsideText (TeXComm parent pws [y]))]]\nmoveStuffOutsideText (TeXComm parent pws [(FixArg, t)])\n    | parent `elem` [\"text\", \"mbox\"]\n    , length t >= 2 = concatMap (\\u -> moveStuffOutsideText $ TeXComm parent pws [(FixArg, [u])]) t\nmoveStuffOutsideText u = [u]\n"
  },
  {
    "path": "Setup.hs",
    "content": "import Distribution.Simple\nmain = defaultMain\n"
  },
  {
    "path": "Toc.hs",
    "content": "{-# OPTIONS_GHC -fno-warn-tabs #-}\n{-# LANGUAGE RecordWildCards, OverloadedStrings, ViewPatterns, NamedFieldPuns #-}\n\nmodule Toc (writeTocFiles) where\n\nimport qualified Data.Text as Text\nimport qualified Data.Text.Lazy as LazyText\nimport qualified Data.Text.Lazy.Builder as TextBuilder\nimport Data.Time.Format (formatTime, defaultTimeLocale)\nimport Data.Time.Clock (getCurrentTime, UTCTime)\nimport Prelude hiding ((.), (++), writeFile)\nimport LaTeXBase (LaTeXUnit(..))\nimport Pages (Link(..), fileContent, applyPageStyle, PageStyle(..), outputDir, writePage)\nimport Render (secnum, linkToSection, simpleRender2, RenderContext(..), render, defaultRenderContext, Page(..))\nimport Util\nimport Document (Section(..), Draft(..), SectionKind(..), indexCatName, isDefinitionSection)\n\ntocSection :: Draft -> Bool -> Section -> TextBuilder.Builder\ntocSection _ _ Section{sectionKind=DefinitionSection _} = \"\"\ntocSection draft expanded s@Section{..} =\n\txml \"div\" [(\"id\", abbreviation)] $ header ++ mconcat (tocSection draft expanded . subsections)\n  where\n  \theader = h (min 4 $ 2 + length parents) $\n\t\tsecnum 0 (if expanded then \"#\" ++ urlChars abbreviation else \"\") s ++ \" \"\n\t\t++ render ( sectionName ++ [TeXRaw \" \"]\n\t\t          , (linkToSection (if expanded then SectionToSection else TocToSection) abbreviation){aClass=\"abbr_ref\"})\n\t\t          defaultRenderContext{page=if expanded then ExpandedTocPage else TocPage, inSectionTitle=True, draft=draft}\n\t\t++ \"<div style='clear:right'></div>\"\n\ntocChapter :: Draft -> Bool -> Section -> TextBuilder.Builder\ntocChapter draft expanded s@Section{abbreviation, sectionName, subsections, parents} =\n\txml \"div\" [(\"id\", abbreviation)] $\n\th (min 4 $ 2 + length parents) header ++\n\txml \"div\" [(\"class\", \"tocChapter\")] (mconcat (tocSection draft expanded . subsections))\n  where\n\thref\n\t    | expanded = \"SectionToSection/\" ++ urlChars abbreviation\n\t    | otherwise = (if any (not . isDefinitionSection . sectionKind) subsections then \"#\" else \"TocToSection/\") ++ urlChars abbreviation\n\tlink = anchor{\n\t\taClass = \"folded_abbr_ref\",\n\t\taText = TextBuilder.fromText $ \"[\" ++ abbreviation ++ \"]\",\n\t\taHref = href}\n\theader\n\t  | abbreviation == \"bibliography\" =\n\t      render anchor{aText = \"Bibliography\", aHref = href}\n\t        defaultRenderContext{inSectionTitle=True, draft=draft}\n\t  | otherwise =\n\t      secnum 0 (if expanded then \"#\" ++ urlChars abbreviation else \"\") s ++ \" \" ++\n\t      render (sectionName ++ [TeXRaw \" \"], link) defaultRenderContext{inSectionTitle=True, draft=draft} ++\n\t      (if expanded then \"\" else simpleRender2 (linkToSection TocToSection abbreviation){aClass=\"unfolded_abbr_ref\"})\n\ntocHeader :: UTCTime -> Text -> Text\ntocHeader date commitUrl =\n\t\"(Generated on \" ++ Text.pack (formatTime defaultTimeLocale \"%F\" date)\n\t++ \" from the <a href='\" ++ commitUrl ++ \"'>LaTeX sources</a>\"\n\t++ \" by <a href='https://github.com/Eelis/cxxdraft-htmlgen'>cxxdraft-htmlgen</a>.\"\n\t++ \" This is <em>not</em> an ISO publication.)\"\n\t++ \"<br><br>\"\n\t++ \"<b>Note: this is an early draft. It's known to be incomplet and incorrekt, and it has lots of\"\n\t++ \" b<span style='position:relative;left:-1.2pt'>a</span><span style='position:relative;left:1pt'>d</span>\"\n\t++ \" for<span style='position:relative;left:-3pt'>matti<span style='position:relative;bottom:0.15ex'>n</span>g.</span></b>\"\n\nwriteTocFiles :: PageStyle -> Draft -> IO ()\nwriteTocFiles sfs draft@Draft{..} = do\n\tdate <- getCurrentTime\n\ttocCss <- readFile \"toc.css\"\n\tlet\n\t    descMeta = \"<meta name='description' content='Browser-friendly rendering of a recent draft of the C++ standard'>\"\n\t    tocStyle = \"<style>\" ++ TextBuilder.fromString tocCss ++ \"</style>\"\n\twriteFile (outputDir ++ \"/index.html\") $ applyPageStyle sfs $ LazyText.toStrict $ TextBuilder.toLazyText $\n\t\tfileContent \"\" \"Draft C++ Standard: Contents\" (descMeta ++ tocStyle) $\n\t\t\t\"<h1 style='text-align:center; hyphens:none; margin: 1cm'>Working Draft<br>Programming Languages &mdash; C++</h1>\" ++\n\t\t\txml \"div\" [(\"class\", \"tocHeader\")] (TextBuilder.fromText $ tocHeader date commitUrl) ++\n\t\t\t\"<br><h1>Contents</h1>\" ++\n\t\t\tmconcat (tocChapter draft False . chapters) ++\n\t\t\tmconcat (h 2\n\t\t\t\t. (\\cat -> simpleRender2 anchor{aHref=\"TocToSection/\" ++ cat, aText=indexCatName cat})\n\t\t\t\t. [\"generalindex\", \"grammarindex\", \"headerindex\", \"libraryindex\", \"conceptindex\", \"impldefindex\"])\n\n\tfullTocCss <- readFile \"fulltoc.css\"\n\tlet\n\t    fullTocStyle = \"<style>\" ++ TextBuilder.fromString fullTocCss ++ \"</style>\"\n\t    pathHome = if sfs == InSubdir then \"../\" else \"\"\n\twritePage \"fulltoc\" sfs $ applyPageStyle sfs $ LazyText.toStrict $ TextBuilder.toLazyText $\n\t\tfileContent pathHome \"Draft C++ Standard: Contents\" (descMeta ++ fullTocStyle) $\n\t\t\t\"<h1 style='text-align:center; hyphens:none; margin: 1cm'>Working Draft<br>Programming Languages &mdash; C++</h1>\" ++\n\t\t\txml \"div\" [(\"class\", \"tocHeader\")] (TextBuilder.fromText $ tocHeader date commitUrl) ++\n\t\t\t\"<br><h1>Contents</h1>\" ++\n\t\t\tmconcat (tocChapter draft True . chapters) ++\n\t\t\tmconcat (h 2\n\t\t\t\t. (\\cat -> simpleRender2 anchor{aHref=\"SectionToSection/\" ++ cat, aText=indexCatName cat})\n\t\t\t\t. [\"generalindex\", \"grammarindex\", \"headerindex\", \"libraryindex\", \"conceptindex\", \"impldefindex\"])\n"
  },
  {
    "path": "Util.hs",
    "content": "{-# OPTIONS_GHC -fno-warn-tabs #-}\n{-# LANGUAGE TupleSections, OverloadedStrings, ViewPatterns #-}\n\nmodule Util (\n\tmconcat, (.), (++), Text, replace, xml, spanTag, h, getDigit, startsWith, urlChars,\n\tanchor, Anchor(..), writeFile, readFile, greekAlphabet, mapLast, mapHead, stripInfix, dropTrailingWs,\n\ttextStripInfix, textSubRegex, splitOn, intercalateBuilders, replaceXmlChars, stripAnyPrefix, trimString,\n\tspanJust, measure, partitionBy\n\t) where\n\nimport Prelude hiding ((.), (++), writeFile)\nimport qualified Data.Text as Text\nimport qualified Data.Map as Map\nimport Data.List (stripPrefix, intersperse)\nimport Data.Char (ord, isDigit, isSpace)\nimport Data.Text (Text, replace)\nimport Data.Text.IO (writeFile)\nimport Data.Time (getCurrentTime, diffUTCTime)\nimport Control.Arrow (first)\nimport Text.Regex (subRegex, Regex)\nimport qualified Data.Text.Lazy.Builder as TextBuilder\n\n(.) :: Functor f => (a -> b) -> (f a -> f b)\n(.) = fmap\n\n(++) :: Monoid a => a -> a -> a\n(++) = mappend\n\nxml :: Text -> [(Text, Text)] -> TextBuilder.Builder -> TextBuilder.Builder\nxml t attrs = (TextBuilder.fromText (\"<\" ++ t ++ \" \" ++ Text.unwords (map f attrs) ++ \">\") ++) . (++ TextBuilder.fromText (\"</\" ++ t ++ \">\"))\n\twhere\n\t\tf (n, v) = n ++ \"='\" ++ v ++ \"'\"\n\nspanTag :: Text -> TextBuilder.Builder -> TextBuilder.Builder\nspanTag = xml \"span\" . (:[]) . (\"class\",)\n\nh :: Int -> TextBuilder.Builder -> TextBuilder.Builder\nh = flip xml [] . (\"h\" ++) . Text.pack . show\n\ndata Anchor = Anchor\n    { aClass, aId, aHref :: Text\n    , aText :: TextBuilder.Builder\n    , aStyle, aTitle :: Text }\n\nintercalateBuilders :: TextBuilder.Builder -> [TextBuilder.Builder] -> TextBuilder.Builder\nintercalateBuilders x y = mconcat $ intersperse x y\n\nanchor :: Anchor\nanchor = Anchor{aClass=\"\", aId=\"\", aHref=\"\", aText=TextBuilder.fromText \"\", aStyle=\"\", aTitle=\"\"}\n\ngreekAlphabet :: [(String, Char)]\ngreekAlphabet =\n\t[ (\"alpha\"          , 'α')\n\t, (\"beta\"           , 'β')\n\t, (\"gamma\"          , 'γ')\n\t, (\"delta\"          , 'δ')\n\t, (\"mu\"             , 'μ')\n\t, (\"nu\"             , 'ν')\n\t, (\"lambda\"         , 'λ')\n\t, (\"pi\"             , 'π')\n\t, (\"phi\"            , 'φ')\n\t, (\"rho\"            , 'ρ')\n\t, (\"sigma\"          , 'σ')\n\t, (\"theta\"          , 'θ')\n\t, (\"zeta\"           , 'ζ')\n\n\t, (\"Gamma\"          , 'Γ')\n\t, (\"Sigma\"          , 'Σ')\n\t, (\"Pi\"             , 'Π') ]\n\nmapLast :: (a -> a) -> [a] -> [a]\nmapLast _ [] = []\nmapLast f [x] = [f x]\nmapLast f (x:xx) = x : mapLast f xx\n\nmapHead :: (a -> a) -> [a] -> [a]\nmapHead f (x:y) = f x : y\nmapHead _ [] = []\n\ngetDigit :: Char -> Maybe Int\ngetDigit c\n\t| isDigit c = Just $ ord c - ord '0'\n\t| otherwise = Nothing\n\nstripInfix :: Eq a => [a] -> [a] -> Maybe ([a], [a])\nstripInfix p s | Just r <- stripPrefix p s = Just ([], r)\nstripInfix p (hd:t) = first (hd:) . stripInfix p t\nstripInfix _ _  = Nothing\n\ntextStripInfix :: Text -> Text -> Maybe (Text, Text)\ntextStripInfix inf (Text.breakOn inf -> (a, b))\n\t| b == \"\" = Nothing\n\t| otherwise = Just (a, Text.drop (Text.length inf) b)\n\nstartsWith :: (Char -> Bool) -> (Text -> Bool)\nstartsWith _ \"\" = False\nstartsWith p t = p (Text.head t)\n\ndropTrailingWs :: String -> String\ndropTrailingWs = reverse . dropWhile isSpace . reverse\n\nurlChars :: Text -> Text\nurlChars =\n\treplace \"'\"  \"&#39;\" .\n\treplace \"<\"  \"%3c\" .\n\treplace \">\"  \"%3e\" .\n\treplace \"\\\"\" \"%22\" .\n\treplace \"#\"  \"%23\" .\n\treplace \"{\"  \"%7b\" .\n\treplace \"|\"  \"%7c\" .\n\treplace \"}\"  \"%7d\" .\n\treplace \"[\"  \"%5b\" .\n\treplace \"\\\\\" \"%5c\" .\n\treplace \"]\"  \"%5d\" .\n\treplace \"^\"  \"%5e\" .\n\treplace \" \"  \"%20\" .\n\treplace \"%\"  \"%25\"\n\ntextSubRegex :: Regex -> String -> Text -> Text\ntextSubRegex pat repl txt = Text.pack $ subRegex pat (Text.unpack txt) repl\n\nsplitOn :: (a -> Bool) -> [a] -> [[a]]\nsplitOn _ [] = [[]]\nsplitOn sep (x:y)\n    | sep x = [] : splitOn sep y\n    | otherwise = mapHead (x :) $ splitOn sep y\n\nreplaceXmlChars :: Text -> Text\nreplaceXmlChars =\n\treplace \">\" \"&gt;\" .\n\treplace \"<\" \"&lt;\" .\n\treplace \"&\" \"&amp;\"\n\nstripAnyPrefix :: [Text] -> Text -> Maybe (Text, Text)\nstripAnyPrefix [] _ = Nothing\nstripAnyPrefix (x:y) z\n    | Just a <- Text.stripPrefix x z = Just (x, a)\n    | otherwise = stripAnyPrefix y z\n\ntrimString :: String -> String\ntrimString = reverse . dropWhile isSpace . reverse . dropWhile isSpace\n\nspanJust :: [a] -> (a -> Maybe b) -> ([b], [a])\nspanJust (x : z) f\n    | Just y <- f x = first (y :) (spanJust z f)\nspanJust z _ = ([], z)\n\nmeasure :: IO a -> IO (a, Float)\nmeasure f = do\n\tstart <- getCurrentTime\n\tr <- f\n\tend <- getCurrentTime\n\treturn (r, realToFrac $ diffUTCTime end start)\n\npartitionBy :: (Ord b, Eq b) => (a -> b) -> [a] -> [(b, [a])]\npartitionBy f l = Map.assocs $ Map.fromListWith (flip (++)) [(f x, [x]) | x <- l]\n"
  },
  {
    "path": "colored.css",
    "content": "div.example {\n\tdisplay: block;\n\tmargin-top: 5pt;\n\tmargin-bottom: 5pt;\n\tfont-size: 11pt;\n\tcolor: #bb00bb;\n}\n\ndiv.note {\n\tdisplay: block;\n\tmargin-top: 5pt;\n\tmargin-bottom: 5pt;\n\tfont-size: 11pt;\n\tcolor: #bb00bb;\n}\n"
  },
  {
    "path": "cxxdraft-htmlgen.cabal",
    "content": "name:                cxxdraft-htmlgen\nversion:             0\nsynopsis:            Converts C++ Standard draft documents from their LaTeX sources to HTML\nlicense:             PublicDomain\nlicense-file:        LICENSE\nauthor:              Eelis\nmaintainer:          eelis@eelis.net\ncategory:            Text\nbuild-type:          Simple\nextra-source-files:  README\ncabal-version:       >=1.10\n\nexecutable cxxdraft-htmlgen\n  main-is:             genhtml.hs\n  other-modules:       Load14882, Render, Util, SectionPages, Toc, Document, LaTeXBase, LaTeXParser, RawDocument, MathJax, Sentences, CxxParser, Pages\n  other-extensions:    OverloadedStrings, RecordWildCards, TupleSections, ViewPatterns\n  build-depends: base >=4.6\n               , text >=1.2\n               , process >=1.1\n               , directory >=1.2\n               , hashable >=1.2\n               , containers >=0.5\n               , mtl >=2.2\n               , time >=1.4\n               , regex-compat-tdfa\n               , temporary\n               , parallel\n               , tagsoup\n               , monad-parallel\n  hs-source-dirs:      .\n  default-language:    Haskell2010\n  ghc-options:         -Wall -fno-warn-tabs -threaded \"-with-rtsopts=-N\"\n"
  },
  {
    "path": "expanded.css",
    "content": "div.example {\n\tdisplay: block;\n\tmargin-top: 5pt;\n\tmargin-bottom: 5pt;\n\tfont-size: 9pt;\n}\n\ndiv.note {\n\tdisplay: block;\n\tmargin-top: 5pt;\n\tmargin-bottom: 5pt;\n\tfont-size: 9pt;\n}\n\ndiv.note .texttt { font-size: 9pt; }\ndiv.example .texttt { font-size: 9pt; }\n\ndiv.note .textsf { font-family: 'Noto Sans'; font-size: 9pt; }\ndiv.example .textsf { font-family: 'Noto Sans'; font-size: 9pt; }\n\ndiv.note .math { font-size: 9pt; }\ndiv.example .math { font-size: 9pt; }\n"
  },
  {
    "path": "fulltoc.css",
    "content": "h1 { margin: 0.2em 5pt 0.2em 5pt; line-height: 1.5; }\nh2 { margin: 0.2em 5pt 0.2em 5pt; border-bottom: 1px dashed rgba(0, 0, 0, 0.2); line-height: 1.5; }\nh3 { margin: 0.2em 5pt 0.2em 5pt; border-bottom: 1px dashed rgba(0, 0, 0, 0.2); line-height: 1.5; }\nh4 { margin: 0.1em 5pt 0.1em 5pt; border-bottom: 1px dashed rgba(0, 0, 0, 0.2); line-height: 1.5; }\n:target h2 { border-bottom: none; }\n.tocHeader { text-align: center; }\n:target > div.tocChapter { display: block; }\n\n@media (prefers-color-scheme: dark) {\n    h2 { border-bottom-color: #b0b0b05a; }\n    h3 { border-bottom-color: #b0b0b05a; }\n    h4 { border-bottom-color: #b0b0b05a; }\n}\n"
  },
  {
    "path": "genhtml.hs",
    "content": "{-# OPTIONS_GHC -fno-warn-tabs #-}\n{-# LANGUAGE LambdaCase, ViewPatterns, RecordWildCards, OverloadedStrings #-}\n\nimport Document (Draft(..))\nimport Load14882 (load14882)\nimport Prelude hiding ((++), (.), writeFile, readFile)\nimport System.Directory (createDirectoryIfMissing, setCurrentDirectory, getCurrentDirectory, copyFile)\nimport System.Environment (getArgs)\nimport Control.Monad (forM_)\nimport Data.Text.IO (readFile)\nimport qualified Control.Monad.Parallel as ParallelMonad\nimport Util hiding (readFile)\nimport Toc (writeTocFiles)\nimport Pages (outputDir, PageStyle(..))\nimport SectionPages\n\ndata CmdLineArgs = CmdLineArgs\n\t{ repo :: FilePath\n\t, sectionFileStyle :: PageStyle\n\t, sectionToWrite :: Maybe String }\n\nreadCmdLineArgs :: [String] -> CmdLineArgs\nreadCmdLineArgs = \\case\n\t[repo, read -> sectionFileStyle, sec] -> CmdLineArgs{sectionToWrite=Just sec, ..}\n\t[repo, read -> sectionFileStyle] -> CmdLineArgs{sectionToWrite=Nothing,..}\n\t[repo] -> CmdLineArgs{sectionFileStyle=WithExtension,sectionToWrite=Nothing,..}\n\t_ -> error \"param: path/to/repo\"\n\nmain :: IO ()\nmain = do\n\tcwd <- getCurrentDirectory\n\tCmdLineArgs{..} <- readCmdLineArgs . getArgs\n\n\textraMacros <- readFile \"macros.tex\"\n\n\tsetCurrentDirectory $ repo ++ \"/source\"\n\tdraft@Draft{..} <- load14882 extraMacros\n\n\tsetCurrentDirectory cwd\n\tcreateDirectoryIfMissing True outputDir\n\tcopyFile \"icon-light.png\" (outputDir ++ \"/icon-light.png\")\n\tcopyFile \"icon-dark.png\" (outputDir ++ \"/icon-dark.png\")\n\tforM_ [\"expanded.css\", \"colored.css\", \"normative-only.css\"] $\n\t\t\\f -> do\n\t\t\tcopyFile f (outputDir ++ \"/\" ++ f)\n\tcase sectionToWrite of\n\t\tJust abbr -> writeSingleSectionFile sectionFileStyle draft abbr\n\t\tNothing -> do\n\t\t\tlet acts =\n\t\t\t\t[ writeTocFiles sectionFileStyle draft\n\t\t\t\t, writeCssFile\n\t\t\t\t, writeFiguresFile sectionFileStyle draft\n\t\t\t\t, writeFigureFiles sectionFileStyle draft\n\t\t\t\t, writeFootnotesFile sectionFileStyle draft\n\t\t\t\t, writeTablesFile sectionFileStyle draft\n\t\t\t\t, writeTableFiles sectionFileStyle draft\n\t\t\t\t] ++\n\t\t\t\twriteXrefDeltaFiles sectionFileStyle draft ++\n\t\t\t\twriteIndexFiles sectionFileStyle draft index ++\n\t\t\t\twriteSectionFiles sectionFileStyle draft\n\n\t\t\t((), took) <- measure $ ParallelMonad.sequence_ acts\n\t\t\tputStrLn $ \"Wrote files to \" ++ outputDir ++ \" in \" ++ show (took * 1000) ++ \"ms.\"\n"
  },
  {
    "path": "macros.tex",
    "content": "%% cxxdraft-htmlgen builtins:\n%\n% \\link\n%   Link to section.\n%   arg 0: link text\n%   arg 1: section abbreviation\n%\n% \\weblink\n%   arg 0: link text\n%   arg 1: URL\n%\n% \\indexlink\n%   Link to indexed position.\n%   arg 0: link text\n%   arg 1: index category\n%   arg 2: index key\n%   arg 3: abbreviation of section to link to (empty to auto-resolve)\n%\n% \\hiddenindexlink\n%   Hidden link to indexed position.\n%   arg 0: link text\n%   arg 1: index category\n%   arg 2: index key\n%   arg 3: abbreviation of section to link to (empty to auto-resolve)\n%\n% \\indexedspan\n%   arg 0: text\n%   arg 1: indices (zero or more \\index commands)\n\t\n%% cxxdraft-htmlgen derived macros:\n\n\\newcommand{\\linkx}[3]{\\indexlink{#1}{generalindex}{#2}{#3}}\n\t% Link to indexed position.\n\t%   arg 0: link text\n\t%   arg 1: generalindex key\n\t%   arg 2: section abbreviation\n\n\\newcommand{\\deflinkx}[3]{\\indexlink{#1}{generalindex}{#2|idxbfpage}{#3}}\n\t% Link to definition.\n\t%   arg 0: link text\n\t%   arg 1: definition key\n\t%   arg 2: section abbreviation\n\n\\newcommand{\\deflink}[2]{\\deflinkx{#1}{#1}{#2}}\n\t% Convenience macro for when the link\n\t% text is also the definition key.\n\n\\newcommand{\\libmemberrefx}[3]{\\indexlink{\\tcode{#1}}{libraryindex}{\\idxcode{#2}!\\idxcode{#3}}{}}\n\\newcommand{\\libglobalref}[1]{\\libglobalrefx{#1}{#1}}\n\\newcommand{\\libglobalrefx}[2]{\\indexlink{\\tcode{#1}}{libraryindex}{\\idxcode{#2}}{}}\n\\newcommand{\\noncxxtcode}[1]{\\tcode{#1}}\n\\newcommand{\\literaltcode}[1]{\\tcode{#1}}\n\\newcommand{\\literalterminal}[1]{\\terminal{##1}}\n\\newcommand{\\noncxxterminal}[1]{\\terminal{##1}}\n\\newcommand{\\oldconceptref}[1]{\\indexlink{\\oldconcept{#1}}{generalindex}{\\idxoldconcept{#1}}{}}\n\n%% replacements for existing macros:\n\n\\newcommand{\\defnoldconcept}[1]{\\indexedspan{\\oldconcept{#1}}{\\indextext{\\idxoldconcept{#1}}}}\n\\newcommand{\\indexdefn}[1]{\\indextext{#1|idxbfpage}}\n\\newcommand{\\idxcode}[1]{#1@\\tcode{#1}}\n\\newcommand{\\nontermdef}[1]{\\hiddenindexlink{\\indexedspan{#1\\textnormal{:}}{\\indexgrammar{\\idxgram{#1}}}}{grammarindex}{\\idxgram{#1}|idxbfpage}{}}\n\\newcommand{\\renontermdef}[1]{#1\\,\\textnormal{::}}\n\\newcommand{\\fmtnontermdef}[1]{#1\\,\\textnormal{:}}\n\\newcommand{\\locnontermdef}[1]{#1\\,\\textnormal{:}}\n\\newcommand{\\grammarterm}[1]{\\indexlink{\\indexedspan{\\gterm{#1}}{\\indexgram{\\idxgram{#1}}}}{grammarindex}{\\idxgram{#1}|idxbfpage}{}}\n\\newcommand{\\cite}[1]{\\indexlink{[bib]}{bibliography}{#1}{bibliography}}\n\\newcommand{\\libglobal}[1]{\\indexedspan{\\hiddenindexlink{#1}{libraryindex}{\\idxcode{#1}}{}}{\\indexlibraryglobal{#1}}}\n\\newcommand{\\libmember}[2]{\\indexedspan{\\hiddenindexlink{#1}{libraryindex}{\\idxcode{#2}!\\idxcode{#1}}{}}{\\indexlibrarymember{#1}{#2}}}\n\\newcommand{\\libheader}[1]{\\indexlink{\\indexedspan{\\tcode{<#1>}}{\\indexhdr{#1}}}{headerindex}{\\idxhdr{#1}|idxbfpage}{}}\n\\newcommand{\\libheaderdef}[1]{\\indexedspan{\\tcode{<#1>}}{\\indexheader{#1}}}\n\\newcommand{\\libheaderrefx}[2]{\\libheader{#1}}\n\\newcommand{\\libconceptx}[2]{\\indexlink{\\indexedspan{\\cname{#1}}{\\indexconcept{\\idxconcept{#2}}}}{conceptindex}{\\idxconcept{#2}|idxbfpage}{}}\n\\newcommand{\\libmacro}[1]{\\indexedspan{\\tcode{#1}}{\\indexlibraryglobal{#1}}}\n\\newcommand{\\libxmacro}[1]{\\indexedspan{\\tcode{__#1}}{\\indexlibraryglobal{__#1}}}\n\\newcommand{\\Range}[4]{#1\\tcode{#3,\\penalty2000{} #4}#2}\n\\newcommand{\\deflibconcept}[1]{\\hiddenindexlink{\\indexedspan{\\cname{#1}}{\\indexlibrary{\\idxconcept{#1}}\\indexconcept{\\idxconcept{#1}|idxbfpage}}}{conceptindex}{\\idxconcept{#1}|idxbfpage}{}}\n\\newcommand{\\defexposconcept}[1]{\\hiddenindexlink{\\indexedspan{\\ecname{#1}}{\\indexconcept{\\idxexposconcept{#1}|idxbfpage}}}{conceptindex}{\\idxexposconcept{#1}|idxbfpage}{}}\n\\newcommand{\\defexposconceptnc}[1]{\\defexposconcept{#1}}\n\\newcommand{\\exposconcept}[1]{\\indexlink{\\indexedspan{\\ecname{#1}}{\\indexconcept{\\idxexposconcept{#1}}}}{conceptindex}{\\idxexposconcept{#1}|idxbfpage}{}}\n\\newcommand{\\exposconceptx}[2]{\\indexedspan{\\ecname{#1}}{\\indexconcept{\\idxexposconcept{#2}}}}\n\\newcommand{\\exposconceptnc}[1]{\\exposconcept{#1}}\n\\newcommand{\\keyword}[1]{\\indexedspan{\\tcode{#1}}{\\indextext{\\idxcode{#1}}}}\n\\newcommand{\\itcorr}[1][]{}\n\\newcommand{\\diffdef}[1]{\\break\\diffhead{#1}}\n\\newcommand{\\defnx}[2]{\\hiddenindexlink{\\indexedspan{\\textit{#1}}{\\indexdefn{#2}}}{generalindex}{#2|idxbfpage}{}}\n\\newcommand{\\defnxname}[1]{\\indexedspan{\\xname{#1}}{\\indextext{\\idxxname{#1}}}}\n\\newcommand{\\defnadj}[2]{\\indextext{#1 #2|see{#2, #1}}\\defnx{#1 #2}{#2!#1}}\n\\newcommand{\\defnadjx}[3]{\\indextext{#1 #3|see{#3, #1}}\\defnx{#1 #2}{#3!#1}}\n\\newcommand{\\defnlibxname}[1]{\\indexedspan{\\xname{#1}}{\\indexlibrary{\\idxxname{#1}}}}\n\\newcommand{\\descr}[1]{\\textnormal{#1}}\n\\newcommand{\\cv}{\\mathit{cv}}\n\\newcommand{\\texorpdfstring}[2]{#2}\n\\newcommand{\\textunderscore}{_}\n\\newcommand{\\emo}[1]{#1}\n\\newcommand{\\bm}[1]{\\textbf{#1}}\n\n\\newenvironment{LongTable}[3]\n{\n \\newcommand{\\continuedcaption}{\\caption[]{#1 (continued)}}\n \\begin{htmlTable}{#1}{#2}{#3}\n \\begin{TableBase}\n}\n{\n \\bottomline\n \\end{TableBase}\n \\end{htmltable}\n}\n"
  },
  {
    "path": "mathjax-batch",
    "content": "#! /usr/bin/env node\n\nvar mjAPI = require(\"mathjax-node\");\nvar split = require(\"split\");\n\nmjAPI.config(\n  { extensions: \"\"\n  , fontURL: \"https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS\" });\nmjAPI.start();\n\nvar math = '';\nfunction processLine(line)\n{\n    var format;\n    if (line == \"NONINLINE\") format = \"TeX\";\n    else if (line == \"INLINE\") format = \"inline-TeX\";\n    else\n    {\n        if (math != '') math += '\\n';\n        math += line;\n        return;\n    }\n\n    mjAPI.typeset({\n      math: math, format: format, html: true, css: false,\n      speakText: true, ex: 6, width: 100, linebreaks: true\n    }, function (data) {\n      // todo: if (data.errors) abort\n      console.log(data.html)\n      console.log(\"DONE\")\n    });\n\n    math = '';\n}\n\nprocess.stdin.pipe(split(/\\n/, null, {trailing: false})).on('data', processLine)\n"
  },
  {
    "path": "normative-only.css",
    "content": "div.example { display: none; }\ndiv.note { display: none; }\n\na.footnotenum { display: none; }\ndiv.footnote { display: none; }\ndiv.footnoteSeparator { display: none; }\n.footnoteref { display: none; }\n\ndiv.nonNormativeOnly { display: none; }\n"
  },
  {
    "path": "stack.yaml",
    "content": "resolver: lts-12.17\npackages:\n- .\n\nextra-deps: []\n\nflags: {}\n\nextra-package-dbs: []\n"
  },
  {
    "path": "toc.css",
    "content": "h1 { margin: 0.2em 5pt 0.2em 5pt; line-height: 1.5; }\nh2 { margin: 0.2em 5pt 0.2em 5pt; border-bottom: 1px dashed rgba(0, 0, 0, 0.2); line-height: 1.5; }\nh3 { margin: 0.2em 5pt 0.2em 5pt; border-bottom: 1px dashed rgba(0, 0, 0, 0.2); line-height: 1.5; }\nh4 { margin: 0.1em 5pt 0.1em 5pt; border-bottom: 1px dashed rgba(0, 0, 0, 0.2); line-height: 1.5; }\n:target h2 { border-bottom: none; }\n.tocHeader { text-align: center; }\ndiv.tocChapter { display: none; }\n:target > div.tocChapter { display: block; }\n\n@media (prefers-color-scheme: dark) {\n    h2 { border-bottom-color: #b0b0b05a; }\n    h3 { border-bottom-color: #b0b0b05a; }\n    h4 { border-bottom-color: #b0b0b05a; }\n}\n"
  }
]