@@ -1,7 +1,6 @@
1−{-# LANGUAGE LambdaCase #-}
2−{-# LANGUAGE FlexibleContexts #-}
1+{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleInstances #-}
2{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE MultiParamTypeClasses #-}
3+{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE OverloadedStrings #-}
6{-# LANGUAGE ViewPatterns #-}
5{-# LANGUAGE ViewPatterns #-}
@@ -29,7 +28,8 @@ import Control.Applicative ((<|>))
29import Control.Arrow (first)
28import Control.Arrow (first)
30import Control.Monad (guard, mplus, msum, mzero, unless, void)
29import Control.Monad (guard, mplus, msum, mzero, unless, void)
31import Control.Monad.Except (throwError)
30import Control.Monad.Except (throwError)
32−import Control.Monad.Reader (ReaderT, ask, asks, lift, local, runReaderT)
31+import Control.Monad.Reader (ask, asks, lift, local, runReaderT)
32+import Data.ByteString.Base64 (encode)
33import Data.Char (isAlphaNum, isLetter)
33import Data.Char (isAlphaNum, isLetter)
34import Data.Default (Default (..), def)
34import Data.Default (Default (..), def)
35import Data.Foldable (for_)
35import Data.Foldable (for_)
@@ -40,17 +40,19 @@ import Data.Monoid (First (..))
40import qualified Data.Set as Set
40import qualified Data.Set as Set
41import Data.Text (Text)
41import Data.Text (Text)
42import qualified Data.Text as T
42import qualified Data.Text as T
43−import Network.URI (URI, nonStrictRelativeTo, parseURIReference)
43+import Network.URI (nonStrictRelativeTo, parseURIReference)
44import Text.HTML.TagSoup
44import Text.HTML.TagSoup
45import Text.HTML.TagSoup.Match
45import Text.HTML.TagSoup.Match
46−import Text.Pandoc.Builder (Blocks, HasMeta (..), Inlines, trimInlines)
46+import Text.Pandoc.Builder (Blocks, Inlines, trimInlines)
47import qualified Text.Pandoc.Builder as B
47import qualified Text.Pandoc.Builder as B
48import Text.Pandoc.Class.PandocMonad (PandocMonad (..))
48import Text.Pandoc.Class.PandocMonad (PandocMonad (..))
49import Text.Pandoc.CSS (foldOrElse, pickStyleAttrProps)
49import Text.Pandoc.CSS (foldOrElse, pickStyleAttrProps)
50import qualified Text.Pandoc.UTF8 as UTF8
50import qualified Text.Pandoc.UTF8 as UTF8
51import Text.Pandoc.Definition
51import Text.Pandoc.Definition
52+import Text.Pandoc.Readers.HTML.Parsing
53+import Text.Pandoc.Readers.HTML.TagCategories
54+import Text.Pandoc.Readers.HTML.Types
52import Text.Pandoc.Readers.LaTeX (rawLaTeXInline)
55import Text.Pandoc.Readers.LaTeX (rawLaTeXInline)
53−import Text.Pandoc.Readers.LaTeX.Types (Macro)
54import Text.Pandoc.XML (html5Attributes, html4Attributes, rdfaAttributes)
56import Text.Pandoc.XML (html5Attributes, html4Attributes, rdfaAttributes)
55import Text.Pandoc.Error
57import Text.Pandoc.Error
56import Text.Pandoc.Logging
58import Text.Pandoc.Logging
@@ -66,7 +68,6 @@ import Text.Pandoc.Shared (addMetaField, blocksToInlines', crFilter, escapeURI,
66import Text.Pandoc.Walk
68import Text.Pandoc.Walk
67import Text.Parsec.Error
69import Text.Parsec.Error
68import Text.TeXMath (readMathML, writeTeX)
70import Text.TeXMath (readMathML, writeTeX)
69−import Data.ByteString.Base64 (encode)
71-- | Convert HTML-formatted string to 'Pandoc' document.
72-- | Convert HTML-formatted string to 'Pandoc' document.
72readHtml :: PandocMonad m
73readHtml :: PandocMonad m
@@ -105,32 +106,12 @@ replaceNotes' noteTbl (RawInline (Format "noteref") ref) =
105 maybe (Str "") (Note . B.toList) $ lookup ref noteTbl
106 maybe (Str "") (Note . B.toList) $ lookup ref noteTbl
106replaceNotes' _ x = x
107replaceNotes' _ x = x
110− { parserState :: ParserState,
111− noteTable :: [(Text, Blocks)],
112− baseHref :: Maybe URI,
113− identifiers :: Set.Set Text,
114− logMessages :: [LogMessage],
115− macros :: M.Map Text Macro,
116− readerOpts :: ReaderOptions
119−data HTMLLocal = HTMLLocal { quoteContext :: QuoteContext
120− , inChapter :: Bool -- ^ Set if in chapter section
121− , inPlain :: Bool -- ^ Set if in pPlain
124setInChapter :: PandocMonad m => HTMLParser m s a -> HTMLParser m s a
109setInChapter :: PandocMonad m => HTMLParser m s a -> HTMLParser m s a
125setInChapter = local (\s -> s {inChapter = True})
110setInChapter = local (\s -> s {inChapter = True})
127setInPlain :: PandocMonad m => HTMLParser m s a -> HTMLParser m s a
112setInPlain :: PandocMonad m => HTMLParser m s a -> HTMLParser m s a
128setInPlain = local (\s -> s {inPlain = True})
113setInPlain = local (\s -> s {inPlain = True})
130−type HTMLParser m s = ParserT s HTMLState (ReaderT HTMLLocal m)
132−type TagParser m = HTMLParser m [Tag Text]
134pHtml :: PandocMonad m => TagParser m Blocks
115pHtml :: PandocMonad m => TagParser m Blocks
135pHtml = try $ do
116pHtml = try $ do
136 (TagOpen "html" attr) <- lookAhead pAny
117 (TagOpen "html" attr) <- lookAhead pAny
@@ -681,22 +662,6 @@ inline = choice
681 , pRawHtmlInline
662 , pRawHtmlInline
684−pLocation :: PandocMonad m => TagParser m ()
686− (TagPosition r c) <- pSat isTagPosition
687− setPosition $ newPos "input" r c
689−pSat :: PandocMonad m => (Tag Text -> Bool) -> TagParser m (Tag Text)
692− token tshow (const pos) (\x -> if f x then Just x else Nothing)
694−pSatisfy :: PandocMonad m => (Tag Text -> Bool) -> TagParser m (Tag Text)
695−pSatisfy f = try $ optional pLocation >> pSat f
697−pAny :: PandocMonad m => TagParser m (Tag Text)
698−pAny = pSatisfy (const True)
700pSelfClosing :: PandocMonad m
665pSelfClosing :: PandocMonad m
701 => (Text -> Bool) -> ([Attribute Text] -> Bool)
666 => (Text -> Bool) -> ([Attribute Text] -> Bool)
702 -> TagParser m (Tag Text)
667 -> TagParser m (Tag Text)
@@ -924,49 +889,6 @@ pInlinesInTags :: PandocMonad m => Text -> (Inlines -> Inlines)
924 -> TagParser m Inlines
889 -> TagParser m Inlines
925pInlinesInTags tagtype f = extractSpaces f <$> pInTags tagtype inline
890pInlinesInTags tagtype f = extractSpaces f <$> pInTags tagtype inline
927−pInTags :: (PandocMonad m, Monoid a) => Text -> TagParser m a -> TagParser m a
928−pInTags tagtype parser = pInTags' tagtype (const True) parser
930−pInTags' :: (PandocMonad m, Monoid a)
932− -> (Tag Text -> Bool)
935−pInTags' tagtype tagtest parser = try $ do
936− pSatisfy (\t -> t ~== TagOpen tagtype [] && tagtest t)
937− mconcat <$> manyTill parser (pCloses tagtype <|> eof)
939−-- parses p, preceded by an opening tag (optional if tagsOptional)
940−-- and followed by a closing tag (optional if tagsOptional)
941−pInTag :: PandocMonad m => Bool -> Text -> TagParser m a -> TagParser m a
942−pInTag tagsOptional tagtype p = try $ do
944− (if tagsOptional then optional else void) $ pSatisfy (matchTagOpen tagtype [])
948− (if tagsOptional then optional else void) $ pSatisfy (matchTagClose tagtype)
952−pCloses :: PandocMonad m => Text -> TagParser m ()
953−pCloses tagtype = try $ do
954− t <- lookAhead $ pSatisfy $ \tag -> isTagClose tag || isTagOpen tag
956− (TagClose t') | t' == tagtype -> void pAny
957− (TagOpen t' _) | t' `closes` tagtype -> return ()
958− (TagClose "ul") | tagtype == "li" -> return ()
959− (TagClose "ol") | tagtype == "li" -> return ()
960− (TagClose "dl") | tagtype == "dd" -> return ()
961− (TagClose "table") | tagtype == "td" -> return ()
962− (TagClose "table") | tagtype == "th" -> return ()
963− (TagClose "table") | tagtype == "tr" -> return ()
964− (TagClose "td") | tagtype `Set.member` blockHtmlTags -> return ()
965− (TagClose "th") | tagtype `Set.member` blockHtmlTags -> return ()
966− (TagClose t') | tagtype == "p" && t' `Set.member` blockHtmlTags
967− -> return () -- see #3794
970pTagText :: PandocMonad m => TagParser m Inlines
892pTagText :: PandocMonad m => TagParser m Inlines
971pTagText = try $ do
893pTagText = try $ do
972 (TagText str) <- pSatisfy isTagText
894 (TagText str) <- pSatisfy isTagText
@@ -975,14 +897,10 @@ pTagText = try $ do
975 parsed <- lift $ lift $
897 parsed <- lift $ lift $
976 flip runReaderT qu $ runParserT (many pTagContents) st "text" str
898 flip runReaderT qu $ runParserT (many pTagContents) st "text" str
977 case parsed of
899 case parsed of
978− Left _ -> throwError $ PandocParseError $ "Could not parse `" <> str <> "'"
900+ Left _ -> throwError $ PandocParseError $
901+ "Could not parse `" <> str <> "'"
979 Right result -> return $ mconcat result
902 Right result -> return $ mconcat result
981−pBlank :: PandocMonad m => TagParser m ()
983− (TagText str) <- pSatisfy isTagText
984− guard $ T.all isSpace str
986type InlinesParser m = HTMLParser m Text
904type InlinesParser m = HTMLParser m Text
988pTagContents :: PandocMonad m => InlinesParser m Inlines
906pTagContents :: PandocMonad m => InlinesParser m Inlines
@@ -1077,54 +995,6 @@ pSpace = many1 (satisfy isSpace) >>= \xs ->
1077 then return B.softbreak
995 then return B.softbreak
1078 else return B.space
996 else return B.space
1084−eitherBlockOrInline :: Set.Set Text
1085−eitherBlockOrInline = Set.fromList
1086− ["audio", "applet", "button", "iframe", "embed",
1087− "del", "ins", "progress", "map", "area", "noscript", "script",
1088− "object", "svg", "video", "source"]
1090−blockHtmlTags :: Set.Set Text
1091−blockHtmlTags = Set.fromList
1092− ["?xml", "!DOCTYPE", "address", "article", "aside",
1093− "blockquote", "body", "canvas",
1094− "caption", "center", "col", "colgroup", "dd", "details",
1095− "dir", "div", "dl", "dt", "fieldset", "figcaption", "figure",
1096− "footer", "form", "h1", "h2", "h3", "h4",
1097− "h5", "h6", "head", "header", "hgroup", "hr", "html",
1098− "isindex", "main", "menu", "meta", "noframes", "nav",
1099− "ol", "output", "p", "pre",
1100− "section", "summary", "table", "tbody", "textarea",
1101− "thead", "tfoot", "ul", "dd",
1102− "dt", "frameset", "li", "tbody", "td", "tfoot",
1103− "th", "thead", "tr", "script", "style"]
1105−-- We want to allow raw docbook in markdown documents, so we
1106−-- include docbook block tags here too.
1107−blockDocBookTags :: Set.Set Text
1108−blockDocBookTags = Set.fromList
1109− ["calloutlist", "bibliolist", "glosslist", "itemizedlist",
1110− "orderedlist", "segmentedlist", "simplelist",
1111− "variablelist", "caution", "important", "note", "tip",
1112− "warning", "address", "literallayout", "programlisting",
1113− "programlistingco", "screen", "screenco", "screenshot",
1114− "synopsis", "example", "informalexample", "figure",
1115− "informalfigure", "table", "informaltable", "para",
1116− "simpara", "formalpara", "equation", "informalequation",
1117− "figure", "screenshot", "mediaobject", "qandaset",
1118− "procedure", "task", "cmdsynopsis", "funcsynopsis",
1119− "classsynopsis", "blockquote", "epigraph", "msgset",
1120− "sidebar", "title"]
1122−epubTags :: Set.Set Text
1123−epubTags = Set.fromList ["case", "switch", "default"]
1125−blockTags :: Set.Set Text
1126−blockTags = Set.unions [blockHtmlTags, blockDocBookTags, epubTags]
1128class NamedTag a where
998class NamedTag a where
1129 getTagName :: a -> Maybe Text
999 getTagName :: a -> Maybe Text
@@ -1162,47 +1032,6 @@ isTextTag = tagText (const True)
1162isCommentTag :: Tag a -> Bool
1032isCommentTag :: Tag a -> Bool
1163isCommentTag = tagComment (const True)
1033isCommentTag = tagComment (const True)
1165−-- taken from HXT and extended
1166−-- See http://www.w3.org/TR/html5/syntax.html sec 8.1.2.4 optional tags
1167−closes :: Text -> Text -> Bool
1168−_ `closes` "body" = False
1169−_ `closes` "html" = False
1170−"body" `closes` "head" = True
1171−"a" `closes` "a" = True
1172−"li" `closes` "li" = True
1173−"th" `closes` t | t `elem` ["th","td"] = True
1174−"td" `closes` t | t `elem` ["th","td"] = True
1175−"tr" `closes` t | t `elem` ["th","td","tr"] = True
1176−"dd" `closes` t | t `elem` ["dt", "dd"] = True
1177−"dt" `closes` t | t `elem` ["dt","dd"] = True
1178−"rt" `closes` t | t `elem` ["rb", "rt", "rtc"] = True
1179−"optgroup" `closes` "optgroup" = True
1180−"optgroup" `closes` "option" = True
1181−"option" `closes` "option" = True
1182−-- https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
1183−x `closes` "p" | x `elem` ["address", "article", "aside", "blockquote",
1184− "dir", "div", "dl", "fieldset", "footer", "form", "h1", "h2", "h3", "h4",
1185− "h5", "h6", "header", "hr", "main", "menu", "nav", "ol", "p", "pre", "section",
1186− "table", "ul"] = True
1187−_ `closes` "meta" = True
1188−"form" `closes` "form" = True
1189−"label" `closes` "label" = True
1190−"map" `closes` "map" = True
1191−"object" `closes` "object" = True
1192−_ `closes` t | t `elem` ["option","style","script","textarea","title"] = True
1193−t `closes` "select" | t /= "option" = True
1194−"thead" `closes` "colgroup" = True
1195−"tfoot" `closes` t | t `elem` ["thead","colgroup"] = True
1196−"tbody" `closes` t | t `elem` ["tbody","tfoot","thead","colgroup"] = True
1198− t `elem` ["h1","h2","h3","h4","h5","h6","dl","ol","ul","table","div","main","p"] &&
1199− t2 `elem` ["h1","h2","h3","h4","h5","h6","p" ] = True -- not "div" or "main"
1201− t1 `Set.member` blockTags &&
1202− t2 `Set.notMember` blockTags &&
1203− t2 `Set.notMember` eitherBlockOrInline = True
1204−_ `closes` _ = False
1206--- parsers for use in markdown, textile readers
1035--- parsers for use in markdown, textile readers
1208-- | Matches a stretch of HTML in balanced tags.
1037-- | Matches a stretch of HTML in balanced tags.
@@ -1347,13 +1176,6 @@ stripPrefix' s =
1347 if T.null t then s else T.drop 1 t
1176 if T.null t then s else T.drop 1 t
1348 where (_, t) = T.span (/= ':') s
1177 where (_, t) = T.span (/= ':') s
1350−isSpace :: Char -> Bool
1357-- Utilities
1179-- Utilities
1359-- | Adjusts a url according to the document's base URL.
1181-- | Adjusts a url according to the document's base URL.
@@ -1364,41 +1186,6 @@ canonicalizeUrl url = do
1364 (Just rel, Just bs) -> tshow (rel `nonStrictRelativeTo` bs)
1186 (Just rel, Just bs) -> tshow (rel `nonStrictRelativeTo` bs)
1365 _ -> url
1187 _ -> url
1370−instance HasMacros HTMLState where
1371− extractMacros = macros
1372− updateMacros f st = st{ macros = f $ macros st }
1374−instance HasIdentifierList HTMLState where
1375− extractIdentifierList = identifiers
1376− updateIdentifierList f s = s{ identifiers = f (identifiers s) }
1378−instance HasLogMessages HTMLState where
1379− addLogMessage m s = s{ logMessages = m : logMessages s }
1380− getLogMessages = reverse . logMessages
1382−-- This signature should be more general
1383−-- MonadReader HTMLLocal m => HasQuoteContext st m
1384−instance PandocMonad m => HasQuoteContext HTMLState (ReaderT HTMLLocal m) where
1385− getQuoteContext = asks quoteContext
1386− withQuoteContext q = local (\s -> s{quoteContext = q})
1388−instance HasReaderOptions HTMLState where
1389− extractReaderOptions = extractReaderOptions . parserState
1391−instance HasMeta HTMLState where
1392− setMeta s b st = st {parserState = setMeta s b $ parserState st}
1393− deleteMeta s st = st {parserState = deleteMeta s $ parserState st}
1395−instance Default HTMLLocal where
1396− def = HTMLLocal NoQuote False False
1398−instance HasLastStrPosition HTMLState where
1399− setLastStrPos s st = st {parserState = setLastStrPos s (parserState st)}
1400− getLastStrPos = getLastStrPos . parserState
1402-- For now we need a special version here; the one in Shared has String type
1189-- For now we need a special version here; the one in Shared has String type
1403renderTags' :: [Tag Text] -> Text
1190renderTags' :: [Tag Text] -> Text
1404renderTags' = renderTagsOptions
1191renderTags' = renderTagsOptions
@@ -1411,21 +1198,6 @@ renderTags' = renderTagsOptions
1411-- EPUB Specific
1198-- EPUB Specific
1414−sectioningContent :: [Text]
1415−sectioningContent = ["article", "aside", "nav", "section"]
1418−groupingContent :: [Text]
1419−groupingContent = ["p", "hr", "pre", "blockquote", "ol"
1420− , "ul", "li", "dl", "dt", "dt", "dd"
1421− , "figure", "figcaption", "div", "main"]
1423−matchTagClose :: Text -> (Tag Text -> Bool)
1424−matchTagClose t = (~== TagClose t)
1426−matchTagOpen :: Text -> [(Text, Text)] -> (Tag Text -> Bool)
1427−matchTagOpen t as = (~== TagOpen t as)
1431types :: [(String, ([String], Int))]
1203types :: [(String, ([String], Int))]