From 9a5e08107386b5592761985fdbc111d42b91caf4 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 25 Feb 2015 10:16:05 -0800 Subject: Markdown writer: Avoid introducing spurious list items through wrapping. Closes #1946. --- src/Text/Pandoc/Writers/Markdown.hs | 53 ++++++++++++++++++++++++++++--------- tests/markdown-reader-more.native | 5 +++- tests/markdown-reader-more.txt | 5 ++++ tests/writer.markdown | 4 +-- tests/writer.opml | 4 +-- tests/writer.plain | 4 +-- 6 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index d71f0daf8..5cc1b3444 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -39,6 +39,7 @@ import Text.Pandoc.Writers.Shared import Text.Pandoc.Options import Text.Pandoc.Parsing hiding (blankline, blanklines, char, space) import Data.Maybe (fromMaybe) +import Data.Either (isRight) import Data.List ( group, stripPrefix, find, intersperse, transpose, sortBy ) import Data.Char ( isSpace, isPunctuation ) import Data.Ord ( comparing ) @@ -57,12 +58,14 @@ import qualified Data.Text as T type Notes = [[Block]] type Refs = [([Inline], Target)] -data WriterState = WriterState { stNotes :: Notes - , stRefs :: Refs - , stIds :: [String] - , stPlain :: Bool } +data WriterState = WriterState { stNotes :: Notes + , stRefs :: Refs + , stInList :: Bool + , stIds :: [String] + , stPlain :: Bool } instance Default WriterState - where def = WriterState{ stNotes = [], stRefs = [], stIds = [], stPlain = False } + where def = WriterState{ stNotes = [], stRefs = [], stInList = False, + stIds = [], stPlain = False } -- | Convert Pandoc to Markdown. writeMarkdown :: WriterOptions -> Pandoc -> String @@ -453,7 +456,7 @@ blockToMarkdown opts t@(Table caption aligns widths headers rows) = do $ Pandoc nullMeta [t] return $ nst $ tbl $$ blankline $$ caption'' $$ blankline blockToMarkdown opts (BulletList items) = do - contents <- mapM (bulletListItemToMarkdown opts) items + contents <- inList $ mapM (bulletListItemToMarkdown opts) items return $ cat contents <> blankline blockToMarkdown opts (OrderedList (start,sty,delim) items) = do let start' = if isEnabled Ext_startnum opts then start else 1 @@ -464,13 +467,22 @@ blockToMarkdown opts (OrderedList (start,sty,delim) items) = do let markers' = map (\m -> if length m < 3 then m ++ replicate (3 - length m) ' ' else m) markers - contents <- mapM (\(item, num) -> orderedListItemToMarkdown opts item num) $ + contents <- inList $ + mapM (\(item, num) -> orderedListItemToMarkdown opts item num) $ zip markers' items return $ cat contents <> blankline blockToMarkdown opts (DefinitionList items) = do - contents <- mapM (definitionListItemToMarkdown opts) items + contents <- inList $ mapM (definitionListItemToMarkdown opts) items return $ cat contents <> blankline +inList :: State WriterState a -> State WriterState a +inList p = do + oldInList <- gets stInList + modify $ \st -> st{ stInList = True } + res <- p + modify $ \st -> st{ stInList = oldInList } + return res + addMarkdownAttribute :: String -> String addMarkdownAttribute s = case span isTagText $ reverse $ parseTags s of @@ -677,12 +689,29 @@ getReference label (src, tit) = do -- | Convert list of Pandoc inline elements to markdown. inlineListToMarkdown :: WriterOptions -> [Inline] -> State WriterState Doc -inlineListToMarkdown opts lst = - mapM (inlineToMarkdown opts) (avoidBadWraps lst) >>= return . cat +inlineListToMarkdown opts lst = do + inlist <- gets stInList + mapM (inlineToMarkdown opts) + (if inlist then avoidBadWraps lst else lst) >>= return . cat where avoidBadWraps [] = [] - avoidBadWraps (Space:Str (c:cs):xs) - | c `elem` ("-*+>" :: String) = Str (' ':c:cs) : avoidBadWraps xs + avoidBadWraps (Space:Str ('>':cs):xs) = + Str (' ':'>':cs) : avoidBadWraps xs + avoidBadWraps (Space:Str [c]:[]) + | c `elem` "-*+" = Str [' ', c] : [] + avoidBadWraps (Space:Str [c]:Space:xs) + | c `elem` "-*+" = Str [' ', c] : Space : avoidBadWraps xs + avoidBadWraps (Space:Str cs:Space:xs) + | isOrderedListMarker cs = Str (' ':cs) : Space : avoidBadWraps xs + avoidBadWraps (Space:Str cs:[]) + | isOrderedListMarker cs = Str (' ':cs) : [] avoidBadWraps (x:xs) = x : avoidBadWraps xs + isOrderedListMarker xs = endsWithListPunct xs && + isRight (runParserT (anyOrderedListMarker >> eof) + defaultParserState "" xs) + endsWithListPunct xs = case reverse xs of + '.':_ -> True + ')':_ -> True + _ -> False escapeSpaces :: Inline -> Inline escapeSpaces (Str s) = Str $ substitute " " "\\ " s diff --git a/tests/markdown-reader-more.native b/tests/markdown-reader-more.native index 3f4bb5740..96204898e 100644 --- a/tests/markdown-reader-more.native +++ b/tests/markdown-reader-more.native @@ -156,4 +156,7 @@ ,Para [Str "MapReduce",Space,Str "is",Space,Str "a",Space,Str "paradigm",Space,Str "popularized",Space,Str "by",Space,Link [Str "Google"] ("http://google.com",""),Space,Cite [Citation {citationId = "mapreduce", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@mapreduce]"],Space,Str "as",Space,Str "its",Space,Str "most",Space,Str "vocal",Space,Str "proponent."] ,Header 2 ("empty-reference-links",[],[]) [Str "Empty",Space,Str "reference",Space,Str "links"] ,Para [Str "bar"] -,Para [Link [Str "foo2"] ("","")]] +,Para [Link [Str "foo2"] ("","")] +,Header 2 ("wrapping-shouldnt-introduce-new-list-items",[],[]) [Str "Wrapping",Space,Str "shouldn\8217t",Space,Str "introduce",Space,Str "new",Space,Str "list",Space,Str "items"] +,BulletList + [[Plain [Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "2015."]]]] diff --git a/tests/markdown-reader-more.txt b/tests/markdown-reader-more.txt index d7439f6cb..99e9ec7e8 100644 --- a/tests/markdown-reader-more.txt +++ b/tests/markdown-reader-more.txt @@ -276,3 +276,8 @@ most vocal proponent. bar [foo2] + +## Wrapping shouldn't introduce new list items + +- blah blah blah blah blah blah blah blah blah blah blah blah blah blah 2015. + diff --git a/tests/writer.markdown b/tests/writer.markdown index ad97b15ef..7276b31c7 100644 --- a/tests/writer.markdown +++ b/tests/writer.markdown @@ -549,8 +549,8 @@ LaTeX These shouldn’t be math: - To get the famous equation, write `$e = mc^2$`. -- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot” is - emphasized.) +- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot” + is emphasized.) - Shoes (\$20) and socks (\$5). - Escaped `$`: \$73 *this should be emphasized* 23\$. diff --git a/tests/writer.opml b/tests/writer.opml index 840c3c6e1..8f79e842c 100644 --- a/tests/writer.opml +++ b/tests/writer.opml @@ -33,7 +33,7 @@ - + @@ -50,7 +50,7 @@ - + diff --git a/tests/writer.plain b/tests/writer.plain index fab0489ac..0332a747b 100644 --- a/tests/writer.plain +++ b/tests/writer.plain @@ -499,8 +499,8 @@ LATEX These shouldn’t be math: - To get the famous equation, write $e = mc^2$. -- $22,000 is a _lot_ of money. So is $34,000. (It worked if “lot” is - emphasized.) +- $22,000 is a _lot_ of money. So is $34,000. (It worked if “lot” + is emphasized.) - Shoes ($20) and socks ($5). - Escaped $: $73 _this should be emphasized_ 23$. -- cgit v1.2.3