From f240adfc13d48288f7f3518f8f879cf0fd4a7cb1 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 12 May 2018 09:31:15 -0700 Subject: EPUB writer: properly escape pagetitle. Previously we weren't escaping `&` and other XML characters in the pagetitle, so a title containing a `&` would be invalid. --- src/Text/Pandoc/Writers/EPUB.hs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index f1ff8b482..3c6ab69b9 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -74,6 +74,7 @@ import Text.Printf (printf) import Text.XML.Light (Attr (..), Element (..), Node (..), QName (..), add_attrs, lookupAttr, node, onlyElems, parseXML, ppElement, showElement, strContent, unode, unqual) +import Text.Pandoc.XML (escapeStringForXML) -- A Chapter includes a list of blocks and maybe a section -- number offset. Note, some chapters are unnumbered. The section @@ -446,7 +447,8 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do cpContent <- lift $ writeHtml opts'{ writerVariables = ("coverpage","true"): - ("pagetitle",plainTitle): + ("pagetitle", + escapeStringForXML plainTitle): cssvars True ++ vars } (Pandoc meta [RawBlock (Format "html") $ "
\n\"cover\n
"]) imgContent <- lift $ P.readFileLazy img @@ -459,7 +461,7 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do -- title page tpContent <- lift $ writeHtml opts'{ writerVariables = ("titlepage","true"): - ("pagetitle",plainTitle): + ("pagetitle", escapeStringForXML plainTitle): cssvars True ++ vars } (Pandoc meta []) tpEntry <- mkEntry "text/title_page.xhtml" tpContent @@ -754,7 +756,8 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do (writeHtmlStringForEPUB version opts{ writerTemplate = Nothing , writerVariables = - ("pagetitle",plainTitle): + ("pagetitle", + escapeStringForXML plainTitle): writerVariables opts} (Pandoc nullMeta [Plain $ walk clean tit])) of -- cgit v1.2.3 From 2b89aaf04dd2d1bdafa0ee507abefd4f0d6df271 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 14 May 2018 10:37:46 -0700 Subject: Make internal links work in ODT/OpenDocument. This adds proper bookmarks to the headers with non-null IDs. Closes #4358. --- src/Text/Pandoc/Writers/OpenDocument.hs | 16 ++++-- test/writer.opendocument | 97 ++++++++++++++++++--------------- 2 files changed, 64 insertions(+), 49 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index 514327e9a..21d709f98 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -193,10 +193,15 @@ formulaStyle mt = inTags False "style:style" ,("style:horizontal-rel", "paragraph-content") ,("style:wrap", "none")] -inHeaderTags :: PandocMonad m => Int -> Doc -> OD m Doc -inHeaderTags i d = +inHeaderTags :: PandocMonad m => Int -> String -> Doc -> OD m Doc +inHeaderTags i ident d = return $ inTags False "text:h" [ ("text:style-name", "Heading_20_" ++ show i) - , ("text:outline-level", show i)] d + , ("text:outline-level", show i)] + $ if null ident + then d + else selfClosingTag "text:bookmark-start" [ ("text:name", ident) ] + <> d <> + selfClosingTag "text:bookmark-end" [ ("text:name", ident) ] inQuotes :: QuoteType -> Doc -> Doc inQuotes SingleQuote s = char '\8216' <> s <> char '\8217' @@ -349,8 +354,9 @@ blockToOpenDocument o bs | LineBlock b <- bs = blockToOpenDocument o $ linesToPara b | Div attr xs <- bs = withLangFromAttr attr (blocksToOpenDocument o xs) - | Header i _ b <- bs = setFirstPara >> - (inHeaderTags i =<< inlinesToOpenDocument o b) + | Header i (ident,_,_) b + <- bs = setFirstPara >> (inHeaderTags i ident + =<< inlinesToOpenDocument o b) | BlockQuote b <- bs = setFirstPara >> mkBlockQuote b | DefinitionList b <- bs = setFirstPara >> defList b | BulletList b <- bs = setFirstPara >> bulletListToOpenDocument o b diff --git a/test/writer.opendocument b/test/writer.opendocument index 081b33971..535130c0a 100644 --- a/test/writer.opendocument +++ b/test/writer.opendocument @@ -803,23 +803,31 @@ This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite. -Headers -Level 2 with an +Headers +Level +2 with an embedded -link -Level 3 with -emphasis -Level 4 -Level 5 -Level 1 -Level 2 with -emphasis -Level 3 +link +Level +3 with +emphasis +Level +4 +Level +5 +Level +1 +Level +2 with +emphasis +Level +3 with no blank line -Level 2 +Level +2 with no blank line -Paragraphs +Paragraphs Here’s a regular paragraph. In Markdown 1.0.0 and earlier. Version @@ -830,8 +838,8 @@ criminey. There should be a hard line breakhere. -Block -Quotes +Block +Quotes E-mail style: This is a block quote. It is pretty short. @@ -855,8 +863,8 @@ short. 2 > 1. And a following paragraph. -Code -Blocks +Code +Blocks Code: ---- (should be four hyphens) @@ -870,8 +878,8 @@ Blocks These should not be escaped: \$ \\ \> \[ \{ -Lists -Unordered +Lists +Unordered Asterisks tight: @@ -944,7 +952,7 @@ Blocks Minus 3 -Ordered +Ordered Tight: @@ -1007,7 +1015,7 @@ Blocks Item 3. -Nested +Nested Tab @@ -1068,8 +1076,8 @@ paragraphs: Third -Tabs and -spaces +Tabs +and spaces this is a list item indented with @@ -1089,8 +1097,8 @@ spaces -Fancy list -markers +Fancy +list markers begins with 2 @@ -1157,8 +1165,8 @@ item: M.A. 2007 B. Williams -Definition -Lists +Definition +Lists Tight using spaces: apple red fruit @@ -1225,8 +1233,8 @@ fruit sublist -HTML -Blocks +HTML +Blocks Simple block on one line: foo @@ -1262,8 +1270,8 @@ spaces on the line: <hr /> Hr’s: -Inline -Markup +Inline +Markup This is emphasized, and so is this. @@ -1300,8 +1308,9 @@ Hmany of themO. These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d. -Smart quotes, -ellipses, dashes +Smart +quotes, ellipses, +dashes “Hello,” said the spider. “‘Shelob’ is my name.” ‘A’, ‘B’, and ‘C’ are letters. @@ -1319,7 +1328,7 @@ five. 1987–1999. Ellipses…and…and…. -LaTeX +LaTeX @@ -1371,8 +1380,8 @@ five. Here’s a LaTeX table: -Special -Characters +Special +Characters Here is some unicode: @@ -1415,8 +1424,8 @@ it. Plus: + Minus: - -Links -Explicit +Links +Explicit Just a URL. URL @@ -1433,7 +1442,7 @@ and title Email link Empty. -Reference +Reference Foo bar. With @@ -1453,8 +1462,8 @@ by itself should be a link. bar. Foo biz. -With -ampersands +With +ampersands Here’s a link with an ampersand in the URL. @@ -1467,7 +1476,7 @@ link. Here’s an inline link in pointy braces. -Autolinks +Autolinks With an ampersand: http://example.com/?foo=1&bar=2 @@ -1489,7 +1498,7 @@ link in pointy braces. <http://example.com/> or here: <http://example.com/> -Images +Images From “Voyage dans la Lune” by Georges Melies (1902): @@ -1498,7 +1507,7 @@ Georges Melies (1902): icon. -Footnotes +Footnotes Here is a footnote reference,1Here is the footnote. It can go anywhere after the footnote reference. It need not -- cgit v1.2.3 From 2936967fa19e77581456189503500de4cfe502b3 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 14 May 2018 11:10:36 -0700 Subject: Docx writer: be sensitive to `toc` in YAML metadata. Closes #4645. --- src/Text/Pandoc/Writers/Docx.hs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 1666c0562..4f7c51a22 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -727,7 +727,7 @@ getNumId = (((baseListId - 1) +) . length) `fmap` gets stLists makeTOC :: (PandocMonad m) => WriterOptions -> WS m [Element] -makeTOC opts | writerTableOfContents opts = do +makeTOC opts = do let depth = "1-"++show (writerTOCDepth opts) let tocCmd = "TOC \\o \""++depth++"\" \\h \\z \\u" tocTitle <- gets stTocTitle @@ -751,8 +751,6 @@ makeTOC opts | writerTableOfContents opts = do ) -- w:p ]) ])] -- w:sdt -makeTOC _ = return [] - -- | Convert Pandoc document to two lists of -- OpenXML elements (the main document and footnotes). @@ -770,6 +768,13 @@ writeOpenXML opts (Pandoc meta blocks) = do Just (MetaBlocks [Para xs]) -> xs Just (MetaInlines xs) -> xs _ -> [] + let includeTOC = writerTableOfContents opts || + case lookupMeta "toc" meta of + Just (MetaBlocks _) -> True + Just (MetaInlines _) -> True + Just (MetaString (_:_)) -> True + Just (MetaBool True) -> True + _ -> False title <- withParaPropM (pStyleM "Title") $ blocksToOpenXML opts [Para tit | not (null tit)] subtitle <- withParaPropM (pStyleM "Subtitle") $ blocksToOpenXML opts [Para subtitle' | not (null subtitle')] authors <- withParaProp (pCustomStyle "Author") $ blocksToOpenXML opts $ @@ -801,7 +806,9 @@ writeOpenXML opts (Pandoc meta blocks) = do ] ++ annotation ] comments' <- mapM toComment comments - toc <- makeTOC opts + toc <- if includeTOC + then makeTOC opts + else return [] let meta' = title ++ subtitle ++ authors ++ date ++ abstract ++ toc return (meta' ++ doc', notes', comments') -- cgit v1.2.3 From 58447bba98cb162b21c30755e0e237f890160a1e Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 15 May 2018 09:15:45 -0700 Subject: rawLaTeXBlock: don't expand macros in macro definitions! Closes #4653. Note that this only affected LaTeX in markdown. Added regression test. --- src/Text/Pandoc/Readers/LaTeX.hs | 22 +++++++++++----------- test/command/4653.md | 8 ++++++++ 2 files changed, 19 insertions(+), 11 deletions(-) create mode 100644 test/command/4653.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 39dffde76..f2c0d1fbb 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -242,8 +242,8 @@ withVerbatimMode parser = do return result rawLaTeXParser :: (PandocMonad m, HasMacros s, HasReaderOptions s) - => LP m a -> LP m a -> ParserT String s m (a, String) -rawLaTeXParser parser valParser = do + => Bool -> LP m a -> LP m a -> ParserT String s m (a, String) +rawLaTeXParser retokenize parser valParser = do inp <- getInput let toks = tokenize "source" $ T.pack inp pstate <- getState @@ -254,10 +254,11 @@ rawLaTeXParser parser valParser = do case res' of Left _ -> mzero Right toks' -> do - res <- lift $ runParserT (do doMacros 0 - -- retokenize, applying macros - ts <- many (satisfyTok (const True)) - setInput ts + res <- lift $ runParserT (do when retokenize $ do + -- retokenize, applying macros + doMacros 0 + ts <- many (satisfyTok (const True)) + setInput ts rawparser) lstate' "chunk" toks' case res of @@ -284,20 +285,19 @@ rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s) => ParserT String s m String rawLaTeXBlock = do lookAhead (try (char '\\' >> letter)) - -- we don't want to apply newly defined latex macros to their own - -- definitions: - snd <$> rawLaTeXParser (environment <|> macroDef <|> blockCommand) blocks + snd <$> (rawLaTeXParser False macroDef blocks + <|> rawLaTeXParser True(environment <|> macroDef <|> blockCommand) blocks) rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s) => ParserT String s m String rawLaTeXInline = do lookAhead (try (char '\\' >> letter)) - snd <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand') inlines + snd <$> rawLaTeXParser True (inlineEnvironment <|> inlineCommand') inlines inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines inlineCommand = do lookAhead (try (char '\\' >> letter)) - fst <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand') inlines + fst <$> rawLaTeXParser True (inlineEnvironment <|> inlineCommand') inlines tokenize :: SourceName -> Text -> [Tok] tokenize sourcename = totoks (initialPos sourcename) diff --git a/test/command/4653.md b/test/command/4653.md new file mode 100644 index 000000000..24a706e89 --- /dev/null +++ b/test/command/4653.md @@ -0,0 +1,8 @@ +``` +% pandoc -t latex +\let\tex\TeX +\renewcommand{\TeX}{\tex\xspace} +^D +\let\tex\TeX +\renewcommand{\TeX}{\tex\xspace} +``` -- cgit v1.2.3 From 48ba3e815f059b3607fa9b707edaa6d7400ffee8 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Wed, 16 May 2018 22:33:27 +0200 Subject: Custom writer: fix error message on script failure Error messages produced by Lua were not displayed by Pandoc. The writer was using the bottom-most stack element, while the error message is the top-most element. This lead to the writer to always show "Lua 5.3" as error message, disregarding the actual message. --- src/Text/Pandoc/Writers/Custom.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs index 53b321c7c..c0940ad78 100644 --- a/src/Text/Pandoc/Writers/Custom.hs +++ b/src/Text/Pandoc/Writers/Custom.hs @@ -113,7 +113,7 @@ writeCustom luaFile opts doc@(Pandoc meta _) = do -- check for error in lua script (later we'll change the return type -- to handle this more gracefully): when (stat /= OK) $ - tostring 1 >>= throw . PandocLuaException . UTF8.toString + tostring (-1) >>= throw . PandocLuaException . UTF8.toString -- TODO - call hierarchicalize, so we have that info rendered <- docToCustom opts doc context <- metaToJSON opts -- cgit v1.2.3 From 884aef31c55e375cd62fcb55a71829d005087cae Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 16 May 2018 15:50:26 -0700 Subject: LaTeX reader: parse more siunitx unit commands. Improves on earlier fix for #4296. --- src/Text/Pandoc/Readers/LaTeX.hs | 74 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index f2c0d1fbb..35c85d023 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1508,12 +1508,84 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList -- siuntix , ("SI", dosiunitx) -- units of siuntix + , ("angstrom", lit "Å") + , ("arcmin", lit "′") + , ("arcminute", lit "′") + , ("arcsecond", lit "″") + , ("astronomicalunit", lit "ua") + , ("atomicmassunit", lit "u") + , ("atto", lit "a") + , ("bar", lit "bar") + , ("barn", lit "b") + , ("becquerel", lit "Bq") + , ("bel", lit "B") + , ("candela", lit "cd") , ("celsius", lit "°C") - , ("degreeCelsius", lit "°C") + , ("centi", lit "c") + , ("coulomb", lit "C") + , ("dalton", lit "Da") + , ("day", lit "d") + , ("deca", lit "d") + , ("deci", lit "d") + , ("decibel", lit "db") + , ("degreeCelsius",lit "°C") + , ("degree", lit "°") + , ("deka", lit "d") + , ("electronvolt", lit "eV") + , ("exa", lit "E") + , ("farad", lit "F") + , ("femto", lit "f") + , ("giga", lit "G") , ("gram", lit "g") + , ("hectare", lit "ha") + , ("hecto", lit "h") + , ("henry", lit "H") + , ("hertz", lit "Hz") + , ("hour", lit "h") + , ("joule", lit "J") + , ("katal", lit "kat") + , ("kelvin", lit "K") + , ("kilo", lit "k") + , ("kilogram", lit "kg") + , ("knot", lit "kn") + , ("liter", lit "L") + , ("litre", lit "l") + , ("lumen", lit "lm") + , ("lux", lit "lx") + , ("mega", lit "M") , ("meter", lit "m") + , ("metre", lit "m") , ("milli", lit "m") + , ("minute", lit "min") + , ("mmHg", lit "mmHg") + , ("mole", lit "mol") + , ("nano", lit "n") + , ("nauticalmile", lit "M") + , ("neper", lit "Np") + , ("newton", lit "N") + , ("ohm", lit "Ω") + , ("Pa", lit "Pa") + , ("pascal", lit "Pa") + , ("percent", lit "%") + , ("per", lit "/") + , ("peta", lit "P") + , ("pico", lit "p") + , ("radian", lit "rad") + , ("second", lit "s") + , ("siemens", lit "S") + , ("sievert", lit "Sv") , ("square", dosquare) + , ("steradian", lit "sr") + , ("tera", lit "T") + , ("tesla", lit "T") + , ("tonne", lit "t") + , ("volt", lit "V") + , ("watt", lit "W") + , ("weber", lit "Wb") + , ("yocto", lit "y") + , ("yotta", lit "Y") + , ("zepto", lit "z") + , ("zetta", lit "Z") -- hyphenat , ("bshyp", lit "\\\173") , ("fshyp", lit "/\173") -- cgit v1.2.3 From 81ed7948da805f5143bf829c3d62afbfb63718c8 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 20 May 2018 17:05:23 -0700 Subject: Use haddock-library 1.6.0. --- pandoc.cabal | 2 +- src/Text/Pandoc/Readers/Haddock.hs | 14 +------------- stack.lts9.yaml | 2 +- stack.yaml | 1 + 4 files changed, 4 insertions(+), 15 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index 98f87d1e4..0fe8bdf0f 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -380,7 +380,7 @@ library hslua-module-text >= 0.1.2 && < 0.2, binary >= 0.5 && < 0.10, SHA >= 1.6 && < 1.7, - haddock-library >= 1.1 && < 1.6, + haddock-library >= 1.6 && < 1.7, deepseq >= 1.3 && < 1.5, JuicyPixels >= 3.1.6.1 && < 3.3, Glob >= 0.7 && < 0.10, diff --git a/src/Text/Pandoc/Readers/Haddock.hs b/src/Text/Pandoc/Readers/Haddock.hs index 967037e4e..072bab350 100644 --- a/src/Text/Pandoc/Readers/Haddock.hs +++ b/src/Text/Pandoc/Readers/Haddock.hs @@ -44,11 +44,7 @@ readHaddockEither :: ReaderOptions -- ^ Reader options -> String -- ^ String to parse -> Either PandocError Pandoc readHaddockEither _opts = -#if MIN_VERSION_haddock_library(1,2,0) - Right . B.doc . docHToBlocks . _doc . parseParas -#else - Right . B.doc . docHToBlocks . parseParas -#endif + Right . B.doc . docHToBlocks . _doc . parseParas Nothing docHToBlocks :: DocH String Identifier -> Blocks docHToBlocks d' = @@ -68,10 +64,8 @@ docHToBlocks d' = DocEmphasis _ -> inlineFallback DocMonospaced _ -> inlineFallback DocBold _ -> inlineFallback -#if MIN_VERSION_haddock_library(1,4,0) DocMathInline _ -> inlineFallback DocMathDisplay _ -> inlineFallback -#endif DocHeader h -> B.header (headerLevel h) (docHToInlines False $ headerTitle h) DocUnorderedList items -> B.bulletList (map docHToBlocks items) @@ -87,7 +81,6 @@ docHToBlocks d' = DocProperty s -> B.codeBlockWith ("",["property","haskell"],[]) (trim s) DocExamples es -> mconcat $ map (\e -> makeExample ">>>" (exampleExpression e) (exampleResult e)) es -#if MIN_VERSION_haddock_library(1,5,0) DocTable H.Table{ tableHeaderRows = headerRows , tableBodyRows = bodyRows } @@ -100,7 +93,6 @@ docHToBlocks d' = colspecs = replicate (maximum (map length body)) (AlignDefault, 0.0) in B.table mempty colspecs header body -#endif where inlineFallback = B.plain $ docHToInlines False d' consolidatePlains = B.fromList . consolidatePlains' . B.toList @@ -133,10 +125,8 @@ docHToInlines isCode d' = DocMonospaced (DocString s) -> B.code s DocMonospaced d -> docHToInlines True d DocBold d -> B.strong (docHToInlines isCode d) -#if MIN_VERSION_haddock_library(1,4,0) DocMathInline s -> B.math s DocMathDisplay s -> B.displayMath s -#endif DocHeader _ -> mempty DocUnorderedList _ -> mempty DocOrderedList _ -> mempty @@ -149,9 +139,7 @@ docHToInlines isCode d' = DocAName s -> B.spanWith (s,["anchor"],[]) mempty DocProperty _ -> mempty DocExamples _ -> mempty -#if MIN_VERSION_haddock_library(1,5,0) DocTable _ -> mempty -#endif -- | Create an 'Example', stripping superfluous characters as appropriate makeExample :: String -> String -> [String] -> Blocks diff --git a/stack.lts9.yaml b/stack.lts9.yaml index c4cc3caf7..750f6403f 100644 --- a/stack.lts9.yaml +++ b/stack.lts9.yaml @@ -26,6 +26,6 @@ extra-deps: - pandoc-citeproc-0.14.3.1 - tagsoup-0.14.6 - pandoc-types-1.17.4.2 -- haddock-library-1.5.0.1 +- haddock-library-1.6.0 - texmath-0.11 resolver: lts-9.14 diff --git a/stack.yaml b/stack.yaml index 5f96a78d9..e2af054ee 100644 --- a/stack.yaml +++ b/stack.yaml @@ -22,6 +22,7 @@ extra-deps: - cmark-gfm-0.1.3 - hslua-module-text-0.1.2.1 - texmath-0.11 +- haddock-library-1.6.0 ghc-options: "$locals": -fhide-source-paths -XNoImplicitPrelude resolver: lts-10.10 -- cgit v1.2.3 From 91aceeeff336e2bcaf56b8c9610c53f79ba40cb6 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 27 May 2018 23:57:19 +0300 Subject: Muse reader: parse links starting with "URL:" explicitly instead of trying to strip "URL:" prefix after parsing. --- src/Text/Pandoc/Readers/Muse.hs | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index fe6b3698c..e49648506 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -46,7 +46,7 @@ import Control.Monad.Except (throwError) import Data.Bifunctor import Data.Char (isLetter) import Data.Default -import Data.List (stripPrefix, intercalate) +import Data.List (intercalate) import Data.List.Split (splitOn) import qualified Data.Map as M import qualified Data.Set as Set @@ -947,24 +947,31 @@ link = try $ do st <- getState guard $ not $ museInLink st setState $ st{ museInLink = True } - (url, content) <- linkText + res <- explicitLink <|> linkText updateState (\state -> state { museInLink = False }) - return $ case stripPrefix "URL:" url of - Nothing -> if isImageUrl url - then B.image url "" <$> fromMaybe (return mempty) content - else B.link url "" <$> fromMaybe (return $ B.str url) content - Just url' -> B.link url' "" <$> fromMaybe (return $ B.str url') content - where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el - imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"] - isImageUrl = (`elem` imageExtensions) . takeExtension + return res linkContent :: PandocMonad m => MuseParser m (F Inlines) linkContent = char '[' >> trimInlinesF . mconcat <$> manyTill inline (string "]") -linkText :: PandocMonad m => MuseParser m (String, Maybe (F Inlines)) +-- | Parse a link starting with @URL:@ +explicitLink :: PandocMonad m => MuseParser m (F Inlines) +explicitLink = try $ do + string "[[URL:" + url <- manyTill anyChar $ char ']' + content <- option (pure $ B.str url) linkContent + char ']' + return $ B.link url "" <$> content + +linkText :: PandocMonad m => MuseParser m (F Inlines) linkText = do string "[[" url <- manyTill anyChar $ char ']' content <- optionMaybe linkContent char ']' - return (url, content) + return $ if isImageUrl url + then B.image url "" <$> fromMaybe (return mempty) content + else B.link url "" <$> fromMaybe (return $ B.str url) content + where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el + imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"] + isImageUrl = (`elem` imageExtensions) . takeExtension -- cgit v1.2.3 From bdf8c01f2c0e3d3cd549c19b118c332cd48eeeb0 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 28 May 2018 01:24:09 +0300 Subject: Muse reader: split link and image parsing into separate functions --- src/Text/Pandoc/Readers/Muse.hs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index e49648506..e8b7d24f7 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -778,7 +778,7 @@ inlineList = [ whitespace , verbatimTag , classTag , nbsp - , link + , linkOrImage , code , codeTag , mathTag @@ -942,17 +942,17 @@ symbol :: PandocMonad m => MuseParser m (F Inlines) symbol = return . B.str <$> count 1 nonspaceChar -- | Parse a link or image. -link :: PandocMonad m => MuseParser m (F Inlines) -link = try $ do +linkOrImage :: PandocMonad m => MuseParser m (F Inlines) +linkOrImage = try $ do st <- getState guard $ not $ museInLink st setState $ st{ museInLink = True } - res <- explicitLink <|> linkText + res <- explicitLink <|> image <|> link updateState (\state -> state { museInLink = False }) return res linkContent :: PandocMonad m => MuseParser m (F Inlines) -linkContent = char '[' >> trimInlinesF . mconcat <$> manyTill inline (string "]") +linkContent = char '[' >> trimInlinesF . mconcat <$> manyTill inline (char ']') -- | Parse a link starting with @URL:@ explicitLink :: PandocMonad m => MuseParser m (F Inlines) @@ -963,15 +963,22 @@ explicitLink = try $ do char ']' return $ B.link url "" <$> content -linkText :: PandocMonad m => MuseParser m (F Inlines) -linkText = do +image :: PandocMonad m => MuseParser m (F Inlines) +image = try $ do string "[[" url <- manyTill anyChar $ char ']' content <- optionMaybe linkContent char ']' - return $ if isImageUrl url - then B.image url "" <$> fromMaybe (return mempty) content - else B.link url "" <$> fromMaybe (return $ B.str url) content + guard $ isImageUrl url + return $ B.image url "" <$> fromMaybe (return mempty) content where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"] isImageUrl = (`elem` imageExtensions) . takeExtension + +link :: PandocMonad m => MuseParser m (F Inlines) +link = try $ do + string "[[" + url <- manyTill anyChar $ char ']' + content <- optionMaybe linkContent + char ']' + return $ B.link url "" <$> fromMaybe (return $ B.str url) content -- cgit v1.2.3 From 1100bfc0e67954760c0c1767018404bf0129dd01 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 30 May 2018 02:25:30 +0300 Subject: Muse reader: parse image URLs without "guard" and "takeExtension" --- src/Text/Pandoc/Readers/Muse.hs | 8 +++----- test/Tests/Readers/Muse.hs | 3 +++ 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index e8b7d24f7..9eda0d4f3 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -52,7 +52,6 @@ import qualified Data.Map as M import qualified Data.Set as Set import Data.Maybe (fromMaybe, isNothing) import Data.Text (Text, unpack) -import System.FilePath (takeExtension) import Text.HTML.TagSoup import Text.Pandoc.Builder (Blocks, Inlines) import qualified Text.Pandoc.Builder as B @@ -966,14 +965,13 @@ explicitLink = try $ do image :: PandocMonad m => MuseParser m (F Inlines) image = try $ do string "[[" - url <- manyTill anyChar $ char ']' + (url, ext) <- manyUntil (noneOf "]") $ (imageExtension <* char ']') content <- optionMaybe linkContent char ']' - guard $ isImageUrl url - return $ B.image url "" <$> fromMaybe (return mempty) content + return $ B.image (url ++ ext) "" <$> fromMaybe (return mempty) content where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"] - isImageUrl = (`elem` imageExtensions) . takeExtension + imageExtension = choice (try . string <$> imageExtensions) link :: PandocMonad m => MuseParser m (F Inlines) link = try $ do diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs index ddfedbff4..6b4e0fdbd 100644 --- a/test/Tests/Readers/Muse.hs +++ b/test/Tests/Readers/Muse.hs @@ -194,6 +194,9 @@ tests = , "Image" =: "[[image.jpg]]" =?> para (image "image.jpg" "" mempty) + , "Closing bracket is not allowed in image filename" =: + "[[foo]bar.jpg]]" =?> + para (text "[[foo]bar.jpg]]") , "Image with description" =: "[[image.jpg][Image]]" =?> para (image "image.jpg" "" (text "Image")) -- cgit v1.2.3 From 252ab9b77323230fa58e3b877101b061d77f673c Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 30 May 2018 09:24:52 -0700 Subject: Markdown writer: preserve `implicit_figures` with attributes... ...even if `implicit_attributes` is not set, by rendering in raw HTML. Fixes #4677. --- src/Text/Pandoc/Writers/Markdown.hs | 16 +++++++++++----- test/command/4677.md | 7 +++++++ 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 test/command/4677.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 075858e5e..fe8f452d3 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -452,8 +452,14 @@ blockToMarkdown' opts (Plain inlines) = do | otherwise -> contents return $ contents' <> cr -- title beginning with fig: indicates figure -blockToMarkdown' opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) = - blockToMarkdown opts (Para [Image attr alt (src,tit)]) +blockToMarkdown' opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) + | isEnabled Ext_raw_html opts && + not (isEnabled Ext_link_attributes opts) && + attr /= nullAttr = -- use raw HTML + (text . T.unpack . T.strip) <$> + writeHtml5String opts{ writerTemplate = Nothing } + (Pandoc nullMeta [Para [Image attr alt (src,"fig:" ++ tit)]]) + | otherwise = blockToMarkdown opts (Para [Image attr alt (src,tit)]) blockToMarkdown' opts (Para inlines) = (<> blankline) `fmap` blockToMarkdown opts (Plain inlines) blockToMarkdown' opts (LineBlock lns) = @@ -619,7 +625,7 @@ blockToMarkdown' opts t@(Table caption aligns widths headers rows) = do (all null headers) aligns' widths' headers rows | isEnabled Ext_raw_html opts -> fmap (id,) $ (text . T.unpack) <$> - (writeHtml5String def $ Pandoc nullMeta [t]) + (writeHtml5String opts{ writerTemplate = Nothing } $ Pandoc nullMeta [t]) | hasSimpleCells && isEnabled Ext_pipe_tables opts -> do rawHeaders <- padRow <$> mapM (blockListToMarkdown opts) headers @@ -1172,7 +1178,7 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit)) not (isEnabled Ext_link_attributes opts) && attr /= nullAttr = -- use raw HTML (text . T.unpack . T.strip) <$> - writeHtml5String def (Pandoc nullMeta [Plain [lnk]]) + writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [lnk]]) | otherwise = do plain <- asks envPlain linktext <- inlineListToMarkdown opts txt @@ -1212,7 +1218,7 @@ inlineToMarkdown opts img@(Image attr alternate (source, tit)) not (isEnabled Ext_link_attributes opts) && attr /= nullAttr = -- use raw HTML (text . T.unpack . T.strip) <$> - writeHtml5String def (Pandoc nullMeta [Plain [img]]) + writeHtml5String opts{ writerTemplate = Nothing } (Pandoc nullMeta [Plain [img]]) | otherwise = do plain <- asks envPlain let txt = if null alternate || alternate == [Str source] diff --git a/test/command/4677.md b/test/command/4677.md new file mode 100644 index 000000000..3ca8add9d --- /dev/null +++ b/test/command/4677.md @@ -0,0 +1,7 @@ +``` +% echo '![Caption](img.png){#img:1}' | pandoc --to "markdown-bracketed_spans-fenced_divs-link_attributes-simple_tables-multiline_tables-grid_tables-pipe_tables-fenced_code_attributes-markdown_in_html_blocks-table_captions-smart" +^D +
+Caption
Caption
+
+``` -- cgit v1.2.3 From 0dbbf16c3ab4d158499fecfb171080a448be65c5 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 30 May 2018 10:08:51 -0700 Subject: LaTeX reader: tighten up reading of beamer overlay specifications. Ideally we'd turn these on only when reading beamer, but currently beamer is not distinguished from latex as an input format. This commit also activates parsing of overlay specifications after commands in general (e.g. `\item`), since they can occur in many contexts in beamer. Closes #4669. --- src/Text/Pandoc/Readers/LaTeX.hs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 35c85d023..2fdb3d43c 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1204,16 +1204,28 @@ rawopt = do return $ "[" <> inner <> "]" skipopts :: PandocMonad m => LP m () -skipopts = skipMany rawopt +skipopts = skipMany (overlaySpecification <|> void rawopt) -- opts in angle brackets are used in beamer -rawangle :: PandocMonad m => LP m () -rawangle = try $ do +overlaySpecification :: PandocMonad m => LP m () +overlaySpecification = try $ do symbol '<' - () <$ manyTill anyTok (symbol '>') - -skipangles :: PandocMonad m => LP m () -skipangles = skipMany rawangle + ts <- manyTill overlayTok (symbol '>') + guard $ case ts of + -- see issue #3368 + [Tok _ Word s] | T.all isLetter s -> s `elem` + ["beamer","presentation", "trans", + "handout","article", "second"] + _ -> True + +overlayTok :: PandocMonad m => LP m Tok +overlayTok = + satisfyTok (\t -> + case t of + Tok _ Word _ -> True + Tok _ Spaces _ -> True + Tok _ Symbol c -> c `elem` ["-","+","@","|",":",","] + _ -> False) ignore :: (Monoid a, PandocMonad m) => String -> ParserT s u m a ignore raw = do @@ -1289,7 +1301,7 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("textup", extractSpaces (spanWith ("",["upright"],[])) <$> tok) , ("texttt", ttfamily) , ("sout", extractSpaces strikeout <$> tok) - , ("alert", skipangles >> spanWith ("",["alert"],[]) <$> tok) -- beamer + , ("alert", skipopts >> spanWith ("",["alert"],[]) <$> tok) -- beamer , ("lq", return (str "‘")) , ("rq", return (str "’")) , ("textquoteleft", return (str "‘")) @@ -1765,7 +1777,6 @@ getRawCommand name txt = do "def" -> void $ manyTill anyTok braced _ -> do - skipangles skipopts option "" (try (optional sp *> dimenarg)) void $ many braced -- cgit v1.2.3 From 7119715a6af7d04d17e40bb76e901c11bf27d3f3 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 30 May 2018 12:48:07 -0700 Subject: LaTeX reader `rawLaTeXBlock`: handle macros that resolve to a... ...`\begin` or `\end`. Fixes #4667. --- src/Text/Pandoc/Readers/LaTeX.hs | 18 +++++++++++++++++- test/command/4667.md | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test/command/4667.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 2fdb3d43c..fff628c46 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -286,7 +286,23 @@ rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s) rawLaTeXBlock = do lookAhead (try (char '\\' >> letter)) snd <$> (rawLaTeXParser False macroDef blocks - <|> rawLaTeXParser True(environment <|> macroDef <|> blockCommand) blocks) + <|> rawLaTeXParser True + (environment <|> macroDef <|> blockCommand) + (mconcat <$> (many (block <|> beginOrEndCommand)))) + +-- See #4667 for motivation; sometimes people write macros +-- that just evaluate to a begin or end command, which blockCommand +-- won't accept. +beginOrEndCommand :: PandocMonad m => LP m Blocks +beginOrEndCommand = try $ do + Tok _ (CtrlSeq name) txt <- anyControlSeq + guard $ name == "begin" || name == "end" + (envname, rawargs) <- withRaw braced + if M.member (untokenize envname) + (inlineEnvironments :: M.Map Text (LP PandocPure Inlines)) + then mzero + else return $ rawBlock "latex" + (T.unpack (txt <> untokenize rawargs)) rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s) => ParserT String s m String diff --git a/test/command/4667.md b/test/command/4667.md new file mode 100644 index 000000000..1fff3708d --- /dev/null +++ b/test/command/4667.md @@ -0,0 +1,20 @@ +``` +pandoc -t latex +--- +header-includes: +- \newcommand{\blandscape}{\begin{landscape}} +- \newcommand{\elandscape}{\end{landscape}} +... + +\blandscape + +testing + +\elandscape +^D +\begin{landscape} + +testing + +\end{landscape} +``` -- cgit v1.2.3 From 50c71b5bc5db797ac46550ed54e91196269716e3 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 30 May 2018 13:06:44 -0700 Subject: ALlow compilation with haddock-library 1.4 and above. haddock-library-1.6 requires Cabal >= 2.0. This change allows systems with older Cabal versions to build pandoc. --- pandoc.cabal | 2 +- src/Text/Pandoc/Readers/Haddock.hs | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index 0fe8bdf0f..16f486531 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -380,7 +380,7 @@ library hslua-module-text >= 0.1.2 && < 0.2, binary >= 0.5 && < 0.10, SHA >= 1.6 && < 1.7, - haddock-library >= 1.6 && < 1.7, + haddock-library >= 1.4 && < 1.7, deepseq >= 1.3 && < 1.5, JuicyPixels >= 3.1.6.1 && < 3.3, Glob >= 0.7 && < 0.10, diff --git a/src/Text/Pandoc/Readers/Haddock.hs b/src/Text/Pandoc/Readers/Haddock.hs index 072bab350..8e06d1e00 100644 --- a/src/Text/Pandoc/Readers/Haddock.hs +++ b/src/Text/Pandoc/Readers/Haddock.hs @@ -44,7 +44,13 @@ readHaddockEither :: ReaderOptions -- ^ Reader options -> String -- ^ String to parse -> Either PandocError Pandoc readHaddockEither _opts = +#if MIN_VERSION_haddock_library(1,6,0) Right . B.doc . docHToBlocks . _doc . parseParas Nothing +#elif MIN_VERSION_haddock_library(1,2,0) + Right . B.doc . docHToBlocks . _doc . parseParas +#else + Right . B.doc . docHToBlocks . parseParas +#endif docHToBlocks :: DocH String Identifier -> Blocks docHToBlocks d' = @@ -64,8 +70,10 @@ docHToBlocks d' = DocEmphasis _ -> inlineFallback DocMonospaced _ -> inlineFallback DocBold _ -> inlineFallback +#if MIN_VERSION_haddock_library(1,4,0) DocMathInline _ -> inlineFallback DocMathDisplay _ -> inlineFallback +#endif DocHeader h -> B.header (headerLevel h) (docHToInlines False $ headerTitle h) DocUnorderedList items -> B.bulletList (map docHToBlocks items) @@ -81,6 +89,7 @@ docHToBlocks d' = DocProperty s -> B.codeBlockWith ("",["property","haskell"],[]) (trim s) DocExamples es -> mconcat $ map (\e -> makeExample ">>>" (exampleExpression e) (exampleResult e)) es +#if MIN_VERSION_haddock_library(1,5,0) DocTable H.Table{ tableHeaderRows = headerRows , tableBodyRows = bodyRows } @@ -93,7 +102,7 @@ docHToBlocks d' = colspecs = replicate (maximum (map length body)) (AlignDefault, 0.0) in B.table mempty colspecs header body - +#endif where inlineFallback = B.plain $ docHToInlines False d' consolidatePlains = B.fromList . consolidatePlains' . B.toList consolidatePlains' zs@(Plain _ : _) = @@ -125,8 +134,10 @@ docHToInlines isCode d' = DocMonospaced (DocString s) -> B.code s DocMonospaced d -> docHToInlines True d DocBold d -> B.strong (docHToInlines isCode d) +#if MIN_VERSION_haddock_library(1,4,0) DocMathInline s -> B.math s DocMathDisplay s -> B.displayMath s +#endif DocHeader _ -> mempty DocUnorderedList _ -> mempty DocOrderedList _ -> mempty @@ -139,7 +150,9 @@ docHToInlines isCode d' = DocAName s -> B.spanWith (s,["anchor"],[]) mempty DocProperty _ -> mempty DocExamples _ -> mempty +#if MIN_VERSION_haddock_library(1,5,0) DocTable _ -> mempty +#endif -- | Create an 'Example', stripping superfluous characters as appropriate makeExample :: String -> String -> [String] -> Blocks -- cgit v1.2.3 From aff401745cc67f3cba6f6e04a40b81e227ecdde8 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 30 May 2018 13:13:57 -0700 Subject: Revert "ALlow compilation with haddock-library 1.4 and above." This reverts commit 50c71b5bc5db797ac46550ed54e91196269716e3. This was a bad idea, since tests depend on recent haddock-library. We'd be able to build but fail tests. --- pandoc.cabal | 2 +- src/Text/Pandoc/Readers/Haddock.hs | 15 +-------------- 2 files changed, 2 insertions(+), 15 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index 16f486531..0fe8bdf0f 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -380,7 +380,7 @@ library hslua-module-text >= 0.1.2 && < 0.2, binary >= 0.5 && < 0.10, SHA >= 1.6 && < 1.7, - haddock-library >= 1.4 && < 1.7, + haddock-library >= 1.6 && < 1.7, deepseq >= 1.3 && < 1.5, JuicyPixels >= 3.1.6.1 && < 3.3, Glob >= 0.7 && < 0.10, diff --git a/src/Text/Pandoc/Readers/Haddock.hs b/src/Text/Pandoc/Readers/Haddock.hs index 8e06d1e00..072bab350 100644 --- a/src/Text/Pandoc/Readers/Haddock.hs +++ b/src/Text/Pandoc/Readers/Haddock.hs @@ -44,13 +44,7 @@ readHaddockEither :: ReaderOptions -- ^ Reader options -> String -- ^ String to parse -> Either PandocError Pandoc readHaddockEither _opts = -#if MIN_VERSION_haddock_library(1,6,0) Right . B.doc . docHToBlocks . _doc . parseParas Nothing -#elif MIN_VERSION_haddock_library(1,2,0) - Right . B.doc . docHToBlocks . _doc . parseParas -#else - Right . B.doc . docHToBlocks . parseParas -#endif docHToBlocks :: DocH String Identifier -> Blocks docHToBlocks d' = @@ -70,10 +64,8 @@ docHToBlocks d' = DocEmphasis _ -> inlineFallback DocMonospaced _ -> inlineFallback DocBold _ -> inlineFallback -#if MIN_VERSION_haddock_library(1,4,0) DocMathInline _ -> inlineFallback DocMathDisplay _ -> inlineFallback -#endif DocHeader h -> B.header (headerLevel h) (docHToInlines False $ headerTitle h) DocUnorderedList items -> B.bulletList (map docHToBlocks items) @@ -89,7 +81,6 @@ docHToBlocks d' = DocProperty s -> B.codeBlockWith ("",["property","haskell"],[]) (trim s) DocExamples es -> mconcat $ map (\e -> makeExample ">>>" (exampleExpression e) (exampleResult e)) es -#if MIN_VERSION_haddock_library(1,5,0) DocTable H.Table{ tableHeaderRows = headerRows , tableBodyRows = bodyRows } @@ -102,7 +93,7 @@ docHToBlocks d' = colspecs = replicate (maximum (map length body)) (AlignDefault, 0.0) in B.table mempty colspecs header body -#endif + where inlineFallback = B.plain $ docHToInlines False d' consolidatePlains = B.fromList . consolidatePlains' . B.toList consolidatePlains' zs@(Plain _ : _) = @@ -134,10 +125,8 @@ docHToInlines isCode d' = DocMonospaced (DocString s) -> B.code s DocMonospaced d -> docHToInlines True d DocBold d -> B.strong (docHToInlines isCode d) -#if MIN_VERSION_haddock_library(1,4,0) DocMathInline s -> B.math s DocMathDisplay s -> B.displayMath s -#endif DocHeader _ -> mempty DocUnorderedList _ -> mempty DocOrderedList _ -> mempty @@ -150,9 +139,7 @@ docHToInlines isCode d' = DocAName s -> B.spanWith (s,["anchor"],[]) mempty DocProperty _ -> mempty DocExamples _ -> mempty -#if MIN_VERSION_haddock_library(1,5,0) DocTable _ -> mempty -#endif -- | Create an 'Example', stripping superfluous characters as appropriate makeExample :: String -> String -> [String] -> Blocks -- cgit v1.2.3 From 5a0e21b9928e0b08072d58484891cfa2573452c6 Mon Sep 17 00:00:00 2001 From: kaizhang91 <37954332+kaizhang91@users.noreply.github.com> Date: Thu, 31 May 2018 04:43:58 +0800 Subject: Clarify how Ext_east_asian_line_breaks extension works (API docs). Note that it will not take effect when readers/writers are called as libraries (#4674). --- src/Text/Pandoc/Extensions.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Extensions.hs b/src/Text/Pandoc/Extensions.hs index 5ccb7dffb..ab510d92d 100644 --- a/src/Text/Pandoc/Extensions.hs +++ b/src/Text/Pandoc/Extensions.hs @@ -101,7 +101,10 @@ data Extension = -- and disallow laziness | Ext_definition_lists -- ^ Definition lists as in pandoc, mmd, php | Ext_east_asian_line_breaks -- ^ Newlines in paragraphs are ignored between - -- East Asian wide characters + -- East Asian wide characters. Note: this extension + -- does not affect readers/writers directly; it causes + -- the eastAsianLineBreakFilter to be applied after + -- parsing, in Text.Pandoc.App.convertWithOpts. | Ext_emoji -- ^ Support emoji like :smile: | Ext_empty_paragraphs -- ^ Allow empty paragraphs | Ext_epub_html_exts -- ^ Recognise the EPUB extended version of HTML -- cgit v1.2.3 From 1f78efff3b903158da557dbe83c2350954d40a2e Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Thu, 31 May 2018 00:57:58 +0300 Subject: Muse reader: add support for images with specified width --- src/Text/Pandoc/Readers/Muse.hs | 13 +++++++++---- test/Tests/Readers/Muse.hs | 6 ++++++ 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 9eda0d4f3..72909dc4d 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -35,7 +35,7 @@ TODO: - Page breaks (five "*") - Org tables - table.el tables -- Images with attributes (floating and width) +- Floating images - tag -} module Text.Pandoc.Readers.Muse (readMuse) where @@ -50,7 +50,7 @@ import Data.List (intercalate) import Data.List.Split (splitOn) import qualified Data.Map as M import qualified Data.Set as Set -import Data.Maybe (fromMaybe, isNothing) +import Data.Maybe (fromMaybe, isNothing, maybeToList) import Data.Text (Text, unpack) import Text.HTML.TagSoup import Text.Pandoc.Builder (Blocks, Inlines) @@ -965,13 +965,18 @@ explicitLink = try $ do image :: PandocMonad m => MuseParser m (F Inlines) image = try $ do string "[[" - (url, ext) <- manyUntil (noneOf "]") $ (imageExtension <* char ']') + (url, (ext, width)) <- manyUntil (noneOf "]") $ (imageExtensionAndOptions <* char ']') content <- optionMaybe linkContent char ']' - return $ B.image (url ++ ext) "" <$> fromMaybe (return mempty) content + let widthAttr = maybeToList (("width",) . (++ "%") <$> width) + return $ B.imageWith ("", [], widthAttr) (url ++ ext) mempty <$> fromMaybe (return mempty) content where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"] imageExtension = choice (try . string <$> imageExtensions) + imageExtensionAndOptions = do + ext <- imageExtension + width <- optionMaybe (many1 spaceChar *> many1 digit) + return (ext, width) link :: PandocMonad m => MuseParser m (F Inlines) link = try $ do diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs index 6b4e0fdbd..1146aa6d2 100644 --- a/test/Tests/Readers/Muse.hs +++ b/test/Tests/Readers/Muse.hs @@ -203,6 +203,12 @@ tests = , "Image with space in filename" =: "[[image name.jpg]]" =?> para (image "image name.jpg" "" mempty) + , "Image with width" =: + "[[image.jpg 60]]" =?> + para (imageWith ("", [], [("width", "60%")]) "image.jpg" mempty mempty) + , "At least one space is required between image filename and width" =: + "[[image.jpg60]]" =?> + para (link "image.jpg60" mempty (str "image.jpg60")) , "Image link" =: "[[URL:image.jpg]]" =?> para (link "image.jpg" "" (str "image.jpg")) -- cgit v1.2.3 From 5fbc981fc24d24652de3061353f09d1912928fba Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Thu, 31 May 2018 23:31:27 +0300 Subject: Muse reader: add support for floating images --- src/Text/Pandoc/Readers/Muse.hs | 24 ++++++++++++++++++------ test/Tests/Readers/Muse.hs | 6 ++++++ 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 72909dc4d..6ff84bff1 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -35,7 +35,6 @@ TODO: - Page breaks (five "*") - Org tables - table.el tables -- Floating images - tag -} module Text.Pandoc.Readers.Muse (readMuse) where @@ -965,18 +964,31 @@ explicitLink = try $ do image :: PandocMonad m => MuseParser m (F Inlines) image = try $ do string "[[" - (url, (ext, width)) <- manyUntil (noneOf "]") $ (imageExtensionAndOptions <* char ']') + (url, (ext, width, align)) <- manyUntil (noneOf "]") $ (imageExtensionAndOptions <* char ']') content <- optionMaybe linkContent char ']' - let widthAttr = maybeToList (("width",) . (++ "%") <$> width) - return $ B.imageWith ("", [], widthAttr) (url ++ ext) mempty <$> fromMaybe (return mempty) content + let widthAttr = case align of + Just 'f' -> [("width", (fromMaybe "100" width) ++ "%"), ("height", "75%")] + _ -> maybeToList (("width",) . (++ "%") <$> width) + let alignClass = case align of + Just 'r' -> ["align-right"] + Just 'l' -> ["align-left"] + Just 'f' -> [] + Nothing -> [] + return $ B.imageWith ("", alignClass, widthAttr) (url ++ ext) mempty <$> fromMaybe (return mempty) content where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"] imageExtension = choice (try . string <$> imageExtensions) imageExtensionAndOptions = do ext <- imageExtension - width <- optionMaybe (many1 spaceChar *> many1 digit) - return (ext, width) + (width, align) <- option (Nothing, Nothing) imageAttrs + return (ext, width, align) + imageAttrs = do + many1 spaceChar + width <- optionMaybe (many1 digit) + many spaceChar + align <- optionMaybe (oneOf "rlf") + return (width, align) link :: PandocMonad m => MuseParser m (F Inlines) link = try $ do diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs index 1146aa6d2..fe25e9c5d 100644 --- a/test/Tests/Readers/Muse.hs +++ b/test/Tests/Readers/Muse.hs @@ -209,6 +209,12 @@ tests = , "At least one space is required between image filename and width" =: "[[image.jpg60]]" =?> para (link "image.jpg60" mempty (str "image.jpg60")) + , "Left-aligned image with width" =: + "[[image.png 60 l][Image]]" =?> + para (imageWith ("", ["align-left"], [("width", "60%")]) "image.png" "" (str "Image")) + , "Right-aligned image with width" =: + "[[image.png 60 r][Image]]" =?> + para (imageWith ("", ["align-right"], [("width", "60%")]) "image.png" "" (str "Image")) , "Image link" =: "[[URL:image.jpg]]" =?> para (link "image.jpg" "" (str "image.jpg")) -- cgit v1.2.3 From 0fc7d38544346779051c2e25fb1d6f9c98a83a00 Mon Sep 17 00:00:00 2001 From: mb21 Date: Fri, 1 Jun 2018 15:35:14 +0200 Subject: Muse reader: get rid of non-exhaustive pattern match warning --- src/Text/Pandoc/Readers/Muse.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 6ff84bff1..4bb34af7e 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -974,7 +974,7 @@ image = try $ do Just 'r' -> ["align-right"] Just 'l' -> ["align-left"] Just 'f' -> [] - Nothing -> [] + _ -> [] return $ B.imageWith ("", alignClass, widthAttr) (url ++ ext) mempty <$> fromMaybe (return mempty) content where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"] -- cgit v1.2.3 From d32e8664498d799932927d9865ce71e014472ef3 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 1 Jun 2018 09:24:26 -0700 Subject: LaTeX reader: handle includes without surrounding blanklines. In addition, `\input` can now be used in an inline context, e.g. to provide part of a paragraph, as it can in LaTeX. Closes #4553. --- pandoc.cabal | 1 + src/Text/Pandoc/Readers/LaTeX.hs | 16 +++++++++------- test/command/4553.md | 15 +++++++++++++++ test/command/bar.tex | 1 + 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 test/command/4553.md create mode 100644 test/command/bar.tex (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index 75eb60d95..3931db123 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -192,6 +192,7 @@ extra-source-files: test/command/inkscape-cube.svg test/command/sub-file-chapter-1.tex test/command/sub-file-chapter-2.tex + test/command/bar.tex test/command/3510-subdoc.org test/command/3510-export.latex test/command/3510-src.hs diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index fff628c46..042295fd9 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1642,6 +1642,8 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("Rn", romanNumeralLower) -- babel , ("foreignlanguage", foreignlanguage) + -- include + , ("input", include "input") ] makeUppercase :: Inlines -> Inlines @@ -1917,7 +1919,6 @@ end_ t = try (do preamble :: PandocMonad m => LP m Blocks preamble = mempty <$ many preambleBlock where preambleBlock = spaces1 - <|> void include <|> void macroDef <|> void blockCommand <|> void braced @@ -1930,11 +1931,8 @@ paragraph = do then return mempty else return $ para x -include :: PandocMonad m => LP m Blocks -include = do - (Tok _ (CtrlSeq name) _) <- - controlSeq "include" <|> controlSeq "input" <|> - controlSeq "subfile" <|> controlSeq "usepackage" +include :: (PandocMonad m, Monoid a) => Text -> LP m a +include name = do skipMany opt fs <- (map (T.unpack . removeDoubleQuotes . T.strip) . T.splitOn "," . untokenize) <$> braced @@ -2251,6 +2249,11 @@ blockCommands = M.fromList -- LaTeX colors , ("textcolor", coloredBlock "color") , ("colorbox", coloredBlock "background-color") + -- include + , ("include", include "include") + , ("input", include "input") + , ("subfile", include "subfile") + , ("usepackage", include "usepackage") ] @@ -2689,7 +2692,6 @@ block :: PandocMonad m => LP m Blocks block = do res <- (mempty <$ spaces1) <|> environment - <|> include <|> macroDef <|> blockCommand <|> paragraph diff --git a/test/command/4553.md b/test/command/4553.md new file mode 100644 index 000000000..e5122d4d9 --- /dev/null +++ b/test/command/4553.md @@ -0,0 +1,15 @@ +``` +pandoc -f latex -t native +foo \include{command/bar} +^D +[Para [Str "foo"] +,Para [Emph [Str "hi",Space,Str "there"]]] +``` + +``` +pandoc -f latex -t native +foo \input{command/bar} +^D +[Para [Str "foo",Space,Emph [Str "hi",Space,Str "there"]]] +``` + diff --git a/test/command/bar.tex b/test/command/bar.tex new file mode 100644 index 000000000..e2113ab93 --- /dev/null +++ b/test/command/bar.tex @@ -0,0 +1 @@ +\emph{hi there} -- cgit v1.2.3 From 6ea706256de67c5480b300b0063729ae8f459c4c Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 2 Jun 2018 21:37:15 -0700 Subject: Support --number-sections in RST output... via the "section-numbering" directive in standalone output. --- data/templates/default.rst | 4 ++++ src/Text/Pandoc/Writers/RST.hs | 1 + 2 files changed, 5 insertions(+) (limited to 'src/Text/Pandoc') diff --git a/data/templates/default.rst b/data/templates/default.rst index e9c0dc203..937eb72ae 100644 --- a/data/templates/default.rst +++ b/data/templates/default.rst @@ -30,6 +30,10 @@ $if(toc)$ :depth: $toc-depth$ .. +$endif$ +$if(number-sections)$ +.. section-numbering:: + $endif$ $for(header-includes)$ $header-includes$ diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index f82597c55..1fd984a6d 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -103,6 +103,7 @@ pandocToRST (Pandoc meta blocks) = do let context = defField "body" main $ defField "toc" (writerTableOfContents opts) $ defField "toc-depth" (show $ writerTOCDepth opts) + $ defField "number-sections" (writerNumberSections opts) $ defField "math" hasMath $ defField "title" (render Nothing title :: String) $ defField "math" hasMath -- cgit v1.2.3 From 764bf86177ca0e85d3cd61b9b7baf197c411c764 Mon Sep 17 00:00:00 2001 From: Mauro Bieg Date: Sun, 3 Jun 2018 22:59:11 +0200 Subject: Regression: make --pdf-engine work with full paths (#4682) Fixes #4681. --- src/Text/Pandoc/App.hs | 4 +- src/Text/Pandoc/PDF.hs | 111 ++++++++++++++++++++++++++----------------------- 2 files changed, 62 insertions(+), 53 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index a59fd9bbe..ac6afa5f1 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -155,9 +155,9 @@ pdfWriterAndProg mWriter mEngine = do where go Nothing Nothing = Right ("latex", "pdflatex") go (Just writer) Nothing = (writer,) <$> engineForWriter writer - go Nothing (Just engine) = (,engine) <$> writerForEngine engine + go Nothing (Just engine) = (,engine) <$> writerForEngine (takeBaseName engine) go (Just writer) (Just engine) = - case find (== (baseWriterName writer, engine)) engines of + case find (== (baseWriterName writer, takeBaseName engine)) engines of Just _ -> Right (writer, engine) Nothing -> Left $ "pdf-engine " ++ engine ++ " is not compatible with output format " ++ writer diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index b171d65b0..7fa2cd26c 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -79,13 +79,52 @@ changePathSeparators = intercalate "/" . splitDirectories #endif makePDF :: String -- ^ pdf creator (pdflatex, lualatex, xelatex, - -- wkhtmltopdf, weasyprint, prince, context, pdfroff) + -- wkhtmltopdf, weasyprint, prince, context, pdfroff, + -- or path to executable) -> [String] -- ^ arguments to pass to pdf creator -> (WriterOptions -> Pandoc -> PandocIO Text) -- ^ writer -> WriterOptions -- ^ options -> Pandoc -- ^ document -> PandocIO (Either ByteString ByteString) -makePDF "wkhtmltopdf" pdfargs writer opts doc@(Pandoc meta _) = do +makePDF program pdfargs writer opts doc = do + case takeBaseName program of + "wkhtmltopdf" -> makeWithWkhtmltopdf program pdfargs writer opts doc + prog | prog `elem` ["weasyprint", "prince"] -> do + source <- writer opts doc + verbosity <- getVerbosity + liftIO $ html2pdf verbosity program pdfargs source + "pdfroff" -> do + source <- writer opts doc + let args = ["-ms", "-mpdfmark", "-e", "-t", "-k", "-KUTF-8", "-i", + "--no-toc-relocation"] ++ pdfargs + verbosity <- getVerbosity + liftIO $ ms2pdf verbosity program args source + baseProg -> do + -- With context and latex, we create a temp directory within + -- the working directory, since pdflatex sometimes tries to + -- use tools like epstopdf.pl, which are restricted if run + -- on files outside the working directory. + let withTemp = withTempDirectory "." + commonState <- getCommonState + verbosity <- getVerbosity + liftIO $ withTemp "tex2pdf." $ \tmpdir -> do + source <- runIOorExplode $ do + putCommonState commonState + doc' <- handleImages tmpdir doc + writer opts doc' + case baseProg of + "context" -> context2pdf verbosity program tmpdir source + prog | prog `elem` ["pdflatex", "lualatex", "xelatex"] + -> tex2pdf verbosity program pdfargs tmpdir source + _ -> return $ Left $ UTF8.fromStringLazy $ "Unknown program " ++ program + +makeWithWkhtmltopdf :: String -- ^ wkhtmltopdf or path + -> [String] -- ^ arguments + -> (WriterOptions -> Pandoc -> PandocIO Text) -- ^ writer + -> WriterOptions -- ^ options + -> Pandoc -- ^ document + -> PandocIO (Either ByteString ByteString) +makeWithWkhtmltopdf program pdfargs writer opts doc@(Pandoc meta _) = do let mathArgs = case writerHTMLMathMethod opts of -- with MathJax, wait til all math is rendered: MathJax _ -> ["--run-script", "MathJax.Hub.Register.StartupHook('End Typeset', function() { window.status = 'mathjax_loaded' });", @@ -111,39 +150,7 @@ makePDF "wkhtmltopdf" pdfargs writer opts doc@(Pandoc meta _) = do ] source <- writer opts doc verbosity <- getVerbosity - liftIO $ html2pdf verbosity "wkhtmltopdf" args source -makePDF "weasyprint" pdfargs writer opts doc = do - source <- writer opts doc - verbosity <- getVerbosity - liftIO $ html2pdf verbosity "weasyprint" pdfargs source -makePDF "prince" pdfargs writer opts doc = do - source <- writer opts doc - verbosity <- getVerbosity - liftIO $ html2pdf verbosity "prince" pdfargs source -makePDF "pdfroff" pdfargs writer opts doc = do - source <- writer opts doc - let args = ["-ms", "-mpdfmark", "-e", "-t", "-k", "-KUTF-8", "-i", - "--no-toc-relocation"] ++ pdfargs - verbosity <- getVerbosity - liftIO $ ms2pdf verbosity args source -makePDF program pdfargs writer opts doc = do - -- With context and latex, we create a temp directory within - -- the working directory, since pdflatex sometimes tries to - -- use tools like epstopdf.pl, which are restricted if run - -- on files outside the working directory. - let withTemp = withTempDirectory "." - commonState <- getCommonState - verbosity <- getVerbosity - liftIO $ withTemp "tex2pdf." $ \tmpdir -> do - source <- runIOorExplode $ do - putCommonState commonState - doc' <- handleImages tmpdir doc - writer opts doc' - case takeBaseName program of - "context" -> context2pdf verbosity tmpdir source - prog | prog `elem` ["pdflatex", "lualatex", "xelatex"] - -> tex2pdf' verbosity pdfargs tmpdir program source - _ -> return $ Left $ UTF8.fromStringLazy $ "Unknown program " ++ program + liftIO $ html2pdf verbosity program args source handleImages :: FilePath -- ^ temp dir to store images -> Pandoc -- ^ document @@ -195,13 +202,13 @@ convertImage tmpdir fname = mime = getMimeType fname doNothing = return (Right fname) -tex2pdf' :: Verbosity -- ^ Verbosity level - -> [String] -- ^ Arguments to the latex-engine - -> FilePath -- ^ temp directory for output - -> String -- ^ tex program - -> Text -- ^ tex source - -> IO (Either ByteString ByteString) -tex2pdf' verbosity args tmpDir program source = do +tex2pdf :: Verbosity -- ^ Verbosity level + -> String -- ^ tex program + -> [String] -- ^ Arguments to the latex-engine + -> FilePath -- ^ temp directory for output + -> Text -- ^ tex source + -> IO (Either ByteString ByteString) +tex2pdf verbosity program args tmpDir source = do let numruns = if "\\tableofcontents" `T.isInfixOf` source then 3 -- to get page numbers else 2 -- 1 run won't give you PDF bookmarks @@ -328,14 +335,15 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir source = do return (exit, log', pdf) ms2pdf :: Verbosity + -> String -> [String] -> Text -> IO (Either ByteString ByteString) -ms2pdf verbosity args source = do +ms2pdf verbosity program args source = do env' <- getEnvironment when (verbosity >= INFO) $ do putStrLn "[makePDF] Command line:" - putStrLn $ "pdfroff " ++ " " ++ unwords (map show args) + putStrLn $ program ++ " " ++ unwords (map show args) putStr "\n" putStrLn "[makePDF] Environment:" mapM_ print env' @@ -344,11 +352,11 @@ ms2pdf verbosity args source = do putStr $ T.unpack source putStr "\n" (exit, out) <- E.catch - (pipeProcess (Just env') "pdfroff" args + (pipeProcess (Just env') program args (BL.fromStrict $ UTF8.fromText source)) (\(e :: IOError) -> if isDoesNotExistError e then E.throwIO $ - PandocPDFProgramNotFoundError "pdfroff" + PandocPDFProgramNotFoundError program else E.throwIO e) when (verbosity >= INFO) $ do BL.hPutStr stdout out @@ -358,7 +366,7 @@ ms2pdf verbosity args source = do ExitSuccess -> Right out html2pdf :: Verbosity -- ^ Verbosity level - -> String -- ^ Program (wkhtmltopdf, weasyprint or prince) + -> String -- ^ Program (wkhtmltopdf, weasyprint, prince, or path) -> [String] -- ^ Args to program -> Text -- ^ HTML5 source -> IO (Either ByteString ByteString) @@ -369,7 +377,7 @@ html2pdf verbosity program args source = do file <- withTempFile "." "html2pdf.html" $ \fp _ -> return fp pdfFile <- withTempFile "." "html2pdf.pdf" $ \fp _ -> return fp BS.writeFile file $ UTF8.fromText source - let pdfFileArgName = ["-o" | program == "prince"] + let pdfFileArgName = ["-o" | takeBaseName program == "prince"] let programArgs = args ++ [file] ++ pdfFileArgName ++ [pdfFile] env' <- getEnvironment when (verbosity >= INFO) $ do @@ -408,10 +416,11 @@ html2pdf verbosity program args source = do (ExitSuccess, Just pdf) -> Right pdf context2pdf :: Verbosity -- ^ Verbosity level + -> String -- ^ "context" or path to it -> FilePath -- ^ temp directory for output -> Text -- ^ ConTeXt source -> IO (Either ByteString ByteString) -context2pdf verbosity tmpDir source = inDirectory tmpDir $ do +context2pdf verbosity program tmpDir source = inDirectory tmpDir $ do let file = "input.tex" BS.writeFile file $ UTF8.fromText source #ifdef _WINDOWS @@ -426,7 +435,7 @@ context2pdf verbosity tmpDir source = inDirectory tmpDir $ do putStrLn "[makePDF] temp dir:" putStrLn tmpDir' putStrLn "[makePDF] Command line:" - putStrLn $ "context" ++ " " ++ unwords (map show programArgs) + putStrLn $ program ++ " " ++ unwords (map show programArgs) putStr "\n" putStrLn "[makePDF] Environment:" mapM_ print env' @@ -435,7 +444,7 @@ context2pdf verbosity tmpDir source = inDirectory tmpDir $ do BL.readFile file >>= BL.putStr putStr "\n" (exit, out) <- E.catch - (pipeProcess (Just env') "context" programArgs BL.empty) + (pipeProcess (Just env') program programArgs BL.empty) (\(e :: IOError) -> if isDoesNotExistError e then E.throwIO $ PandocPDFProgramNotFoundError "context" -- cgit v1.2.3 From 9536eb7c7920fa49baec2b90c64fdbb933220df0 Mon Sep 17 00:00:00 2001 From: Adrian Sieber <36796532+ad-si@users.noreply.github.com> Date: Tue, 5 Jun 2018 16:50:34 +0000 Subject: Add missing re-export of "breezeDark" style (#4687) --- src/Text/Pandoc/Highlighting.hs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Highlighting.hs b/src/Text/Pandoc/Highlighting.hs index 70bb70302..672eca392 100644 --- a/src/Text/Pandoc/Highlighting.hs +++ b/src/Text/Pandoc/Highlighting.hs @@ -45,6 +45,7 @@ module Text.Pandoc.Highlighting ( highlightingStyles , tango , kate , monochrome + , breezeDark , haddock , Style , fromListingsLanguage -- cgit v1.2.3 From 905dee6ee3c96560d67e82f6786b8f248b5c83c8 Mon Sep 17 00:00:00 2001 From: Mauro Bieg Date: Thu, 7 Jun 2018 19:50:14 +0200 Subject: beamer output: fix single digit column percentage (#4691) fixes #4690 --- src/Text/Pandoc/Writers/LaTeX.hs | 2 +- test/command/1710.md | 7 +++---- test/command/4016.md | 4 ++-- test/command/4690.md | 28 ++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 test/command/4690.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 2904bec06..4c791aa44 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -487,7 +487,7 @@ blockToLaTeX (Div (identifier,classes,kvs) bs) then \contents -> let fromPct xs = case reverse xs of - '%':ds -> '0':'.': reverse ds + '%':ds -> showFl (read (reverse ds) / 100 :: Double) _ -> xs w = maybe "0.48" fromPct (lookup "width" kvs) in inCmd "begin" "column" <> diff --git a/test/command/1710.md b/test/command/1710.md index d20dfe191..4d9c64b30 100644 --- a/test/command/1710.md +++ b/test/command/1710.md @@ -58,7 +58,7 @@ ok \protect\hypertarget{slide-one}{} \begin{columns}[T] -\begin{column}{0.40\textwidth} +\begin{column}{0.4\textwidth} \begin{itemize} \tightlist \item @@ -68,7 +68,7 @@ ok \end{itemize} \end{column} -\begin{column}{0.40\textwidth} +\begin{column}{0.4\textwidth} \begin{itemize} \tightlist \item @@ -78,11 +78,10 @@ ok \end{itemize} \end{column} -\begin{column}{0.10\textwidth} +\begin{column}{0.1\textwidth} ok \end{column} \end{columns} \end{frame} ``` - diff --git a/test/command/4016.md b/test/command/4016.md index 3918251c6..5e4e35e0d 100644 --- a/test/command/4016.md +++ b/test/command/4016.md @@ -17,7 +17,7 @@ pandoc -t beamer \protect\hypertarget{level-2-blocks}{} \begin{columns}[T] -\begin{column}{0.40\textwidth} +\begin{column}{0.4\textwidth} \begin{block}{Block one} \begin{itemize} @@ -29,7 +29,7 @@ pandoc -t beamer \end{block} \end{column} -\begin{column}{0.60\textwidth} +\begin{column}{0.6\textwidth} \begin{block}{Block two} \begin{itemize} diff --git a/test/command/4690.md b/test/command/4690.md new file mode 100644 index 000000000..deccfba13 --- /dev/null +++ b/test/command/4690.md @@ -0,0 +1,28 @@ +``` +% pandoc -t beamer +# title + +:::: {.columns} +::: {.column width="8%"} +content +::: +::: {.column width="84%"} +content2 +::: +:::: +^D +\begin{frame}{title} +\protect\hypertarget{title}{} + +\begin{columns}[T] +\begin{column}{0.08\textwidth} +content +\end{column} + +\begin{column}{0.84\textwidth} +content2 +\end{column} +\end{columns} + +\end{frame} +``` -- cgit v1.2.3 From c1ae8d00ee0c021592900adaf8225a0c65c9fd42 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 7 Jun 2018 21:30:14 -0700 Subject: LaTeX writer: properly handle footnotes in table captions. Refactored code from figure captions to use in both places. Closes #4683. --- src/Text/Pandoc/Writers/LaTeX.hs | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 4c791aa44..dde4fe86d 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -517,25 +517,15 @@ blockToLaTeX (Plain lst) = inlineListToLaTeX $ dropWhile isLineBreakOrSpace lst -- title beginning with fig: indicates that the image is a figure blockToLaTeX (Para [Image attr@(ident, _, _) txt (src,'f':'i':'g':':':tit)]) = do - inNote <- gets stInNote - inMinipage <- gets stInMinipage - modify $ \st -> st{ stInMinipage = True, stNotes = [] } - capt <- inlineListToLaTeX txt - notes <- gets stNotes - modify $ \st -> st{ stInMinipage = False, stNotes = [] } - - -- We can't have footnotes in the list of figures, so remove them: - captForLof <- if null notes - then return empty - else brackets <$> inlineListToLaTeX (walk deNote txt) - img <- inlineToLaTeX (Image attr txt (src,tit)) - let footnotes = notesToLaTeX notes + (capt, captForLof, footnotes) <- getCaption txt lab <- labelFor ident let caption = "\\caption" <> captForLof <> braces capt <> lab + img <- inlineToLaTeX (Image attr txt (src,tit)) innards <- hypertarget True ident $ "\\centering" $$ img $$ caption <> cr let figure = cr <> "\\begin{figure}" $$ innards $$ "\\end{figure}" - return $ if inNote || inMinipage + st <- get + return $ if stInNote st || stInMinipage st -- can't have figures in notes or minipage (here, table cell) -- http://www.tex.ac.uk/FAQ-ouparmd.html then "\\begin{center}" $$ img $+$ capt $$ "\\end{center}" @@ -714,11 +704,11 @@ blockToLaTeX (Header level (id',classes,_) lst) = do modify $ \s -> s{stInHeading = False} return hdr blockToLaTeX (Table caption aligns widths heads rows) = do + (captionText, captForLof, footnotes) <- getCaption caption let toHeaders hs = do contents <- tableRowToLaTeX True aligns widths hs return ("\\toprule" $$ contents $$ "\\midrule") let removeNote (Note _) = Span ("", [], []) [] removeNote x = x - captionText <- inlineListToLaTeX caption firsthead <- if isEmpty captionText || all null heads then return empty else ($$ text "\\endfirsthead") <$> toHeaders heads @@ -730,8 +720,8 @@ blockToLaTeX (Table caption aligns widths heads rows) = do else walk removeNote heads) let capt = if isEmpty captionText then empty - else text "\\caption" <> - braces captionText <> "\\tabularnewline" + else "\\caption" <> captForLof <> braces captionText + <> "\\tabularnewline" rows' <- mapM (tableRowToLaTeX False aligns widths) rows let colDescriptors = text $ concatMap toColDescriptor aligns modify $ \s -> s{ stTable = True } @@ -745,6 +735,21 @@ blockToLaTeX (Table caption aligns widths heads rows) = do $$ vcat rows' $$ "\\bottomrule" $$ "\\end{longtable}" + $$ footnotes + +getCaption :: PandocMonad m => [Inline] -> LW m (Doc, Doc, Doc) +getCaption txt = do + inMinipage <- gets stInMinipage + modify $ \st -> st{ stInMinipage = True, stNotes = [] } + capt <- inlineListToLaTeX txt + notes <- gets stNotes + modify $ \st -> st{ stInMinipage = inMinipage, stNotes = [] } + -- We can't have footnotes in the list of figures/tables, so remove them: + captForLof <- if null notes + then return empty + else brackets <$> inlineListToLaTeX (walk deNote txt) + let footnotes = notesToLaTeX notes + return (capt, captForLof, footnotes) toColDescriptor :: Alignment -> String toColDescriptor align = -- cgit v1.2.3 From 54d16545c970dcb3fefdd16f2f48c6dfaefff727 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 12 Jun 2018 14:48:52 +0300 Subject: FB2 writer: fix order of items in title-info Address issue #2424 --- src/Text/Pandoc/Writers/FB2.hs | 2 +- test/writer.fb2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index a46011a8f..bac3121d9 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -135,7 +135,7 @@ description meta' = do Just (MetaString s) -> coverimage s _ -> return [] return $ el "description" - [ el "title-info" (genre : (bt ++ annotation ++ as ++ dd ++ lang)) + [ el "title-info" (genre : (as ++ bt ++ annotation ++ dd ++ lang)) , el "document-info" (el "program-used" "pandoc" : coverpage) ] diff --git a/test/writer.fb2 b/test/writer.fb2 index b2d002230..6940e6217 100644 --- a/test/writer.fb2 +++ b/test/writer.fb2 @@ -3,7 +3,6 @@ unrecognised -Pandoc Test Suite John MacFarlane @@ -11,6 +10,7 @@ Anonymous +Pandoc Test Suite July 17, 2006 -- cgit v1.2.3 From b6305a63cd2307b7d80de76bef150cba3d328763 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 12 Jun 2018 15:32:30 +0300 Subject: FB2 writer: convert Plain to Para in annotation Address #2424 --- src/Text/Pandoc/Writers/FB2.hs | 7 ++++++- test/fb2/meta.fb2 | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index bac3121d9..3227aaed8 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -119,7 +119,7 @@ description meta' = do let as = authors meta' dd <- docdate meta' annotation <- case lookupMeta "abstract" meta' of - Just (MetaBlocks bs) -> (list . el "annotation") <$> cMapM blockToXml bs + Just (MetaBlocks bs) -> (list . el "annotation") <$> (cMapM blockToXml $ map unPlain bs) _ -> pure mempty let lang = case lookupMeta "lang" meta' of Just (MetaInlines [Str s]) -> [el "lang" $ iso639 s] @@ -398,6 +398,11 @@ plainToPara (Para inlines : rest) = Para inlines : HorizontalRule : plainToPara rest -- HorizontalRule will be converted to plainToPara (p:rest) = p : plainToPara rest +-- Replace plain text with paragraphs +unPlain :: Block -> Block +unPlain (Plain inlines) = Para inlines +unPlain x = x + -- Simulate increased indentation level. Will not really work -- for multi-line paragraphs. indentPrefix :: String -> Block -> Block diff --git a/test/fb2/meta.fb2 b/test/fb2/meta.fb2 index 04bd5f3c5..1db48c068 100644 --- a/test/fb2/meta.fb2 +++ b/test/fb2/meta.fb2 @@ -1,3 +1,3 @@ -unrecognisedBook title

This is the abstract.

It consists of two paragraphs.
pandoc
<p>Book title</p>
+unrecognisedBook title

This is the abstract.

It consists of two paragraphs.

pandoc
<p>Book title</p>
-- cgit v1.2.3 From 1e45bb0041a184a6ae02549c4deb4a9cdf26ecb3 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 12 Jun 2018 09:25:42 -0700 Subject: LaTeX reader: allow spaces around `\graphicspath` arguments. Closes #4698. --- src/Text/Pandoc/Readers/LaTeX.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 042295fd9..d6b5f8685 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -2423,7 +2423,8 @@ coloredBlock stylename = try $ do graphicsPath :: PandocMonad m => LP m Blocks graphicsPath = do - ps <- map toksToString <$> (bgroup *> manyTill braced egroup) + ps <- map toksToString <$> + (bgroup *> spaces *> manyTill (braced <* spaces) egroup) getResourcePath >>= setResourcePath . (++ ps) return mempty -- cgit v1.2.3 From 417346068989d6b5bdca3620dcb95cbe4e7d8bbf Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 12 Jun 2018 09:35:27 -0700 Subject: reveal.js writer and template: reuse mathjax URL... ...provided by the argument to `--mathjax` or the normal pandoc default, rather than a hard-coded one in the template. Closes #4701. --- data/templates/default.revealjs | 2 +- src/Text/Pandoc/Writers/HTML.hs | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/data/templates/default.revealjs b/data/templates/default.revealjs index 6f847e23a..68723efa6 100644 --- a/data/templates/default.revealjs +++ b/data/templates/default.revealjs @@ -237,7 +237,7 @@ $if(maxScale)$ $endif$ $if(mathjax)$ math: { - mathjax: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js', + mathjax: '$mathjaxurl$', config: 'TeX-AMS_HTML-full', tex2jax: { inlineMath: [['\\(','\\)']], diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index a09ad2fda..f07d0381f 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -259,7 +259,7 @@ pandocToHtml opts (Pandoc meta blocks) = do st <- get notes <- footnoteSection opts (reverse (stNotes st)) let thebody = blocks' >> notes - let math = case writerHTMLMathMethod opts of + let math = case writerHTMLMathMethod opts of MathJax url | slideVariant /= RevealJsSlides -> -- mathjax is handled via a special plugin in revealjs @@ -296,10 +296,11 @@ pandocToHtml opts (Pandoc meta blocks) = do (if stMath st then defField "math" (renderHtml' math) else id) $ - defField "mathjax" - (case writerHTMLMathMethod opts of - MathJax _ -> True - _ -> False) $ + (case writerHTMLMathMethod opts of + MathJax u -> defField "mathjax" True . + defField "mathjaxurl" + (takeWhile (/='?') u) + _ -> defField "mathjax" False) $ defField "quotes" (stQuotes st) $ -- for backwards compatibility we populate toc -- with the contents of the toc, rather than a -- cgit v1.2.3 From 07bce91f4f1614967dd6f3698238d51f5290aae7 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 12 Jun 2018 10:30:16 -0700 Subject: Allow --template to take a URL argument. --- MANUAL.txt | 6 +++--- src/Text/Pandoc/App.hs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/MANUAL.txt b/MANUAL.txt index 97b9972b2..03da6b0bf 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -645,10 +645,10 @@ General writer options output. For `native` output, this option causes metadata to be included; otherwise, metadata is suppressed. -`--template=`*FILE* +`--template=`*FILE*|*URL* -: Use *FILE* as a custom template for the generated document. Implies - `--standalone`. See [Templates], below, for a description +: Use the specified file as a custom template for the generated document. + Implies `--standalone`. See [Templates], below, for a description of template syntax. If no extension is specified, an extension corresponding to the writer will be added, so that `--template=special` looks for `special.html` for HTML output. If the template is not diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index ac6afa5f1..093f0fcfc 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -381,7 +381,7 @@ convertWithOpts opts = do "" -> tp <.> format _ -> tp Just . UTF8.toString <$> - (readFileStrict tp' `catchError` + ((fst <$> fetchItem tp') `catchError` (\e -> case e of PandocIOError _ e' | -- cgit v1.2.3 From 2c1a309c9f117f55acc4e8be32b037b273fd7732 Mon Sep 17 00:00:00 2001 From: Raymond Ehlers Date: Tue, 12 Jun 2018 13:39:20 -0400 Subject: Beamer: Allow "noframenumbering" option (#4696) As noted [here](https://tex.stackexchange.com/a/49805) ([beamer commit here](https://github.com/josephwright/beamer/commit/ff70090f36b631667b472cfe675fc3514fe46f7e)), `noframenumbering` is an undocumented, but long existing option to disable frame numbering for a particular slide. This is useful to avoid numbering backup slides. --- MANUAL.txt | 2 +- src/Text/Pandoc/Writers/LaTeX.hs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/MANUAL.txt b/MANUAL.txt index 03da6b0bf..e08d3cdf2 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -4438,7 +4438,7 @@ introducing the slide: All of the other frame attributes described in Section 8.1 of the [Beamer User's Guide] may also be used: `allowdisplaybreaks`, `allowframebreaks`, `b`, `c`, `t`, `environment`, `label`, `plain`, -`shrink`. +`shrink`, `standout`, `noframenumbering`. Background in reveal.js ----------------------- diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index dde4fe86d..a3be5ecb7 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -402,7 +402,8 @@ elementToBeamer slideLevel (Sec lvl _num (ident,classes,kvs) tit elts) not (null $ query hasCodeBlock elts ++ query hasCode elts) let frameoptions = ["allowdisplaybreaks", "allowframebreaks", "fragile", "b", "c", "t", "environment", - "label", "plain", "shrink", "standout"] + "label", "plain", "shrink", "standout", + "noframenumbering"] let optionslist = ["fragile" | fragile && isNothing (lookup "fragile" kvs)] ++ [k | k <- classes, k `elem` frameoptions] ++ [k ++ "=" ++ v | (k,v) <- kvs, k `elem` frameoptions] -- cgit v1.2.3 From 7e477db95cfb02d155b3a0ede86094143b5ab7ee Mon Sep 17 00:00:00 2001 From: Mauro Bieg Date: Wed, 13 Jun 2018 19:41:30 +0200 Subject: LaTeX Reader: parse figure label into Image id (#4704) closes #4700 --- src/Text/Pandoc/Readers/LaTeX.hs | 34 ++++++++++++++++++++-------------- test/command/2118.md | 2 +- test/command/refs.md | 2 +- 3 files changed, 22 insertions(+), 16 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index d6b5f8685..7b7fba87b 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -159,7 +159,7 @@ data LaTeXState = LaTeXState{ sOptions :: ReaderOptions , sLogMessages :: [LogMessage] , sIdentifiers :: Set.Set String , sVerbatimMode :: Bool - , sCaption :: Maybe Inlines + , sCaption :: (Maybe Inlines, Maybe String) , sInListItem :: Bool , sInTableCell :: Bool , sLastHeaderNum :: HeaderNum @@ -179,7 +179,7 @@ defaultLaTeXState = LaTeXState{ sOptions = def , sLogMessages = [] , sIdentifiers = Set.empty , sVerbatimMode = False - , sCaption = Nothing + , sCaption = (Nothing, Nothing) , sInListItem = False , sInTableCell = False , sLastHeaderNum = HeaderNum [] @@ -2100,11 +2100,13 @@ setCaption = do ils <- tok mblabel <- option Nothing $ try $ spaces >> controlSeq "label" >> (Just <$> tok) - let ils' = case mblabel of - Just lab -> ils <> spanWith - ("",[],[("label", stringify lab)]) mempty - Nothing -> ils - updateState $ \st -> st{ sCaption = Just ils' } + let capt = case mblabel of + Just lab -> let slab = stringify lab + ils' = ils <> spanWith + ("",[],[("label", slab)]) mempty + in (Just ils', Just slab) + Nothing -> (Just ils, Nothing) + updateState $ \st -> st{ sCaption = capt } return mempty looseItem :: PandocMonad m => LP m Blocks @@ -2115,7 +2117,7 @@ looseItem = do return mempty resetCaption :: PandocMonad m => LP m () -resetCaption = updateState $ \st -> st{ sCaption = Nothing } +resetCaption = updateState $ \st -> st{ sCaption = (Nothing, Nothing) } section :: PandocMonad m => Bool -> Attr -> Int -> LP m Blocks section starred (ident, classes, kvs) lvl = do @@ -2405,12 +2407,16 @@ figure = try $ do addImageCaption :: PandocMonad m => Blocks -> LP m Blocks addImageCaption = walkM go - where go (Image attr alt (src,tit)) + where go (Image attr@(_, cls, kvs) alt (src,tit)) | not ("fig:" `isPrefixOf` tit) = do - mbcapt <- sCaption <$> getState - return $ case mbcapt of - Just ils -> Image attr (toList ils) (src, "fig:" ++ tit) - Nothing -> Image attr alt (src,tit) + (mbcapt, mblab) <- sCaption <$> getState + let (alt', tit') = case mbcapt of + Just ils -> (toList ils, "fig:" ++ tit) + Nothing -> (alt, tit) + attr' = case mblab of + Just lab -> (lab, cls, kvs) + Nothing -> attr + return $ Image attr' alt' (src, tit') go x = return x coloredBlock :: PandocMonad m => String -> LP m Blocks @@ -2682,7 +2688,7 @@ simpTable envname hasWidthParameter = try $ do addTableCaption :: PandocMonad m => Blocks -> LP m Blocks addTableCaption = walkM go where go (Table c als ws hs rs) = do - mbcapt <- sCaption <$> getState + (mbcapt, _) <- sCaption <$> getState return $ case mbcapt of Just ils -> Table (toList ils) als ws hs rs Nothing -> Table c als ws hs rs diff --git a/test/command/2118.md b/test/command/2118.md index 27b3723d3..9730dd383 100644 --- a/test/command/2118.md +++ b/test/command/2118.md @@ -7,5 +7,5 @@ \label{fig:setminus} \end{figure} ^D -[Para [Image ("",[],[("width","80%")]) [Str "Set",Space,Str "subtraction",Span ("",[],[("label","fig:setminus")]) []] ("setminus.png","fig:")]] +[Para [Image ("fig:setminus",[],[("width","80%")]) [Str "Set",Space,Str "subtraction",Span ("",[],[("label","fig:setminus")]) []] ("setminus.png","fig:")]] ``` diff --git a/test/command/refs.md b/test/command/refs.md index 66959e5c3..dd62fa33d 100644 --- a/test/command/refs.md +++ b/test/command/refs.md @@ -42,7 +42,7 @@ Accuracy~\eqref{eq:Accuracy} is the proportion, measuring true results among all Figure \ref{fig:Logo} illustrated the SVG logo ^D -[Para [Image ("",[],[]) [Str "Logo",Span ("",[],[("label","fig:Logo")]) []] ("command/SVG_logo.svg","fig:")] +[Para [Image ("fig:Logo",[],[]) [Str "Logo",Span ("",[],[("label","fig:Logo")]) []] ("command/SVG_logo.svg","fig:")] ,Para [Str "Figure",Space,Link ("",[],[("reference-type","ref"),("reference","fig:Logo")]) [Str "[fig:Logo]"] ("#fig:Logo",""),Space,Str "illustrated",Space,Str "the",Space,Str "SVG",Space,Str "logo"]] ``` -- cgit v1.2.3 From 48a505c5a07e846c65825994d1be7a403944faf2 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 13 Jun 2018 11:12:10 -0700 Subject: Markdown reader: allow empty code spans. E.g. `` ` ` ``. --- src/Text/Pandoc/Readers/Markdown.hs | 2 +- test/command/empty-inline-code.txt | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 test/command/empty-inline-code.txt (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 156b2b622..0cd9ce63f 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -1591,7 +1591,7 @@ code = try $ do starts <- many1 (char '`') skipSpaces result <- (trim . concat) <$> - many1Till (many1 (noneOf "`\n") <|> many1 (char '`') <|> + manyTill (many1 (noneOf "`\n") <|> many1 (char '`') <|> (char '\n' >> notFollowedBy' blankline >> return " ")) (try (skipSpaces >> count (length starts) (char '`') >> notFollowedBy (char '`'))) diff --git a/test/command/empty-inline-code.txt b/test/command/empty-inline-code.txt new file mode 100644 index 000000000..b57072a44 --- /dev/null +++ b/test/command/empty-inline-code.txt @@ -0,0 +1,6 @@ +``` +% pandoc -t native +` ` +^D +[Code ("",[],[]) ""] +``` -- cgit v1.2.3 From ebf4ed89440d459684e2becad06a34ac3cdba7d5 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 25 Jun 2018 03:14:04 +0300 Subject: Texinfo writer: use @sup and @sub instead of custom macros Fixes #4728 --- data/templates/default.texinfo | 22 ---------------------- src/Text/Pandoc/Writers/Texinfo.hs | 13 +++---------- test/writer.texinfo | 24 ++---------------------- 3 files changed, 5 insertions(+), 54 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/data/templates/default.texinfo b/data/templates/default.texinfo index 458d4fdda..693827810 100644 --- a/data/templates/default.texinfo +++ b/data/templates/default.texinfo @@ -9,28 +9,6 @@ $if(strikeout)$ ~~\text\~~ @end macro -$endif$ -$if(subscript)$ -@macro textsubscript{text} -@iftex -@textsubscript{\text\} -@end iftex -@ifnottex -_@{\text\@} -@end ifnottex -@end macro - -$endif$ -$if(superscript)$ -@macro textsuperscript{text} -@iftex -@textsuperscript{\text\} -@end iftex -@ifnottex -^@{\text\@} -@end ifnottex -@end macro - $endif$ @ifnottex @paragraphindent 0 diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs index 305b41206..9c73eb9ca 100644 --- a/src/Text/Pandoc/Writers/Texinfo.hs +++ b/src/Text/Pandoc/Writers/Texinfo.hs @@ -56,8 +56,6 @@ import Text.Printf (printf) data WriterState = WriterState { stStrikeout :: Bool -- document contains strikeout - , stSuperscript :: Bool -- document contains superscript - , stSubscript :: Bool -- document contains subscript , stEscapeComma :: Bool -- in a context where we need @comma , stIdentifiers :: Set.Set String -- header ids used already , stOptions :: WriterOptions -- writer options @@ -74,8 +72,7 @@ type TI m = StateT WriterState m writeTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> m Text writeTexinfo options document = evalStateT (pandocToTexinfo options $ wrapTop document) - WriterState { stStrikeout = False, stSuperscript = False, - stEscapeComma = False, stSubscript = False, + WriterState { stStrikeout = False, stEscapeComma = False, stIdentifiers = Set.empty, stOptions = options} -- | Add a "Top" node around the document, needed by Texinfo. @@ -102,8 +99,6 @@ pandocToTexinfo options (Pandoc meta blocks) = do let context = defField "body" body $ defField "toc" (writerTableOfContents options) $ defField "titlepage" titlePage - $ defField "subscript" (stSubscript st) - $ defField "superscript" (stSuperscript st) $ defField "strikeout" (stStrikeout st) metadata case writerTemplate options of @@ -427,14 +422,12 @@ inlineToTexinfo (Strikeout lst) = do return $ text "@textstrikeout{" <> contents <> text "}" inlineToTexinfo (Superscript lst) = do - modify $ \st -> st{ stSuperscript = True } contents <- inlineListToTexinfo lst - return $ text "@textsuperscript{" <> contents <> char '}' + return $ text "@sup{" <> contents <> char '}' inlineToTexinfo (Subscript lst) = do - modify $ \st -> st{ stSubscript = True } contents <- inlineListToTexinfo lst - return $ text "@textsubscript{" <> contents <> char '}' + return $ text "@sub{" <> contents <> char '}' inlineToTexinfo (SmallCaps lst) = inlineListToTexinfo lst >>= return . inCmd "sc" diff --git a/test/writer.texinfo b/test/writer.texinfo index f5727d96d..ebc0447ee 100644 --- a/test/writer.texinfo +++ b/test/writer.texinfo @@ -5,24 +5,6 @@ ~~\text\~~ @end macro -@macro textsubscript{text} -@iftex -@textsubscript{\text\} -@end iftex -@ifnottex -_@{\text\@} -@end ifnottex -@end macro - -@macro textsuperscript{text} -@iftex -@textsuperscript{\text\} -@end iftex -@ifnottex -^@{\text\@} -@end ifnottex -@end macro - @ifnottex @paragraphindent 0 @end ifnottex @@ -738,11 +720,9 @@ This is code: @code{>}, @code{$}, @code{\}, @code{\$}, @code{}. @textstrikeout{This is @emph{strikeout}.} -Superscripts: a@textsuperscript{bc}d a@textsuperscript{@emph{hello}} -a@textsuperscript{hello@ there}. +Superscripts: a@sup{bc}d a@sup{@emph{hello}} a@sup{hello@ there}. -Subscripts: H@textsubscript{2}O, H@textsubscript{23}O, -H@textsubscript{many@ of@ them}O. +Subscripts: H@sub{2}O, H@sub{23}O, H@sub{many@ of@ them}O. These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d. -- cgit v1.2.3 From 7eb08169aa3a4517e30599df310e712cb8e9cbc4 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 25 Jun 2018 22:12:40 +0200 Subject: Fixed typo in LaTeX writer. --- src/Text/Pandoc/Readers/LaTeX.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 7b7fba87b..5c0264b02 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -2338,7 +2338,7 @@ rawVerbEnv :: PandocMonad m => Text -> LP m Blocks rawVerbEnv name = do pos <- getPosition (_, raw) <- withRaw $ verbEnv name - let raw' = "\\begin{tikzpicture}" ++ toksToString raw + let raw' = "\\begin{" ++ name ++ "}" ++ toksToString raw exts <- getOption readerExtensions let parseRaw = extensionEnabled Ext_raw_tex exts if parseRaw -- cgit v1.2.3 From 45904ab27f2bc0daf0e7a37b79b204474a5c77a8 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 25 Jun 2018 22:16:30 +0200 Subject: LaTeX reader: Treat `lilypond` as a verbatim environment. Closes #4725. --- src/Text/Pandoc/Readers/LaTeX.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 5c0264b02..0578e4836 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -2296,6 +2296,7 @@ environments = M.fromList , ("minted", minted) , ("obeylines", obeylines) , ("tikzpicture", rawVerbEnv "tikzpicture") + , ("lilypond", rawVerbEnv "lilypond") -- etoolbox , ("ifstrequal", ifstrequal) , ("newtoggle", braced >>= newToggle) @@ -2338,7 +2339,7 @@ rawVerbEnv :: PandocMonad m => Text -> LP m Blocks rawVerbEnv name = do pos <- getPosition (_, raw) <- withRaw $ verbEnv name - let raw' = "\\begin{" ++ name ++ "}" ++ toksToString raw + let raw' = "\\begin{" ++ T.unpack name ++ "}" ++ toksToString raw exts <- getOption readerExtensions let parseRaw = extensionEnabled Ext_raw_tex exts if parseRaw -- cgit v1.2.3 From 06bcb7c87285afb130fd6271ab7df3baf81d38e9 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 28 Jun 2018 11:51:52 +0200 Subject: Remove network-uri flag and use 'Network.Socket'. This removes a compiler warning. There is no need for the old network-uri flag, since network 2.6 was released in 2014. --- pandoc.cabal | 10 ++-------- src/Text/Pandoc/Class.hs | 2 +- stack.lts9.yaml | 1 - stack.yaml | 1 - 4 files changed, 3 insertions(+), 11 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index 6d8060553..3ba24d7fc 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -335,10 +335,6 @@ flag trypandoc Description: Build trypandoc cgi executable. Default: False -flag network-uri - Description: Get Network.URI from the network-uri package - Default: True - custom-setup setup-depends: base, Cabal >= 2.0 @@ -387,6 +383,8 @@ library Glob >= 0.7 && < 0.10, cmark-gfm >= 0.1.1 && < 0.2, doctemplates >= 0.2.1 && < 0.3, + network-uri >= 2.6 && < 2.7, + network >= 2.6, http-client >= 0.4.30 && < 0.6, http-client-tls >= 0.2.4 && < 0.4, http-types >= 0.8 && < 0.13, @@ -401,10 +399,6 @@ library cpp-options: -D_WINDOWS else build-depends: unix >= 2.4 && < 2.8 - if flag(network-uri) - build-depends: network-uri >= 2.6 && < 2.7, network >= 2.6 - else - build-depends: network >= 2 && < 2.6 if flag(embed_data_files) cpp-options: -DEMBED_DATA_FILES build-depends: file-embed >= 0.0 && < 0.1 diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs index 4ade2dc6d..657a48d75 100644 --- a/src/Text/Pandoc/Class.hs +++ b/src/Text/Pandoc/Class.hs @@ -132,7 +132,7 @@ import Network.HTTP.Client.Internal (addProxy) import Network.HTTP.Client.TLS (tlsManagerSettings) import System.Environment (getEnv) import Network.HTTP.Types.Header ( hContentType ) -import Network (withSocketsDo) +import Network.Socket (withSocketsDo) import Data.ByteString.Lazy (toChunks) import qualified Control.Exception as E import qualified Data.Time.LocalTime as IO (getCurrentTimeZone) diff --git a/stack.lts9.yaml b/stack.lts9.yaml index dac7dc0e4..355254618 100644 --- a/stack.lts9.yaml +++ b/stack.lts9.yaml @@ -2,7 +2,6 @@ flags: pandoc: trypandoc: false embed_data_files: true - network-uri: true pandoc-citeproc: bibutils: true embed_data_files: true diff --git a/stack.yaml b/stack.yaml index fb80afde6..e0d7045c8 100644 --- a/stack.yaml +++ b/stack.yaml @@ -2,7 +2,6 @@ flags: pandoc: trypandoc: false embed_data_files: true - network-uri: true pandoc-citeproc: bibutils: true embed_data_files: true -- cgit v1.2.3 From 0459d1be260ba9e9f51e181471368477a65409a9 Mon Sep 17 00:00:00 2001 From: Mauro Bieg Date: Thu, 28 Jun 2018 13:35:54 +0200 Subject: TikiWiki reader: improve list parsing (#4723) - remove trailing Space from list items - parse lists that have no space after marker (fixes #4722) --- src/Text/Pandoc/Readers/TikiWiki.hs | 7 +++-- test/command/4722.md | 34 ++++++++++++++++++++++ test/tikiwiki-reader.native | 58 ++++++++++++++++++------------------- 3 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 test/command/4722.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/TikiWiki.hs b/src/Text/Pandoc/Readers/TikiWiki.hs index 5c7507248..333144c56 100644 --- a/src/Text/Pandoc/Readers/TikiWiki.hs +++ b/src/Text/Pandoc/Readers/TikiWiki.hs @@ -22,6 +22,7 @@ import Prelude import Control.Monad import Control.Monad.Except (throwError) import qualified Data.Foldable as F +import Data.List (dropWhileEnd) import Data.Maybe (fromMaybe) import Data.Text (Text) import qualified Data.Text as T @@ -319,7 +320,7 @@ listItem = choice [ bulletItem :: PandocMonad m => TikiWikiParser m (ListNesting, B.Blocks) bulletItem = try $ do prefix <- many1 $ char '*' - many1 $ char ' ' + many $ char ' ' content <- listItemLine (length prefix) return (LN Bullet (length prefix), B.plain content) @@ -331,7 +332,7 @@ bulletItem = try $ do numberedItem :: PandocMonad m => TikiWikiParser m (ListNesting, B.Blocks) numberedItem = try $ do prefix <- many1 $ char '#' - many1 $ char ' ' + many $ char ' ' content <- listItemLine (length prefix) return (LN Numbered (length prefix), B.plain content) @@ -346,7 +347,7 @@ listItemLine nest = lineContent >>= parseContent listContinuation = string (replicate nest '+') >> lineContent parseContent x = do parsed <- parseFromString (many1 inline) x - return $ mconcat parsed + return $ mconcat $ dropWhileEnd (== B.space) parsed -- Turn the CODE macro attributes into Pandoc code block attributes. mungeAttrs :: [(String, String)] -> (String, [String], [(String, String)]) diff --git a/test/command/4722.md b/test/command/4722.md new file mode 100644 index 000000000..6c8c14716 --- /dev/null +++ b/test/command/4722.md @@ -0,0 +1,34 @@ +``` +% pandoc -f tikiwiki -t native +*Level 1 +*Level 1 +**Level 2 +***Level 3 +*Level 1 +^D +[BulletList + [[Plain [Str "Level",Space,Str "1"]] + ,[Plain [Str "Level",Space,Str "1"] + ,BulletList + [[Plain [Str "Level",Space,Str "2"] + ,BulletList + [[Plain [Str "Level",Space,Str "3"]]]]]] + ,[Plain [Str "Level",Space,Str "1"]]]] +``` +``` +% pandoc -f tikiwiki -t native +#Level 1 +#Level 1 +##Level 2 +###Level 3 +#Level 1 +^D +[OrderedList (1,DefaultStyle,DefaultDelim) + [[Plain [Str "Level",Space,Str "1"]] + ,[Plain [Str "Level",Space,Str "1"] + ,OrderedList (1,DefaultStyle,DefaultDelim) + [[Plain [Str "Level",Space,Str "2"] + ,OrderedList (1,DefaultStyle,DefaultDelim) + [[Plain [Str "Level",Space,Str "3"]]]]]] + ,[Plain [Str "Level",Space,Str "1"]]]] +``` diff --git a/test/tikiwiki-reader.native b/test/tikiwiki-reader.native index 2ab053217..79dc4b708 100644 --- a/test/tikiwiki-reader.native +++ b/test/tikiwiki-reader.native @@ -43,52 +43,52 @@ Pandoc (Meta {unMeta = fromList []}) ,Para [Str "info@example.org"] ,Header 1 ("lists",[],[]) [Str "lists"] ,BulletList - [[Plain [Str "Start",Space,Str "each",Space,Str "line",Space]] - ,[Plain [Str "with",Space,Str "an",Space,Str "asterisk",Space,Str "(*).",Space] + [[Plain [Str "Start",Space,Str "each",Space,Str "line"]] + ,[Plain [Str "with",Space,Str "an",Space,Str "asterisk",Space,Str "(*)."] ,BulletList - [[Plain [Str "More",Space,Str "asterisks",Space,Str "gives",Space,Str "deeper",Space] + [[Plain [Str "More",Space,Str "asterisks",Space,Str "gives",Space,Str "deeper"] ,BulletList - [[Plain [Str "and",Space,Str "deeper",Space,Str "levels.",Space]]]]]] - ,[Plain [Str "Line",Space,Str "breaks",LineBreak,Str "don't",Space,Str "break",Space,Str "levels.",Space]] - ,[Plain [Str "Continuations",Space,Str "are",Space,Str "also",Space,Str "possible",Space] + [[Plain [Str "and",Space,Str "deeper",Space,Str "levels."]]]]]] + ,[Plain [Str "Line",Space,Str "breaks",LineBreak,Str "don't",Space,Str "break",Space,Str "levels."]] + ,[Plain [Str "Continuations",Space,Str "are",Space,Str "also",Space,Str "possible"] ,BulletList - [[Plain [Str "and",Space,Str "do",Space,Str "not",Space,Str "break",Space,Str "the",Space,Str "list",Space,Str "flow",Space]]]] - ,[Plain [Str "Level",Space,Str "one",Space]]] + [[Plain [Str "and",Space,Str "do",Space,Str "not",Space,Str "break",Space,Str "the",Space,Str "list",Space,Str "flow"]]]] + ,[Plain [Str "Level",Space,Str "one"]]] ,Para [Str "Any",Space,Str "other",Space,Str "start",Space,Str "ends",Space,Str "the",Space,Str "list."] ,OrderedList (1,DefaultStyle,DefaultDelim) - [[Plain [Str "Start",Space,Str "each",Space,Str "line",Space]] - ,[Plain [Str "with",Space,Str "a",Space,Str "number",Space,Str "(1.).",Space] + [[Plain [Str "Start",Space,Str "each",Space,Str "line"]] + ,[Plain [Str "with",Space,Str "a",Space,Str "number",Space,Str "(1.)."] ,OrderedList (1,DefaultStyle,DefaultDelim) - [[Plain [Str "More",Space,Str "number",Space,Str "signs",Space,Str "gives",Space,Str "deeper",Space] + [[Plain [Str "More",Space,Str "number",Space,Str "signs",Space,Str "gives",Space,Str "deeper"] ,OrderedList (1,DefaultStyle,DefaultDelim) - [[Plain [Str "and",Space,Str "deeper",Space]] - ,[Plain [Str "levels.",Space]]]]]] - ,[Plain [Str "Line",Space,Str "breaks",LineBreak,Str "don't",Space,Str "break",Space,Str "levels.",Space]] - ,[Plain [Str "Blank",Space,Str "lines",Space]]] + [[Plain [Str "and",Space,Str "deeper"]] + ,[Plain [Str "levels."]]]]]] + ,[Plain [Str "Line",Space,Str "breaks",LineBreak,Str "don't",Space,Str "break",Space,Str "levels."]] + ,[Plain [Str "Blank",Space,Str "lines"]]] ,OrderedList (1,DefaultStyle,DefaultDelim) - [[Plain [Str "end",Space,Str "the",Space,Str "list",Space,Str "and",Space,Str "start",Space,Str "another.",Space]]] + [[Plain [Str "end",Space,Str "the",Space,Str "list",Space,Str "and",Space,Str "start",Space,Str "another."]]] ,Para [Str "Any",Space,Str "other",Space,Str "start",Space,Str "also",Space,Str "ends",Space,Str "the",Space,Str "list."] ,DefinitionList [([Str "item",Space,Str "1"], - [[Plain [Str "definition",Space,Str "1",Space]]]) + [[Plain [Str "definition",Space,Str "1"]]]) ,([Str "item",Space,Str "2"], - [[Plain [Str "definition",Space,Str "2-1",Space,Str "definition",Space,Str "2-2",Space]]]) + [[Plain [Str "definition",Space,Str "2-1",Space,Str "definition",Space,Str "2-2"]]]) ,([Str "item",Space,Emph [Str "3"]], - [[Plain [Str "definition",Space,Emph [Str "3"],Space]]])] + [[Plain [Str "definition",Space,Emph [Str "3"]]]])] ,OrderedList (1,DefaultStyle,DefaultDelim) - [[Plain [Str "one",Space]] - ,[Plain [Str "two",Space] + [[Plain [Str "one"]] + ,[Plain [Str "two"] ,BulletList - [[Plain [Str "two",Space,Str "point",Space,Str "one",Space]] - ,[Plain [Str "two",Space,Str "point",Space,Str "two",Space]]]] - ,[Plain [Str "three",Space]] - ,[Plain [Str "four",Space]] - ,[Plain [Str "five",Space] + [[Plain [Str "two",Space,Str "point",Space,Str "one"]] + ,[Plain [Str "two",Space,Str "point",Space,Str "two"]]]] + ,[Plain [Str "three"]] + ,[Plain [Str "four"]] + ,[Plain [Str "five"] ,OrderedList (1,DefaultStyle,DefaultDelim) - [[Plain [Str "five",Space,Str "sub",Space,Str "1",Space] + [[Plain [Str "five",Space,Str "sub",Space,Str "1"] ,OrderedList (1,DefaultStyle,DefaultDelim) - [[Plain [Str "five",Space,Str "sub",Space,Str "1",Space,Str "sub",Space,Str "1",Space]]]] - ,[Plain [Str "five",Space,Str "sub",Space,Str "2",Space]]]]] + [[Plain [Str "five",Space,Str "sub",Space,Str "1",Space,Str "sub",Space,Str "1"]]]] + ,[Plain [Str "five",Space,Str "sub",Space,Str "2"]]]]] ,Header 1 ("tables",[],[]) [Str "tables"] ,Table [] [AlignDefault,AlignDefault] [0.0,0.0] [[Plain [Str ""]] -- cgit v1.2.3 From edce81734e3ba80773920dafd5bb60c3528fbacd Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 28 Jun 2018 17:38:58 +0200 Subject: Avoid using deprecated 'decode' from yaml. --- src/Text/Pandoc/App.hs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index 093f0fcfc..f2b7ab7a3 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -62,7 +62,7 @@ import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.Encoding as TE import qualified Data.Text.Encoding.Error as TE -import Data.Yaml (decode) +import Data.Yaml (decodeEither) import qualified Data.Yaml as Yaml import GHC.Generics import Network.URI (URI (..), parseURI) @@ -702,10 +702,10 @@ removeMetaKeys :: [(String,String)] -> Pandoc -> Pandoc removeMetaKeys kvs pdc = foldr (deleteMeta . fst) pdc kvs readMetaValue :: String -> MetaValue -readMetaValue s = case decode (UTF8.fromString s) of - Just (Yaml.String t) -> MetaString $ T.unpack t - Just (Yaml.Bool b) -> MetaBool b - _ -> MetaString s +readMetaValue s = case decodeEither (UTF8.fromString s) of + Right (Yaml.String t) -> MetaString $ T.unpack t + Right (Yaml.Bool b) -> MetaBool b + _ -> MetaString s -- Determine default reader based on source file extensions defaultReaderName :: String -> [FilePath] -> String -- cgit v1.2.3 From 904924d172d2fced32a96aa1d022d47a0fb59cd6 Mon Sep 17 00:00:00 2001 From: Anders Waldenborg Date: Fri, 29 Jun 2018 10:41:26 +0200 Subject: CommonMark reader: Handle ascii_identifiers extension (#4733) Non-ascii characters were not stripped from identifiers even if the `ascii_identifiers` extension was enabled (which is is by default for gfm). Closes #4742 --- src/Text/Pandoc/Readers/CommonMark.hs | 31 ++++++++++++++++++------------- test/command/4742.md | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 test/command/4742.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/CommonMark.hs b/src/Text/Pandoc/Readers/CommonMark.hs index 79a4abbc2..a742ca666 100644 --- a/src/Text/Pandoc/Readers/CommonMark.hs +++ b/src/Text/Pandoc/Readers/CommonMark.hs @@ -39,7 +39,9 @@ import Control.Monad.State import Data.Char (isAlphaNum, isLetter, isSpace, toLower) import Data.List (groupBy) import qualified Data.Map as Map +import Data.Maybe (mapMaybe) import Data.Text (Text, unpack) +import Text.Pandoc.Asciify (toAsciiChar) import Text.Pandoc.Class (PandocMonad) import Text.Pandoc.Definition import Text.Pandoc.Emoji (emojis) @@ -51,7 +53,7 @@ import Text.Pandoc.Walk (walkM) readCommonMark :: PandocMonad m => ReaderOptions -> Text -> m Pandoc readCommonMark opts s = return $ (if isEnabled Ext_gfm_auto_identifiers opts - then addHeaderIdentifiers + then addHeaderIdentifiers opts else id) $ nodeToPandoc opts $ commonmarkToNode opts' exts s where opts' = [ optSmart | isEnabled Ext_smart opts ] @@ -70,13 +72,13 @@ convertEmojis (':':xs) = convertEmojis (x:xs) = x : convertEmojis xs convertEmojis [] = [] -addHeaderIdentifiers :: Pandoc -> Pandoc -addHeaderIdentifiers doc = evalState (walkM addHeaderId doc) mempty +addHeaderIdentifiers :: ReaderOptions -> Pandoc -> Pandoc +addHeaderIdentifiers opts doc = evalState (walkM (addHeaderId opts) doc) mempty -addHeaderId :: Block -> State (Map.Map String Int) Block -addHeaderId (Header lev (_,classes,kvs) ils) = do +addHeaderId :: ReaderOptions -> Block -> State (Map.Map String Int) Block +addHeaderId opts (Header lev (_,classes,kvs) ils) = do idmap <- get - let ident = toIdent ils + let ident = toIdent opts ils ident' <- case Map.lookup ident idmap of Nothing -> do put (Map.insert ident 1 idmap) @@ -85,13 +87,16 @@ addHeaderId (Header lev (_,classes,kvs) ils) = do put (Map.adjust (+ 1) ident idmap) return (ident ++ "-" ++ show i) return $ Header lev (ident',classes,kvs) ils -addHeaderId x = return x - -toIdent :: [Inline] -> String -toIdent = map (\c -> if isSpace c then '-' else c) - . filter (\c -> isLetter c || isAlphaNum c || isSpace c || - c == '_' || c == '-') - . map toLower . stringify +addHeaderId _ x = return x + +toIdent :: ReaderOptions -> [Inline] -> String +toIdent opts = map (\c -> if isSpace c then '-' else c) + . filterer + . map toLower . stringify + where filterer = if isEnabled Ext_ascii_identifiers opts + then mapMaybe toAsciiChar + else filter (\c -> isLetter c || isAlphaNum c || isSpace c || + c == '_' || c == '-') nodeToPandoc :: ReaderOptions -> Node -> Pandoc nodeToPandoc opts (Node _ DOCUMENT nodes) = diff --git a/test/command/4742.md b/test/command/4742.md new file mode 100644 index 000000000..72751d727 --- /dev/null +++ b/test/command/4742.md @@ -0,0 +1,25 @@ +Check that the commonmark reader handles the `ascii_identifiers` +extension properly. + +``` +% pandoc -f commonmark+gfm_auto_identifiers+ascii_identifiers -t native +# non ascii ⚠️ räksmörgås +^D +[Header 1 ("non-ascii--raksmorgas",[],[]) [Str "non",Space,Str "ascii",Space,Str "\9888\65039",Space,Str "r\228ksm\246rg\229s"]] +``` + +``` +% pandoc -f commonmark+gfm_auto_identifiers-ascii_identifiers -t native +# non ascii ⚠️ räksmörgås +^D +[Header 1 ("non-ascii-\65039-r\228ksm\246rg\229s",[],[]) [Str "non",Space,Str "ascii",Space,Str "\9888\65039",Space,Str "r\228ksm\246rg\229s"]] +``` + +`gfm` should have `ascii_identifiers` enabled by default. + +``` +% pandoc -f gfm -t native +# non ascii ⚠️ räksmörgås +^D +[Header 1 ("non-ascii--raksmorgas",[],[]) [Str "non",Space,Str "ascii",Space,Str "\9888\65039",Space,Str "r\228ksm\246rg\229s"]] +``` -- cgit v1.2.3 From 6ed114cb5d34641253c8be0079bfc4a3bf906af4 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 29 Jun 2018 11:47:58 +0200 Subject: Use decodeEither' not decodeEither (deprecated). --- src/Text/Pandoc/App.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index f2b7ab7a3..5cbbe13e7 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -62,7 +62,7 @@ import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.Encoding as TE import qualified Data.Text.Encoding.Error as TE -import Data.Yaml (decodeEither) +import Data.Yaml (decodeEither') import qualified Data.Yaml as Yaml import GHC.Generics import Network.URI (URI (..), parseURI) @@ -702,7 +702,7 @@ removeMetaKeys :: [(String,String)] -> Pandoc -> Pandoc removeMetaKeys kvs pdc = foldr (deleteMeta . fst) pdc kvs readMetaValue :: String -> MetaValue -readMetaValue s = case decodeEither (UTF8.fromString s) of +readMetaValue s = case decodeEither' (UTF8.fromString s) of Right (Yaml.String t) -> MetaString $ T.unpack t Right (Yaml.Bool b) -> MetaBool b _ -> MetaString s -- cgit v1.2.3 From e49b8304e43d8381a2c7693643ab648f32482359 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 29 Jun 2018 22:32:49 +0200 Subject: Use HsYAML instead of yaml for translations, YAML metadata. yaml wraps a C library; HsYAML is pure Haskell. Closes #4747. Advances #4535. --- MANUAL.txt | 4 +- pandoc.cabal | 9 ++-- src/Text/Pandoc/App.hs | 11 ++-- src/Text/Pandoc/Readers/Markdown.hs | 102 ++++++++++++++++-------------------- src/Text/Pandoc/Translations.hs | 39 +++++++++++--- src/Text/Pandoc/Writers/Markdown.hs | 2 +- stack.lts9.yaml | 2 + stack.yaml | 2 + 8 files changed, 94 insertions(+), 77 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/MANUAL.txt b/MANUAL.txt index 93b82f81c..8421ef674 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -3059,7 +3059,9 @@ Metadata will be taken from the fields of the YAML object and added to any existing document metadata. Metadata can contain lists and objects (nested arbitrarily), but all string scalars will be interpreted as Markdown. Fields with names ending in an underscore will be ignored by pandoc. (They may be -given a role by external processors.) +given a role by external processors.) Field names must not be +interpretable as YAML numbers or boolean values (so, for +example, `yes`, `True`, and `15` cannot be used as field names). A document may contain multiple metadata blocks. The metadata fields will be combined through a *left-biased union*: if two metadata blocks attempt diff --git a/pandoc.cabal b/pandoc.cabal index af76a9c3c..636f77482 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -370,7 +370,6 @@ library temporary >= 1.1 && < 1.4, blaze-html >= 0.9 && < 0.10, blaze-markup >= 0.8 && < 0.9, - scientific >= 0.2 && < 0.4, vector >= 0.10 && < 0.13, hslua >= 0.9.5 && < 0.9.6, hslua-module-text >= 0.1.2 && < 0.2, @@ -387,12 +386,10 @@ library http-client >= 0.4.30 && < 0.6, http-client-tls >= 0.2.4 && < 0.4, http-types >= 0.8 && < 0.13, - case-insensitive >= 1.2 && < 1.3 + case-insensitive >= 1.2 && < 1.3, + HsYAML >= 0.1.1.1 && < 0.2 if impl(ghc < 8.0) - build-depends: semigroups == 0.18.*, - yaml >= 0.8.11 && < 0.8.31 - else - build-depends: yaml >= 0.8.11 && < 0.9 + build-depends: semigroups == 0.18.* if impl(ghc < 8.4) hs-source-dirs: prelude other-modules: Prelude diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index 5cbbe13e7..b79273092 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -62,8 +62,7 @@ import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.Encoding as TE import qualified Data.Text.Encoding.Error as TE -import Data.Yaml (decodeEither') -import qualified Data.Yaml as Yaml +import qualified Data.YAML as YAML import GHC.Generics import Network.URI (URI (..), parseURI) #ifdef EMBED_DATA_FILES @@ -702,9 +701,11 @@ removeMetaKeys :: [(String,String)] -> Pandoc -> Pandoc removeMetaKeys kvs pdc = foldr (deleteMeta . fst) pdc kvs readMetaValue :: String -> MetaValue -readMetaValue s = case decodeEither' (UTF8.fromString s) of - Right (Yaml.String t) -> MetaString $ T.unpack t - Right (Yaml.Bool b) -> MetaBool b +readMetaValue s = case YAML.decodeStrict (UTF8.fromString s) of + Right [YAML.Scalar (YAML.SStr t)] + -> MetaString $ T.unpack t + Right [YAML.Scalar (YAML.SBool b)] + -> MetaBool b _ -> MetaString s -- Determine default reader based on source file extensions diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 0cd9ce63f..9fe84013f 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -37,18 +37,14 @@ import Prelude import Control.Monad import Control.Monad.Except (throwError) import Data.Char (isAlphaNum, isPunctuation, isSpace, toLower) -import qualified Data.HashMap.Strict as H import Data.List (intercalate, sortBy, transpose, elemIndex) import qualified Data.Map as M import Data.Maybe import Data.Ord (comparing) -import Data.Scientific (base10Exponent, coefficient) import qualified Data.Set as Set import Data.Text (Text) import qualified Data.Text as T -import qualified Data.Vector as V -import Data.Yaml (ParseException (..), YamlException (..), YamlMark (..)) -import qualified Data.Yaml as Yaml +import qualified Data.YAML as YAML import System.FilePath (addExtension, takeExtension) import Text.HTML.TagSoup import Text.Pandoc.Builder (Blocks, Inlines) @@ -246,47 +242,38 @@ yamlMetaBlock = try $ do -- by including --- and ..., we allow yaml blocks with just comments: let rawYaml = unlines ("---" : (rawYamlLines ++ ["..."])) optional blanklines - case Yaml.decodeEither' $ UTF8.fromString rawYaml of - Right (Yaml.Object hashmap) -> do - let alist = H.toList hashmap - mapM_ (\(k, v) -> - if ignorable k - then return () - else do - v' <- yamlToMeta v - let k' = T.unpack k - updateState $ \st -> st{ stateMeta' = - do m <- stateMeta' st - -- if there's already a value, leave it unchanged - case lookupMeta k' m of - Just _ -> return m - Nothing -> do - v'' <- v' - return $ B.setMeta (T.unpack k) v'' m} + case YAML.decodeStrict (UTF8.fromString rawYaml) of + Right (YAML.Mapping _ hashmap : _) -> do + let alist = M.toList hashmap + mapM_ (\(k', v) -> + case YAML.parseEither (YAML.parseYAML k') of + Left e -> fail e + Right k -> do + if ignorable k + then return () + else do + v' <- yamlToMeta v + let k' = T.unpack k + updateState $ \st -> st{ stateMeta' = + do m <- stateMeta' st + -- if there's already a value, leave it unchanged + case lookupMeta k' m of + Just _ -> return m + Nothing -> do + v'' <- v' + return $ B.setMeta (T.unpack k) v'' m} ) alist - Right Yaml.Null -> return () + Right [] -> return () + Right (YAML.Scalar YAML.SNull:_) -> return () Right _ -> do - logMessage $ - CouldNotParseYamlMetadata "not an object" - pos - return () + logMessage $ + CouldNotParseYamlMetadata "not an object" + pos + return () Left err' -> do - case err' of - InvalidYaml (Just YamlParseException{ - yamlProblem = problem - , yamlContext = _ctxt - , yamlProblemMark = Yaml.YamlMark { - yamlLine = yline - , yamlColumn = ycol - }}) -> - logMessage $ CouldNotParseYamlMetadata - problem (setSourceLine - (setSourceColumn pos - (sourceColumn pos + ycol)) - (sourceLine pos + 1 + yline)) - _ -> logMessage $ CouldNotParseYamlMetadata - (show err') pos - return () + logMessage $ CouldNotParseYamlMetadata + err' pos + return () return mempty -- ignore fields ending with _ @@ -313,22 +300,25 @@ toMetaValue x = -- `|` or `>` will. yamlToMeta :: PandocMonad m - => Yaml.Value -> MarkdownParser m (F MetaValue) -yamlToMeta (Yaml.String t) = toMetaValue t -yamlToMeta (Yaml.Number n) - -- avoid decimal points for numbers that don't need them: - | base10Exponent n >= 0 = return $ return $ MetaString $ show - $ coefficient n * (10 ^ base10Exponent n) - | otherwise = return $ return $ MetaString $ show n -yamlToMeta (Yaml.Bool b) = return $ return $ MetaBool b -yamlToMeta (Yaml.Array xs) = do - xs' <- mapM yamlToMeta (V.toList xs) + => YAML.Node -> MarkdownParser m (F MetaValue) +yamlToMeta (YAML.Scalar x) = + case x of + YAML.SStr t -> toMetaValue t + YAML.SBool b -> return $ return $ MetaBool b + YAML.SFloat d -> return $ return $ MetaString (show d) + YAML.SInt i -> return $ return $ MetaString (show i) + _ -> return $ return $ MetaString "" +yamlToMeta (YAML.Sequence _ xs) = do + xs' <- mapM yamlToMeta xs return $ do xs'' <- sequence xs' return $ B.toMetaValue xs'' -yamlToMeta (Yaml.Object o) = do - let alist = H.toList o - foldM (\m (k,v) -> +yamlToMeta (YAML.Mapping _ o) = do + let alist = M.toList o + foldM (\m (k',v) -> + case YAML.parseEither (YAML.parseYAML k') of + Left e -> fail e + Right k -> do if ignorable k then return m else do diff --git a/src/Text/Pandoc/Translations.hs b/src/Text/Pandoc/Translations.hs index 4a216af92..13dcb3b61 100644 --- a/src/Text/Pandoc/Translations.hs +++ b/src/Text/Pandoc/Translations.hs @@ -48,11 +48,12 @@ module Text.Pandoc.Translations ( ) where import Prelude -import Data.Aeson.Types (typeMismatch) +import Data.Aeson.Types (Value(..), FromJSON(..)) +import qualified Data.Aeson.Types as Aeson import qualified Data.HashMap.Strict as HM import qualified Data.Map as M import Data.Text as T -import Data.Yaml as Yaml +import qualified Data.YAML as YAML import GHC.Generics (Generic) import Text.Pandoc.Shared (safeRead) import qualified Text.Pandoc.UTF8 as UTF8 @@ -90,7 +91,15 @@ instance FromJSON Term where Just t' -> pure t' Nothing -> fail $ "Invalid Term name " ++ show t - parseJSON invalid = typeMismatch "Term" invalid + parseJSON invalid = Aeson.typeMismatch "Term" invalid + +instance YAML.FromYAML Term where + parseYAML (YAML.Scalar (YAML.SStr t)) = + case safeRead (T.unpack t) of + Just t' -> pure t' + Nothing -> fail $ "Invalid Term name " ++ + show t + parseYAML invalid = YAML.typeMismatch "Term" invalid instance FromJSON Translations where parseJSON (Object hm) = do @@ -102,14 +111,28 @@ instance FromJSON Translations where Just t -> case v of (String s) -> return (t, T.unpack $ T.strip s) - inv -> typeMismatch "String" inv - parseJSON invalid = typeMismatch "Translations" invalid + inv -> Aeson.typeMismatch "String" inv + parseJSON invalid = Aeson.typeMismatch "Translations" invalid + +instance YAML.FromYAML Translations where + parseYAML = YAML.withMap "Translations" $ + \tr -> Translations .M.fromList <$> mapM addItem (M.toList tr) + where addItem (n@(YAML.Scalar (YAML.SStr k)), v) = + case safeRead (T.unpack k) of + Nothing -> YAML.typeMismatch "Term" n + Just t -> + case v of + (YAML.Scalar (YAML.SStr s)) -> + return (t, T.unpack (T.strip s)) + n' -> YAML.typeMismatch "String" n' + addItem (n, _) = YAML.typeMismatch "String" n lookupTerm :: Term -> Translations -> Maybe String lookupTerm t (Translations tm) = M.lookup t tm readTranslations :: String -> Either String Translations readTranslations s = - case Yaml.decodeEither' $ UTF8.fromString s of - Left err' -> Left $ prettyPrintParseException err' - Right t -> Right t + case YAML.decodeStrict $ UTF8.fromString s of + Left err' -> Left err' + Right (t:_) -> Right t + Right [] -> Left "empty YAML document" diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index fe8f452d3..dc0b154bf 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -50,7 +50,7 @@ import qualified Data.Set as Set import Data.Text (Text) import qualified Data.Text as T import qualified Data.Vector as V -import Data.Yaml (Value (Array, Bool, Number, Object, String)) +import Data.Aeson (Value (Array, Bool, Number, Object, String)) import Network.HTTP (urlEncode) import Text.HTML.TagSoup (Tag (..), isTagText, parseTags) import Text.Pandoc.Class (PandocMonad, report) diff --git a/stack.lts9.yaml b/stack.lts9.yaml index 355254618..75b6763b2 100644 --- a/stack.lts9.yaml +++ b/stack.lts9.yaml @@ -27,4 +27,6 @@ extra-deps: - pandoc-types-1.17.5 - haddock-library-1.6.0 - texmath-0.11 +- HsYAML-0.1.1.1 +- text-1.2.3.0 resolver: lts-9.14 diff --git a/stack.yaml b/stack.yaml index e0d7045c8..f9b573931 100644 --- a/stack.yaml +++ b/stack.yaml @@ -22,6 +22,8 @@ extra-deps: - hslua-module-text-0.1.2.1 - texmath-0.11 - haddock-library-1.6.0 +- HsYAML-0.1.1.1 +- text-1.2.3.0 ghc-options: "$locals": -fhide-source-paths -XNoImplicitPrelude resolver: lts-10.10 -- cgit v1.2.3 From 5d78ad12b2949d7c500acf8941a2077860da37b0 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 29 Jun 2018 23:47:07 +0200 Subject: Fix compiler warnings. --- src/Text/Pandoc/Readers/Markdown.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 9fe84013f..68f076e35 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -245,8 +245,8 @@ yamlMetaBlock = try $ do case YAML.decodeStrict (UTF8.fromString rawYaml) of Right (YAML.Mapping _ hashmap : _) -> do let alist = M.toList hashmap - mapM_ (\(k', v) -> - case YAML.parseEither (YAML.parseYAML k') of + mapM_ (\(key, v) -> + case YAML.parseEither (YAML.parseYAML key) of Left e -> fail e Right k -> do if ignorable k @@ -315,8 +315,8 @@ yamlToMeta (YAML.Sequence _ xs) = do return $ B.toMetaValue xs'' yamlToMeta (YAML.Mapping _ o) = do let alist = M.toList o - foldM (\m (k',v) -> - case YAML.parseEither (YAML.parseYAML k') of + foldM (\m (key, v) -> + case YAML.parseEither (YAML.parseYAML key) of Left e -> fail e Right k -> do if ignorable k -- cgit v1.2.3 From 016e0a09e2e2ffa823157a28a3a7f0268b9c6f42 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 30 Jun 2018 11:45:49 +0200 Subject: RST writer: don't treat 'example' as a syntax name. This fixes conversions from org with example blocks. Closes #4748. --- src/Text/Pandoc/Writers/RST.hs | 3 ++- test/command/4748.md | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 test/command/4748.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index 1fd984a6d..a2f2739a0 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -273,7 +273,8 @@ blockToRST (CodeBlock (_,classes,kvs) str) = do then return $ prefixed "> " (text str) $$ blankline else return $ (case [c | c <- classes, - c `notElem` ["sourceCode","literate","numberLines"]] of + c `notElem` ["sourceCode","literate","numberLines", + "number-lines","example"]] of [] -> "::" (lang:_) -> (".. code:: " <> text lang) $$ numberlines) $+$ nest 3 (text str) $$ blankline diff --git a/test/command/4748.md b/test/command/4748.md new file mode 100644 index 000000000..1de0fa9ed --- /dev/null +++ b/test/command/4748.md @@ -0,0 +1,16 @@ +``` +% pandoc -f org -t rst +Before example block. +#+begin_example +This is in an example block. +#+end_example +After example block. +^D +Before example block. + +:: + + This is in an example block. + +After example block. +``` -- cgit v1.2.3 From f6dfb632ff38cc9dd5156297959ce8028fd766ea Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 2 Jul 2018 18:30:37 +0300 Subject: Spellcheck comments --- src/Text/Pandoc/Class.hs | 4 ++-- src/Text/Pandoc/Lua/Init.hs | 2 +- src/Text/Pandoc/Parsing.hs | 2 +- src/Text/Pandoc/Readers/Creole.hs | 2 +- src/Text/Pandoc/Readers/Docx/Parse.hs | 2 +- src/Text/Pandoc/Readers/EPUB.hs | 2 +- src/Text/Pandoc/Readers/HTML.hs | 4 ++-- src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs | 4 ++-- src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs | 2 +- src/Text/Pandoc/Readers/Odt/Generic/Utils.hs | 4 ++-- src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs | 2 +- src/Text/Pandoc/Readers/Odt/StyleReader.hs | 2 +- src/Text/Pandoc/Readers/Org/Blocks.hs | 2 +- src/Text/Pandoc/Readers/Org/Inlines.hs | 2 +- src/Text/Pandoc/Readers/Textile.hs | 2 +- src/Text/Pandoc/Readers/TikiWiki.hs | 2 +- src/Text/Pandoc/Readers/Txt2Tags.hs | 2 +- src/Text/Pandoc/Shared.hs | 2 +- src/Text/Pandoc/Writers/Docx.hs | 2 +- src/Text/Pandoc/Writers/ICML.hs | 2 +- src/Text/Pandoc/Writers/Org.hs | 2 +- src/Text/Pandoc/Writers/RST.hs | 2 +- 22 files changed, 26 insertions(+), 26 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs index 657a48d75..e47546dfc 100644 --- a/src/Text/Pandoc/Class.hs +++ b/src/Text/Pandoc/Class.hs @@ -882,10 +882,10 @@ adjustImagePath _ _ x = x -- of things that would normally be obtained through IO. data PureState = PureState { stStdGen :: StdGen , stWord8Store :: [Word8] -- should be - -- inifinite, + -- infinite, -- i.e. [1..] , stUniqStore :: [Int] -- should be - -- inifinite and + -- infinite and -- contain every -- element at most -- once, e.g. [1..] diff --git a/src/Text/Pandoc/Lua/Init.hs b/src/Text/Pandoc/Lua/Init.hs index c8c7fdfbd..15f90664e 100644 --- a/src/Text/Pandoc/Lua/Init.hs +++ b/src/Text/Pandoc/Lua/Init.hs @@ -55,7 +55,7 @@ import qualified Foreign.Lua.Module.Text as Lua import qualified Text.Pandoc.Definition as Pandoc -- | Run the lua interpreter, using pandoc's default way of environment --- initalization. +-- initialization. runPandocLua :: Lua a -> PandocIO (Either LuaException a) runPandocLua luaOp = do luaPkgParams <- luaPackageParams diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs index 05f4f7d36..79022d6f1 100644 --- a/src/Text/Pandoc/Parsing.hs +++ b/src/Text/Pandoc/Parsing.hs @@ -1289,7 +1289,7 @@ type SubstTable = M.Map Key Inlines -- unique identifier, and update the list of identifiers -- in state. Issue a warning if an explicit identifier -- is encountered that duplicates an earlier identifier --- (explict or automatically generated). +-- (explicit or automatically generated). registerHeader :: (Stream s m a, HasReaderOptions st, HasHeaderMap st, HasLogMessages st, HasIdentifierList st) => Attr -> Inlines -> ParserT s st m Attr diff --git a/src/Text/Pandoc/Readers/Creole.hs b/src/Text/Pandoc/Readers/Creole.hs index 4fd38c0fd..a337bf937 100644 --- a/src/Text/Pandoc/Readers/Creole.hs +++ b/src/Text/Pandoc/Readers/Creole.hs @@ -2,7 +2,7 @@ {- Copyright (C) 2017 Sascha Wilde - partly based on all the other readers, especialy the work by + partly based on all the other readers, especially the work by John MacFarlane and Alexander Sulfrian all bugs are solely created by me. diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs index 4c4c06073..99f50ba97 100644 --- a/src/Text/Pandoc/Readers/Docx/Parse.hs +++ b/src/Text/Pandoc/Readers/Docx/Parse.hs @@ -785,7 +785,7 @@ So we do this in a number of steps. If we encounter the fldchar begin tag, we start open a fldchar state variable (see state above). We add the instrtext to it as FieldInfo. Then we close that and start adding the runs when we get to separate. Then when we get to end, we produce -the Field type with approriate FieldInfo and Runs. +the Field type with appropriate FieldInfo and Runs. -} elemToParPart ns element | isElem ns "w" "r" element diff --git a/src/Text/Pandoc/Readers/EPUB.hs b/src/Text/Pandoc/Readers/EPUB.hs index c26447641..bfc3fc3ee 100644 --- a/src/Text/Pandoc/Readers/EPUB.hs +++ b/src/Text/Pandoc/Readers/EPUB.hs @@ -73,7 +73,7 @@ readEPUB opts bytes = case toArchiveOrFail bytes of -- runEPUB :: Except PandocError a -> Either PandocError a -- runEPUB = runExcept --- Note that internal reference are aggresively normalised so that all ids +-- Note that internal reference are aggressively normalised so that all ids -- are of the form "filename#id" -- archiveToEPUB :: (PandocMonad m) => ReaderOptions -> Archive -> m Pandoc diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs index 32a1ba5a6..df8dc1a2d 100644 --- a/src/Text/Pandoc/Readers/HTML.hs +++ b/src/Text/Pandoc/Readers/HTML.hs @@ -852,7 +852,7 @@ pInTags' tagtype tagtest parser = try $ do pSatisfy (\t -> t ~== TagOpen tagtype [] && tagtest t) mconcat <$> manyTill parser (pCloses tagtype <|> eof) --- parses p, preceeded by an optional opening tag +-- parses p, preceded by an optional opening tag -- and followed by an optional closing tags pOptInTag :: PandocMonad m => Text -> TagParser m a -> TagParser m a pOptInTag tagtype p = try $ do @@ -1281,7 +1281,7 @@ instance HasLastStrPosition HTMLState where setLastStrPos s st = st {parserState = setLastStrPos s (parserState st)} getLastStrPos = getLastStrPos . parserState --- For now we need a special verison here; the one in Shared has String type +-- For now we need a special version here; the one in Shared has String type renderTags' :: [Tag Text] -> Text renderTags' = renderTagsOptions renderOptions{ optMinimize = matchTags ["hr", "br", "img", diff --git a/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs b/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs index d3db3a9e2..9e8221248 100644 --- a/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs +++ b/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs @@ -100,7 +100,7 @@ liftA fun a = a >>^ fun -- | Duplicate a value to subsequently feed it into different arrows. -- Can almost always be replaced with '(&&&)', 'keepingTheValue', -- or even '(|||)'. --- Aequivalent to +-- Equivalent to -- > returnA &&& returnA duplicate :: (Arrow a) => a b (b,b) duplicate = arr $ join (,) @@ -114,7 +114,7 @@ infixr 2 >>% -- | Duplicate a value and apply an arrow to the second instance. --- Aequivalent to +-- Equivalent to -- > \a -> duplicate >>> second a -- or -- > \a -> returnA &&& a diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs b/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs index 6d96897aa..e76bbf5cf 100644 --- a/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs +++ b/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs @@ -50,7 +50,7 @@ class (Eq nsID, Ord nsID) => NameSpaceID nsID where getNamespaceID :: NameSpaceIRI -> NameSpaceIRIs nsID -> Maybe (NameSpaceIRIs nsID, nsID) - -- | Given a namespace id, lookup its IRI. May be overriden for performance. + -- | Given a namespace id, lookup its IRI. May be overridden for performance. getIRI :: nsID -> NameSpaceIRIs nsID -> Maybe NameSpaceIRI diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs index 616d9290b..722c30a33 100644 --- a/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs +++ b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs @@ -61,7 +61,7 @@ import qualified Data.Foldable as F (Foldable, foldr) import Data.Maybe --- | Aequivalent to +-- | Equivalent to -- > foldr (.) id -- where '(.)' are 'id' are the ones from "Control.Category" -- and 'foldr' is the one from "Data.Foldable". @@ -72,7 +72,7 @@ import Data.Maybe composition :: (Category cat, F.Foldable f) => f (cat a a) -> cat a a composition = F.foldr (<<<) Cat.id --- | Aequivalent to +-- | Equivalent to -- > foldr (flip (.)) id -- where '(.)' are 'id' are the ones from "Control.Category" -- and 'foldr' is the one from "Data.Foldable". diff --git a/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs index 81392e16b..2327ea908 100644 --- a/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs +++ b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs @@ -261,7 +261,7 @@ convertingExtraState v a = withSubStateF setVAsExtraState modifyWithA -- The resulting converter even behaves like an identity converter on the -- value level. -- --- Aequivalent to +-- Equivalent to -- -- > \v x a -> convertingExtraState v (returnV x >>> a) -- diff --git a/src/Text/Pandoc/Readers/Odt/StyleReader.hs b/src/Text/Pandoc/Readers/Odt/StyleReader.hs index e0444559b..fa5c2d142 100644 --- a/src/Text/Pandoc/Readers/Odt/StyleReader.hs +++ b/src/Text/Pandoc/Readers/Odt/StyleReader.hs @@ -342,7 +342,7 @@ instance Read XslUnit where readsPrec _ _ = [] -- | Rough conversion of measures into millimetres. --- Pixels and em's are actually implementation dependant/relative measures, +-- Pixels and em's are actually implementation dependent/relative measures, -- so I could not really easily calculate anything exact here even if I wanted. -- But I do not care about exactness right now, as I only use measures -- to determine if a paragraph is "indented" or not. diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs index 888cd9307..d2a749efb 100644 --- a/src/Text/Pandoc/Readers/Org/Blocks.hs +++ b/src/Text/Pandoc/Readers/Org/Blocks.hs @@ -743,7 +743,7 @@ latexEnd envName = try $ -- --- Footnote defintions +-- Footnote definitions -- noteBlock :: PandocMonad m => OrgParser m (F Blocks) noteBlock = try $ do diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs index 7d1568b80..b7378e3e4 100644 --- a/src/Text/Pandoc/Readers/Org/Inlines.hs +++ b/src/Text/Pandoc/Readers/Org/Inlines.hs @@ -510,7 +510,7 @@ anchor = try $ do <* string ">>" <* skipSpaces --- | Replace every char but [a-zA-Z0-9_.-:] with a hypen '-'. This mirrors +-- | Replace every char but [a-zA-Z0-9_.-:] with a hyphen '-'. This mirrors -- the org function @org-export-solidify-link-text@. solidify :: String -> String diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs index bc3bcaf26..4b65be347 100644 --- a/src/Text/Pandoc/Readers/Textile.hs +++ b/src/Text/Pandoc/Readers/Textile.hs @@ -540,7 +540,7 @@ wordChunk = try $ do str :: PandocMonad m => ParserT [Char] ParserState m Inlines str = do baseStr <- hyphenedWords - -- RedCloth compliance : if parsed word is uppercase and immediatly + -- RedCloth compliance : if parsed word is uppercase and immediately -- followed by parens, parens content is unconditionally word acronym fullStr <- option baseStr $ try $ do guard $ all isUpper baseStr diff --git a/src/Text/Pandoc/Readers/TikiWiki.hs b/src/Text/Pandoc/Readers/TikiWiki.hs index 333144c56..8458b05e5 100644 --- a/src/Text/Pandoc/Readers/TikiWiki.hs +++ b/src/Text/Pandoc/Readers/TikiWiki.hs @@ -167,7 +167,7 @@ table = try $ do -- return $ B.simpleTable (headers rows) $ trace ("rows: " ++ (show rows)) rows return $B.simpleTable (headers rows) rows where - -- The headers are as many empty srings as the number of columns + -- The headers are as many empty strings as the number of columns -- in the first row headers rows = map (B.plain . B.str) $replicate (length $ head rows) "" diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs index bed49fd46..525e675bf 100644 --- a/src/Text/Pandoc/Readers/Txt2Tags.hs +++ b/src/Text/Pandoc/Readers/Txt2Tags.hs @@ -198,7 +198,7 @@ para = try $ do commentBlock :: T2T Blocks commentBlock = try (blockMarkupArea anyLine (const mempty) "%%%") <|> comment --- Seperator and Strong line treated the same +-- Separator and Strong line treated the same hrule :: T2T Blocks hrule = try $ do spaces diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs index 26b01bc90..5b011c46a 100644 --- a/src/Text/Pandoc/Shared.hs +++ b/src/Text/Pandoc/Shared.hs @@ -712,7 +712,7 @@ schemes = Set.fromList , "ws", "wss", "wtai", "wyciwyg", "xcon", "xcon-userid", "xfire" , "xmlrpc.beep", "xmlrpc.beeps", "xmpp", "xri", "ymsgr", "z39.50", "z39.50r" , "z39.50s" - -- Inofficial schemes + -- Unofficial schemes , "doi", "isbn", "javascript", "pmid" ] diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 4f7c51a22..380374bd6 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -230,7 +230,7 @@ writeDocx opts doc@(Pandoc meta _) = do let mbAttrMarLeft = (elAttribs <$> mbpgmar) >>= lookupAttrBy ((=="left") . qName) let mbAttrMarRight = (elAttribs <$> mbpgmar) >>= lookupAttrBy ((=="right") . qName) - -- Get the avaible area (converting the size and the margins to int and + -- Get the available area (converting the size and the margins to int and -- doing the difference let pgContentWidth = (-) <$> (read <$> mbAttrSzWidth ::Maybe Integer) <*> ( diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index 266d58007..b8fc0dc94 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -153,7 +153,7 @@ writeICML opts (Pandoc meta blocks) = do Nothing -> return main Just tpl -> renderTemplate' tpl context --- | Auxilary functions for parStylesToDoc and charStylesToDoc. +-- | Auxiliary functions for parStylesToDoc and charStylesToDoc. contains :: String -> (String, (String, String)) -> [(String, String)] contains s rule = [snd rule | (fst rule) `isInfixOf` s] diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs index a71775e13..1dd825b79 100644 --- a/src/Text/Pandoc/Writers/Org.hs +++ b/src/Text/Pandoc/Writers/Org.hs @@ -266,7 +266,7 @@ orderedListItemToOrg marker items = do contents <- blockListToOrg items return $ hang (length marker + 1) (text marker <> space) (contents <> cr) --- | Convert defintion list item (label, list of blocks) to Org. +-- | Convert definition list item (label, list of blocks) to Org. definitionListItemToOrg :: PandocMonad m => ([Inline], [[Block]]) -> Org m Doc definitionListItemToOrg (label, defs) = do diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index a2f2739a0..817fb665d 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -333,7 +333,7 @@ orderedListItemToRST marker items = do let marker' = marker ++ " " return $ hang (length marker') (text marker') $ contents <> cr --- | Convert defintion list item (label, list of blocks) to RST. +-- | Convert definition list item (label, list of blocks) to RST. definitionListItemToRST :: PandocMonad m => ([Inline], [[Block]]) -> RST m Doc definitionListItemToRST (label, defs) = do label' <- inlineListToRST label -- cgit v1.2.3 From 5479ea300a5c02d63fe1ffafb060bfa1134b4f97 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 2 Jul 2018 18:31:46 +0300 Subject: JATS reader: fix typo ("lable" instead of "label") --- src/Text/Pandoc/Readers/JATS.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/JATS.hs b/src/Text/Pandoc/Readers/JATS.hs index 59af76d23..695c86b5d 100644 --- a/src/Text/Pandoc/Readers/JATS.hs +++ b/src/Text/Pandoc/Readers/JATS.hs @@ -191,7 +191,7 @@ parseBlock (Elem e) = listType -> do let start = fromMaybe 1 $ (strContent <$> (filterElement (named "list-item") e - >>= filterElement (named "lable"))) + >>= filterElement (named "label"))) >>= safeRead orderedListWith (start, parseListStyleType listType, DefaultDelim) <$> listitems -- cgit v1.2.3 From 55e8cb07d02318a3005b4070af3ae21cd00c44ba Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 6 Jul 2018 23:43:19 +0200 Subject: PDF: Fix logic error in runTeXProgram. We were running the tex program one more time than requested. This should speed up pdf production. --- src/Text/Pandoc/PDF.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index 7fa2cd26c..e951c8c3e 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -314,7 +314,7 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir source = do putStrLn $ "[makePDF] Run #" ++ show runNumber BL.hPutStr stdout out putStr "\n" - if runNumber <= numRuns + if runNumber < numRuns then runTeXProgram verbosity program args (runNumber + 1) numRuns tmpDir source else do let pdfFile = replaceDirectory (replaceExtension file ".pdf") tmpDir -- cgit v1.2.3 From 146555e63623bfd1b960a0ef9b66c7853f6f6b3c Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 6 Jul 2018 23:51:20 +0200 Subject: PDF: revert fix for #4484 (only compress images on last run). Closes #4755. This will mean some increase in the time it takes to produce an image-heavy PDF with xelatex, but it will make tables of contents correct, which is more important. Note that the production time should also be decreased by the previous commit, which fixed a logic error affecting the number of runs. That change might mitigate the effect of this one. --- src/Text/Pandoc/PDF.hs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index e951c8c3e..65de3e45a 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -285,12 +285,7 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir source = do let file' = file #endif let programArgs = ["-halt-on-error", "-interaction", "nonstopmode", - "-output-directory", tmpDir'] ++ - -- see #4484, only compress images on last run: - if program == "xelatex" && runNumber < numRuns - then ["-output-driver", "xdvipdfmx -z0"] - else [] - ++ args ++ [file'] + "-output-directory", tmpDir'] ++ args ++ [file'] env' <- getEnvironment let sep = [searchPathSeparator] let texinputs = maybe (tmpDir' ++ sep) ((tmpDir' ++ sep) ++) -- cgit v1.2.3 From 5809d5bef2de59757fc9cd72c6508b8cfeeae186 Mon Sep 17 00:00:00 2001 From: Mauro Bieg Date: Thu, 12 Jul 2018 19:37:37 +0200 Subject: AsciiDoc Writer: escape square brackets at start of line (#4708) closes #4545 --- src/Text/Pandoc/Writers/AsciiDoc.hs | 21 +++++++++++++-------- test/command/4545.md | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 test/command/4545.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs index 036185282..df1b9c8d0 100644 --- a/src/Text/Pandoc/Writers/AsciiDoc.hs +++ b/src/Text/Pandoc/Writers/AsciiDoc.hs @@ -44,7 +44,7 @@ import Data.Aeson (Result (..), Value (String), fromJSON, toJSON) import Data.Char (isPunctuation, isSpace) import Data.List (intercalate, intersperse, stripPrefix) import qualified Data.Map as M -import Data.Maybe (fromMaybe, isJust) +import Data.Maybe (fromMaybe, isJust, listToMaybe) import qualified Data.Set as Set import Data.Text (Text) import qualified Data.Text as T @@ -126,11 +126,16 @@ olMarker = do (start, style', delim) <- anyOrderedListMarker else spaceChar -- | True if string begins with an ordered list marker -beginsWithOrderedListMarker :: String -> Bool -beginsWithOrderedListMarker str = - case runParser olMarker defaultParserState "para start" (take 10 str) of - Left _ -> False - Right _ -> True +-- or would be interpreted as an AsciiDoc option command +needsEscaping :: String -> Bool +needsEscaping s = beginsWithOrderedListMarker s || isBracketed s + where + beginsWithOrderedListMarker str = + case runParser olMarker defaultParserState "para start" (take 10 str) of + Left _ -> False + Right _ -> True + isBracketed ('[':cs) = listToMaybe (reverse cs) == Just ']' + isBracketed _ = False -- | Convert Pandoc block element to asciidoc. blockToAsciiDoc :: PandocMonad m @@ -146,8 +151,8 @@ blockToAsciiDoc opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) = blockToAsciiDoc opts (Para inlines) = do contents <- inlineListToAsciiDoc opts inlines -- escape if para starts with ordered list marker - let esc = if beginsWithOrderedListMarker (render Nothing contents) - then text "\\" + let esc = if needsEscaping (render Nothing contents) + then text "{empty}" else empty return $ esc <> contents <> blankline blockToAsciiDoc opts (LineBlock lns) = do diff --git a/test/command/4545.md b/test/command/4545.md new file mode 100644 index 000000000..e5fc6e244 --- /dev/null +++ b/test/command/4545.md @@ -0,0 +1,20 @@ +``` +% pandoc -t asciidoc +Test 1 + +[my text] + +Test 2 +^D +Test 1 + +{empty}[my text] + +Test 2 +``` +``` +% pandoc -t asciidoc +4\. foo +^D +{empty}4. foo +``` -- cgit v1.2.3 From 339a9e1b8b2aa34aab847d114a65d2d759bd25ed Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 15 Jul 2018 12:53:42 -0700 Subject: LaTeX reader: be more forgiving in key/value option parsing. We now allow arbitrary LaTeX values. This helps with #4761. The `\maxwidth` is still not propagated to the latex destination, but at least we don't choke on parsing. --- src/Text/Pandoc/Readers/LaTeX.hs | 55 ++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 16 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 0578e4836..504ac6db0 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -501,13 +501,17 @@ setpos spos (Tok _ tt txt) = Tok spos tt txt anyControlSeq :: PandocMonad m => LP m Tok anyControlSeq = satisfyTok isCtrlSeq - where isCtrlSeq (Tok _ (CtrlSeq _) _) = True - isCtrlSeq _ = False + +isCtrlSeq :: Tok -> Bool +isCtrlSeq (Tok _ (CtrlSeq _) _) = True +isCtrlSeq _ = False anySymbol :: PandocMonad m => LP m Tok -anySymbol = satisfyTok isSym - where isSym (Tok _ Symbol _) = True - isSym _ = False +anySymbol = satisfyTok isSymbolTok + +isSymbolTok :: Tok -> Bool +isSymbolTok (Tok _ Symbol _) = True +isSymbolTok _ = False spaces :: PandocMonad m => LP m () spaces = skipMany (satisfyTok (tokTypeIn [Comment, Spaces, Newline])) @@ -542,8 +546,10 @@ sp = whitespace <|> endline whitespace :: PandocMonad m => LP m () whitespace = () <$ satisfyTok isSpaceTok - where isSpaceTok (Tok _ Spaces _) = True - isSpaceTok _ = False + +isSpaceTok :: Tok -> Bool +isSpaceTok (Tok _ Spaces _) = True +isSpaceTok _ = False newlineTok :: PandocMonad m => LP m () newlineTok = () <$ satisfyTok isNewlineTok @@ -554,8 +560,10 @@ isNewlineTok _ = False comment :: PandocMonad m => LP m () comment = () <$ satisfyTok isCommentTok - where isCommentTok (Tok _ Comment _) = True - isCommentTok _ = False + +isCommentTok :: Tok -> Bool +isCommentTok (Tok _ Comment _) = True +isCommentTok _ = False anyTok :: PandocMonad m => LP m Tok anyTok = satisfyTok (const True) @@ -819,18 +827,25 @@ dolstinline = do keyval :: PandocMonad m => LP m (String, String) keyval = try $ do Tok _ Word key <- satisfyTok isWordTok - let isSpecSym (Tok _ Symbol t) = t /= "]" && t /= "," - isSpecSym _ = False optional sp - val <- option [] $ do + val <- option mempty $ do symbol '=' optional sp - braced <|> many1 (satisfyTok isWordTok <|> satisfyTok isSpecSym - <|> anyControlSeq) - optional sp + (untokenize <$> braced) <|> + (mconcat <$> many1 ( + (untokenize . snd <$> withRaw braced) + <|> + (untokenize <$> (many1 + (satisfyTok + (\t -> case t of + Tok _ Symbol "]" -> False + Tok _ Symbol "," -> False + Tok _ Symbol "{" -> False + Tok _ Symbol "}" -> False + _ -> True)))))) optional (symbol ',') optional sp - return (T.unpack key, T.unpack . untokenize $ val) + return (T.unpack key, T.unpack $ T.strip val) keyvals :: PandocMonad m => LP m [(String, String)] keyvals = try $ symbol '[' >> manyTill keyval (symbol ']') @@ -1644,8 +1659,16 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("foreignlanguage", foreignlanguage) -- include , ("input", include "input") + -- plain tex stuff that should just be passed through as raw tex + , ("ifdim", ifdim) ] +ifdim :: PandocMonad m => LP m Inlines +ifdim = do + contents <- manyTill anyTok (controlSeq "fi") + return $ rawInline "latex" $ T.unpack $ + "\\ifdim" <> untokenize contents <> "\\fi" + makeUppercase :: Inlines -> Inlines makeUppercase = fromList . walk (alterStr (map toUpper)) . toList -- cgit v1.2.3 From 1579e578332536e9b36534dfeb3c0f36f9162fd5 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 15 Jul 2018 13:35:37 -0700 Subject: Support abbreviated units for siunitx (#4773). --- src/Text/Pandoc/Readers/LaTeX.hs | 89 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 504ac6db0..facafe63d 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1551,6 +1551,95 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList -- siuntix , ("SI", dosiunitx) -- units of siuntix + , ("fg", lit "fg") + , ("pg", lit "pg") + , ("ng", lit "ng") + , ("ug", lit "μg") + , ("mg", lit "mg") + , ("g", lit "g") + , ("kg", lit "kg") + , ("amu", lit "u") + , ("pm", lit "pm") + , ("nm", lit "nm") + , ("um", lit "μm") + , ("mm", lit "mm") + , ("cm", lit "cm") + , ("dm", lit "dm") + , ("m", lit "m") + , ("km", lit "km") + , ("as", lit "as") + , ("fs", lit "fs") + , ("ps", lit "ps") + , ("ns", lit "ns") + , ("us", lit "μs") + , ("ms", lit "ms") + , ("s", lit "s") + , ("fmol", lit "fmol") + , ("pmol", lit "pmol") + , ("nmol", lit "nmol") + , ("umol", lit "μmol") + , ("mmol", lit "mmol") + , ("mol", lit "mol") + , ("kmol", lit "kmol") + , ("pA", lit "pA") + , ("nA", lit "nA") + , ("uA", lit "μA") + , ("mA", lit "mA") + , ("A", lit "A") + , ("kA", lit "kA") + , ("ul", lit "μl") + , ("ml", lit "ml") + , ("l", lit "l") + , ("hl", lit "hl") + , ("uL", lit "μL") + , ("mL", lit "mL") + , ("L", lit "L") + , ("hL", lit "hL") + , ("mHz", lit "mHz") + , ("Hz", lit "Hz") + , ("kHz", lit "kHz") + , ("MHz", lit "MHz") + , ("GHz", lit "GHz") + , ("THz", lit "THz") + , ("mN", lit "mN") + , ("N", lit "N") + , ("kN", lit "kN") + , ("MN", lit "MN") + , ("Pa", lit "Pa") + , ("kPa", lit "kPa") + , ("MPa", lit "MPa") + , ("GPa", lit "GPa") + , ("mohm", lit "mΩ") + , ("kohm", lit "kΩ") + , ("Mohm", lit "MΩ") + , ("pV", lit "pV") + , ("nV", lit "nV") + , ("uV", lit "μV") + , ("mV", lit "mV") + , ("V", lit "V") + , ("kV", lit "kV") + , ("W", lit "W") + , ("uW", lit "μW") + , ("mW", lit "mW") + , ("kW", lit "kW") + , ("MW", lit "MW") + , ("GW", lit "GW") + , ("J", lit "J") + , ("uJ", lit "μJ") + , ("mJ", lit "mJ") + , ("kJ", lit "kJ") + , ("eV", lit "eV") + , ("meV", lit "meV") + , ("keV", lit "keV") + , ("MeV", lit "MeV") + , ("GeV", lit "GeV") + , ("TeV", lit "TeV") + , ("kWh", lit "kWh") + , ("F", lit "F") + , ("fF", lit "fF") + , ("pF", lit "pF") + , ("K", lit "K") + , ("dB", lit "dB") , ("angstrom", lit "Å") , ("arcmin", lit "′") , ("arcminute", lit "′") -- cgit v1.2.3 From ec30fb37c12fc5d1a248971831414891cf6dcbe7 Mon Sep 17 00:00:00 2001 From: Anders Waldenborg Date: Mon, 16 Jul 2018 00:14:40 +0200 Subject: Wrap emojis in span nodes (#4759) Text.Pandoc.Emoji now exports `emojiToInline`, which returns a Span inline containing the emoji character and some attributes with metadata (class `emoji`, attribute `data-emoji` with emoji name). Previously, emojis (as supported in Markdown and CommonMark readers, e.g ":smile:") were simply translated into the corresponding unicode code point. By wrapping them in Span nodes, we make it possible to do special handling such as giving them a special font in HTML output. We also open up the possibility of treating them differently when the `--ascii` option is selected (though that is not part of this commit). Closes #4743. --- src/Text/Pandoc/Emoji.hs | 7 ++++++- src/Text/Pandoc/Readers/CommonMark.hs | 31 +++++++++++++++++-------------- src/Text/Pandoc/Readers/Markdown.hs | 8 ++++---- test/Tests/Readers/Markdown.hs | 4 +++- test/command/4743.md | 25 +++++++++++++++++++++++++ test/command/gfm.md | 2 +- 6 files changed, 56 insertions(+), 21 deletions(-) create mode 100644 test/command/4743.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Emoji.hs b/src/Text/Pandoc/Emoji.hs index 5cc965153..7d0af1a72 100644 --- a/src/Text/Pandoc/Emoji.hs +++ b/src/Text/Pandoc/Emoji.hs @@ -28,9 +28,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Emoji symbol lookup from canonical string identifier. -} -module Text.Pandoc.Emoji ( emojis ) where +module Text.Pandoc.Emoji ( emojis, emojiToInline ) where import Prelude import qualified Data.Map as M +import Text.Pandoc.Definition (Inline (Span, Str)) emojis :: M.Map String String emojis = M.fromList @@ -905,3 +906,7 @@ emojis = M.fromList ,("zero","0\65039\8419") ,("zzz","\128164") ] + +emojiToInline :: String -> Maybe Inline +emojiToInline emojikey = makeSpan <$> M.lookup emojikey emojis + where makeSpan = Span ("", ["emoji"], [("data-emoji", emojikey)]) . (:[]) . Str diff --git a/src/Text/Pandoc/Readers/CommonMark.hs b/src/Text/Pandoc/Readers/CommonMark.hs index a742ca666..9c4f7a8ac 100644 --- a/src/Text/Pandoc/Readers/CommonMark.hs +++ b/src/Text/Pandoc/Readers/CommonMark.hs @@ -44,7 +44,7 @@ import Data.Text (Text, unpack) import Text.Pandoc.Asciify (toAsciiChar) import Text.Pandoc.Class (PandocMonad) import Text.Pandoc.Definition -import Text.Pandoc.Emoji (emojis) +import Text.Pandoc.Emoji (emojiToInline) import Text.Pandoc.Options import Text.Pandoc.Shared (stringify) import Text.Pandoc.Walk (walkM) @@ -61,16 +61,19 @@ readCommonMark opts s = return $ [ extTable | isEnabled Ext_pipe_tables opts ] ++ [ extAutolink | isEnabled Ext_autolink_bare_uris opts ] -convertEmojis :: String -> String -convertEmojis (':':xs) = +convertEmojis :: String -> [Inline] +convertEmojis s@(':':xs) = case break (==':') xs of (ys,':':zs) -> - case Map.lookup ys emojis of - Just s -> s ++ convertEmojis zs - Nothing -> ':' : ys ++ convertEmojis (':':zs) - _ -> ':':xs -convertEmojis (x:xs) = x : convertEmojis xs -convertEmojis [] = [] + case emojiToInline ys of + Just em -> em : convertEmojis zs + Nothing -> Str (':' : ys) : convertEmojis (':':zs) + _ -> [Str s] +convertEmojis s = + case break (==':') s of + ("","") -> [] + (_,"") -> [Str s] + (xs,ys) -> Str xs:convertEmojis ys addHeaderIdentifiers :: ReaderOptions -> Pandoc -> Pandoc addHeaderIdentifiers opts doc = evalState (walkM (addHeaderId opts) doc) mempty @@ -205,17 +208,17 @@ addInlines :: ReaderOptions -> [Node] -> [Inline] addInlines opts = foldr (addInline opts) [] addInline :: ReaderOptions -> Node -> [Inline] -> [Inline] -addInline opts (Node _ (TEXT t) _) = (map toinl clumps ++) +addInline opts (Node _ (TEXT t) _) = (foldr ((++) . toinl) [] clumps ++) where raw = unpack t clumps = groupBy samekind raw samekind ' ' ' ' = True samekind ' ' _ = False samekind _ ' ' = False samekind _ _ = True - toinl (' ':_) = Space - toinl xs = Str $ if isEnabled Ext_emoji opts - then convertEmojis xs - else xs + toinl (' ':_) = [Space] + toinl xs = if isEnabled Ext_emoji opts + then convertEmojis xs + else [Str xs] addInline _ (Node _ LINEBREAK _) = (LineBreak :) addInline opts (Node _ SOFTBREAK _) | isEnabled Ext_hard_line_breaks opts = (LineBreak :) diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 68f076e35..e491f6276 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -51,7 +51,7 @@ import Text.Pandoc.Builder (Blocks, Inlines) import qualified Text.Pandoc.Builder as B import Text.Pandoc.Class (PandocMonad (..), report) import Text.Pandoc.Definition -import Text.Pandoc.Emoji (emojis) +import Text.Pandoc.Emoji (emojiToInline) import Text.Pandoc.Error import Text.Pandoc.Logging import Text.Pandoc.Options @@ -2027,9 +2027,9 @@ emoji = try $ do char ':' emojikey <- many1 (oneOf emojiChars) char ':' - case M.lookup emojikey emojis of - Just s -> return (return (B.str s)) - Nothing -> mzero + case emojiToInline emojikey of + Just i -> return (return $ B.singleton i) + Nothing -> mzero -- Citations diff --git a/test/Tests/Readers/Markdown.hs b/test/Tests/Readers/Markdown.hs index e44c7fc19..bc8e55615 100644 --- a/test/Tests/Readers/Markdown.hs +++ b/test/Tests/Readers/Markdown.hs @@ -199,7 +199,9 @@ tests = [ testGroup "inline code" ] , testGroup "emoji" [ test markdownGH "emoji symbols" $ - ":smile: and :+1:" =?> para (text "😄 and 👍") + ":smile: and :+1:" =?> para (spanWith ("", ["emoji"], [("data-emoji", "smile")]) "😄" <> + space <> str "and" <> space <> + spanWith ("", ["emoji"], [("data-emoji", "+1")]) "👍") ] , "unbalanced brackets" =: "[[[[[[[[[[[[hi" =?> para (text "[[[[[[[[[[[[hi") diff --git a/test/command/4743.md b/test/command/4743.md new file mode 100644 index 000000000..49b4b6d59 --- /dev/null +++ b/test/command/4743.md @@ -0,0 +1,25 @@ +Test that emojis are wrapped in Span + +``` +% pandoc -f commonmark+emoji -t native +My:thumbsup:emoji:heart: +^D +[Para [Str "My",Span ("",["emoji"],[("data-emoji","thumbsup")]) [Str "\128077"],Str "emoji",Span ("",["emoji"],[("data-emoji","heart")]) [Str "\10084\65039"]]] +``` + +``` +% pandoc -f markdown+emoji -t native +My:thumbsup:emoji:heart: +^D +[Para [Str "My",Span ("",["emoji"],[("data-emoji","thumbsup")]) [Str "\128077"],Str "emoji",Span ("",["emoji"],[("data-emoji","heart")]) [Str "\10084\65039"]]] +``` + +``` +% pandoc -f commonmark+emoji -t html +:zero: header +============= +My:thumbsup:emoji:heart:x :hearts: xyz +^D +

0️⃣ header

+

My👍emoji❤️x ♥️ xyz

+``` diff --git a/test/command/gfm.md b/test/command/gfm.md index 670f3cd6e..7a7098989 100644 --- a/test/command/gfm.md +++ b/test/command/gfm.md @@ -38,7 +38,7 @@ gfm tests: % pandoc -f gfm -t native My:thumbsup:emoji:heart: ^D -[Para [Str "My\128077emoji\10084\65039"]] +[Para [Str "My",Span ("",["emoji"],[("data-emoji","thumbsup")]) [Str "\128077"],Str "emoji",Span ("",["emoji"],[("data-emoji","heart")]) [Str "\10084\65039"]]] ``` ``` -- cgit v1.2.3 From af445b34d8ec1a6f60cd6eb7c6964e7de450ae83 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 15 Jul 2018 16:02:46 -0700 Subject: Make markdown and github writers respect the `emoji` extension. --- src/Text/Pandoc/Writers/CommonMark.hs | 5 +++++ src/Text/Pandoc/Writers/Markdown.hs | 5 +++++ test/command/emoji.md | 27 +++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 test/command/emoji.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs index 98c1101fa..27179496c 100644 --- a/src/Text/Pandoc/Writers/CommonMark.hs +++ b/src/Text/Pandoc/Writers/CommonMark.hs @@ -304,6 +304,11 @@ inlineToNodes opts (Math mt str) = (node (HTML_INLINE (T.pack ("\\(" ++ str ++ "\\)"))) [] :) DisplayMath -> (node (HTML_INLINE (T.pack ("\\[" ++ str ++ "\\]"))) [] :) +inlineToNodes opts (Span ("",["emoji"],kvs) [Str s]) = do + case lookup "data-emoji" kvs of + Just emojiname | isEnabled Ext_emoji opts -> + (node (TEXT (":" <> T.pack emojiname <> ":")) [] :) + _ -> (node (TEXT (T.pack s)) [] :) inlineToNodes opts (Span attr ils) = let nodes = inlinesToNodes opts ils op = tagWithAttributes opts True False "span" attr diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index dc0b154bf..c07771384 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -982,6 +982,11 @@ isRight (Left _) = False -- | Convert Pandoc inline element to markdown. inlineToMarkdown :: PandocMonad m => WriterOptions -> Inline -> MD m Doc +inlineToMarkdown opts (Span ("",["emoji"],kvs) [Str s]) = do + case lookup "data-emoji" kvs of + Just emojiname | isEnabled Ext_emoji opts -> + return $ ":" <> text emojiname <> ":" + _ -> inlineToMarkdown opts (Str s) inlineToMarkdown opts (Span attrs ils) = do plain <- asks envPlain contents <- inlineListToMarkdown opts ils diff --git a/test/command/emoji.md b/test/command/emoji.md new file mode 100644 index 000000000..b5c573b3f --- /dev/null +++ b/test/command/emoji.md @@ -0,0 +1,27 @@ +``` +% pandoc -t markdown+emoji -f markdown+emoji +:smile: +^D +:smile: +``` + +``` +% pandoc -t markdown-emoji -f markdown+emoji +:smile: +^D +😄 +``` + +``` +% pandoc -t gfm -f markdown+emoji +:smile: +^D +:smile: +``` + +``` +% pandoc -t gfm-emoji -f markdown+emoji +:smile: +^D +😄 +``` -- cgit v1.2.3 From d7edfbdf4d0680dcbc6cb1e7ed01e64c13db0871 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 18 Jul 2018 18:53:55 -0700 Subject: Fix regression finding templates in user data directory. Under version 2.2.1 and prior pandoc found latex templates in the templates directory under the data directory, but this no longer works in 2.2.2. MANUAL says: "If the template is not found, pandoc will search for it in the templates subdirectory of the user data directory (see `--data-dir`)." This commit fixes the regression, which stems from 07bce91. Closes #4777. --- src/Text/Pandoc/App.hs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index b79273092..f4b7f1904 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -83,7 +83,6 @@ import System.Exit (exitSuccess) import System.FilePath import System.IO (nativeNewline, stdout) import qualified System.IO as IO (Newline (..)) -import System.IO.Error (isDoesNotExistError) import Text.Pandoc import Text.Pandoc.BCP47 (Lang (..), parseBCP47) import Text.Pandoc.Builder (setMeta, deleteMeta) @@ -383,8 +382,7 @@ convertWithOpts opts = do ((fst <$> fetchItem tp') `catchError` (\e -> case e of - PandocIOError _ e' | - isDoesNotExistError e' -> + PandocResourceNotFound _ -> readDataFile ("templates" tp') _ -> throwError e)) -- cgit v1.2.3 From ac1a46b0cb4206eb3d46e2f29f29d53b0489c184 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 19 Jul 2018 10:14:05 -0700 Subject: rawLaTeXBlock: never retokenize macroDef. --- src/Text/Pandoc/Readers/LaTeX.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index facafe63d..c15312cd8 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -287,7 +287,7 @@ rawLaTeXBlock = do lookAhead (try (char '\\' >> letter)) snd <$> (rawLaTeXParser False macroDef blocks <|> rawLaTeXParser True - (environment <|> macroDef <|> blockCommand) + (environment <|> blockCommand) (mconcat <$> (many (block <|> beginOrEndCommand)))) -- See #4667 for motivation; sometimes people write macros -- cgit v1.2.3 From 34b229dd5a8493bad62498e5485f2775e2289ce8 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 19 Jul 2018 13:58:02 -0700 Subject: Fix for bug in parsing `\include` in markdown. Starting in 2.2.2, everything after an `\input` (or `\include`) in a markdown file would be parsed as raw LaTeX. This commit fixes the issue and adds a regression test. Closes #4781. --- src/Text/Pandoc/Readers/LaTeX.hs | 11 ++++++++++- test/command/4781.md | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 test/command/4781.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index c15312cd8..1dd31d402 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -286,6 +286,12 @@ rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s) rawLaTeXBlock = do lookAhead (try (char '\\' >> letter)) snd <$> (rawLaTeXParser False macroDef blocks + <|> (rawLaTeXParser True + (do choice (map controlSeq + ["include", "input", "subfile", "usepackage"]) + skipMany opt + braced + return mempty) blocks) <|> rawLaTeXParser True (environment <|> blockCommand) (mconcat <$> (many (block <|> beginOrEndCommand)))) @@ -308,7 +314,10 @@ rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s) => ParserT String s m String rawLaTeXInline = do lookAhead (try (char '\\' >> letter)) - snd <$> rawLaTeXParser True (inlineEnvironment <|> inlineCommand') inlines + snd <$> ( rawLaTeXParser True + (mempty <$ (controlSeq "input" >> skipMany opt >> braced)) + inlines + <|> rawLaTeXParser True (inlineEnvironment <|> inlineCommand') inlines) inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines inlineCommand = do diff --git a/test/command/4781.md b/test/command/4781.md new file mode 100644 index 000000000..7dc973c7c --- /dev/null +++ b/test/command/4781.md @@ -0,0 +1,22 @@ +``` +% pandoc -t native +Markdown parsed *here* + +\include{command/bar} + +*But not here* +^D +[Para [Str "Markdown",Space,Str "parsed",Space,Emph [Str "here"]] +,RawBlock (Format "latex") "\\include{command/bar}" +,Para [Emph [Str "But",Space,Str "not",Space,Str "here"]]] +``` + +``` +% pandoc -t native +*here* \input{command/bar} + +*But not here* +^D +[Para [Emph [Str "here"],Space,RawInline (Format "tex") "\\input{command/bar}"] +,Para [Emph [Str "But",Space,Str "not",Space,Str "here"]]] +``` -- cgit v1.2.3 From 6419819b46c0d69c7024ba8aa4a6381cb311341c Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 21 Jul 2018 22:51:53 -0700 Subject: RST reader: fix double-link bug. Link labels containing raw URLs were parsed as autolinks, but links within links are not allowed. Closes #4581. --- src/Text/Pandoc/Readers/RST.hs | 9 ++++++++- test/command/4581.md | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 test/command/4581.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index 71a38cf82..2a36ca1f1 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -45,6 +45,7 @@ import Data.Maybe (fromMaybe, isJust) import Data.Sequence (ViewR (..), viewr) import Data.Text (Text) import qualified Data.Text as T +import Text.Pandoc.Walk (walk) import Text.Pandoc.Builder (Blocks, Inlines, fromList, setMeta, trimInlines) import qualified Text.Pandoc.Builder as B import Text.Pandoc.Class (PandocMonad, fetchItem, readFileFromDirs) @@ -1479,7 +1480,7 @@ explicitLink :: PandocMonad m => RSTParser m Inlines explicitLink = try $ do char '`' notFollowedBy (char '`') -- `` marks start of inline code - label' <- trimInlines . mconcat <$> + label' <- removeLinks . trimInlines . mconcat <$> manyTill (notFollowedBy (char '`') >> inline) (char '<') src <- trim <$> manyTill (noneOf ">\n") (char '>') skipSpaces @@ -1494,6 +1495,12 @@ explicitLink = try $ do _ -> return ((src, ""), nullAttr) return $ B.linkWith attr (escapeURI src') tit label'' +removeLinks :: B.Inlines -> B.Inlines +removeLinks = B.fromList . walk (concatMap go) . B.toList + where go :: Inline -> [Inline] + go (Link _ lab _) = lab + go x = [x] + citationName :: PandocMonad m => RSTParser m String citationName = do raw <- citationMarker diff --git a/test/command/4581.md b/test/command/4581.md new file mode 100644 index 000000000..b38ebaaf0 --- /dev/null +++ b/test/command/4581.md @@ -0,0 +1,6 @@ +``` +% pandoc -f rst -t native +`http://loc `__ +^D +[Para [Link ("",[],[]) [Str "http://loc"] ("http://loc","")]] +``` -- cgit v1.2.3 From 4e899eb9c886df2200551f69a3f593ab5258f2e2 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Mon, 23 Jul 2018 22:05:41 +0200 Subject: Org reader: fix parsers relying on parseFromString Emphasis was not parsed when it followed directly after some block types (e.g., lists). The org reader uses a wrapper for the `parseFromString` function to handle org-specific state. The last position of a character allowed before emphasis was reset incorrectly in this wrapper. Emphasized text was not recognized when placed directly behind a block which the reader parses using `parseFromString`. Fixes: #4784 --- src/Text/Pandoc/Readers/Org/Parsing.hs | 7 +++---- test/Tests/Readers/Org/Block/List.hs | 11 +++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Org/Parsing.hs b/src/Text/Pandoc/Readers/Org/Parsing.hs index e014de65e..b37b36624 100644 --- a/src/Text/Pandoc/Readers/Org/Parsing.hs +++ b/src/Text/Pandoc/Readers/Org/Parsing.hs @@ -137,14 +137,13 @@ anyLine = <* updateLastPreCharPos <* updateLastForbiddenCharPos --- The version Text.Pandoc.Parsing cannot be used, as we need additional parts --- of the state saved and restored. +-- | Like @'Text.Pandoc.Parsing'@, but resets the position of the last character +-- allowed before emphasised text. parseFromString :: Monad m => OrgParser m a -> String -> OrgParser m a parseFromString parser str' = do - oldLastPreCharPos <- orgStateLastPreCharPos <$> getState updateState $ \s -> s{ orgStateLastPreCharPos = Nothing } result <- P.parseFromString parser str' - updateState $ \s -> s{ orgStateLastPreCharPos = oldLastPreCharPos } + updateState $ \s -> s { orgStateLastPreCharPos = Nothing } return result -- | Skip one or more tab or space characters. diff --git a/test/Tests/Readers/Org/Block/List.hs b/test/Tests/Readers/Org/Block/List.hs index f273b684d..bdab01404 100644 --- a/test/Tests/Readers/Org/Block/List.hs +++ b/test/Tests/Readers/Org/Block/List.hs @@ -243,4 +243,15 @@ tests = mconcat [ para "CLOSED: [2015-10-19 Mon 15:03]" , bulletList [ plain "Note taken on [2015-10-19 Mon 13:24]" ] ] + + , "Markup after header and list" =: + T.unlines [ "* headline" + , "- list" + , "" + , "~variable name~" + ] =?> + mconcat [ headerWith ("headline", [], []) 1 "headline" + , bulletList [ plain "list" ] + , para (code "variable name") + ] ] -- cgit v1.2.3 From 50e8c3b107c56d5de4840f369a2e49e4f55cd591 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 24 Jul 2018 11:36:49 -0700 Subject: MediaWiki writer: Avoid extra blank line in tables with empty cells. Note that the old output is semantically identical, but the new output looks better. Closes #4794. --- src/Text/Pandoc/Writers/MediaWiki.hs | 1 + test/command/4794.md | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 test/command/4794.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs index df50028a0..666853a3c 100644 --- a/src/Text/Pandoc/Writers/MediaWiki.hs +++ b/src/Text/Pandoc/Writers/MediaWiki.hs @@ -313,6 +313,7 @@ tableCellToMediaWiki headless rownum (alignment, width, bs) = do let sep = case bs of [Plain _] -> " " [Para _] -> " " + [] -> "" _ -> "\n" return $ marker ++ attr ++ sep ++ trimr contents diff --git a/test/command/4794.md b/test/command/4794.md new file mode 100644 index 000000000..8356d2157 --- /dev/null +++ b/test/command/4794.md @@ -0,0 +1,18 @@ +``` +% pandoc -f markdown -t mediawiki +| Column1 | Column2 | Column3 | +| ------- | ------- | ------- | +| text | | text | +^D +{| +! Column1 +! Column2 +! Column3 +|- +| text +| +| text +|} + + +``` -- cgit v1.2.3 From be2d7921cbf33a3aa839cd54a0b3ec0a7dfc4a9b Mon Sep 17 00:00:00 2001 From: danse Date: Mon, 23 Apr 2018 08:54:06 +0200 Subject: RST reader: remove support for nested inlines. RST does not allow nested emphasis, links, or other inline constructs. Closes #4581, double parsing of links with URLs as link text. This supersedes the earlier fix for #4581 in 6419819b46c0d69c7024ba8aa4a6381cb311341c. Fixes #4561, a bug parsing with URLs inside emphasis. Closes #4792. --- src/Text/Pandoc/Readers/RST.hs | 32 +++++++++++++++----------------- test/Tests/Readers/RST.hs | 11 +++++++++++ test/command/4581.md | 6 ------ 3 files changed, 26 insertions(+), 23 deletions(-) delete mode 100644 test/command/4581.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index 2a36ca1f1..f9752a83c 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -45,7 +45,6 @@ import Data.Maybe (fromMaybe, isJust) import Data.Sequence (ViewR (..), viewr) import Data.Text (Text) import qualified Data.Text as T -import Text.Pandoc.Walk (walk) import Text.Pandoc.Builder (Blocks, Inlines, fromList, setMeta, trimInlines) import qualified Text.Pandoc.Builder as B import Text.Pandoc.Class (PandocMonad, fetchItem, readFileFromDirs) @@ -1314,19 +1313,24 @@ table = gridTable False <|> simpleTable False <|> inline :: PandocMonad m => RSTParser m Inlines inline = choice [ note -- can start with whitespace, so try before ws - , whitespace , link - , str , endline , strong , emph , code , subst , interpretedRole - , smart - , hyphens - , escapedChar - , symbol ] "inline" + , inlineContent ] "inline" + +-- strings, spaces and other characters that can appear either by +-- themselves or within inline markup +inlineContent :: PandocMonad m => RSTParser m Inlines +inlineContent = choice [ whitespace + , str + , smart + , hyphens + , escapedChar + , symbol ] "inline content" parseInlineFromString :: PandocMonad m => String -> RSTParser m Inlines parseInlineFromString = parseFromString' (trimInlines . mconcat <$> many inline) @@ -1369,11 +1373,11 @@ atStart p = do emph :: PandocMonad m => RSTParser m Inlines emph = B.emph . trimInlines . mconcat <$> - enclosed (atStart $ char '*') (char '*') inline + enclosed (atStart $ char '*') (char '*') inlineContent strong :: PandocMonad m => RSTParser m Inlines strong = B.strong . trimInlines . mconcat <$> - enclosed (atStart $ string "**") (try $ string "**") inline + enclosed (atStart $ string "**") (try $ string "**") inlineContent -- Note, this doesn't precisely implement the complex rule in -- http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules @@ -1480,8 +1484,8 @@ explicitLink :: PandocMonad m => RSTParser m Inlines explicitLink = try $ do char '`' notFollowedBy (char '`') -- `` marks start of inline code - label' <- removeLinks . trimInlines . mconcat <$> - manyTill (notFollowedBy (char '`') >> inline) (char '<') + label' <- trimInlines . mconcat <$> + manyTill (notFollowedBy (char '`') >> inlineContent) (char '<') src <- trim <$> manyTill (noneOf ">\n") (char '>') skipSpaces string "`_" @@ -1495,12 +1499,6 @@ explicitLink = try $ do _ -> return ((src, ""), nullAttr) return $ B.linkWith attr (escapeURI src') tit label'' -removeLinks :: B.Inlines -> B.Inlines -removeLinks = B.fromList . walk (concatMap go) . B.toList - where go :: Inline -> [Inline] - go (Link _ lab _) = lab - go x = [x] - citationName :: PandocMonad m => RSTParser m String citationName = do raw <- citationMarker diff --git a/test/Tests/Readers/RST.hs b/test/Tests/Readers/RST.hs index 906ed4ff9..540c5d45a 100644 --- a/test/Tests/Readers/RST.hs +++ b/test/Tests/Readers/RST.hs @@ -188,4 +188,15 @@ tests = [ "line block with blank line" =: ] =?> para ("foo" <> note (para "bar")) ] + , testGroup "inlines" + [ "links can contain an URI without being parsed twice (#4581)" =: + "`http://loc `__" =?> + para (link "http://loc" "" "http://loc") + , "inline markup cannot be nested" =: + "**a*b*c**" =?> + para (strong "a*b*c") + , "bare URI parsing disabled inside emphasis (#4561)" =: + "*http://location*" =?> + para (emph (text "http://location")) + ] ] diff --git a/test/command/4581.md b/test/command/4581.md deleted file mode 100644 index b38ebaaf0..000000000 --- a/test/command/4581.md +++ /dev/null @@ -1,6 +0,0 @@ -``` -% pandoc -f rst -t native -`http://loc `__ -^D -[Para [Link ("",[],[]) [Str "http://loc"] ("http://loc","")]] -``` -- cgit v1.2.3 From fb94c0f6a1b98d4f7ff34107d3b63c2c1d0afe1f Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Mon, 30 Jul 2018 19:55:25 +0200 Subject: Lua Utils module: add function blocks_to_inlines (#4799) Exposes a function converting which flattenes a list of blocks into a list of inlines. An example use case would be the conversion of Note elements into other inlines. --- doc/lua-filters.md | 31 +++++++++++++++++++++++++++++++ src/Text/Pandoc/Lua/Module/Utils.hs | 10 ++++++++++ src/Text/Pandoc/Shared.hs | 13 +++++++++++-- test/Tests/Lua.hs | 3 ++- test/lua/test-pandoc-utils.lua | 15 +++++++++++++++ 5 files changed, 69 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/doc/lua-filters.md b/doc/lua-filters.md index 881c981f5..19428cde6 100644 --- a/doc/lua-filters.md +++ b/doc/lua-filters.md @@ -1438,6 +1438,37 @@ Lua functions for pandoc scripts. This module exposes internal pandoc functions and utility functions. +[`blocks_to_inlines (blocks[, sep])`]{#utils-blocks_to_inlines} + +: Squash a list of blocks into a list of inlines. + + Parameters: + + `blocks`: + : List of blocks to be flattened. + + `sep`: + : List of inlines inserted as separator between two + consecutive blocks; defaults to `{ pandoc.Space(), + pandoc.Str'¶', pandoc.Space()}`. + + Returns: + + - ({[Inline][#Inline]}) List of inlines + + Usage: + + local blocks = { + pandoc.Para{ pandoc.Str 'Paragraph1' }, + pandoc.Para{ pandoc.Emph 'Paragraph2' } + } + local inlines = pandoc.utils.blocks_to_inlines(blocks) + -- inlines = { + -- pandoc.Str 'Paragraph1', + -- pandoc.Space(), pandoc.Str'¶', pandoc.Space(), + -- pandoc.Emph{ pandoc.Str 'Paragraph2' } + -- } + [`hierarchicalize (blocks)`]{#utils-hierarchicalize} : Convert list of blocks into an hierarchical list. An diff --git a/src/Text/Pandoc/Lua/Module/Utils.hs b/src/Text/Pandoc/Lua/Module/Utils.hs index 7fa4616be..7016c7ebd 100644 --- a/src/Text/Pandoc/Lua/Module/Utils.hs +++ b/src/Text/Pandoc/Lua/Module/Utils.hs @@ -42,6 +42,7 @@ import Text.Pandoc.Lua.Util (addFunction, popValue) import qualified Data.Digest.Pure.SHA as SHA import qualified Data.ByteString.Lazy as BSL import qualified Foreign.Lua as Lua +import qualified Text.Pandoc.Builder as B import qualified Text.Pandoc.Filter.JSON as JSONFilter import qualified Text.Pandoc.Shared as Shared @@ -49,6 +50,7 @@ import qualified Text.Pandoc.Shared as Shared pushModule :: Maybe FilePath -> Lua NumResults pushModule mbDatadir = do Lua.newtable + addFunction "blocks_to_inlines" blocksToInlines addFunction "hierarchicalize" hierarchicalize addFunction "normalize_date" normalizeDate addFunction "run_json_filter" (runJSONFilter mbDatadir) @@ -57,6 +59,14 @@ pushModule mbDatadir = do addFunction "to_roman_numeral" toRomanNumeral return 1 +-- | Squashes a list of blocks into inlines. +blocksToInlines :: [Block] -> Lua.Optional [Inline] -> Lua [Inline] +blocksToInlines blks optSep = do + let sep = case Lua.fromOptional optSep of + Just x -> B.fromList x + Nothing -> Shared.defaultBlocksSeparator + return $ B.toList (Shared.blocksToInlinesWithSep sep blks) + -- | Convert list of Pandoc blocks into (hierarchical) list of Elements. hierarchicalize :: [Block] -> Lua [Shared.Element] hierarchicalize = return . Shared.hierarchicalize diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs index 5b011c46a..412de99a0 100644 --- a/src/Text/Pandoc/Shared.hs +++ b/src/Text/Pandoc/Shared.hs @@ -94,6 +94,8 @@ module Text.Pandoc.Shared ( -- * for squashing blocks blocksToInlines, blocksToInlines', + blocksToInlinesWithSep, + defaultBlocksSeparator, -- * Safe read safeRead, -- * Temp directory @@ -757,12 +759,19 @@ blocksToInlinesWithSep sep = mconcat . intersperse sep . map blockToInlines blocksToInlines' :: [Block] -> Inlines -blocksToInlines' = blocksToInlinesWithSep parSep - where parSep = B.space <> B.str "¶" <> B.space +blocksToInlines' = blocksToInlinesWithSep defaultBlocksSeparator blocksToInlines :: [Block] -> [Inline] blocksToInlines = B.toList . blocksToInlines' +-- | Inline elements used to separate blocks when squashing blocks into +-- inlines. +defaultBlocksSeparator :: Inlines +defaultBlocksSeparator = + -- This is used in the pandoc.utils.blocks_to_inlines function. Docs + -- there should be updated if this is changed. + B.space <> B.str "¶" <> B.space + -- -- Safe read diff --git a/test/Tests/Lua.hs b/test/Tests/Lua.hs index 9d2d3b635..f00142f1d 100644 --- a/test/Tests/Lua.hs +++ b/test/Tests/Lua.hs @@ -109,7 +109,8 @@ tests = map (localOption (QuickCheckTests 20)) assertFilterConversion "pandoc.utils doesn't work as expected." "test-pandoc-utils.lua" (doc $ para "doesn't matter") - (doc $ mconcat [ plain (str "hierarchicalize: OK") + (doc $ mconcat [ plain (str "blocks_to_inlines: OK") + , plain (str "hierarchicalize: OK") , plain (str "normalize_date: OK") , plain (str "pipe: OK") , plain (str "failing pipe: OK") diff --git a/test/lua/test-pandoc-utils.lua b/test/lua/test-pandoc-utils.lua index 21f937edb..4421603ec 100644 --- a/test/lua/test-pandoc-utils.lua +++ b/test/lua/test-pandoc-utils.lua @@ -1,5 +1,19 @@ utils = require 'pandoc.utils' +-- Squash blocks to inlines +------------------------------------------------------------------------ +function test_blocks_to_inlines () + local blocks = { + pandoc.Para{ pandoc.Str 'Paragraph1' }, + pandoc.Para{ pandoc.Emph 'Paragraph2' } + } + local inlines = utils.blocks_to_inlines(blocks, {pandoc.LineBreak()}) + return #inlines == 3 + and inlines[1].text == "Paragraph1" + and inlines[2].t == 'LineBreak' + and inlines[3].content[1].text == "Paragraph2" +end + -- hierarchicalize ------------------------------------------------------------------------ function test_hierarchicalize () @@ -110,6 +124,7 @@ end function Para (el) return { + pandoc.Plain{pandoc.Str("blocks_to_inlines: " .. run(test_blocks_to_inlines))}, pandoc.Plain{pandoc.Str("hierarchicalize: " .. run(test_hierarchicalize))}, pandoc.Plain{pandoc.Str("normalize_date: " .. run(test_normalize_date))}, pandoc.Plain{pandoc.Str("pipe: " .. run(test_pipe))}, -- cgit v1.2.3 From 78dca68a0a484f3230535e91a98a30cb8090aee8 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 30 Jul 2018 14:38:38 -0700 Subject: DocBook reader: metadata handling improvements. Now we properly parse title and subtitle elements that are direct children of book and article (as well as children of bookinfo, articleinfo, or info). We also now use the "subtitle" metadata field for subtitles, rather than tacking the subtitle on to the title. --- src/Text/Pandoc/Readers/DocBook.hs | 66 ++++++++++++++++---------------------- test/docbook-xref.native | 2 +- 2 files changed, 29 insertions(+), 39 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs index 3d48c7ee8..b7bd71754 100644 --- a/src/Text/Pandoc/Readers/DocBook.hs +++ b/src/Text/Pandoc/Readers/DocBook.hs @@ -537,7 +537,6 @@ type DB m = StateT DBState m data DBState = DBState{ dbSectionLevel :: Int , dbQuoteType :: QuoteType , dbMeta :: Meta - , dbAcceptsMeta :: Bool , dbBook :: Bool , dbFigureTitle :: Inlines , dbContent :: [Content] @@ -547,7 +546,6 @@ instance Default DBState where def = DBState{ dbSectionLevel = 0 , dbQuoteType = DoubleQuote , dbMeta = mempty - , dbAcceptsMeta = False , dbBook = False , dbFigureTitle = mempty , dbContent = [] } @@ -609,18 +607,26 @@ named s e = qName (elName e) == s -- -acceptingMetadata :: PandocMonad m => DB m a -> DB m a -acceptingMetadata p = do - modify (\s -> s { dbAcceptsMeta = True } ) - res <- p - modify (\s -> s { dbAcceptsMeta = False }) - return res - -checkInMeta :: (PandocMonad m, Monoid a) => DB m () -> DB m a -checkInMeta p = do - accepts <- dbAcceptsMeta <$> get - when accepts p - return mempty +addMetadataFromElement :: PandocMonad m => Element -> DB m Blocks +addMetadataFromElement e = do + case filterChild (named "title") e of + Nothing -> return () + Just z -> do + getInlines z >>= addMeta "title" + addMetaField "subtitle" z + case filterChild (named "authorgroup") e of + Nothing -> return () + Just z -> addMetaField "author" z + addMetaField "subtitle" e + addMetaField "author" e + addMetaField "date" e + addMetaField "release" e + return mempty + where addMetaField fieldname elt = + case filterChildren (named fieldname) elt of + [] -> return () + [z] -> getInlines z >>= addMeta fieldname + zs -> mapM getInlines zs >>= addMeta fieldname addMeta :: PandocMonad m => ToMetaValue a => String -> a -> DB m () addMeta field val = modify (setMeta field val) @@ -718,11 +724,6 @@ parseBlock (Elem e) = "attribution" -> return mempty "titleabbrev" -> return mempty "authorinitials" -> return mempty - "title" -> checkInMeta getTitle - "author" -> checkInMeta getAuthor - "authorgroup" -> checkInMeta getAuthorGroup - "releaseinfo" -> checkInMeta (getInlines e >>= addMeta "release") - "date" -> checkInMeta getDate "bibliography" -> sect 0 "bibliodiv" -> sect 1 "biblioentry" -> parseMixed para (elContent e) @@ -788,8 +789,8 @@ parseBlock (Elem e) = "figure" -> getFigure e "mediaobject" -> para <$> getMediaobject e "caption" -> return mempty - "info" -> metaBlock - "articleinfo" -> metaBlock + "info" -> addMetadataFromElement e + "articleinfo" -> addMetadataFromElement e "sectioninfo" -> return mempty -- keywords & other metadata "refsectioninfo" -> return mempty -- keywords & other metadata "refsect1info" -> return mempty -- keywords & other metadata @@ -803,10 +804,11 @@ parseBlock (Elem e) = "chapterinfo" -> return mempty -- keywords & other metadata "glossaryinfo" -> return mempty -- keywords & other metadata "appendixinfo" -> return mempty -- keywords & other metadata - "bookinfo" -> metaBlock + "bookinfo" -> addMetadataFromElement e "article" -> modify (\st -> st{ dbBook = False }) >> - getBlocks e - "book" -> modify (\st -> st{ dbBook = True }) >> getBlocks e + addMetadataFromElement e >> getBlocks e + "book" -> modify (\st -> st{ dbBook = True }) >> + addMetadataFromElement e >> getBlocks e "table" -> parseTable "informaltable" -> parseTable "informalexample" -> divWith ("", ["informalexample"], []) <$> @@ -816,6 +818,8 @@ parseBlock (Elem e) = "screen" -> codeBlockWithLang "programlisting" -> codeBlockWithLang "?xml" -> return mempty + "title" -> return mempty -- handled in parent element + "subtitle" -> return mempty -- handled in parent element _ -> getBlocks e where parseMixed container conts = do let (ils,rest) = break isBlockElement conts @@ -857,19 +861,6 @@ parseBlock (Elem e) = terms' <- mapM getInlines terms items' <- mapM getBlocks items return (mconcat $ intersperse (str "; ") terms', items') - getTitle = do - tit <- getInlines e - subtit <- case filterChild (named "subtitle") e of - Just s -> (text ": " <>) <$> - getInlines s - Nothing -> return mempty - addMeta "title" (tit <> subtit) - - getAuthor = (:[]) <$> getInlines e >>= addMeta "author" - getAuthorGroup = do - let terms = filterChildren (named "author") e - mapM getInlines terms >>= addMeta "author" - getDate = getInlines e >>= addMeta "date" parseTable = do let isCaption x = named "title" x || named "caption" x caption <- case filterChild isCaption e of @@ -935,7 +926,6 @@ parseBlock (Elem e) = modify $ \st -> st{ dbSectionLevel = n - 1 } return $ headerWith (ident,[],[]) n' headerText <> b lineItems = mapM getInlines $ filterChildren (named "line") e - metaBlock = acceptingMetadata (getBlocks e) >> return mempty getInlines :: PandocMonad m => Element -> DB m Inlines getInlines e' = (trimInlines . mconcat) <$> diff --git a/test/docbook-xref.native b/test/docbook-xref.native index 23bc497b2..54a63768e 100644 --- a/test/docbook-xref.native +++ b/test/docbook-xref.native @@ -1,4 +1,4 @@ -Pandoc (Meta {unMeta = fromList []}) +Pandoc (Meta {unMeta = fromList [("title",MetaInlines [Str "An",Space,Str "Example",Space,Str "Book"])]}) [Header 1 ("ch01",[],[]) [Str "XRef",Space,Str "Samples"] ,Para [Str "This",Space,Str "paragraph",Space,Str "demonstrates",Space,Str "several",Space,Str "features",Space,Str "of",SoftBreak,Str "XRef."] ,BulletList -- cgit v1.2.3 From cbb662ca07acf23ead5479ab4bd479883432c7d7 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 30 Jul 2018 22:02:45 -0700 Subject: Use YAML.decode rather than YAML.decodeStrict. (Minor) --- src/Text/Pandoc/Readers/Markdown.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index e491f6276..a12437299 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -242,7 +242,7 @@ yamlMetaBlock = try $ do -- by including --- and ..., we allow yaml blocks with just comments: let rawYaml = unlines ("---" : (rawYamlLines ++ ["..."])) optional blanklines - case YAML.decodeStrict (UTF8.fromString rawYaml) of + case YAML.decode (UTF8.fromStringLazy rawYaml) of Right (YAML.Mapping _ hashmap : _) -> do let alist = M.toList hashmap mapM_ (\(key, v) -> -- cgit v1.2.3 From d3d932f42cd361a7b4d7e2b22a3238f53cb54f6b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 30 Jul 2018 23:04:53 -0700 Subject: Markdown reader: allow unquoted numbers, booleans as YAML mapping keys. Previously in 2.2.2 you could not do --- 0: bar ... but only --- '0': bar ... With this change, both forms work. --- src/Text/Pandoc/Readers/Markdown.hs | 54 +++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index a12437299..8c70de4af 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -230,7 +230,6 @@ pandocTitleBlock = try $ do $ nullMeta updateState $ \st -> st{ stateMeta' = stateMeta' st <> meta' } - yamlMetaBlock :: PandocMonad m => MarkdownParser m (F Blocks) yamlMetaBlock = try $ do guardEnabled Ext_yaml_metadata_block @@ -242,29 +241,31 @@ yamlMetaBlock = try $ do -- by including --- and ..., we allow yaml blocks with just comments: let rawYaml = unlines ("---" : (rawYamlLines ++ ["..."])) optional blanklines - case YAML.decode (UTF8.fromStringLazy rawYaml) of - Right (YAML.Mapping _ hashmap : _) -> do + case YAML.decodeNode' YAML.failsafeSchemaResolver False False + (UTF8.fromStringLazy rawYaml) of + Right [YAML.Doc (YAML.Mapping _ hashmap)] -> do let alist = M.toList hashmap mapM_ (\(key, v) -> - case YAML.parseEither (YAML.parseYAML key) of - Left e -> fail e - Right k -> do - if ignorable k - then return () - else do - v' <- yamlToMeta v - let k' = T.unpack k - updateState $ \st -> st{ stateMeta' = - do m <- stateMeta' st - -- if there's already a value, leave it unchanged - case lookupMeta k' m of - Just _ -> return m - Nothing -> do - v'' <- v' - return $ B.setMeta (T.unpack k) v'' m} - ) alist + case key of + (YAML.Scalar (YAML.SStr t)) -> handleKey t v + (YAML.Scalar (YAML.SUnknown _ t)) -> handleKey t v + _ -> fail "Non-string key in YAML mapping") alist + where handleKey k v = + if ignorable k + then return () + else do + v' <- yamlToMeta v + let k' = T.unpack k + updateState $ \st -> st{ stateMeta' = + do m <- stateMeta' st + -- if there's already a value, leave it unchanged + case lookupMeta k' m of + Just _ -> return m + Nothing -> do + v'' <- v' + return $ B.setMeta (T.unpack k) v'' m} Right [] -> return () - Right (YAML.Scalar YAML.SNull:_) -> return () + Right [YAML.Doc (YAML.Scalar YAML.SNull)] -> return () Right _ -> do logMessage $ CouldNotParseYamlMetadata "not an object" @@ -303,11 +304,12 @@ yamlToMeta :: PandocMonad m => YAML.Node -> MarkdownParser m (F MetaValue) yamlToMeta (YAML.Scalar x) = case x of - YAML.SStr t -> toMetaValue t - YAML.SBool b -> return $ return $ MetaBool b - YAML.SFloat d -> return $ return $ MetaString (show d) - YAML.SInt i -> return $ return $ MetaString (show i) - _ -> return $ return $ MetaString "" + YAML.SStr t -> toMetaValue t + YAML.SBool b -> return $ return $ MetaBool b + YAML.SFloat d -> return $ return $ MetaString (show d) + YAML.SInt i -> return $ return $ MetaString (show i) + YAML.SUnknown _ t -> toMetaValue t + YAML.SNull -> return $ return $ MetaString "" yamlToMeta (YAML.Sequence _ xs) = do xs' <- mapM yamlToMeta xs return $ do -- cgit v1.2.3 From 2661658a696ebaab14b2792b7bbd38ef2b5904e4 Mon Sep 17 00:00:00 2001 From: Francesco Occhipinti Date: Wed, 1 Aug 2018 21:32:16 +0200 Subject: RST writer: use `titleblock` instead of `title` variable for title block Closes #4803 After this commit use `$titleblock$` in order to get what was contained in `$title$` before, that is a title and subtitle rendered according to the official rST method: http://docutils.sourceforge.net/docs/user/rst/quickstart.html#document-title-subtitle. from With this commit, the `$title$` and `$subtitle$` metadata are available and they simply carry the metadata values. This opens up more possibilities in templates. --- data/templates/default.rst | 4 ++-- src/Text/Pandoc/Writers/RST.hs | 9 +++++---- test/Tests/Writers/RST.hs | 8 ++++++++ 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/data/templates/default.rst b/data/templates/default.rst index 937eb72ae..9ba15f546 100644 --- a/data/templates/default.rst +++ b/data/templates/default.rst @@ -1,5 +1,5 @@ -$if(title)$ -$title$ +$if(titleblock)$ +$titleblock$ $endif$ $for(author)$ diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index 817fb665d..0c118669b 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -83,13 +83,14 @@ pandocToRST (Pandoc meta blocks) = do let render' :: Doc -> Text render' = render colwidth let subtit = case lookupMeta "subtitle" meta of - Just (MetaBlocks [Plain xs]) -> xs - _ -> [] + Just (MetaBlocks [Plain xs]) -> xs + Just (MetaInlines xs) -> xs + _ -> [] title <- titleToRST (docTitle meta) subtit metadata <- metaToJSON opts (fmap render' . blockListToRST) (fmap (stripEnd . render') . inlineListToRST) - $ B.deleteMeta "title" $ B.deleteMeta "subtitle" meta + meta body <- blockListToRST' True $ case writerTemplate opts of Just _ -> normalizeHeadings 1 blocks Nothing -> blocks @@ -105,7 +106,7 @@ pandocToRST (Pandoc meta blocks) = do $ defField "toc-depth" (show $ writerTOCDepth opts) $ defField "number-sections" (writerNumberSections opts) $ defField "math" hasMath - $ defField "title" (render Nothing title :: String) + $ defField "titleblock" (render Nothing title :: String) $ defField "math" hasMath $ defField "rawtex" rawTeX metadata case writerTemplate opts of diff --git a/test/Tests/Writers/RST.hs b/test/Tests/Writers/RST.hs index a1a4510e0..0d5b7c38a 100644 --- a/test/Tests/Writers/RST.hs +++ b/test/Tests/Writers/RST.hs @@ -16,6 +16,11 @@ infix 4 =: => String -> (a, String) -> TestTree (=:) = test (purely (writeRST def . toPandoc)) +testTemplate :: (ToString a, ToString c, ToPandoc a) => + String -> String -> (a, c) -> TestTree +testTemplate t = + test (purely (writeRST def{ writerTemplate = Just t }) . toPandoc) + tests :: [TestTree] tests = [ testGroup "rubrics" [ "in list item" =: @@ -156,4 +161,7 @@ tests = [ testGroup "rubrics" , "Header 2" , "--------"] ] + , testTemplate "$subtitle$\n" "subtitle" $ + (setMeta "subtitle" ("subtitle" :: Inlines) $ doc $ plain "") =?> + ("subtitle" :: String) ] -- cgit v1.2.3 From f83bdb1ac50064714cb80502a4b7ad895a897c14 Mon Sep 17 00:00:00 2001 From: Mauro Bieg Date: Fri, 3 Aug 2018 21:04:38 +0200 Subject: Better error message on `-t pdf -o out.pdf` (#4815) closes #1155 (again) --- src/Text/Pandoc/App.hs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index f4b7f1904..44bb30223 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -142,6 +142,13 @@ engines = map ("html",) htmlEngines ++ pdfEngines :: [String] pdfEngines = ordNub $ map snd engines +pdfIsNoWriterErrorMsg :: String +pdfIsNoWriterErrorMsg = + "To create a pdf using pandoc, use " ++ + "-t latex|beamer|context|ms|html5" ++ + "\nand specify an output file with " ++ + ".pdf extension (-o filename.pdf)." + pdfWriterAndProg :: Maybe String -- ^ user-specified writer name -> Maybe String -- ^ user-specified pdf-engine -> IO (String, Maybe String) -- ^ IO (writerName, maybePdfEngineProg) @@ -165,6 +172,7 @@ pdfWriterAndProg mWriter mEngine = do [] -> Left $ "pdf-engine " ++ eng ++ " not known" + engineForWriter "pdf" = Left pdfIsNoWriterErrorMsg engineForWriter w = case [e | (f,e) <- engines, f == baseWriterName w] of eng : _ -> Right eng [] -> Left $ @@ -233,11 +241,7 @@ convertWithOpts opts = do else case getWriter (map toLower writerName) of Left e -> E.throwIO $ PandocAppError $ if format == "pdf" - then e ++ - "\nTo create a pdf using pandoc, use " ++ - "-t latex|beamer|context|ms|html5" ++ - "\nand specify an output file with " ++ - ".pdf extension (-o filename.pdf)." + then e ++ "\n" ++ pdfIsNoWriterErrorMsg else e Right (w, es) -> return (w :: Writer PandocIO, es) -- cgit v1.2.3 From 74a35b123cad558915f82031056ea1b9bf84a9d3 Mon Sep 17 00:00:00 2001 From: Francesco Occhipinti Date: Fri, 3 Aug 2018 21:13:18 +0200 Subject: RST writer: allow images to be directly nested within links, closes #4810 (#4814) --- src/Text/Pandoc/Writers/RST.hs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index 0c118669b..f355a8f5b 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -473,6 +473,8 @@ flatten outer -- them and they will be readable and parsable (Quoted _ _, _) -> keep f i (_, Quoted _ _) -> keep f i + -- inlineToRST handles this case properly so it's safe to keep + (Link _ _ _, Image _ _ _) -> keep f i -- parent inlines would prevent links from being correctly -- parsed, in this case we prioritise the content over the -- style -- cgit v1.2.3 From 581a3514ca266e20e70f05d9ffe314515a0a7bb9 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 5 Aug 2018 09:15:06 -0700 Subject: RST reader: improve parsing of inline interpreted text roles. * Use a Span with class "title-reference" for the default title-reference role. * Use B.text to split up contents into Spaces, SoftBreaks, and Strs for title-reference. * Use Code with class "interpreted-text" instead of Span and Str for unknown roles. (The RST writer has also been modified to round-trip this properly.) * Disallow blank lines in interpreted text. * Backslash-escape now works in interpreted text. * Backticks followed by alphanumerics no longer end interpreted text. Closes #4811. --- src/Text/Pandoc/Readers/RST.hs | 40 ++++++++++++++++++++++++----------- src/Text/Pandoc/Writers/RST.hs | 9 +++++--- test/Tests/Readers/RST.hs | 2 +- test/command/3407.md | 4 ++-- test/command/4811.md | 48 ++++++++++++++++++++++++++++++++++++++++++ test/rst-reader.native | 2 +- 6 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 test/command/4811.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index f9752a83c..576c3b77c 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -37,7 +37,7 @@ import Control.Arrow (second) import Control.Monad (forM_, guard, liftM, mplus, mzero, when) import Control.Monad.Except (throwError) import Control.Monad.Identity (Identity (..)) -import Data.Char (isHexDigit, isSpace, toLower, toUpper) +import Data.Char (isHexDigit, isSpace, toLower, toUpper, isAlphaNum) import Data.List (deleteFirstsBy, elemIndex, intercalate, isInfixOf, isSuffixOf, nub, sort, transpose, union) import qualified Data.Map as M @@ -1385,7 +1385,6 @@ strong = B.strong . trimInlines . mconcat <$> -- -- TODO: -- - Classes are silently discarded in addNewRole --- - Lacks sensible implementation for title-reference (which is the default) -- - Allows direct use of the :raw: role, rST only allows inherited use. interpretedRole :: PandocMonad m => RSTParser m Inlines interpretedRole = try $ do @@ -1395,12 +1394,12 @@ interpretedRole = try $ do renderRole :: PandocMonad m => String -> Maybe String -> String -> Attr -> RSTParser m Inlines renderRole contents fmt role attr = case role of - "sup" -> return $ B.superscript $ B.str contents - "superscript" -> return $ B.superscript $ B.str contents - "sub" -> return $ B.subscript $ B.str contents - "subscript" -> return $ B.subscript $ B.str contents - "emphasis" -> return $ B.emph $ B.str contents - "strong" -> return $ B.strong $ B.str contents + "sup" -> return $ B.superscript $ treatAsText contents + "superscript" -> return $ B.superscript $ treatAsText contents + "sub" -> return $ B.subscript $ treatAsText contents + "subscript" -> return $ B.subscript $ treatAsText contents + "emphasis" -> return $ B.emph $ treatAsText contents + "strong" -> return $ B.strong $ treatAsText contents "rfc-reference" -> return $ rfcLink contents "RFC" -> return $ rfcLink contents "pep-reference" -> return $ pepLink contents @@ -1411,7 +1410,7 @@ renderRole contents fmt role attr = case role of "title" -> titleRef contents "t" -> titleRef contents "code" -> return $ B.codeWith (addClass "sourceCode" attr) contents - "span" -> return $ B.spanWith attr $ B.str contents + "span" -> return $ B.spanWith attr $ treatAsText contents "raw" -> return $ B.rawInline (fromMaybe "" fmt) contents custom -> do customRoles <- stateRstCustomRoles <$> getState @@ -1419,14 +1418,20 @@ renderRole contents fmt role attr = case role of Just (newRole, newFmt, newAttr) -> renderRole contents newFmt newRole newAttr Nothing -> -- undefined role - return $ B.spanWith ("",[],[("role",role)]) (B.str contents) + return $ B.codeWith ("",["interpreted-text"],[("role",role)]) + contents where - titleRef ref = return $ B.str ref -- FIXME: Not a sensible behaviour + titleRef ref = return $ B.spanWith ("",["title-ref"],[]) $ treatAsText ref rfcLink rfcNo = B.link rfcUrl ("RFC " ++ rfcNo) $ B.str ("RFC " ++ rfcNo) where rfcUrl = "http://www.faqs.org/rfcs/rfc" ++ rfcNo ++ ".html" pepLink pepNo = B.link pepUrl ("PEP " ++ pepNo) $ B.str ("PEP " ++ pepNo) where padNo = replicate (4 - length pepNo) '0' ++ pepNo pepUrl = "http://www.python.org/dev/peps/pep-" ++ padNo ++ "/" + treatAsText = B.text . handleEscapes + handleEscapes [] = [] + handleEscapes ('\\':' ':cs) = handleEscapes cs + handleEscapes ('\\':c:cs) = c : handleEscapes cs + handleEscapes (c:cs) = c : handleEscapes cs addClass :: String -> Attr -> Attr addClass c (ident, classes, keyValues) = (ident, classes `union` [c], keyValues) @@ -1450,7 +1455,18 @@ roleAfter = try $ do return (role,contents) unmarkedInterpretedText :: PandocMonad m => RSTParser m [Char] -unmarkedInterpretedText = enclosed (atStart $ char '`') (char '`') anyChar +unmarkedInterpretedText = try $ do + atStart (char '`') + contents <- mconcat <$> (many1 + ( many1 (noneOf "`\\\n") + <|> (char '\\' >> ((\c -> ['\\',c]) <$> noneOf "\n")) + <|> (string "\n" <* notFollowedBy blankline) + <|> try (string "`" <* + notFollowedBy (() <$ roleMarker) <* + lookAhead (satisfy isAlphaNum)) + )) + char '`' + return contents whitespace :: PandocMonad m => RSTParser m Inlines whitespace = B.space <$ skipMany1 spaceChar "whitespace" diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index f355a8f5b..566bcbeef 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -574,15 +574,18 @@ inlineToRST (Quoted DoubleQuote lst) = do else return $ "“" <> contents <> "”" inlineToRST (Cite _ lst) = writeInlines lst +inlineToRST (Code (_,["interpreted-text"],[("role",role)]) str) = do + return $ ":" <> text role <> ":`" <> text str <> "`" inlineToRST (Code _ str) = do opts <- gets stOptions -- we trim the string because the delimiters must adjoin a -- non-space character; see #3496 -- we use :literal: when the code contains backticks, since -- :literal: allows backslash-escapes; see #3974 - return $ if '`' `elem` str - then ":literal:`" <> text (escapeString opts (trim str)) <> "`" - else "``" <> text (trim str) <> "``" + return $ + if '`' `elem` str + then ":literal:`" <> text (escapeString opts (trim str)) <> "`" + else "``" <> text (trim str) <> "``" inlineToRST (Str str) = do opts <- gets stOptions return $ text $ diff --git a/test/Tests/Readers/RST.hs b/test/Tests/Readers/RST.hs index 540c5d45a..8916eed6f 100644 --- a/test/Tests/Readers/RST.hs +++ b/test/Tests/Readers/RST.hs @@ -177,7 +177,7 @@ tests = [ "line block with blank line" =: =: ".. role:: haskell(code)\n.. role:: lhs(haskell)\n\n:lhs:`text`" =?> para (codeWith ("", ["lhs", "haskell", "sourceCode"], []) "text") , "unknown role" =: ":unknown:`text`" =?> - para (spanWith ("",[],[("role","unknown")]) (str "text")) + para (codeWith ("",["interpreted-text"],[("role","unknown")]) "text") ] , testGroup "footnotes" [ "remove space before note" =: T.unlines diff --git a/test/command/3407.md b/test/command/3407.md index 3160d1263..aec253ff5 100644 --- a/test/command/3407.md +++ b/test/command/3407.md @@ -1,6 +1,6 @@ ``` % pandoc -f native -t rst -[Para [Span ("",[],[("role","foo")]) [Str "text"]]] +[Para [Code ("",["interpreted-text"],[("role","foo")]) "text"]] ^D :foo:`text` ``` @@ -9,5 +9,5 @@ % pandoc -f rst -t native :foo:`text` ^D -[Para [Span ("",[],[("role","foo")]) [Str "text"]]] +[Para [Code ("",["interpreted-text"],[("role","foo")]) "text"]] ``` diff --git a/test/command/4811.md b/test/command/4811.md new file mode 100644 index 000000000..9c8bea7ce --- /dev/null +++ b/test/command/4811.md @@ -0,0 +1,48 @@ +No blank lines in inline interpreted roles: + +``` +% pandoc -f rst -t native +`no + +blank`:myrole: +^D +[Para [Str "`no"] +,Para [Str "blank`:myrole:"]] +``` + +Backslash escape behaves properly in interpreted roles: + +``` +% pandoc -f rst -t native +`hi\ there`:sup: + +`hi\ there`:code: +^D +[Para [Superscript [Str "hithere"]] +,Para [Code ("",["sourceCode"],[]) "hi\\ there"]] +``` + +Backtick followed by alphanumeric doesn't end the span: +``` +% pandoc -f rst -t native +`hi`there`:myrole: +^D +[Para [Code ("",["interpreted-text"],[("role","myrole")]) "hi`there"]] +``` + +Newline is okay, as long as not blank: +``` +% pandoc -f rst -t native +`hi +there`:myrole: +^D +[Para [Code ("",["interpreted-text"],[("role","myrole")]) "hi\nthere"]] +``` + +Use span for title-reference: +``` +% pandoc -f rst -t native +`default` +^D +[Para [Span ("",["title-ref"],[]) [Str "default"]]] +``` diff --git a/test/rst-reader.native b/test/rst-reader.native index b0e51bd3f..89dde7396 100644 --- a/test/rst-reader.native +++ b/test/rst-reader.native @@ -326,7 +326,7 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa ,Para [Math DisplayMath "\\alpha = beta",Math DisplayMath "E = mc^2"] ,Para [Str "Some",Space,Superscript [Str "of"],Space,Str "these",Space,Superscript [Str "words"],Space,Str "are",Space,Str "in",Space,Superscript [Str "superscript"],Str "."] ,Para [Str "Reset",Space,Str "default-role",Space,Str "to",Space,Str "the",Space,Str "default",Space,Str "default."] -,Para [Str "And",Space,Str "now",Space,Str "some-invalid-string-3231231",Space,Str "is",Space,Str "nonsense."] +,Para [Str "And",Space,Str "now",Space,Span ("",["title-ref"],[]) [Str "some-invalid-string-3231231"],Space,Str "is",Space,Str "nonsense."] ,Para [Str "And",Space,Str "now",Space,Str "with",Space,RawInline (Format "html") "inline HTML",Str "."] ,Para [Str "And",Space,Str "some",Space,Str "inline",Space,Str "haskell",Space,Code ("",["haskell","sourceCode"],[]) "fmap id [1,2..10]",Str "."] ,Para [Str "Indirect",Space,Str "python",Space,Str "role",Space,Code ("",["py","python","indirect","sourceCode"],[]) "[x*x for x in [1,2,3,4,5]]",Str "."] -- cgit v1.2.3 From 94c3753c08073fea030119c6944997c33b8eae56 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 6 Aug 2018 12:32:04 -0700 Subject: Fix parsing of embedded mappings in YAML metadata. This fixes a regression in 2.2.3 which caused embedded mappings (e.g. mappings in sequences) not to work in YAML metadata. Closes #4817. --- src/Text/Pandoc/Readers/Markdown.hs | 46 ++++++++++++++++++------------------- test/command/4817.md | 10 ++++++++ 2 files changed, 32 insertions(+), 24 deletions(-) create mode 100644 test/command/4817.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 8c70de4af..3965392d6 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -243,14 +243,9 @@ yamlMetaBlock = try $ do optional blanklines case YAML.decodeNode' YAML.failsafeSchemaResolver False False (UTF8.fromStringLazy rawYaml) of - Right [YAML.Doc (YAML.Mapping _ hashmap)] -> do - let alist = M.toList hashmap - mapM_ (\(key, v) -> - case key of - (YAML.Scalar (YAML.SStr t)) -> handleKey t v - (YAML.Scalar (YAML.SUnknown _ t)) -> handleKey t v - _ -> fail "Non-string key in YAML mapping") alist - where handleKey k v = + Right [YAML.Doc (YAML.Mapping _ hashmap)] -> + mapM_ (\(key, v) -> do + k <- nodeToKey key if ignorable k then return () else do @@ -263,7 +258,8 @@ yamlMetaBlock = try $ do Just _ -> return m Nothing -> do v'' <- v' - return $ B.setMeta (T.unpack k) v'' m} + return $ B.setMeta (T.unpack k) v'' m}) + (M.toList hashmap) Right [] -> return () Right [YAML.Doc (YAML.Scalar YAML.SNull)] -> return () Right _ -> do @@ -277,6 +273,11 @@ yamlMetaBlock = try $ do return () return mempty +nodeToKey :: Monad m => YAML.Node -> m Text +nodeToKey (YAML.Scalar (YAML.SStr t)) = return t +nodeToKey (YAML.Scalar (YAML.SUnknown _ t)) = return t +nodeToKey _ = fail "Non-string key in YAML mapping" + -- ignore fields ending with _ ignorable :: Text -> Bool ignorable t = (T.pack "_") `T.isSuffixOf` t @@ -315,22 +316,19 @@ yamlToMeta (YAML.Sequence _ xs) = do return $ do xs'' <- sequence xs' return $ B.toMetaValue xs'' -yamlToMeta (YAML.Mapping _ o) = do - let alist = M.toList o - foldM (\m (key, v) -> - case YAML.parseEither (YAML.parseYAML key) of - Left e -> fail e - Right k -> do - if ignorable k - then return m - else do - v' <- yamlToMeta v - return $ do - MetaMap m' <- m - v'' <- v' - return (MetaMap $ M.insert (T.unpack k) v'' m')) +yamlToMeta (YAML.Mapping _ o) = + foldM (\m (key, v) -> do + k <- nodeToKey key + if ignorable k + then return m + else do + v' <- yamlToMeta v + return $ do + MetaMap m' <- m + v'' <- v' + return (MetaMap $ M.insert (T.unpack k) v'' m')) (return $ MetaMap M.empty) - alist + (M.toList o) yamlToMeta _ = return $ return $ MetaString "" stopLine :: PandocMonad m => MarkdownParser m () diff --git a/test/command/4817.md b/test/command/4817.md new file mode 100644 index 000000000..7718e3b3a --- /dev/null +++ b/test/command/4817.md @@ -0,0 +1,10 @@ +``` +% pandoc -t native -s +--- +foo: +- bar: bam +... +^D +Pandoc (Meta {unMeta = fromList [("foo",MetaList [MetaMap (fromList [("bar",MetaInlines [Str "bam"])])])]}) +[] +``` -- cgit v1.2.3 From b76203ccf11c44dcea3837d1e06c8a2969be52bc Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 7 Aug 2018 09:26:11 -0700 Subject: Markdown reader: Properly handle boolean values in YAML metadata. This fixes a regression in 2.2.3, which cause boolean values to be parsed as MetaInlines instead of MetaBool. Note also an undocumented (but desirable) change in 2.2.3: numbers are now parsed as MetaInlines rather than MetaString. Closes #4819. --- src/Text/Pandoc/Readers/Markdown.hs | 13 +++++++++- test/command/4819.md | 50 +++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 test/command/4819.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 3965392d6..c4e8a6524 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -301,6 +301,14 @@ toMetaValue x = -- not end in a newline, but a "block" set off with -- `|` or `>` will. +checkBoolean :: Text -> Maybe Bool +checkBoolean t = + if t == T.pack "true" || t == T.pack "True" || t == T.pack "TRUE" + then Just True + else if t == T.pack "false" || t == T.pack "False" || t == T.pack "FALSE" + then Just False + else Nothing + yamlToMeta :: PandocMonad m => YAML.Node -> MarkdownParser m (F MetaValue) yamlToMeta (YAML.Scalar x) = @@ -309,7 +317,10 @@ yamlToMeta (YAML.Scalar x) = YAML.SBool b -> return $ return $ MetaBool b YAML.SFloat d -> return $ return $ MetaString (show d) YAML.SInt i -> return $ return $ MetaString (show i) - YAML.SUnknown _ t -> toMetaValue t + YAML.SUnknown _ t -> + case checkBoolean t of + Just b -> return $ return $ MetaBool b + Nothing -> toMetaValue t YAML.SNull -> return $ return $ MetaString "" yamlToMeta (YAML.Sequence _ xs) = do xs' <- mapM yamlToMeta xs diff --git a/test/command/4819.md b/test/command/4819.md new file mode 100644 index 000000000..548583387 --- /dev/null +++ b/test/command/4819.md @@ -0,0 +1,50 @@ +``` +% pandoc -f markdown -t native -s +--- +foo: 42 +... +^D +Pandoc (Meta {unMeta = fromList [("foo",MetaInlines [Str "42"])]}) +[] +``` + +``` +% pandoc -f markdown -t native -s +--- +foo: true +... +^D +Pandoc (Meta {unMeta = fromList [("foo",MetaBool True)]}) +[] +``` + +``` +% pandoc -f markdown -t native -s +--- +foo: True +... +^D +Pandoc (Meta {unMeta = fromList [("foo",MetaBool True)]}) +[] +``` + +``` +% pandoc -f markdown -t native -s +--- +foo: FALSE +... +^D +Pandoc (Meta {unMeta = fromList [("foo",MetaBool False)]}) +[] +``` + +``` +% pandoc -f markdown -t native -s +--- +foo: no +... +^D +Pandoc (Meta {unMeta = fromList [("foo",MetaInlines [Str "no"])]}) +[] +``` + -- cgit v1.2.3 From 9752dcd61aa72a9e1e59bafcd55376ab1d275620 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 8 Aug 2018 09:53:13 -0700 Subject: HTML writer: Don't prefix epub: attributes with data-. --- src/Text/Pandoc/Writers/HTML.hs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index f07d0381f..25f3163c2 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -580,6 +580,7 @@ toAttrs kvs = do return $ map (\(x,y) -> customAttribute (fromString (if not html5 || x `Set.member` html5Attributes + || "epub:" `isPrefixOf` x || "data-" `isPrefixOf` x then x else "data-" ++ x)) (toValue y)) kvs -- cgit v1.2.3 From ec896289841297e5d7cdcc433b8db3fa90508d6d Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 10 Aug 2018 14:59:59 -0700 Subject: Avoid a non-exhaustive pattern match. --- src/Text/Pandoc/Readers/Docx/Lists.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Docx/Lists.hs b/src/Text/Pandoc/Readers/Docx/Lists.hs index 49ea71601..0be363f3d 100644 --- a/src/Text/Pandoc/Readers/Docx/Lists.hs +++ b/src/Text/Pandoc/Readers/Docx/Lists.hs @@ -183,14 +183,13 @@ blocksToDefinitions' defAcc acc pair = if remainingAttr2 == ("", [], []) then (concatMap plainParaInlines blks1, [blks2]) else (concatMap plainParaInlines blks1, [[Div remainingAttr2 blks2]]) in blocksToDefinitions' (pair : defAcc) acc blks -blocksToDefinitions' defAcc acc +blocksToDefinitions' ((defTerm, defItems):defs) acc (Div (ident2, classes2, kvs2) blks2 : blks) - | (not . null) defAcc && "Definition" `elem` classes2 = + | "Definition" `elem` classes2 = let remainingAttr2 = (ident2, delete "Definition" classes2, kvs2) defItems2 = case remainingAttr2 == ("", [], []) of True -> blks2 False -> [Div remainingAttr2 blks2] - ((defTerm, defItems):defs) = defAcc defAcc' = case null defItems of True -> (defTerm, [defItems2]) : defs False -> (defTerm, init defItems ++ [last defItems ++ defItems2]) : defs -- cgit v1.2.3 From e055f1b21e0c9a4486850eac3a2dea12b7d74849 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 10 Aug 2018 15:05:25 -0700 Subject: Avoid non-exhaustive pattern match. --- src/Text/Pandoc/Readers/Docx/Parse.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs index 99f50ba97..cbf865de8 100644 --- a/src/Text/Pandoc/Readers/Docx/Parse.hs +++ b/src/Text/Pandoc/Readers/Docx/Parse.hs @@ -1153,8 +1153,9 @@ getSymChar :: NameSpaces -> Element -> RunElem getSymChar ns element | Just s <- lowerFromPrivate <$> getCodepoint , Just font <- getFont = - let [(char, _)] = readLitChar ("\\x" ++ s) in - TextRun . maybe "" (:[]) $ getUnicode font char + case readLitChar ("\\x" ++ s) of + [(char, _)] -> TextRun . maybe "" (:[]) $ getUnicode font char + _ -> TextRun "" where getCodepoint = findAttrByName ns "w" "char" element getFont = stringToFont =<< findAttrByName ns "w" "font" element -- cgit v1.2.3 From 7bc879268c1a86799a642280c296011e07e98c77 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 10 Aug 2018 15:13:19 -0700 Subject: Avoid non-exhaustive pattern match. --- src/Text/Pandoc/ImageSize.hs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/ImageSize.hs b/src/Text/Pandoc/ImageSize.hs index c5fe98a66..00ab86eab 100644 --- a/src/Text/Pandoc/ImageSize.hs +++ b/src/Text/Pandoc/ImageSize.hs @@ -319,20 +319,22 @@ pngSize img = do (shift w1 24 + shift w2 16 + shift w3 8 + w4, shift h1 24 + shift h2 16 + shift h3 8 + h4) _ -> Nothing -- "PNG parse error" - let (dpix, dpiy) = findpHYs rest'' + (dpix, dpiy) <- findpHYs rest'' return ImageSize { pxX = x, pxY = y, dpiX = dpix, dpiY = dpiy } -findpHYs :: ByteString -> (Integer, Integer) +findpHYs :: ByteString -> Maybe (Integer, Integer) findpHYs x - | B.null x || "IDAT" `B.isPrefixOf` x = (72,72) + | B.null x || "IDAT" `B.isPrefixOf` x = return (72,72) | "pHYs" `B.isPrefixOf` x = - let [x1,x2,x3,x4,y1,y2,y3,y4,u] = - map fromIntegral $ unpack $ B.take 9 $ B.drop 4 x - factor = if u == 1 -- dots per meter - then \z -> z * 254 `div` 10000 - else const 72 - in ( factor $ shift x1 24 + shift x2 16 + shift x3 8 + x4, - factor $ shift y1 24 + shift y2 16 + shift y3 8 + y4 ) + case map fromIntegral $ unpack $ B.take 9 $ B.drop 4 x of + [x1,x2,x3,x4,y1,y2,y3,y4,u] -> do + let factor = if u == 1 -- dots per meter + then \z -> z * 254 `div` 10000 + else const 72 + return + ( factor $ shift x1 24 + shift x2 16 + shift x3 8 + x4, + factor $ shift y1 24 + shift y2 16 + shift y3 8 + y4 ) + _ -> mzero | otherwise = findpHYs $ B.drop 1 x -- read another byte gifSize :: ByteString -> Maybe ImageSize -- cgit v1.2.3 From 0ae79275a980e158c3ac93df79ed33329150b7e0 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 10 Aug 2018 15:17:49 -0700 Subject: Avoid non-exhaustive pattern match. --- src/Text/Pandoc/ImageSize.hs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/ImageSize.hs b/src/Text/Pandoc/ImageSize.hs index 00ab86eab..43d4877a0 100644 --- a/src/Text/Pandoc/ImageSize.hs +++ b/src/Text/Pandoc/ImageSize.hs @@ -410,20 +410,21 @@ jpegSize img = jfifSize :: ByteString -> Either String ImageSize jfifSize rest = - let [dpiDensity,dpix1,dpix2,dpiy1,dpiy2] = map fromIntegral - $ unpack $ B.take 5 $B.drop 9 rest - factor = case dpiDensity of - 1 -> id - 2 -> \x -> x * 254 `div` 10 - _ -> const 72 - dpix = factor (shift dpix1 8 + dpix2) - dpiy = factor (shift dpiy1 8 + dpiy2) - in case findJfifSize rest of - Left msg -> Left msg - Right (w,h) ->Right ImageSize { pxX = w + case map fromIntegral $ unpack $ B.take 5 $ B.drop 9 rest of + [dpiDensity,dpix1,dpix2,dpiy1,dpiy2] -> + let factor = case dpiDensity of + 1 -> id + 2 -> \x -> x * 254 `div` 10 + _ -> const 72 + dpix = factor (shift dpix1 8 + dpix2) + dpiy = factor (shift dpiy1 8 + dpiy2) + in case findJfifSize rest of + Left msg -> Left msg + Right (w,h) -> Right ImageSize { pxX = w , pxY = h , dpiX = dpix , dpiY = dpiy } + _ -> Left "unable to determine JFIF size" findJfifSize :: ByteString -> Either String (Integer,Integer) findJfifSize bs = -- cgit v1.2.3 From 7a1ec21faac7d61782f1595b8bcc671139268e39 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 10 Aug 2018 15:22:10 -0700 Subject: Avoid non-exhaustive pattern matches. --- src/Text/Pandoc/ImageSize.hs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/ImageSize.hs b/src/Text/Pandoc/ImageSize.hs index 43d4877a0..d57f66da5 100644 --- a/src/Text/Pandoc/ImageSize.hs +++ b/src/Text/Pandoc/ImageSize.hs @@ -544,10 +544,12 @@ exifHeader hdr = do let resfactor = case lookup ResolutionUnit allentries of Just (UnsignedShort 1) -> 100 / 254 _ -> 1 - let xres = maybe 72 (\(UnsignedRational x) -> floor $ x * resfactor) - $ lookup XResolution allentries - let yres = maybe 72 (\(UnsignedRational x) -> floor $ x * resfactor) - $ lookup YResolution allentries + let xres = case lookup XResolution allentries of + Just (UnsignedRational x) -> floor (x * resfactor) + _ -> 72 + let yres = case lookup YResolution allentries of + Just (UnsignedRational y) -> floor (y * resfactor) + _ -> 72 return ImageSize{ pxX = wdth , pxY = hght -- cgit v1.2.3 From 84e0b905196fae9924c847741c271f40ed57c83f Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 10 Aug 2018 15:34:10 -0700 Subject: Avoid non-exhaustive pattern match. --- src/Text/Pandoc/Readers/Odt/Generic/Utils.hs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs index 722c30a33..45c6cd58c 100644 --- a/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs +++ b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs @@ -133,9 +133,7 @@ class Lookupable a where -- can be used directly in almost any case. readLookupables :: (Lookupable a) => String -> [(a,String)] readLookupables s = [ (a,rest) | (word,rest) <- lex s, - let result = lookup word lookupTable, - isJust result, - let Just a = result + a <- maybeToList (lookup word lookupTable) ] -- | Very similar to a simple 'lookup' in the 'lookupTable', but with a lexer. -- cgit v1.2.3 From 6003c596d7b348b29dd4f452f504bfd717634fa2 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 10 Aug 2018 15:44:20 -0700 Subject: Avoid non-exhaustive pattern match. --- src/Text/Pandoc/UUID.hs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/UUID.hs b/src/Text/Pandoc/UUID.hs index c1bae7038..60ff269da 100644 --- a/src/Text/Pandoc/UUID.hs +++ b/src/Text/Pandoc/UUID.hs @@ -67,13 +67,14 @@ instance Show UUID where getUUID :: RandomGen g => g -> UUID getUUID gen = - let [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] = take 16 $ randoms gen :: [Word8] - -- set variant - i' = i `setBit` 7 `clearBit` 6 - -- set version (0100 for random) - g' = g `clearBit` 7 `setBit` 6 `clearBit` 5 `clearBit` 4 - in - UUID a b c d e f g' h i' j k l m n o p + case take 16 (randoms gen :: [Word8]) of + [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] -> + -- set variant + let i' = i `setBit` 7 `clearBit` 6 + -- set version (0100 for random) + g' = g `clearBit` 7 `setBit` 6 `clearBit` 5 `clearBit` 4 + in UUID a b c d e f g' h i' j k l m n o p + _ -> error "not enough random numbers for UUID" -- should not happen getRandomUUID :: IO UUID getRandomUUID = getUUID <$> getStdGen -- cgit v1.2.3 From 65aea82a04f6147a5ab952b88f7f16b528bc9c50 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 10 Aug 2018 15:56:43 -0700 Subject: Avoid non-exhaustive pattern match. --- src/Text/Pandoc/Parsing.hs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs index 79022d6f1..cab18b645 100644 --- a/src/Text/Pandoc/Parsing.hs +++ b/src/Text/Pandoc/Parsing.hs @@ -514,22 +514,16 @@ charsInBalanced open close parser = try $ do -- Auxiliary functions for romanNumeral: -lowercaseRomanDigits :: [Char] -lowercaseRomanDigits = ['i','v','x','l','c','d','m'] - -uppercaseRomanDigits :: [Char] -uppercaseRomanDigits = map toUpper lowercaseRomanDigits - -- | Parses a roman numeral (uppercase or lowercase), returns number. romanNumeral :: Stream s m Char => Bool -- ^ Uppercase if true -> ParserT s st m Int romanNumeral upperCase = do - let romanDigits = if upperCase - then uppercaseRomanDigits - else lowercaseRomanDigits - lookAhead $ oneOf romanDigits let [one, five, ten, fifty, hundred, fivehundred, thousand] = - map char romanDigits + map char $ + if upperCase + then ['I','V','X','L','C','D','M'] + else ['i','v','x','l','c','d','m'] + lookAhead $ choice [one, five, ten, fifty, hundred, fivehundred, thousand] thousands <- ((1000 *) . length) <$> many thousand ninehundreds <- option 0 $ try $ hundred >> thousand >> return 900 fivehundreds <- option 0 $ 500 <$ fivehundred -- cgit v1.2.3 From 1e0439710b0bbc54e9e4fa4f9f88ecc4e15b7c5a Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 10 Aug 2018 22:10:07 -0700 Subject: Avoid incomplete pattern patch. --- src/Text/Pandoc/Parsing.hs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs index cab18b645..5d95d0e27 100644 --- a/src/Text/Pandoc/Parsing.hs +++ b/src/Text/Pandoc/Parsing.hs @@ -518,11 +518,14 @@ charsInBalanced open close parser = try $ do romanNumeral :: Stream s m Char => Bool -- ^ Uppercase if true -> ParserT s st m Int romanNumeral upperCase = do - let [one, five, ten, fifty, hundred, fivehundred, thousand] = - map char $ - if upperCase - then ['I','V','X','L','C','D','M'] - else ['i','v','x','l','c','d','m'] + let rchar uc = char $ if upperCase then uc else toLower uc + let one = rchar 'I' + let five = rchar 'V' + let ten = rchar 'X' + let fifty = rchar 'L' + let hundred = rchar 'C' + let fivehundred = rchar 'D' + let thousand = rchar 'M' lookAhead $ choice [one, five, ten, fifty, hundred, fivehundred, thousand] thousands <- ((1000 *) . length) <$> many thousand ninehundreds <- option 0 $ try $ hundred >> thousand >> return 900 -- cgit v1.2.3 From b3c9d94fe036d1c42b1118a43d55a89a2244eaeb Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 10 Aug 2018 22:31:49 -0700 Subject: Avoid non-exhaustive pattern match. --- src/Text/Pandoc/Readers/Txt2Tags.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs index 525e675bf..26dc934a9 100644 --- a/src/Text/Pandoc/Readers/Txt2Tags.hs +++ b/src/Text/Pandoc/Readers/Txt2Tags.hs @@ -575,8 +575,10 @@ symbol = B.str . (:[]) <$> oneOf specialChars getTarget :: T2T String getTarget = do mv <- lookupMeta "target" . stateMeta <$> getState - let MetaString target = fromMaybe (MetaString "html") mv - return target + return $ case mv of + Just (MetaString target) -> target + Just (MetaInlines [Str target]) -> target + _ -> "html" atStart :: T2T () atStart = (sourceColumn <$> getPosition) >>= guard . (== 1) -- cgit v1.2.3 From acf6df1aef337f71612f6d05c8aaa526255b3942 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Sun, 12 Aug 2018 00:38:43 +0200 Subject: Lua: cleanup Lua utils, remove unused functions. --- src/Text/Pandoc/Lua.hs | 16 +++---- src/Text/Pandoc/Lua/Module/Pandoc.hs | 9 ++-- src/Text/Pandoc/Lua/StackInstances.hs | 56 +++++++++++------------ src/Text/Pandoc/Lua/Util.hs | 84 ++++++++++++----------------------- src/Text/Pandoc/Writers/Custom.hs | 14 +++--- 5 files changed, 75 insertions(+), 104 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Lua.hs b/src/Text/Pandoc/Lua.hs index cd7117074..be448cf48 100644 --- a/src/Text/Pandoc/Lua.hs +++ b/src/Text/Pandoc/Lua.hs @@ -34,14 +34,14 @@ module Text.Pandoc.Lua import Prelude import Control.Monad ((>=>)) -import Foreign.Lua (FromLuaStack (peek), Lua, LuaException (..), - Status (OK), ToLuaStack (push)) +import Foreign.Lua (Lua, LuaException (..)) import Text.Pandoc.Class (PandocIO) import Text.Pandoc.Definition (Pandoc) import Text.Pandoc.Lua.Filter (LuaFilter, walkMWithLuaFilter) import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath) import Text.Pandoc.Lua.Util (popValue) import Text.Pandoc.Options (ReaderOptions) + import qualified Foreign.Lua as Lua -- | Run the Lua filter in @filterPath@ for a transformation to target @@ -60,25 +60,23 @@ runLuaFilter' ropts filterPath format pd = do registerScriptPath filterPath top <- Lua.gettop stat <- Lua.dofile filterPath - if stat /= OK - then do - luaErrMsg <- popValue - Lua.throwLuaError luaErrMsg + if stat /= Lua.OK + then Lua.throwTopMessageAsError else do newtop <- Lua.gettop -- Use the returned filters, or the implicitly defined global filter if -- nothing was returned. luaFilters <- if newtop - top >= 1 - then peek (-1) + then Lua.peek Lua.stackTop else Lua.getglobal "_G" *> fmap (:[]) popValue runAll luaFilters pd where registerFormat = do - push format + Lua.push format Lua.setglobal "FORMAT" registerReaderOptions = do - push ropts + Lua.push ropts Lua.setglobal "PANDOC_READER_OPTIONS" runAll :: [LuaFilter] -> Pandoc -> Lua Pandoc diff --git a/src/Text/Pandoc/Lua/Module/Pandoc.hs b/src/Text/Pandoc/Lua/Module/Pandoc.hs index 8cb630d7b..ca337941f 100644 --- a/src/Text/Pandoc/Lua/Module/Pandoc.hs +++ b/src/Text/Pandoc/Lua/Module/Pandoc.hs @@ -42,7 +42,7 @@ import Text.Pandoc.Class (runIO) import Text.Pandoc.Definition (Block, Inline) import Text.Pandoc.Lua.Filter (walkInlines, walkBlocks, LuaFilter) import Text.Pandoc.Lua.StackInstances () -import Text.Pandoc.Lua.Util (addFunction, addValue, loadScriptFromDataDir) +import Text.Pandoc.Lua.Util (addFunction, loadScriptFromDataDir) import Text.Pandoc.Walk (Walkable) import Text.Pandoc.Options (ReaderOptions (readerExtensions)) import Text.Pandoc.Process (pipeProcess) @@ -51,6 +51,7 @@ import Text.Pandoc.Readers (Reader (..), getReader) import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy.Char8 as BSL import qualified Foreign.Lua as Lua +import qualified Text.Pandoc.Lua.Util as LuaUtil -- | Push the "pandoc" on the lua stack. Requires the `list` module to be -- loaded. @@ -114,9 +115,9 @@ instance FromLuaStack PipeError where instance ToLuaStack PipeError where push pipeErr = do Lua.newtable - addValue "command" (pipeErrorCommand pipeErr) - addValue "error_code" (pipeErrorCode pipeErr) - addValue "output" (pipeErrorOutput pipeErr) + LuaUtil.addField "command" (pipeErrorCommand pipeErr) + LuaUtil.addField "error_code" (pipeErrorCode pipeErr) + LuaUtil.addField "output" (pipeErrorOutput pipeErr) pushPipeErrorMetaTable Lua.setmetatable (-2) where diff --git a/src/Text/Pandoc/Lua/StackInstances.hs b/src/Text/Pandoc/Lua/StackInstances.hs index 3298079c5..9c3b40f12 100644 --- a/src/Text/Pandoc/Lua/StackInstances.hs +++ b/src/Text/Pandoc/Lua/StackInstances.hs @@ -44,7 +44,7 @@ import Foreign.Lua (FromLuaStack (peek), Lua, LuaInteger, LuaNumber, StackIndex, ToLuaStack (push), Type (..), throwLuaError, tryLua) import Text.Pandoc.Definition import Text.Pandoc.Extensions (Extensions) -import Text.Pandoc.Lua.Util (getTable, getTag, pushViaConstructor, typeCheck) +import Text.Pandoc.Lua.Util (pushViaConstructor, typeCheck) import Text.Pandoc.Options (ReaderOptions (..), TrackChanges) import Text.Pandoc.Shared (Element (Blk, Sec), safeRead) @@ -62,7 +62,7 @@ instance ToLuaStack Pandoc where instance FromLuaStack Pandoc where peek idx = defineHowTo "get Pandoc value" $ do typeCheck idx Lua.TypeTable - blocks <- getTable idx "blocks" + blocks <- LuaUtil.rawField idx "blocks" meta <- Lua.getfield idx "meta" *> (Lua.peek Lua.stackTop `finally` Lua.pop 1) return $ Pandoc meta blocks @@ -99,12 +99,12 @@ instance ToLuaStack Citation where instance FromLuaStack Citation where peek idx = do - id' <- getTable idx "id" - prefix <- getTable idx "prefix" - suffix <- getTable idx "suffix" - mode <- getTable idx "mode" - num <- getTable idx "note_num" - hash <- getTable idx "hash" + id' <- LuaUtil.rawField idx "id" + prefix <- LuaUtil.rawField idx "prefix" + suffix <- LuaUtil.rawField idx "suffix" + mode <- LuaUtil.rawField idx "mode" + num <- LuaUtil.rawField idx "note_num" + hash <- LuaUtil.rawField idx "hash" return $ Citation id' prefix suffix mode num hash instance ToLuaStack Alignment where @@ -178,7 +178,7 @@ peekMetaValue idx = defineHowTo "get MetaValue" $ do TypeBoolean -> MetaBool <$> peek idx TypeString -> MetaString <$> peek idx TypeTable -> do - tag <- tryLua $ getTag idx + tag <- tryLua $ LuaUtil.getTag idx case tag of Right "MetaBlocks" -> MetaBlocks <$> elementContent Right "MetaBool" -> MetaBool <$> elementContent @@ -220,7 +220,7 @@ pushBlock = \case peekBlock :: StackIndex -> Lua Block peekBlock idx = defineHowTo "get Block value" $ do typeCheck idx Lua.TypeTable - tag <- getTag idx + tag <- LuaUtil.getTag idx case tag of "BlockQuote" -> BlockQuote <$> elementContent "BulletList" -> BulletList <$> elementContent @@ -243,7 +243,7 @@ peekBlock idx = defineHowTo "get Block value" $ do where -- Get the contents of an AST element. elementContent :: FromLuaStack a => Lua a - elementContent = getTable idx "c" + elementContent = LuaUtil.rawField idx "c" -- | Push an inline element to the top of the lua stack. pushInline :: Inline -> Lua () @@ -272,7 +272,7 @@ pushInline = \case peekInline :: StackIndex -> Lua Inline peekInline idx = defineHowTo "get Inline value" $ do typeCheck idx Lua.TypeTable - tag <- getTag idx + tag <- LuaUtil.getTag idx case tag of "Cite" -> uncurry Cite <$> elementContent "Code" -> withAttr Code <$> elementContent @@ -299,7 +299,7 @@ peekInline idx = defineHowTo "get Inline value" $ do where -- Get the contents of an AST element. elementContent :: FromLuaStack a => Lua a - elementContent = getTable idx "c" + elementContent = LuaUtil.rawField idx "c" withAttr :: (Attr -> a -> b) -> (LuaAttr, a) -> b withAttr f (attributes, x) = f (fromLuaAttr attributes) x @@ -321,11 +321,11 @@ instance ToLuaStack Element where push (Blk blk) = push blk push (Sec lvl num attr label contents) = do Lua.newtable - LuaUtil.addValue "level" lvl - LuaUtil.addValue "numbering" num - LuaUtil.addValue "attr" (LuaAttr attr) - LuaUtil.addValue "label" label - LuaUtil.addValue "contents" contents + LuaUtil.addField "level" lvl + LuaUtil.addField "numbering" num + LuaUtil.addField "attr" (LuaAttr attr) + LuaUtil.addField "label" label + LuaUtil.addField "contents" contents pushSecMetaTable Lua.setmetatable (-2) where @@ -333,7 +333,7 @@ instance ToLuaStack Element where pushSecMetaTable = do inexistant <- Lua.newmetatable "PandocElementSec" when inexistant $ do - LuaUtil.addValue "t" "Sec" + LuaUtil.addField "t" "Sec" Lua.push "__index" Lua.pushvalue (-2) Lua.rawset (-3) @@ -367,12 +367,12 @@ instance ToLuaStack ReaderOptions where (stripComments :: Bool) = ro Lua.newtable - LuaUtil.addValue "extensions" extensions - LuaUtil.addValue "standalone" standalone - LuaUtil.addValue "columns" columns - LuaUtil.addValue "tabStop" tabStop - LuaUtil.addValue "indentedCodeClasses" indentedCodeClasses - LuaUtil.addValue "abbreviations" abbreviations - LuaUtil.addValue "defaultImageExtension" defaultImageExtension - LuaUtil.addValue "trackChanges" trackChanges - LuaUtil.addValue "stripComments" stripComments + LuaUtil.addField "extensions" extensions + LuaUtil.addField "standalone" standalone + LuaUtil.addField "columns" columns + LuaUtil.addField "tabStop" tabStop + LuaUtil.addField "indentedCodeClasses" indentedCodeClasses + LuaUtil.addField "abbreviations" abbreviations + LuaUtil.addField "defaultImageExtension" defaultImageExtension + LuaUtil.addField "trackChanges" trackChanges + LuaUtil.addField "stripComments" stripComments diff --git a/src/Text/Pandoc/Lua/Util.hs b/src/Text/Pandoc/Lua/Util.hs index ea9ec2554..c12884a10 100644 --- a/src/Text/Pandoc/Lua/Util.hs +++ b/src/Text/Pandoc/Lua/Util.hs @@ -31,14 +31,11 @@ Lua utility functions. -} module Text.Pandoc.Lua.Util ( getTag - , getTable - , addValue + , rawField + , addField , addFunction - , getRawInt - , setRawInt - , addRawInt + , addValue , typeCheck - , raiseError , popValue , PushViaCall , pushViaCall @@ -51,34 +48,30 @@ import Prelude import Control.Monad (when) import Control.Monad.Catch (finally) import Data.ByteString.Char8 (unpack) -import Foreign.Lua (FromLuaStack (..), NumResults, Lua, NumArgs, StackIndex, - ToLuaStack (..), ToHaskellFunction) -import Foreign.Lua.Api (Status, call, pop, rawget, rawgeti, rawset, rawseti) +import Foreign.Lua (FromLuaStack, Lua, NumArgs, StackIndex, Status, + ToLuaStack, ToHaskellFunction) import Text.Pandoc.Class (readDataFile, runIOorExplode, setUserDataDir) import qualified Foreign.Lua as Lua --- | Adjust the stack index, assuming that @n@ new elements have been pushed on --- the stack. -adjustIndexBy :: StackIndex -> StackIndex -> StackIndex -adjustIndexBy idx n = - if idx < 0 - then idx - n - else idx - -- | Get value behind key from table at given index. -getTable :: (ToLuaStack a, FromLuaStack b) => StackIndex -> a -> Lua b -getTable idx key = do - push key - rawget (idx `adjustIndexBy` 1) +rawField :: FromLuaStack a => StackIndex -> String -> Lua a +rawField idx key = do + absidx <- Lua.absindex idx + Lua.push key + Lua.rawget absidx popValue +-- | Add a value to the table at the top of the stack at a string-index. +addField :: ToLuaStack a => String -> a -> Lua () +addField = addValue + -- | Add a key-value pair to the table at the top of the stack. addValue :: (ToLuaStack a, ToLuaStack b) => a -> b -> Lua () addValue key value = do - push key - push value - rawset (-3) + Lua.push key + Lua.push value + Lua.rawset (Lua.nthFromTop 3) -- | Add a function to the table at the top of the stack, using the given name. addFunction :: ToHaskellFunction a => String -> a -> Lua () @@ -88,22 +81,6 @@ addFunction name fn = do Lua.wrapHaskellFunction Lua.rawset (-3) --- | Get value behind key from table at given index. -getRawInt :: FromLuaStack a => StackIndex -> Int -> Lua a -getRawInt idx key = do - rawgeti idx key - popValue - --- | Set numeric key/value in table at the given index -setRawInt :: ToLuaStack a => StackIndex -> Int -> a -> Lua () -setRawInt idx key value = do - push value - rawseti (idx `adjustIndexBy` 1) key - --- | Set numeric key/value in table at the top of the stack. -addRawInt :: ToLuaStack a => Int -> a -> Lua () -addRawInt = setRawInt (-1) - typeCheck :: StackIndex -> Lua.Type -> Lua () typeCheck idx expected = do actual <- Lua.ltype idx @@ -112,16 +89,11 @@ typeCheck idx expected = do actName <- Lua.typename actual Lua.throwLuaError $ "expected " ++ expName ++ " but got " ++ actName ++ "." -raiseError :: ToLuaStack a => a -> Lua NumResults -raiseError e = do - Lua.push e - fromIntegral <$> Lua.lerror - -- | Get, then pop the value at the top of the stack. popValue :: FromLuaStack a => Lua a popValue = do resOrError <- Lua.peekEither (-1) - pop 1 + Lua.pop 1 case resOrError of Left err -> Lua.throwLuaError err Right x -> return x @@ -136,11 +108,11 @@ instance PushViaCall (Lua ()) where Lua.push fn Lua.rawget Lua.registryindex pushArgs - call num 1 + Lua.call num 1 instance (ToLuaStack a, PushViaCall b) => PushViaCall (a -> b) where pushViaCall' fn pushArgs num x = - pushViaCall' fn (pushArgs *> push x) (num + 1) + pushViaCall' fn (pushArgs *> Lua.push x) (num + 1) -- | Push an value to the stack via a lua function. The lua function is called -- with all arguments that are passed to this function and is expected to return @@ -163,9 +135,9 @@ loadScriptFromDataDir datadir scriptFile = do "Couldn't load '" ++ scriptFile ++ "'.\n" ++ msg -- | Load a string and immediately perform a full garbage collection. This is --- important to keep the program from hanging: If the program contained a call --- to @require@, the a new loader function was created which then become --- garbage. If that function is collected at an inopportune times, i.e. when the +-- important to keep the program from hanging: If the program containes a call +-- to @require@, then a new loader function is created which then becomes +-- garbage. If that function is collected at an inopportune time, i.e. when the -- Lua API is called via a function that doesn't allow calling back into Haskell -- (getraw, setraw, …), then the function's finalizer, and the full program, -- will hang. @@ -182,8 +154,8 @@ dostring' script = do -- metatable. getTag :: StackIndex -> Lua String getTag idx = do - top <- Lua.gettop - hasMT <- Lua.getmetatable idx - push "tag" - if hasMT then Lua.rawget (-2) else Lua.rawget (idx `adjustIndexBy` 1) - peek Lua.stackTop `finally` Lua.settop top + -- push metatable or just the table + Lua.getmetatable idx >>= \hasMT -> when (not hasMT) (Lua.pushvalue idx) + Lua.push "tag" + Lua.rawget (Lua.nthFromTop 2) + Lua.peek Lua.stackTop `finally` Lua.pop 2 diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs index c0940ad78..866df85be 100644 --- a/src/Text/Pandoc/Writers/Custom.hs +++ b/src/Text/Pandoc/Writers/Custom.hs @@ -48,7 +48,7 @@ import Text.Pandoc.Definition import Text.Pandoc.Error import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath) import Text.Pandoc.Lua.StackInstances () -import Text.Pandoc.Lua.Util (addValue, dostring') +import Text.Pandoc.Lua.Util (addField, addValue, dostring') import Text.Pandoc.Options import Text.Pandoc.Templates import qualified Text.Pandoc.UTF8 as UTF8 @@ -82,12 +82,12 @@ instance ToLuaStack (Stringify MetaValue) where instance ToLuaStack (Stringify Citation) where push (Stringify cit) = do createtable 6 0 - addValue "citationId" $ citationId cit - addValue "citationPrefix" . Stringify $ citationPrefix cit - addValue "citationSuffix" . Stringify $ citationSuffix cit - addValue "citationMode" $ show (citationMode cit) - addValue "citationNoteNum" $ citationNoteNum cit - addValue "citationHash" $ citationHash cit + addField "citationId" $ citationId cit + addField "citationPrefix" . Stringify $ citationPrefix cit + addField "citationSuffix" . Stringify $ citationSuffix cit + addField "citationMode" $ show (citationMode cit) + addField "citationNoteNum" $ citationNoteNum cit + addField "citationHash" $ citationHash cit -- | Key-value pair, pushed as a table with @a@ as the only key and @v@ as the -- associated value. -- cgit v1.2.3 From 81131ef5d19052948b4ac12a727e2ceef8a98186 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 12 Aug 2018 21:20:07 +0300 Subject: Muse reader: don't allow digits after closing marker in lightweight markup This change makes reader more compatible with Emacs Muse --- src/Text/Pandoc/Readers/Muse.hs | 4 ++-- test/Tests/Readers/Muse.hs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 4bb34af7e..01f9be41f 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -43,7 +43,7 @@ import Prelude import Control.Monad import Control.Monad.Except (throwError) import Data.Bifunctor -import Data.Char (isLetter) +import Data.Char (isLetter, isDigit) import Data.Default import Data.List (intercalate) import Data.List.Split (splitOn) @@ -841,7 +841,7 @@ enclosedInlines :: (PandocMonad m, Show a, Show b) -> MuseParser m b -> MuseParser m (F Inlines) enclosedInlines start end = try $ - trimInlinesF . mconcat <$> (enclosed (atStart start) end inline <* notFollowedBy (satisfy isLetter)) + trimInlinesF . mconcat <$> (enclosed (atStart start) end inline <* notFollowedBy (satisfy ((||) <$> isLetter <*> isDigit))) -- | Parse an inline tag, such as @\@ and @\@. inlineTag :: PandocMonad m diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs index fe25e9c5d..1035fb5f1 100644 --- a/test/Tests/Readers/Muse.hs +++ b/test/Tests/Readers/Muse.hs @@ -74,6 +74,10 @@ tests = "Foo x*bar* baz" =?> para "Foo x*bar* baz" + , "Digit after closing *" =: + "Foo *bar*0 baz" =?> + para "Foo *bar*0 baz" + , "Emphasis tag" =: "Foo bar" =?> para (emph . spcSep $ ["Foo", "bar"]) -- cgit v1.2.3 From 6d14f53bd96f123acb5d8030cf9402ddb2e41f01 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 12 Aug 2018 16:45:44 -0700 Subject: LaTeX reader: Allow `%` characters in URLs. This affects `\href` and `\url`. Closes #4832. --- src/Text/Pandoc/Readers/LaTeX.hs | 44 ++++++++++++++++++++++++++++------------ test/command/4832.md | 21 +++++++++++++++++++ 2 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 test/command/4832.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 1dd31d402..e9869290f 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -615,21 +615,28 @@ grouped parser = try $ do -- {{a,b}} should be parsed the same as {a,b} try (grouped parser <* egroup) <|> (mconcat <$> manyTill parser egroup) -braced :: PandocMonad m => LP m [Tok] -braced = bgroup *> braced' 1 - where braced' (n :: Int) = - handleEgroup n <|> handleBgroup n <|> handleOther n - handleEgroup n = do +braced' :: PandocMonad m => LP m Tok -> Int -> LP m [Tok] +braced' getTok n = + handleEgroup <|> handleBgroup <|> handleOther + where handleEgroup = do t <- egroup if n == 1 then return [] - else (t:) <$> braced' (n - 1) - handleBgroup n = do + else (t:) <$> braced' getTok (n - 1) + handleBgroup = do t <- bgroup - (t:) <$> braced' (n + 1) - handleOther n = do - t <- anyTok - (t:) <$> braced' n + (t:) <$> braced' getTok (n + 1) + handleOther = do + t <- getTok + (t:) <$> braced' getTok n + +braced :: PandocMonad m => LP m [Tok] +braced = bgroup *> braced' anyTok 1 + +-- URLs require special handling, because they can contain % +-- characters. So we retonenize comments as we go... +bracedUrl :: PandocMonad m => LP m [Tok] +bracedUrl = bgroup *> braced' (retokenizeComment >> anyTok) 1 bracketed :: PandocMonad m => Monoid a => LP m a -> LP m a bracketed parser = try $ do @@ -1290,6 +1297,17 @@ unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs unescapeURL (x:xs) = x:unescapeURL xs unescapeURL [] = "" +-- For handling URLs, which allow literal % characters... +retokenizeComment :: PandocMonad m => LP m () +retokenizeComment = (do + Tok pos Comment txt <- satisfyTok isCommentTok + let updPos (Tok pos' toktype' txt') = + Tok (incSourceColumn (incSourceLine pos' (sourceLine pos - 1)) + (sourceColumn pos)) toktype' txt' + let newtoks = map updPos $ tokenize (sourceName pos) $ T.tail txt + getInput >>= setInput . ((Tok pos Symbol "%" : newtoks) ++)) + <|> return () + mathEnvWith :: PandocMonad m => (Inlines -> a) -> Maybe Text -> Text -> LP m a mathEnvWith f innerEnv name = f . mathDisplay . inner <$> mathEnv name @@ -1445,10 +1463,10 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("verb", doverb) , ("lstinline", dolstinline) , ("Verb", doverb) - , ("url", ((unescapeURL . T.unpack . untokenize) <$> braced) >>= \url -> + , ("url", ((unescapeURL . T.unpack . untokenize) <$> bracedUrl) >>= \url -> pure (link url "" (str url))) , ("href", (unescapeURL . toksToString <$> - braced <* optional sp) >>= \url -> + bracedUrl <* optional sp) >>= \url -> tok >>= \lab -> pure (link url "" lab)) , ("includegraphics", do options <- option [] keyvals src <- unescapeURL . T.unpack . diff --git a/test/command/4832.md b/test/command/4832.md new file mode 100644 index 000000000..9ba40804c --- /dev/null +++ b/test/command/4832.md @@ -0,0 +1,21 @@ +``` +% pandoc -f latex -t native +\url{http://example.com/foo%20bar.htm} +^D +[Para [Link ("",[],[]) [Str "http://example.com/foo%20bar.htm"] ("http://example.com/foo%20bar.htm","")]] +``` + +``` +% pandoc -f latex -t native +\url{http://example.com/foo{bar}.htm} +^D +[Para [Link ("",[],[]) [Str "http://example.com/foo{bar}.htm"] ("http://example.com/foo{bar}.htm","")]] +``` + +``` +% pandoc -f latex -t native +\href{http://example.com/foo%20bar}{Foobar} +^D +[Para [Link ("",[],[]) [Str "Foobar"] ("http://example.com/foo%20bar","")]] +``` + -- cgit v1.2.3 From c3f17cb0d7d590c828214deda1d58e65da1b3812 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 13 Aug 2018 11:00:28 -0700 Subject: RST writer: use `.. container` for generic Divs, instead of raw HTML. --- src/Text/Pandoc/Writers/RST.hs | 14 +++++--- test/writer.rst | 82 ++++++++---------------------------------- 2 files changed, 24 insertions(+), 72 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index 566bcbeef..7a299e4e9 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -211,11 +211,17 @@ blockToRST :: PandocMonad m => Block -- ^ Block element -> RST m Doc blockToRST Null = return empty -blockToRST (Div attr bs) = do +blockToRST (Div (ident,classes,_kvs) bs) = do contents <- blockListToRST bs - let startTag = ".. raw:: html" $+$ nest 3 (tagWithAttrs "div" attr) - let endTag = ".. raw:: html" $+$ nest 3 "" - return $ blankline <> startTag $+$ contents $+$ endTag $$ blankline + let classes' = filter (/= "container") classes + return $ blankline $$ + (".. container::" <> space <> + text (unwords classes')) $$ + (if null ident + then blankline + else " :name: " <> text ident $$ blankline) $$ + nest 3 contents $$ + blankline blockToRST (Plain inlines) = inlineListToRST inlines -- title beginning with fig: indicates that the image is a figure blockToRST (Para [Image attr txt (src,'f':'i':'g':':':tit)]) = do diff --git a/test/writer.rst b/test/writer.rst index 0c986b887..b47490de2 100644 --- a/test/writer.rst +++ b/test/writer.rst @@ -385,53 +385,23 @@ HTML Blocks Simple block on one line: -.. raw:: html - -
- -foo +.. container:: -.. raw:: html - -
+ foo And nested without indentation: -.. raw:: html - -
- -.. raw:: html - -
- -.. raw:: html - -
- -foo - -.. raw:: html - -
- -.. raw:: html - -
+.. container:: -.. raw:: html + .. container:: -
+ .. container:: -bar + foo -.. raw:: html + .. container:: -
- -.. raw:: html - -
+ bar Interpreted markdown in a table: @@ -477,15 +447,9 @@ And this is **strong** Here’s a simple block: -.. raw:: html - -
- -foo - -.. raw:: html +.. container:: -
+ foo This should be a code block, though: @@ -503,31 +467,13 @@ As should this: Now, nested: -.. raw:: html - -
+.. container:: -.. raw:: html + .. container:: -
+ .. container:: -.. raw:: html - -
- -foo - -.. raw:: html - -
- -.. raw:: html - -
- -.. raw:: html - -
+ foo This should just be an HTML comment: -- cgit v1.2.3 From 919c50162ccc3d7a347a9427ca23887e54e8a333 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 13 Aug 2018 11:12:16 -0700 Subject: RST writer: render Divs with admonition classes as admonitions. Also omit Div with class "admonition-title". These are generated by the RST reader and should be omitted on round-trip. Closes #4833. --- src/Text/Pandoc/Writers/RST.hs | 15 ++++++++++++--- test/command/4833.md | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 test/command/4833.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index 7a299e4e9..005db5e77 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -211,12 +211,21 @@ blockToRST :: PandocMonad m => Block -- ^ Block element -> RST m Doc blockToRST Null = return empty +blockToRST (Div ("",["admonition-title"],[]) _) = return empty + -- this is generated by the rst reader and can safely be + -- omitted when we're generating rst blockToRST (Div (ident,classes,_kvs) bs) = do contents <- blockListToRST bs - let classes' = filter (/= "container") classes + let admonitions = ["attention","caution","danger","error","hint", + "important","note","tip","warning","admonition"] + let admonition = case classes of + (cl:_) + | cl `elem` admonitions + -> ".. " <> text cl <> "::" + cls -> ".. container::" <> space <> + text (unwords (filter (/= "container") cls)) return $ blankline $$ - (".. container::" <> space <> - text (unwords classes')) $$ + admonition $$ (if null ident then blankline else " :name: " <> text ident $$ blankline) $$ diff --git a/test/command/4833.md b/test/command/4833.md new file mode 100644 index 000000000..ed6de606b --- /dev/null +++ b/test/command/4833.md @@ -0,0 +1,20 @@ +``` +pandoc -f native -t rst +[Div ("",["warning"],[]) + [Div ("",["admonition-title"],[]) + [Para [Str "Warning"]] + ,Para [Str "Hi"]]] +^D +.. warning:: + + Hi +``` +``` +pandoc -f native -t rst +[Div ("",["unknown"],[]) + [Para [Str "Hi"]]] +^D +.. container:: unknown + + Hi +``` -- cgit v1.2.3 From c27ce1e70e72302d6cdc05ad59f45d0d04bda363 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 14 Aug 2018 00:03:55 -0700 Subject: LaTeX reader: handle parameter patterns for `\def`. For example: `\def\foo#1[#2]{#1 and #2}`. Closes #4768. Also fixes #4771. API change: in Text.Pandoc.Readers.LaTeX.Types, new type ArgSpec added. Second parameter of Macro constructor is now `[ArgSpec]` instead of `Int`. --- src/Text/Pandoc/Readers/LaTeX.hs | 67 +++++++++++++++++++++++----------- src/Text/Pandoc/Readers/LaTeX/Types.hs | 6 ++- test/command/4768.md | 7 ++++ 3 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 test/command/4768.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index e9869290f..3006e7326 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -71,7 +71,7 @@ import Text.Pandoc.Options import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline, optional, space, spaces, withRaw, (<|>)) import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..), - Tok (..), TokType (..)) + ArgSpec (..), Tok (..), TokType (..)) import Text.Pandoc.Shared import qualified Text.Pandoc.Translations as Translations import Text.Pandoc.Walk @@ -473,21 +473,38 @@ doMacros n = do macros <- sMacros <$> getState case M.lookup name macros of Nothing -> return () - Just (Macro expansionPoint numargs optarg newtoks) -> do + Just (Macro expansionPoint argspecs optarg newtoks) -> do setInput ts - let getarg = try $ spaces >> bracedOrToken + let matchTok (Tok _ toktype txt) = + satisfyTok (\(Tok _ toktype' txt') -> + toktype == toktype' && + txt == txt') + let matchPattern toks = try $ mapM_ matchTok toks + let getargs argmap [] = return argmap + getargs argmap (Pattern toks : rest) = try $ do + matchPattern toks + getargs argmap rest + getargs argmap (ArgNum i : Pattern toks : rest) = + try $ do + x <- mconcat <$> manyTill + (braced <|> ((:[]) <$> anyTok)) + (matchPattern toks) + getargs (M.insert i x argmap) rest + getargs argmap (ArgNum i : rest) = do + x <- try $ spaces >> bracedOrToken + getargs (M.insert i x argmap) rest args <- case optarg of - Nothing -> count numargs getarg - Just o -> - (:) <$> option o bracketedToks - <*> count (numargs - 1) getarg + Nothing -> getargs M.empty argspecs + Just o -> do + x <- option o bracketedToks + getargs (M.singleton 1 x) argspecs -- first boolean param is true if we're tokenizing -- an argument (in which case we don't want to -- expand #1 etc.) - let addTok False (Tok _ (Arg i) _) acc | i > 0 - , i <= numargs = - foldr (addTok True) acc (args !! (i - 1)) - -- add space if needed after control sequence + let addTok False (Tok _ (Arg i) _) acc = + case M.lookup i args of + Nothing -> mzero + Just xs -> foldr (addTok True) acc xs -- see #4007 addTok _ (Tok _ (CtrlSeq x) txt) acc@(Tok _ Word _ : _) @@ -2148,24 +2165,28 @@ letmacro = do optional $ symbol '=' spaces contents <- bracedOrToken - return (name, Macro ExpandWhenDefined 0 Nothing contents) + return (name, Macro ExpandWhenDefined [] Nothing contents) defmacro :: PandocMonad m => LP m (Text, Macro) defmacro = try $ do controlSeq "def" Tok _ (CtrlSeq name) _ <- anyControlSeq - numargs <- option 0 $ argSeq 1 + argspecs <- many (argspecArg <|> argspecPattern) -- we use withVerbatimMode, because macros are to be expanded -- at point of use, not point of definition contents <- withVerbatimMode bracedOrToken - return (name, Macro ExpandWhenUsed numargs Nothing contents) + return (name, Macro ExpandWhenUsed argspecs Nothing contents) --- Note: we don't yet support fancy things like #1.#2 -argSeq :: PandocMonad m => Int -> LP m Int -argSeq n = do +argspecArg :: PandocMonad m => LP m ArgSpec +argspecArg = do Tok _ (Arg i) _ <- satisfyTok isArgTok - guard $ i == n - argSeq (n+1) <|> return n + return $ ArgNum i + +argspecPattern :: PandocMonad m => LP m ArgSpec +argspecPattern = + Pattern <$> many1 (satisfyTok (\(Tok _ toktype' txt) -> + (toktype' == Symbol || toktype' == Word) && + (txt /= "{" && txt /= "\\" && txt /= "}"))) isArgTok :: Tok -> Bool isArgTok (Tok _ (Arg _) _) = True @@ -2186,6 +2207,7 @@ newcommand = do (symbol '{' *> spaces *> anyControlSeq <* spaces <* symbol '}') spaces numargs <- option 0 $ try bracketedNum + let argspecs = map (\i -> ArgNum i) [1..numargs] spaces optarg <- option Nothing $ Just <$> try bracketedToks spaces @@ -2195,7 +2217,7 @@ newcommand = do case M.lookup name macros of Just _ -> report $ MacroAlreadyDefined (T.unpack txt) pos Nothing -> return () - return (name, Macro ExpandWhenUsed numargs optarg contents) + return (name, Macro ExpandWhenUsed argspecs optarg contents) newenvironment :: PandocMonad m => LP m (Text, Macro, Macro) newenvironment = do @@ -2208,6 +2230,7 @@ newenvironment = do name <- untokenize <$> braced spaces numargs <- option 0 $ try bracketedNum + let argspecs = map (\i -> ArgNum i) [1..numargs] spaces optarg <- option Nothing $ Just <$> try bracketedToks spaces @@ -2219,8 +2242,8 @@ newenvironment = do case M.lookup name macros of Just _ -> report $ MacroAlreadyDefined (T.unpack name) pos Nothing -> return () - return (name, Macro ExpandWhenUsed numargs optarg startcontents, - Macro ExpandWhenUsed 0 Nothing endcontents) + return (name, Macro ExpandWhenUsed argspecs optarg startcontents, + Macro ExpandWhenUsed [] Nothing endcontents) bracketedToks :: PandocMonad m => LP m [Tok] bracketedToks = do diff --git a/src/Text/Pandoc/Readers/LaTeX/Types.hs b/src/Text/Pandoc/Readers/LaTeX/Types.hs index fa832114b..e3a302d49 100644 --- a/src/Text/Pandoc/Readers/LaTeX/Types.hs +++ b/src/Text/Pandoc/Readers/LaTeX/Types.hs @@ -31,6 +31,7 @@ Types for LaTeX tokens and macros. module Text.Pandoc.Readers.LaTeX.Types ( Tok(..) , TokType(..) , Macro(..) + , ArgSpec(..) , ExpansionPoint(..) , SourcePos ) @@ -49,5 +50,8 @@ data Tok = Tok SourcePos TokType Text data ExpansionPoint = ExpandWhenDefined | ExpandWhenUsed deriving (Eq, Ord, Show) -data Macro = Macro ExpansionPoint Int (Maybe [Tok]) [Tok] +data Macro = Macro ExpansionPoint [ArgSpec] (Maybe [Tok]) [Tok] + deriving Show + +data ArgSpec = ArgNum Int | Pattern [Tok] deriving Show diff --git a/test/command/4768.md b/test/command/4768.md new file mode 100644 index 000000000..60d407d8b --- /dev/null +++ b/test/command/4768.md @@ -0,0 +1,7 @@ +``` +% pandoc -f latex -t plain +\def\foo#1!#2!#3{#1 or #2 and #3} +\foo aa!bbb bbb!{ccc} +^D +aa or bbb bbb and ccc +``` -- cgit v1.2.3 From dae3a09433b54d7a7c9276b41f17cbc5e144afcc Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 14 Aug 2018 11:52:14 -0700 Subject: ODT reader: deal gracefully with missing ``. This allows pandoc to parse ODT document produced by KDE's Calligra. Closes #4336. --- src/Text/Pandoc/Readers/Odt/StyleReader.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Odt/StyleReader.hs b/src/Text/Pandoc/Readers/Odt/StyleReader.hs index fa5c2d142..6a1682829 100644 --- a/src/Text/Pandoc/Readers/Odt/StyleReader.hs +++ b/src/Text/Pandoc/Readers/Odt/StyleReader.hs @@ -138,7 +138,7 @@ fontPitchReader = executeIn NsOffice "font-face-decls" ( lookupDefaultingAttr NsStyle "font-pitch" )) >>?^ ( M.fromList . foldl accumLegalPitches [] ) - ) + ) `ifFailedDo` (returnV (Right M.empty)) where accumLegalPitches ls (Nothing,_) = ls accumLegalPitches ls (Just n,p) = (n,p):ls -- cgit v1.2.3 From 13dea94a9128a4caf3fb820bb21cd8176465c82e Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 15 Aug 2018 10:25:12 -0700 Subject: Markdown reader: Use "tex" instead of "latex" for raw tex-ish content. We can't always tell if it's LaTeX, ConTeXt, or plain TeX. Better just to use "tex" always. Also changed: ConTeXt writer: now outputs raw "tex" blocks as well as "context". (Closes #969). RST writer: uses ".. raw:: latex" for "tex" content. (RST doesn't support raw context anyway.) Note that if "context" or "latex" specifically is desired, you can still force that in a markdown document by using the raw attribute (see MANUAL.txt): ```{=latex} \foo ``` Note that this change may affect some filters, if they assume that raw tex parsed by the Markdown reader will be RawBlock (Format "latex"). In most cases it should be trivial to modify the filters to accept "tex" as well. --- src/Text/Pandoc/Readers/Markdown.hs | 10 +++------- src/Text/Pandoc/Writers/ConTeXt.hs | 15 ++++++--------- src/Text/Pandoc/Writers/RST.hs | 1 + test/command/3558.md | 4 ++-- test/command/3804.md | 2 +- test/command/3947.md | 2 +- test/command/4056.md | 2 +- test/command/4159.md | 2 +- test/command/4781.md | 2 +- test/command/adjacent_latex_blocks.md | 4 ++-- test/command/hspace.md | 6 +++--- test/command/write18.md | 2 +- test/markdown-reader-more.native | 9 +++++---- test/testsuite.native | 2 +- test/writer.context | 6 ++++++ test/writer.muse | 2 +- test/writer.native | 2 +- 17 files changed, 37 insertions(+), 36 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index c4e8a6524..a81942a9e 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -1143,10 +1143,9 @@ rawTeXBlock :: PandocMonad m => MarkdownParser m (F Blocks) rawTeXBlock = do guardEnabled Ext_raw_tex lookAhead $ try $ char '\\' >> letter - result <- (B.rawBlock "context" . trim . concat <$> - many1 ((++) <$> (rawConTeXtEnvironment <|> conTeXtCommand) - <*> spnl')) - <|> (B.rawBlock "latex" . trim . concat <$> + result <- (B.rawBlock "tex" . trim . concat <$> + many1 ((++) <$> rawConTeXtEnvironment <*> spnl')) + <|> (B.rawBlock "tex" . trim . concat <$> many1 ((++) <$> rawLaTeXBlock <*> spnl')) return $ case B.toList result of [RawBlock _ cs] @@ -1154,9 +1153,6 @@ rawTeXBlock = do -- don't create a raw block for suppressed macro defs _ -> return result -conTeXtCommand :: PandocMonad m => MarkdownParser m String -conTeXtCommand = oneOfStrings ["\\placeformula"] - rawHtmlBlocks :: PandocMonad m => MarkdownParser m (F Blocks) rawHtmlBlocks = do (TagOpen tagtype _, raw) <- htmlTag isBlockTag diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs index 10e996bdb..594812294 100644 --- a/src/Text/Pandoc/Writers/ConTeXt.hs +++ b/src/Text/Pandoc/Writers/ConTeXt.hs @@ -190,10 +190,9 @@ blockToConTeXt (BlockQuote lst) = do blockToConTeXt (CodeBlock _ str) = return $ flush ("\\starttyping" <> cr <> text str <> cr <> "\\stoptyping") $$ blankline -- blankline because \stoptyping can't have anything after it, inc. '}' -blockToConTeXt (RawBlock "context" str) = return $ text str <> blankline -blockToConTeXt b@(RawBlock _ _ ) = do - report $ BlockNotRendered b - return empty +blockToConTeXt b@(RawBlock f str) + | f == Format "context" || f == Format "tex" = return $ text str <> blankline + | otherwise = empty <$ report (BlockNotRendered b) blockToConTeXt (Div (ident,_,kvs) bs) = do let align dir txt = "\\startalignment[" <> dir <> "]" $$ txt $$ "\\stopalignment" mblang <- fromBCP47 (lookup "lang" kvs) @@ -401,11 +400,9 @@ inlineToConTeXt (Math InlineMath str) = return $ char '$' <> text str <> char '$' inlineToConTeXt (Math DisplayMath str) = return $ text "\\startformula " <> text str <> text " \\stopformula" <> space -inlineToConTeXt (RawInline "context" str) = return $ text str -inlineToConTeXt (RawInline "tex" str) = return $ text str -inlineToConTeXt il@(RawInline _ _) = do - report $ InlineNotRendered il - return empty +inlineToConTeXt il@(RawInline f str) + | f == Format "tex" || f == Format "context" = return $ text str + | otherwise = empty <$ report (InlineNotRendered il) inlineToConTeXt LineBreak = return $ text "\\crlf" <> cr inlineToConTeXt SoftBreak = do wrapText <- gets (writerWrapText . stOptions) diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index 005db5e77..b416eca59 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -253,6 +253,7 @@ blockToRST (LineBlock lns) = linesToLineBlock lns blockToRST (RawBlock f@(Format f') str) | f == "rst" = return $ text str + | f == "tex" = blockToRST (RawBlock (Format "latex") str) | otherwise = return $ blankline <> ".. raw:: " <> text (map toLower f') $+$ nest 3 (text str) $$ blankline diff --git a/test/command/3558.md b/test/command/3558.md index 795858b78..956b09e57 100644 --- a/test/command/3558.md +++ b/test/command/3558.md @@ -6,7 +6,7 @@ hello \endmulti ^D -[RawBlock (Format "latex") "\\multi" +[RawBlock (Format "tex") "\\multi" ,Para [Str "hello"] -,RawBlock (Format "latex") "\\endmulti"] +,RawBlock (Format "tex") "\\endmulti"] ``` diff --git a/test/command/3804.md b/test/command/3804.md index c13c2ef42..520d408df 100644 --- a/test/command/3804.md +++ b/test/command/3804.md @@ -2,5 +2,5 @@ % pandoc -t native \titleformat{\chapter}[display]{\normalfont\large\bfseries}{第\thechapter{}章}{20pt}{\Huge} ^D -[RawBlock (Format "latex") "\\titleformat{\\chapter}[display]{\\normalfont\\large\\bfseries}{\31532\\thechapter{}\31456}{20pt}{\\Huge}"] +[RawBlock (Format "tex") "\\titleformat{\\chapter}[display]{\\normalfont\\large\\bfseries}{\31532\\thechapter{}\31456}{20pt}{\\Huge}"] ``` diff --git a/test/command/3947.md b/test/command/3947.md index 7ce0be171..b1d695fbd 100644 --- a/test/command/3947.md +++ b/test/command/3947.md @@ -6,6 +6,6 @@ Another Code block ^D -[RawBlock (Format "latex") "\\newpage" +[RawBlock (Format "tex") "\\newpage" ,CodeBlock ("",[],[]) "Code block\n\nAnother Code block"] ``` diff --git a/test/command/4056.md b/test/command/4056.md index eed4f6d6a..e972931dd 100644 --- a/test/command/4056.md +++ b/test/command/4056.md @@ -5,7 +5,7 @@ \end{shaded} } ^D -[RawBlock (Format "latex") "\\parbox[t]{0.4\\textwidth}{\n\\begin{shaded}\n\\end{shaded}\n}"] +[RawBlock (Format "tex") "\\parbox[t]{0.4\\textwidth}{\n\\begin{shaded}\n\\end{shaded}\n}"] ``` ``` diff --git a/test/command/4159.md b/test/command/4159.md index 4881edcc5..d61959950 100644 --- a/test/command/4159.md +++ b/test/command/4159.md @@ -3,6 +3,6 @@ \newcommand{\gen}{a\ Gen\ b} abc ^D -[RawBlock (Format "latex") "\\newcommand{\\gen}{a\\ Gen\\ b}" +[RawBlock (Format "tex") "\\newcommand{\\gen}{a\\ Gen\\ b}" ,Para [Str "abc"]] ``` diff --git a/test/command/4781.md b/test/command/4781.md index 7dc973c7c..8a75e09a0 100644 --- a/test/command/4781.md +++ b/test/command/4781.md @@ -7,7 +7,7 @@ Markdown parsed *here* *But not here* ^D [Para [Str "Markdown",Space,Str "parsed",Space,Emph [Str "here"]] -,RawBlock (Format "latex") "\\include{command/bar}" +,RawBlock (Format "tex") "\\include{command/bar}" ,Para [Emph [Str "But",Space,Str "not",Space,Str "here"]]] ``` diff --git a/test/command/adjacent_latex_blocks.md b/test/command/adjacent_latex_blocks.md index 3e72f1d4f..e7dc6d895 100644 --- a/test/command/adjacent_latex_blocks.md +++ b/test/command/adjacent_latex_blocks.md @@ -4,6 +4,6 @@ \listoftables ^D -[RawBlock (Format "latex") "\\listoffigures" -,RawBlock (Format "latex") "\\listoftables"] +[RawBlock (Format "tex") "\\listoffigures" +,RawBlock (Format "tex") "\\listoftables"] ``` diff --git a/test/command/hspace.md b/test/command/hspace.md index ec1669ca5..a8b97b8bc 100644 --- a/test/command/hspace.md +++ b/test/command/hspace.md @@ -8,7 +8,7 @@ Here they need to be inline: \caption{lalune \hspace{2em} \vspace{1em} bloo} \end{figure} ^D -[RawBlock (Format "latex") "\\begin{figure}\n\\includegraphics{lalune.jpg}\n\\caption{lalune \\hspace{2em} \\vspace{1em} bloo}\n\\end{figure}"] +[RawBlock (Format "tex") "\\begin{figure}\n\\includegraphics{lalune.jpg}\n\\caption{lalune \\hspace{2em} \\vspace{1em} bloo}\n\\end{figure}"] ``` Here block: @@ -32,7 +32,7 @@ F & T &\\ F & F &\\ \end{tabular} ^D -[RawBlock (Format "latex") "\\begin{tabular}[t]{cc|c}\n\\(P\\) & \\(Q\\) & \\(P\\wedge Q\\)\\\\\n\\hline\nT & T &\\\\\nT & F &\\\\\nF & T &\\\\\nF & F &\\\\\n\\end{tabular}\n\\hspace{1em}\n\\begin{tabular}[t]{cc|c}\n\\(P\\) & \\(Q\\) & \\(P\\vee Q\\)\\\\\n\\hline\nT & T &\\\\\nT & F &\\\\\nF & T &\\\\\nF & F &\\\\\n\\end{tabular}"] +[RawBlock (Format "tex") "\\begin{tabular}[t]{cc|c}\n\\(P\\) & \\(Q\\) & \\(P\\wedge Q\\)\\\\\n\\hline\nT & T &\\\\\nT & F &\\\\\nF & T &\\\\\nF & F &\\\\\n\\end{tabular}\n\\hspace{1em}\n\\begin{tabular}[t]{cc|c}\n\\(P\\) & \\(Q\\) & \\(P\\vee Q\\)\\\\\n\\hline\nT & T &\\\\\nT & F &\\\\\nF & T &\\\\\nF & F &\\\\\n\\end{tabular}"] ``` ``` @@ -51,6 +51,6 @@ hi there ^D [Para [Str "hi"] -,RawBlock (Format "latex") "\\hspace{1em}" +,RawBlock (Format "tex") "\\hspace{1em}" ,Para [Str "there"]] ``` diff --git a/test/command/write18.md b/test/command/write18.md index 344dfc8cf..5000c298b 100644 --- a/test/command/write18.md +++ b/test/command/write18.md @@ -3,7 +3,7 @@ Handle \write18{..} as raw tex: % pandoc -t native \write18{git --version} ^D -[RawBlock (Format "latex") "\\write18{git --version}"] +[RawBlock (Format "tex") "\\write18{git --version}"] ``` ``` diff --git a/test/markdown-reader-more.native b/test/markdown-reader-more.native index 17e91bb89..799f4ffa7 100644 --- a/test/markdown-reader-more.native +++ b/test/markdown-reader-more.native @@ -3,10 +3,11 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "Author",S ,Header 2 ("blank-line-before-url-in-link-reference",[],[]) [Str "Blank",Space,Str "line",Space,Str "before",Space,Str "URL",Space,Str "in",Space,Str "link",Space,Str "reference"] ,Para [Link ("",[],[]) [Str "foo"] ("/url",""),Space,Str "and",Space,Link ("",[],[]) [Str "bar"] ("/url","title")] ,Header 2 ("raw-context-environments",[],[]) [Str "Raw",Space,Str "ConTeXt",Space,Str "environments"] -,RawBlock (Format "context") "\\placeformula \\startformula\n L_{1} = L_{2}\n \\stopformula" -,RawBlock (Format "context") "\\start[a2]\n\\start[a2]\n\\stop[a2]\n\\stop[a2]" +,RawBlock (Format "tex") "\\placeformula \\startformula" +,Para [Str "L_{1}",Space,Str "=",Space,Str "L_{2}",SoftBreak,RawInline (Format "tex") "\\stopformula"] +,RawBlock (Format "tex") "\\start[a2]\n\\start[a2]\n\\stop[a2]\n\\stop[a2]" ,Header 2 ("raw-latex-environments",[],[]) [Str "Raw",Space,Str "LaTeX",Space,Str "environments"] -,RawBlock (Format "latex") "\\begin{center}\n\\begin{tikzpicture}[baseline={([yshift=+-.5ex]current bounding box.center)}, level distance=24pt]\n\\Tree [.{S} [.NP John\\index{i} ] [.VP [.V likes ] [.NP himself\\index{i,*j} ]]]\n\\end{tikzpicture}\n\\end{center}" +,RawBlock (Format "tex") "\\begin{center}\n\\begin{tikzpicture}[baseline={([yshift=+-.5ex]current bounding box.center)}, level distance=24pt]\n\\Tree [.{S} [.NP John\\index{i} ] [.VP [.V likes ] [.NP himself\\index{i,*j} ]]]\n\\end{tikzpicture}\n\\end{center}" ,Header 2 ("urls-with-spaces-and-punctuation",[],[]) [Str "URLs",Space,Str "with",Space,Str "spaces",Space,Str "and",Space,Str "punctuation"] ,Para [Link ("",[],[]) [Str "foo"] ("/bar%20and%20baz",""),SoftBreak,Link ("",[],[]) [Str "foo"] ("/bar%20and%20baz",""),SoftBreak,Link ("",[],[]) [Str "foo"] ("/bar%20and%20baz",""),SoftBreak,Link ("",[],[]) [Str "foo"] ("bar%20baz","title")] ,Para [Link ("",[],[]) [Str "baz"] ("/foo%20foo",""),Space,Link ("",[],[]) [Str "bam"] ("/foo%20fee",""),Space,Link ("",[],[]) [Str "bork"] ("/foo/zee%20zob","title")] @@ -55,7 +56,7 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "Author",S ,OrderedList (3,Example,TwoParens) [[Plain [Str "Third",Space,Str "example."]]] ,Header 2 ("macros",[],[]) [Str "Macros"] -,RawBlock (Format "latex") "\\newcommand{\\tuple}[1]{\\langle #1 \\rangle}" +,RawBlock (Format "tex") "\\newcommand{\\tuple}[1]{\\langle #1 \\rangle}" ,Para [Math InlineMath "\\langle x,y \\rangle"] ,Header 2 ("case-insensitive-references",[],[]) [Str "Case-insensitive",Space,Str "references"] ,Para [Link ("",[],[]) [Str "Fum"] ("/fum","")] diff --git a/test/testsuite.native b/test/testsuite.native index 0587bddb8..fcd189eb0 100644 --- a/test/testsuite.native +++ b/test/testsuite.native @@ -324,7 +324,7 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa ,[Plain [Str "Shoes",Space,Str "($20)",Space,Str "and",Space,Str "socks",Space,Str "($5)."]] ,[Plain [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."]]] ,Para [Str "Here\8217s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"] -,RawBlock (Format "latex") "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}" +,RawBlock (Format "tex") "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}" ,HorizontalRule ,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"] ,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"] diff --git a/test/writer.context b/test/writer.context index bb69f4e43..d6a36f0dd 100644 --- a/test/writer.context +++ b/test/writer.context @@ -706,6 +706,12 @@ These shouldn't be math: Here's a LaTeX table: +\begin{tabular}{|l|l|}\hline +Animal & Number \\ \hline +Dog & 2 \\ +Cat & 1 \\ \hline +\end{tabular} + \thinrule \section[title={Special Characters},reference={special-characters}] diff --git a/test/writer.muse b/test/writer.muse index 9492a5517..5993ec357 100644 --- a/test/writer.muse +++ b/test/writer.muse @@ -534,7 +534,7 @@ These shouldn’t be math: Here’s a LaTeX table: - + \begin{tabular}{|l|l|}\hline Animal & Number \\ \hline Dog & 2 \\ diff --git a/test/writer.native b/test/writer.native index 0587bddb8..fcd189eb0 100644 --- a/test/writer.native +++ b/test/writer.native @@ -324,7 +324,7 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa ,[Plain [Str "Shoes",Space,Str "($20)",Space,Str "and",Space,Str "socks",Space,Str "($5)."]] ,[Plain [Str "Escaped",Space,Code ("",[],[]) "$",Str ":",Space,Str "$73",Space,Emph [Str "this",Space,Str "should",Space,Str "be",Space,Str "emphasized"],Space,Str "23$."]]] ,Para [Str "Here\8217s",Space,Str "a",Space,Str "LaTeX",Space,Str "table:"] -,RawBlock (Format "latex") "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}" +,RawBlock (Format "tex") "\\begin{tabular}{|l|l|}\\hline\nAnimal & Number \\\\ \\hline\nDog & 2 \\\\\nCat & 1 \\\\ \\hline\n\\end{tabular}" ,HorizontalRule ,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"] ,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"] -- cgit v1.2.3 From fe312b0a7a0e63e307162da47dc9f1ca8f47737f Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 16 Aug 2018 20:48:51 -0700 Subject: LaTeX writer/template: be sensitive to `filecolor` variable. `linkcolor` only affects internal links, and `urlcolor` only affects linked URLs. For external links, the option to use is `filecolor`. Closes #4822. --- MANUAL.txt | 14 ++++++++------ data/templates/default.latex | 1 + src/Text/Pandoc/Writers/LaTeX.hs | 3 ++- 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/MANUAL.txt b/MANUAL.txt index 3e0e92452..7ba9e188e 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -1526,12 +1526,14 @@ LaTeX variables are used when [creating a PDF]. : options to pass to the microtype package `colorlinks` -: add color to link text; automatically enabled if any of `linkcolor`, `citecolor`, - `urlcolor`, or `toccolor` are set - -`linkcolor`, `citecolor`, `urlcolor`, `toccolor` -: color for internal links, citation links, external links, and links in table of contents: - uses options allowed by [`xcolor`], including the `dvipsnames`, `svgnames`, and `x11names` lists +: add color to link text; automatically enabled if any of + `linkcolor`, `filecolor`, `citecolor`, `urlcolor`, or `toccolor` are set + +`linkcolor`, `filecolor`, `citecolor`, `urlcolor`, `toccolor` +: color for internal links, external links, citation links, linked + URLs, and links in table of contents, respectively: uses options + allowed by [`xcolor`], including the `dvipsnames`, `svgnames`, and + `x11names` lists `links-as-notes` : causes links to be printed as footnotes diff --git a/data/templates/default.latex b/data/templates/default.latex index 795b6c868..c2e32e006 100644 --- a/data/templates/default.latex +++ b/data/templates/default.latex @@ -183,6 +183,7 @@ $endif$ $if(colorlinks)$ colorlinks=true, linkcolor=$if(linkcolor)$$linkcolor$$else$Maroon$endif$, + filecolor=$if(filecolor)$$filecolor$$else$Maroon$endif$, citecolor=$if(citecolor)$$citecolor$$else$Blue$endif$, urlcolor=$if(urlcolor)$$urlcolor$$else$Blue$endif$, $else$ diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index a3be5ecb7..3db643503 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -248,7 +248,8 @@ pandocToLaTeX options (Pandoc meta blocks) = do defField "biblatex" True _ -> id) $ defField "colorlinks" (any hasStringValue - ["citecolor", "urlcolor", "linkcolor", "toccolor"]) $ + ["citecolor", "urlcolor", "linkcolor", "toccolor", + "filecolor"]) $ (if null dirs then id else defField "dir" ("ltr" :: String)) $ -- cgit v1.2.3 From 0910e9218728c85feb562745ed5eb44d586e824d Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 16 Aug 2018 21:06:49 -0700 Subject: TEI improvements. - Ensure that title element is always present, even if empty. - Put author tags in the template, rather than adding them in the writer. Closes #4839. --- data/templates/default.tei | 4 +--- src/Text/Pandoc/Writers/TEI.hs | 15 +-------------- 2 files changed, 2 insertions(+), 17 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/data/templates/default.tei b/data/templates/default.tei index 3778dccd5..824c9f0e7 100644 --- a/data/templates/default.tei +++ b/data/templates/default.tei @@ -3,11 +3,9 @@ -$if(title)$ $title$ -$endif$ $for(author)$ - $author$ + $author$ $endfor$ diff --git a/src/Text/Pandoc/Writers/TEI.hs b/src/Text/Pandoc/Writers/TEI.hs index e461f5715..9169c8515 100644 --- a/src/Text/Pandoc/Writers/TEI.hs +++ b/src/Text/Pandoc/Writers/TEI.hs @@ -35,7 +35,6 @@ import Prelude import Data.Char (toLower) import Data.List (isPrefixOf, stripPrefix) import Data.Text (Text) -import qualified Text.Pandoc.Builder as B import Text.Pandoc.Class (PandocMonad, report) import Text.Pandoc.Definition import Text.Pandoc.Highlighting (languages, languagesByExtension) @@ -48,16 +47,6 @@ import Text.Pandoc.Templates (renderTemplate') import Text.Pandoc.Writers.Shared import Text.Pandoc.XML --- | Convert list of authors to a docbook section -authorToTEI :: PandocMonad m => WriterOptions -> [Inline] -> m B.Inlines -authorToTEI opts name' = do - name <- render Nothing <$> inlinesToTEI opts name' - let colwidth = if writerWrapText opts == WrapAuto - then Just $ writerColumns opts - else Nothing - return $ B.rawInline "tei" $ render colwidth $ - inTagsSimple "author" (text $ escapeStringForXML name) - -- | Convert Pandoc document to string in Docbook format. writeTEI :: PandocMonad m => WriterOptions -> Pandoc -> m Text writeTEI opts (Pandoc meta blocks) = do @@ -72,13 +61,11 @@ writeTEI opts (Pandoc meta blocks) = do TopLevelChapter -> 0 TopLevelSection -> 1 TopLevelDefault -> 1 - auths' <- mapM (authorToTEI opts) $ docAuthors meta - let meta' = B.setMeta "author" auths' meta metadata <- metaToJSON opts (fmap (render' . vcat) . mapM (elementToTEI opts startLvl) . hierarchicalize) (fmap render' . inlinesToTEI opts) - meta' + meta main <- (render' . vcat) <$> mapM (elementToTEI opts startLvl) elements let context = defField "body" main $ -- cgit v1.2.3 From 58dcdb0e56c53e20205add1742f741145160c6ae Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 16 Aug 2018 21:28:20 -0700 Subject: LaTeX reader: fix double `unnumbered` class. The `unnumbered` class was being included twice for starred sections. Closes #4838. --- src/Text/Pandoc/Readers/LaTeX.hs | 41 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 21 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 3006e7326..afd0f34b9 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -2281,17 +2281,16 @@ looseItem = do resetCaption :: PandocMonad m => LP m () resetCaption = updateState $ \st -> st{ sCaption = (Nothing, Nothing) } -section :: PandocMonad m => Bool -> Attr -> Int -> LP m Blocks -section starred (ident, classes, kvs) lvl = do +section :: PandocMonad m => Attr -> Int -> LP m Blocks +section (ident, classes, kvs) lvl = do skipopts contents <- grouped inline lab <- option ident $ try (spaces >> controlSeq "label" >> spaces >> toksToString <$> braced) - let classes' = if starred then "unnumbered" : classes else classes when (lvl == 0) $ updateState $ \st -> st{ sHasChapters = True } - unless starred $ do + unless ("unnumbered" `elem` classes) $ do hn <- sLastHeaderNum <$> getState hasChapters <- sHasChapters <$> getState let lvl' = lvl + if hasChapters then 1 else 0 @@ -2300,7 +2299,7 @@ section starred (ident, classes, kvs) lvl = do updateState $ \st -> st{ sLabels = M.insert lab [Str (renderHeaderNum num)] (sLabels st) } - attr' <- registerHeader (lab, classes', kvs) contents + attr' <- registerHeader (lab, classes, kvs) contents return $ headerWith attr' lvl contents blockCommand :: PandocMonad m => LP m Blocks @@ -2361,23 +2360,23 @@ blockCommands = M.fromList -- Koma-script metadata commands , ("dedication", mempty <$ (skipopts *> tok >>= addMeta "dedication")) -- sectioning - , ("part", section False nullAttr (-1)) - , ("part*", section True nullAttr (-1)) - , ("chapter", section False nullAttr 0) - , ("chapter*", section True ("",["unnumbered"],[]) 0) - , ("section", section False nullAttr 1) - , ("section*", section True ("",["unnumbered"],[]) 1) - , ("subsection", section False nullAttr 2) - , ("subsection*", section True ("",["unnumbered"],[]) 2) - , ("subsubsection", section False nullAttr 3) - , ("subsubsection*", section True ("",["unnumbered"],[]) 3) - , ("paragraph", section False nullAttr 4) - , ("paragraph*", section True ("",["unnumbered"],[]) 4) - , ("subparagraph", section False nullAttr 5) - , ("subparagraph*", section True ("",["unnumbered"],[]) 5) + , ("part", section nullAttr (-1)) + , ("part*", section nullAttr (-1)) + , ("chapter", section nullAttr 0) + , ("chapter*", section ("",["unnumbered"],[]) 0) + , ("section", section nullAttr 1) + , ("section*", section ("",["unnumbered"],[]) 1) + , ("subsection", section nullAttr 2) + , ("subsection*", section ("",["unnumbered"],[]) 2) + , ("subsubsection", section nullAttr 3) + , ("subsubsection*", section ("",["unnumbered"],[]) 3) + , ("paragraph", section nullAttr 4) + , ("paragraph*", section ("",["unnumbered"],[]) 4) + , ("subparagraph", section nullAttr 5) + , ("subparagraph*", section ("",["unnumbered"],[]) 5) -- beamer slides - , ("frametitle", section False nullAttr 3) - , ("framesubtitle", section False nullAttr 4) + , ("frametitle", section nullAttr 3) + , ("framesubtitle", section nullAttr 4) -- letters , ("opening", (para . trimInlines) <$> (skipopts *> tok)) , ("closing", skipopts *> closing) -- cgit v1.2.3 From 1b668657632c58964e8d7df42ea88e5ea6abfb1e Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 17 Aug 2018 15:22:47 -0700 Subject: LaTeX reader: fix siunitx unit commands... ...they should only be recognized in siunitx contexts. For example, `\l` outside of an siunitx context should be l-slash, not l (for liter)! Closes #4842. --- src/Text/Pandoc/Readers/LaTeX.hs | 356 ++++++++++++++++++++------------------- test/command/4842.md | 6 + 2 files changed, 188 insertions(+), 174 deletions(-) create mode 100644 test/command/4842.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index afd0f34b9..ebcb9fecf 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -735,7 +735,7 @@ dosiunitx = do skipopts value <- tok valueprefix <- option "" $ bracketed tok - unit <- inlineCommand' <|> tok + unit <- grouped (mconcat <$> many1 siUnit) <|> siUnit <|> tok let emptyOr160 "" = "" emptyOr160 _ = "\160" return . mconcat $ [valueprefix, @@ -744,11 +744,187 @@ dosiunitx = do emptyOr160 unit, unit] --- siunitx's \square command -dosquare :: PandocMonad m => LP m Inlines -dosquare = do - unit <- inlineCommand' <|> tok - return . mconcat $ [unit, "\178"] +siUnit :: PandocMonad m => LP m Inlines +siUnit = do + Tok _ (CtrlSeq name) cmd <- anyControlSeq + if name == "square" + then do + unit <- grouped (mconcat <$> many1 siUnit) <|> siUnit <|> tok + return . mconcat $ [unit, "\178"] + else + case M.lookup name siUnitMap of + Just il -> return il + Nothing -> mzero + +siUnitMap :: M.Map Text Inlines +siUnitMap = M.fromList + [ ("fg", str "fg") + , ("pg", str "pg") + , ("ng", str "ng") + , ("ug", str "μg") + , ("mg", str "mg") + , ("g", str "g") + , ("kg", str "kg") + , ("amu", str "u") + , ("pm", str "pm") + , ("nm", str "nm") + , ("um", str "μm") + , ("mm", str "mm") + , ("cm", str "cm") + , ("dm", str "dm") + , ("m", str "m") + , ("km", str "km") + , ("as", str "as") + , ("fs", str "fs") + , ("ps", str "ps") + , ("ns", str "ns") + , ("us", str "μs") + , ("ms", str "ms") + , ("s", str "s") + , ("fmol", str "fmol") + , ("pmol", str "pmol") + , ("nmol", str "nmol") + , ("umol", str "μmol") + , ("mmol", str "mmol") + , ("mol", str "mol") + , ("kmol", str "kmol") + , ("pA", str "pA") + , ("nA", str "nA") + , ("uA", str "μA") + , ("mA", str "mA") + , ("A", str "A") + , ("kA", str "kA") + , ("ul", str "μl") + , ("ml", str "ml") + , ("l", str "l") + , ("hl", str "hl") + , ("uL", str "μL") + , ("mL", str "mL") + , ("L", str "L") + , ("hL", str "hL") + , ("mHz", str "mHz") + , ("Hz", str "Hz") + , ("kHz", str "kHz") + , ("MHz", str "MHz") + , ("GHz", str "GHz") + , ("THz", str "THz") + , ("mN", str "mN") + , ("N", str "N") + , ("kN", str "kN") + , ("MN", str "MN") + , ("Pa", str "Pa") + , ("kPa", str "kPa") + , ("MPa", str "MPa") + , ("GPa", str "GPa") + , ("mohm", str "mΩ") + , ("kohm", str "kΩ") + , ("Mohm", str "MΩ") + , ("pV", str "pV") + , ("nV", str "nV") + , ("uV", str "μV") + , ("mV", str "mV") + , ("V", str "V") + , ("kV", str "kV") + , ("W", str "W") + , ("uW", str "μW") + , ("mW", str "mW") + , ("kW", str "kW") + , ("MW", str "MW") + , ("GW", str "GW") + , ("J", str "J") + , ("uJ", str "μJ") + , ("mJ", str "mJ") + , ("kJ", str "kJ") + , ("eV", str "eV") + , ("meV", str "meV") + , ("keV", str "keV") + , ("MeV", str "MeV") + , ("GeV", str "GeV") + , ("TeV", str "TeV") + , ("kWh", str "kWh") + , ("F", str "F") + , ("fF", str "fF") + , ("pF", str "pF") + , ("K", str "K") + , ("dB", str "dB") + , ("angstrom", str "Å") + , ("arcmin", str "′") + , ("arcminute", str "′") + , ("arcsecond", str "″") + , ("astronomicalunit", str "ua") + , ("atomicmassunit", str "u") + , ("atto", str "a") + , ("bar", str "bar") + , ("barn", str "b") + , ("becquerel", str "Bq") + , ("bel", str "B") + , ("candela", str "cd") + , ("celsius", str "°C") + , ("centi", str "c") + , ("coulomb", str "C") + , ("dalton", str "Da") + , ("day", str "d") + , ("deca", str "d") + , ("deci", str "d") + , ("decibel", str "db") + , ("degreeCelsius",str "°C") + , ("degree", str "°") + , ("deka", str "d") + , ("electronvolt", str "eV") + , ("exa", str "E") + , ("farad", str "F") + , ("femto", str "f") + , ("giga", str "G") + , ("gram", str "g") + , ("hectare", str "ha") + , ("hecto", str "h") + , ("henry", str "H") + , ("hertz", str "Hz") + , ("hour", str "h") + , ("joule", str "J") + , ("katal", str "kat") + , ("kelvin", str "K") + , ("kilo", str "k") + , ("kilogram", str "kg") + , ("knot", str "kn") + , ("liter", str "L") + , ("litre", str "l") + , ("lumen", str "lm") + , ("lux", str "lx") + , ("mega", str "M") + , ("meter", str "m") + , ("metre", str "m") + , ("milli", str "m") + , ("minute", str "min") + , ("mmHg", str "mmHg") + , ("mole", str "mol") + , ("nano", str "n") + , ("nauticalmile", str "M") + , ("neper", str "Np") + , ("newton", str "N") + , ("ohm", str "Ω") + , ("Pa", str "Pa") + , ("pascal", str "Pa") + , ("percent", str "%") + , ("per", str "/") + , ("peta", str "P") + , ("pico", str "p") + , ("radian", str "rad") + , ("second", str "s") + , ("siemens", str "S") + , ("sievert", str "Sv") + , ("steradian", str "sr") + , ("tera", str "T") + , ("tesla", str "T") + , ("tonne", str "t") + , ("volt", str "V") + , ("watt", str "W") + , ("weber", str "Wb") + , ("yocto", str "y") + , ("yotta", str "Y") + , ("zepto", str "z") + , ("zetta", str "Z") + ] lit :: String -> LP m Inlines lit = pure . str @@ -1594,174 +1770,6 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("acsp", doAcronymPlural "abbrv") -- siuntix , ("SI", dosiunitx) - -- units of siuntix - , ("fg", lit "fg") - , ("pg", lit "pg") - , ("ng", lit "ng") - , ("ug", lit "μg") - , ("mg", lit "mg") - , ("g", lit "g") - , ("kg", lit "kg") - , ("amu", lit "u") - , ("pm", lit "pm") - , ("nm", lit "nm") - , ("um", lit "μm") - , ("mm", lit "mm") - , ("cm", lit "cm") - , ("dm", lit "dm") - , ("m", lit "m") - , ("km", lit "km") - , ("as", lit "as") - , ("fs", lit "fs") - , ("ps", lit "ps") - , ("ns", lit "ns") - , ("us", lit "μs") - , ("ms", lit "ms") - , ("s", lit "s") - , ("fmol", lit "fmol") - , ("pmol", lit "pmol") - , ("nmol", lit "nmol") - , ("umol", lit "μmol") - , ("mmol", lit "mmol") - , ("mol", lit "mol") - , ("kmol", lit "kmol") - , ("pA", lit "pA") - , ("nA", lit "nA") - , ("uA", lit "μA") - , ("mA", lit "mA") - , ("A", lit "A") - , ("kA", lit "kA") - , ("ul", lit "μl") - , ("ml", lit "ml") - , ("l", lit "l") - , ("hl", lit "hl") - , ("uL", lit "μL") - , ("mL", lit "mL") - , ("L", lit "L") - , ("hL", lit "hL") - , ("mHz", lit "mHz") - , ("Hz", lit "Hz") - , ("kHz", lit "kHz") - , ("MHz", lit "MHz") - , ("GHz", lit "GHz") - , ("THz", lit "THz") - , ("mN", lit "mN") - , ("N", lit "N") - , ("kN", lit "kN") - , ("MN", lit "MN") - , ("Pa", lit "Pa") - , ("kPa", lit "kPa") - , ("MPa", lit "MPa") - , ("GPa", lit "GPa") - , ("mohm", lit "mΩ") - , ("kohm", lit "kΩ") - , ("Mohm", lit "MΩ") - , ("pV", lit "pV") - , ("nV", lit "nV") - , ("uV", lit "μV") - , ("mV", lit "mV") - , ("V", lit "V") - , ("kV", lit "kV") - , ("W", lit "W") - , ("uW", lit "μW") - , ("mW", lit "mW") - , ("kW", lit "kW") - , ("MW", lit "MW") - , ("GW", lit "GW") - , ("J", lit "J") - , ("uJ", lit "μJ") - , ("mJ", lit "mJ") - , ("kJ", lit "kJ") - , ("eV", lit "eV") - , ("meV", lit "meV") - , ("keV", lit "keV") - , ("MeV", lit "MeV") - , ("GeV", lit "GeV") - , ("TeV", lit "TeV") - , ("kWh", lit "kWh") - , ("F", lit "F") - , ("fF", lit "fF") - , ("pF", lit "pF") - , ("K", lit "K") - , ("dB", lit "dB") - , ("angstrom", lit "Å") - , ("arcmin", lit "′") - , ("arcminute", lit "′") - , ("arcsecond", lit "″") - , ("astronomicalunit", lit "ua") - , ("atomicmassunit", lit "u") - , ("atto", lit "a") - , ("bar", lit "bar") - , ("barn", lit "b") - , ("becquerel", lit "Bq") - , ("bel", lit "B") - , ("candela", lit "cd") - , ("celsius", lit "°C") - , ("centi", lit "c") - , ("coulomb", lit "C") - , ("dalton", lit "Da") - , ("day", lit "d") - , ("deca", lit "d") - , ("deci", lit "d") - , ("decibel", lit "db") - , ("degreeCelsius",lit "°C") - , ("degree", lit "°") - , ("deka", lit "d") - , ("electronvolt", lit "eV") - , ("exa", lit "E") - , ("farad", lit "F") - , ("femto", lit "f") - , ("giga", lit "G") - , ("gram", lit "g") - , ("hectare", lit "ha") - , ("hecto", lit "h") - , ("henry", lit "H") - , ("hertz", lit "Hz") - , ("hour", lit "h") - , ("joule", lit "J") - , ("katal", lit "kat") - , ("kelvin", lit "K") - , ("kilo", lit "k") - , ("kilogram", lit "kg") - , ("knot", lit "kn") - , ("liter", lit "L") - , ("litre", lit "l") - , ("lumen", lit "lm") - , ("lux", lit "lx") - , ("mega", lit "M") - , ("meter", lit "m") - , ("metre", lit "m") - , ("milli", lit "m") - , ("minute", lit "min") - , ("mmHg", lit "mmHg") - , ("mole", lit "mol") - , ("nano", lit "n") - , ("nauticalmile", lit "M") - , ("neper", lit "Np") - , ("newton", lit "N") - , ("ohm", lit "Ω") - , ("Pa", lit "Pa") - , ("pascal", lit "Pa") - , ("percent", lit "%") - , ("per", lit "/") - , ("peta", lit "P") - , ("pico", lit "p") - , ("radian", lit "rad") - , ("second", lit "s") - , ("siemens", lit "S") - , ("sievert", lit "Sv") - , ("square", dosquare) - , ("steradian", lit "sr") - , ("tera", lit "T") - , ("tesla", lit "T") - , ("tonne", lit "t") - , ("volt", lit "V") - , ("watt", lit "W") - , ("weber", lit "Wb") - , ("yocto", lit "y") - , ("yotta", lit "Y") - , ("zepto", lit "z") - , ("zetta", lit "Z") -- hyphenat , ("bshyp", lit "\\\173") , ("fshyp", lit "/\173") diff --git a/test/command/4842.md b/test/command/4842.md new file mode 100644 index 000000000..a311739b7 --- /dev/null +++ b/test/command/4842.md @@ -0,0 +1,6 @@ +``` +pandoc -f latex -t native +\l +^D +[Para [Str "\322"]] +``` -- cgit v1.2.3 From 822a071bb2ef8bfca0af74e3cc501a3346e47ae9 Mon Sep 17 00:00:00 2001 From: Joe Hermaszewski Date: Fri, 20 Apr 2018 19:09:51 +0800 Subject: Haddock Writer: Use proper format for latex math in haddock (#4571). Inline math in `\(..\)`, display math in `\[..\]`, tex is now used. Previously we'd "fake it with unicode" and fall back to tex when that didn't work. But as of https://github.com/haskell/haddock/commit/3f50b955324bd4b42f88a421f0203bc46a3ccf64 haddock supports latex math. --- src/Text/Pandoc/Writers/Haddock.hs | 10 ++++------ test/writer.haddock | 14 +++++++------- 2 files changed, 11 insertions(+), 13 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs index 75b8c78dc..6cb720489 100644 --- a/src/Text/Pandoc/Writers/Haddock.hs +++ b/src/Text/Pandoc/Writers/Haddock.hs @@ -45,7 +45,6 @@ import Text.Pandoc.Options import Text.Pandoc.Pretty import Text.Pandoc.Shared import Text.Pandoc.Templates (renderTemplate') -import Text.Pandoc.Writers.Math (texMathToInlines) import Text.Pandoc.Writers.Shared type Notes = [[Block]] @@ -250,11 +249,10 @@ inlineToHaddock _ (Code _ str) = return $ "@" <> text (escapeString str) <> "@" inlineToHaddock _ (Str str) = return $ text $ escapeString str -inlineToHaddock opts (Math mt str) = do - let adjust x = case mt of - DisplayMath -> cr <> x <> cr - InlineMath -> x - adjust <$> (lift (texMathToInlines mt str) >>= inlineListToHaddock opts) +inlineToHaddock _ (Math mt str) = + return $ case mt of + DisplayMath -> cr <> "\\[" <> text str <> "\\]" <> cr + InlineMath -> "\\(" <> text str <> "\\)" inlineToHaddock _ il@(RawInline f str) | f == "haddock" = return $ text str | otherwise = do diff --git a/test/writer.haddock b/test/writer.haddock index 7f783abd1..13f22021d 100644 --- a/test/writer.haddock +++ b/test/writer.haddock @@ -455,14 +455,14 @@ ______________________________________________________________________________ #latex# - -- 2 + 2 = 4 -- /x/ ∈ /y/ -- /α/ ∧ /ω/ -- 223 -- /p/-Tree +- \(2+2=4\) +- \(x \in y\) +- \(\alpha \wedge \omega\) +- \(223\) +- \(p\)-Tree - Here’s some display math: - $$\\frac{d}{dx}f(x)=\\lim_{h\\to 0}\\frac{f(x+h)-f(x)}{h}$$ -- Here’s one that has a line break in it: /α/ + /ω/ × /x/2. + \[\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}\] +- Here’s one that has a line break in it: \(\alpha + \omega \times x^2\). These shouldn’t be math: -- cgit v1.2.3 From 175da00295da72ae08e23405327f63ba08c3c3a2 Mon Sep 17 00:00:00 2001 From: Marc Schreiber Date: Sat, 18 Aug 2018 05:57:36 +0200 Subject: Add support for latex mintinline (#4365) --- src/Text/Pandoc/Readers/LaTeX.hs | 11 +++++++++++ test/command/3534.md | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index ebcb9fecf..44b93439d 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1024,6 +1024,16 @@ dolstinline :: PandocMonad m => LP m Inlines dolstinline = do options <- option [] keyvals let classes = maybeToList $ lookup "language" options >>= fromListingsLanguage + doinlinecode classes + +domintinline :: PandocMonad m => LP m Inlines +domintinline = do + skipopts + cls <- toksToString <$> braced + doinlinecode [cls] + +doinlinecode :: PandocMonad m => [String] -> LP m Inlines +doinlinecode classes = do Tok _ Symbol t <- anySymbol marker <- case T.uncons t of Just (c, ts) | T.null ts -> return c @@ -1655,6 +1665,7 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("footnote", skipopts >> note <$> grouped block) , ("verb", doverb) , ("lstinline", dolstinline) + , ("mintinline", domintinline) , ("Verb", doverb) , ("url", ((unescapeURL . T.unpack . untokenize) <$> bracedUrl) >>= \url -> pure (link url "" (str url))) diff --git a/test/command/3534.md b/test/command/3534.md index 89224551b..cd0915d88 100644 --- a/test/command/3534.md +++ b/test/command/3534.md @@ -21,3 +21,25 @@ I want to explain the interface of \lstinline[language=Java]{public class MyClas [Para [Str "I",Space,Str "want",Space,Str "to",Space,Str "explain",Space,Str "the",Space,Str "interface",Space,Str "of",Space,Code ("",["java"],[]) "public class MyClass",Str "."]] ``` +``` +% pandoc -f latex -t html +I want to explain the interface of \mintinline{java}{public class MyClass}. +^D +

I want to explain the interface of public class MyClass.

+ +``` + +``` +% pandoc -f latex -t html +I want to explain the interface of \mintinline{java}|public class MyClass|. +^D +

I want to explain the interface of public class MyClass.

+ +``` + +``` +% pandoc -f latex -t native +I want to explain the interface of \mintinline[linenos]{java}{public class MyClass}. +^D +[Para [Str "I",Space,Str "want",Space,Str "to",Space,Str "explain",Space,Str "the",Space,Str "interface",Space,Str "of",Space,Code ("",["java"],[]) "public class MyClass",Str "."]] +``` -- cgit v1.2.3 From 4ec02053bba3f280b63267c90f2faeafe74d5c64 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 17 Aug 2018 21:25:14 -0700 Subject: Docx writer: properly handle display math in spans. Closes #4826. This isn't a complete solution, since other nestings of display math may still cause problems, but it should work for what is by far the most common case. Note that this also involves an API change: `isDisplayMath` is now exported from Text.Pandoc.Writers.Shared. --- src/Text/Pandoc/Writers/Docx.hs | 10 ++++++---- src/Text/Pandoc/Writers/Shared.hs | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 380374bd6..2055ee1da 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -66,7 +66,8 @@ import Text.Pandoc.Readers.Docx.StyleMap import Text.Pandoc.Shared hiding (Element) import Text.Pandoc.Walk import Text.Pandoc.Writers.Math -import Text.Pandoc.Writers.Shared (fixDisplayMath, metaValueToInlines) +import Text.Pandoc.Writers.Shared (isDisplayMath, fixDisplayMath, + metaValueToInlines) import Text.Printf (printf) import Text.TeXMath import Text.XML.Light as XML @@ -915,9 +916,10 @@ blockToOpenXML' opts (Para lst) | null lst && not (isEnabled Ext_empty_paragraphs opts) = return [] | otherwise = do isFirstPara <- gets stFirstPara - paraProps <- getParaProps $ case lst of - [Math DisplayMath _] -> True - _ -> False + let displayMathPara = case lst of + [x] -> isDisplayMath x + _ -> False + paraProps <- getParaProps displayMathPara bodyTextStyle <- pStyleM "Body Text" let paraProps' = case paraProps of [] | isFirstPara -> [mknode "w:pPr" [] diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs index 2edce7deb..438a35ca4 100644 --- a/src/Text/Pandoc/Writers/Shared.hs +++ b/src/Text/Pandoc/Writers/Shared.hs @@ -38,6 +38,7 @@ module Text.Pandoc.Writers.Shared ( , resetField , defField , tagWithAttrs + , isDisplayMath , fixDisplayMath , unsmartify , gridTable @@ -187,8 +188,9 @@ tagWithAttrs tag (ident,classes,kvs) = hsep ] <> ">" isDisplayMath :: Inline -> Bool -isDisplayMath (Math DisplayMath _) = True -isDisplayMath _ = False +isDisplayMath (Math DisplayMath _) = True +isDisplayMath (Span _ [Math DisplayMath _]) = True +isDisplayMath _ = False stripLeadingTrailingSpace :: [Inline] -> [Inline] stripLeadingTrailingSpace = go . reverse . go . reverse -- cgit v1.2.3 From 159863e8dad24e98be3478867d0f8ea63b2a764b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 17 Aug 2018 22:11:31 -0700 Subject: LaTeX reader: use combining characters when needed for accents. For example, there is no unicode code point corresponding to \"{X}, so we use a combining accent. --- src/Text/Pandoc/Readers/LaTeX.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 44b93439d..cafa55f57 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1073,7 +1073,10 @@ accent :: PandocMonad m => Char -> (Char -> String) -> LP m Inlines accent c f = try $ do ils <- tok case toList ils of - (Str (x:xs) : ys) -> return $ fromList (Str (f x ++ xs) : ys) + (Str (x:xs) : ys) -> return $ fromList $ + case f x of + [z] | z == x -> Str ([z,c] ++ xs) : ys -- combining accent + zs -> Str (zs ++ xs) : ys [Space] -> return $ str [c] [] -> return $ str [c] _ -> return ils -- cgit v1.2.3 From 42f4632e600dea34e5dcbe75fc734899a2436c05 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 17 Aug 2018 23:19:38 -0700 Subject: LaTeX reader: Support more text-mode accents. Add support for `\|`, `\b`, `\G`, `\h`, `\d`, `\f`, `\r`, `\t`, `\U`, `\i`, `\j`, `\newtie`, `\textcircled`. Also fall back to combining characters when composed characters are not available. Closes #4652. --- src/Text/Pandoc/Readers/LaTeX.hs | 92 +++++++++++++++++++++++++++++++++++++++- test/command/macros.md | 8 ++-- 2 files changed, 95 insertions(+), 5 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index cafa55f57..b385e4462 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1214,6 +1214,84 @@ macron 'o' = "ō" macron 'u' = "ū" macron c = [c] +ringabove :: Char -> String +ringabove 'A' = "Å" +ringabove 'a' = "å" +ringabove 'U' = "Ů" +ringabove 'u' = "ů" +ringabove c = [c] + +dotbelow :: Char -> String +dotbelow 'B' = "Ḅ" +dotbelow 'b' = "ḅ" +dotbelow 'D' = "Ḍ" +dotbelow 'd' = "ḍ" +dotbelow 'H' = "Ḥ" +dotbelow 'h' = "ḥ" +dotbelow 'K' = "Ḳ" +dotbelow 'k' = "ḳ" +dotbelow 'L' = "Ḷ" +dotbelow 'l' = "ḷ" +dotbelow 'M' = "Ṃ" +dotbelow 'm' = "ṃ" +dotbelow 'N' = "Ṇ" +dotbelow 'n' = "ṇ" +dotbelow 'R' = "Ṛ" +dotbelow 'r' = "ṛ" +dotbelow 'S' = "Ṣ" +dotbelow 's' = "ṣ" +dotbelow 'T' = "Ṭ" +dotbelow 't' = "ṭ" +dotbelow 'V' = "Ṿ" +dotbelow 'v' = "ṿ" +dotbelow 'W' = "Ẉ" +dotbelow 'w' = "ẉ" +dotbelow 'Z' = "Ẓ" +dotbelow 'z' = "ẓ" +dotbelow 'A' = "Ạ" +dotbelow 'a' = "ạ" +dotbelow 'E' = "Ẹ" +dotbelow 'e' = "ẹ" +dotbelow 'I' = "Ị" +dotbelow 'i' = "ị" +dotbelow 'O' = "Ọ" +dotbelow 'o' = "ọ" +dotbelow 'U' = "Ụ" +dotbelow 'u' = "ụ" +dotbelow 'Y' = "Ỵ" +dotbelow 'y' = "ỵ" +dotbelow c = [c] + +doublegrave :: Char -> String +doublegrave 'A' = "Ȁ" +doublegrave 'a' = "ȁ" +doublegrave 'E' = "Ȅ" +doublegrave 'e' = "ȅ" +doublegrave 'I' = "Ȉ" +doublegrave 'i' = "ȉ" +doublegrave 'O' = "Ȍ" +doublegrave 'o' = "ȍ" +doublegrave 'R' = "Ȑ" +doublegrave 'r' = "ȑ" +doublegrave 'U' = "Ȕ" +doublegrave 'u' = "ȕ" +doublegrave c = [c] + +hookabove :: Char -> String +hookabove 'A' = "Ả" +hookabove 'a' = "ả" +hookabove 'E' = "Ẻ" +hookabove 'e' = "ẻ" +hookabove 'I' = "Ỉ" +hookabove 'i' = "ỉ" +hookabove 'O' = "Ỏ" +hookabove 'o' = "ỏ" +hookabove 'U' = "Ủ" +hookabove 'u' = "ủ" +hookabove 'Y' = "Ỷ" +hookabove 'y' = "ỷ" +hookabove c = [c] + cedilla :: Char -> String cedilla 'c' = "ç" cedilla 'C' = "Ç" @@ -1645,12 +1723,24 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("\"", accent '\776' umlaut) , (".", accent '\775' dot) , ("=", accent '\772' macron) + , ("|", accent '\781' (:[])) -- vertical line above + , ("b", accent '\817' (:[])) -- macron below , ("c", accent '\807' cedilla) + , ("G", accent '\783' doublegrave) + , ("h", accent '\777' hookabove) + , ("d", accent '\803' dotbelow) + , ("f", accent '\785' (:[])) -- inverted breve + , ("r", accent '\778' ringabove) + , ("t", accent '\865' (:[])) -- double inverted breve + , ("U", accent '\782' (:[])) -- double vertical line above , ("v", accent 'ˇ' hacek) , ("u", accent '\774' breve) , ("k", accent '\808' ogonek) , ("textogonekcentered", accent '\808' ogonek) - , ("i", lit "i") + , ("i", lit "ı") -- dotless i + , ("j", lit "ȷ") -- dotless j + , ("newtie", accent '\785' (:[])) -- inverted breve + , ("textcircled", accent '\8413' (:[])) -- combining circle , ("\\", linebreak <$ (do inTableCell <- sInTableCell <$> getState guard $ not inTableCell optional opt diff --git a/test/command/macros.md b/test/command/macros.md index 9de87e7a0..d091c2191 100644 --- a/test/command/macros.md +++ b/test/command/macros.md @@ -24,18 +24,18 @@ expanded at point of use: % pandoc -f latex -t latex \let\a\b \newcommand{\b}{\emph{ouk}} -\a +\a a ^D -\b +a̱ ``` ``` % pandoc -f latex -t latex \newcommand{\a}{\b} \newcommand{\b}{\emph{ouk}} -\a +\a a ^D -\emph{ouk} +\emph{ouk}a ``` ``` -- cgit v1.2.3 From bebfda62dcc90db9e7866c4b8e3709873dcf80ac Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 18 Aug 2018 09:09:43 -0700 Subject: Fix compiler warning. --- src/Text/Pandoc/Readers/LaTeX.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index b385e4462..2f16738ac 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -746,7 +746,7 @@ dosiunitx = do siUnit :: PandocMonad m => LP m Inlines siUnit = do - Tok _ (CtrlSeq name) cmd <- anyControlSeq + Tok _ (CtrlSeq name) _ <- anyControlSeq if name == "square" then do unit <- grouped (mconcat <$> many1 siUnit) <|> siUnit <|> tok -- cgit v1.2.3 From fb3295cb9e54260b5395afde669aa2a14334592b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 19 Aug 2018 10:32:25 -0700 Subject: Markdown writer: escape `~` if strikeout extension enabled. See #4840. --- src/Text/Pandoc/Writers/Markdown.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index c07771384..741d11580 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -298,7 +298,8 @@ escapeString opts (c:cs) = '\\':c:escapeString opts cs '|' | isEnabled Ext_pipe_tables opts -> '\\':'|':escapeString opts cs '^' | isEnabled Ext_superscript opts -> '\\':'^':escapeString opts cs - '~' | isEnabled Ext_subscript opts -> '\\':'~':escapeString opts cs + '~' | isEnabled Ext_subscript opts || + isEnabled Ext_strikeout opts -> '\\':'~':escapeString opts cs '$' | isEnabled Ext_tex_math_dollars opts -> '\\':'$':escapeString opts cs '\'' | isEnabled Ext_smart opts -> '\\':'\'':escapeString opts cs '"' | isEnabled Ext_smart opts -> '\\':'"':escapeString opts cs -- cgit v1.2.3 From a733068ebf4b9dea2769c5698a4d46e6e5918bf1 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 21 Aug 2018 17:39:27 -0700 Subject: LaTeX reader: support enquote*, foreignquote, hypphenquote... from csquotes. See #4848. Still TBD: blockquote, blockcquote, foreignblockquote. --- src/Text/Pandoc/Readers/LaTeX.hs | 30 ++++++++++++++++----- test/command/4848.md | 58 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 6 deletions(-) create mode 100644 test/command/4848.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 2f16738ac..cd21179df 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -975,13 +975,22 @@ quoted' f starter ender = do cs -> cs) else lit startchs -enquote :: PandocMonad m => LP m Inlines -enquote = do +enquote :: PandocMonad m => Bool -> Maybe Text -> LP m Inlines +enquote starred mblang = do skipopts + let lang = (T.unpack <$> mblang) >>= babelLangToBCP47 + let langspan = case lang of + Nothing -> id + Just l -> spanWith ("",[],[("lang", renderLang l)]) quoteContext <- sQuoteContext <$> getState - if quoteContext == InDoubleQuote - then singleQuoted <$> withQuoteContext InSingleQuote tok - else doubleQuoted <$> withQuoteContext InDoubleQuote tok + if starred || quoteContext == InDoubleQuote + then singleQuoted . langspan <$> withQuoteContext InSingleQuote tok + else doubleQuoted . langspan <$> withQuoteContext InDoubleQuote tok + +blockquote :: PandocMonad m => LP m Blocks +blockquote = do + bs <- grouped block + return $ blockQuote bs doAcronym :: PandocMonad m => String -> LP m Inlines doAcronym form = do @@ -1769,7 +1778,14 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList src <- unescapeURL . T.unpack . removeDoubleQuotes . untokenize <$> braced mkImage options src) - , ("enquote", enquote) + , ("enquote*", enquote True Nothing) + , ("enquote", enquote False Nothing) + -- foreignquote is supposed to use native quote marks + , ("foreignquote*", braced >>= enquote True . Just . untokenize) + , ("foreignquote", braced >>= enquote False . Just . untokenize) + -- hypehnquote uses regular quotes + , ("hyphenquote*", braced >>= enquote True . Just . untokenize) + , ("hyphenquote", braced >>= enquote False . Just . untokenize) , ("figurename", doTerm Translations.Figure) , ("prefacename", doTerm Translations.Preface) , ("refname", doTerm Translations.References) @@ -2524,6 +2540,8 @@ blockCommands = M.fromList -- LaTeX colors , ("textcolor", coloredBlock "color") , ("colorbox", coloredBlock "background-color") + -- csquotse + , ("blockquote", blockquote) -- include , ("include", include "include") , ("input", include "input") diff --git a/test/command/4848.md b/test/command/4848.md new file mode 100644 index 000000000..287bd9d33 --- /dev/null +++ b/test/command/4848.md @@ -0,0 +1,58 @@ +``` +% pandoc -f latex -t native +\enquote*{hi} +^D +[Para [Quoted SingleQuote [Str "hi"]]] +``` + +``` +% pandoc -f latex -t native +\foreignquote{italian}{hi} +^D +[Para [Quoted DoubleQuote [Span ("",[],[("lang","it")]) [Str "hi"]]]] +``` + +``` +% pandoc -f latex -t native +\hyphenquote*{italian}{hi} +^D +[Para [Quoted SingleQuote [Span ("",[],[("lang","it")]) [Str "hi"]]]] +``` + +``` +% pandoc -f latex -t native +Lorem ipsum +\blockquote{dolor sit amet} +consectetuer. +^D +[Para [Str "Lorem",Space,Str "ipsum"] +,BlockQuote + [Para [Str "dolor",Space,Str "sit",Space,Str "amet"]] +,Para [Str "consectetuer."]] +``` + +``` +% pandoc -f latex -t native +Lorem ipsum +\blockcquote[198]{Knu86}{dolor sit amet} +consectetuer. +^D +[Para [Str "Lorem",Space,Str "ipsum"] +,BlockQuote + [Para [Str "dolor",Space,Str "sit",Space,Str "amet",Space,Cite [Citation {citationId = "Knu86", citationPrefix = [], citationSuffix = [Str "198"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cite[198]{Knu86}"]]] +,Para [Str "consectetuer."]] +``` + +``` +% pandoc -f latex -t native +Lorem ipsum +\foreignblockquote{italian}{dolor sit amet} +consectetuer. +^D +[Para [Str "Lorem",Space,Str "ipsum"] +,Div ("",[],[("lang","it")]) + [BlockQuote + [Para [Str "dolor",Space,Str "sit",Space,Str "amet"]]] +,Para [Str "consectetuer."]] +``` + -- cgit v1.2.3 From 3b5949e8f278a8d407777f567fdaf8e421323ced Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 21 Aug 2018 21:01:52 -0700 Subject: LaTeX reader: support blockcquote, foreignblockquote from csquotes. Also foreigncblockquote, hyphenblockquote, hyphencblockquote. Closes #4848. But note: currently foreignquote will be parsed as a regular Quoted inline (not using the quotes appropriate to the foreign language). --- src/Text/Pandoc/Readers/LaTeX.hs | 24 +++++++++++++++++++----- test/command/4848.md | 7 ++++--- 2 files changed, 23 insertions(+), 8 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index cd21179df..56f14752a 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -987,10 +987,19 @@ enquote starred mblang = do then singleQuoted . langspan <$> withQuoteContext InSingleQuote tok else doubleQuoted . langspan <$> withQuoteContext InDoubleQuote tok -blockquote :: PandocMonad m => LP m Blocks -blockquote = do +blockquote :: PandocMonad m => Bool -> Maybe Text -> LP m Blocks +blockquote citations mblang = do + citePar <- if citations + then do + cs <- cites NormalCitation False + return $ para (cite cs mempty) + else return mempty + let lang = (T.unpack <$> mblang) >>= babelLangToBCP47 + let langdiv = case lang of + Nothing -> id + Just l -> divWith ("",[],[("lang", renderLang l)]) bs <- grouped block - return $ blockQuote bs + return $ blockQuote . langdiv $ (bs <> citePar) doAcronym :: PandocMonad m => String -> LP m Inlines doAcronym form = do @@ -2540,8 +2549,13 @@ blockCommands = M.fromList -- LaTeX colors , ("textcolor", coloredBlock "color") , ("colorbox", coloredBlock "background-color") - -- csquotse - , ("blockquote", blockquote) + -- csquotes + , ("blockquote", blockquote False Nothing) + , ("blockcquote", blockquote True Nothing) + , ("foreignblockquote", braced >>= blockquote False . Just . untokenize) + , ("foreignblockcquote", braced >>= blockquote True . Just . untokenize) + , ("hyphenblockquote", braced >>= blockquote False . Just . untokenize) + , ("hyphenblockcquote", braced >>= blockquote True . Just . untokenize) -- include , ("include", include "include") , ("input", include "input") diff --git a/test/command/4848.md b/test/command/4848.md index 287bd9d33..2cd2bab34 100644 --- a/test/command/4848.md +++ b/test/command/4848.md @@ -39,7 +39,8 @@ consectetuer. ^D [Para [Str "Lorem",Space,Str "ipsum"] ,BlockQuote - [Para [Str "dolor",Space,Str "sit",Space,Str "amet",Space,Cite [Citation {citationId = "Knu86", citationPrefix = [], citationSuffix = [Str "198"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cite[198]{Knu86}"]]] + [Para [Str "dolor",Space,Str "sit",Space,Str "amet"] + ,Para [Cite [Citation {citationId = "Knu86", citationPrefix = [], citationSuffix = [Str "198"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] []]] ,Para [Str "consectetuer."]] ``` @@ -50,8 +51,8 @@ Lorem ipsum consectetuer. ^D [Para [Str "Lorem",Space,Str "ipsum"] -,Div ("",[],[("lang","it")]) - [BlockQuote +,BlockQuote + [Div ("",[],[("lang","it")]) [Para [Str "dolor",Space,Str "sit",Space,Str "amet"]]] ,Para [Str "consectetuer."]] ``` -- cgit v1.2.3 From 937b92cd304a6a404f750c7f9a894adfb3638d01 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 22 Aug 2018 12:16:57 +0300 Subject: HTML reader: extract spaces inside links instead of trimming them Fixes #4845 --- src/Text/Pandoc/Readers/HTML.hs | 6 +++--- test/command/4845.md | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 test/command/4845.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs index df8dc1a2d..697ab89e9 100644 --- a/src/Text/Pandoc/Readers/HTML.hs +++ b/src/Text/Pandoc/Readers/HTML.hs @@ -745,18 +745,18 @@ pLink = try $ do let uid = fromMaybe (T.unpack $ fromAttrib "name" tag) $ maybeFromAttrib "id" tag let cls = words $ T.unpack $ fromAttrib "class" tag - lab <- trimInlines . mconcat <$> manyTill inline (pCloses "a") + lab <- mconcat <$> manyTill inline (pCloses "a") -- check for href; if href, then a link, otherwise a span case maybeFromAttrib "href" tag of Nothing -> - return $ B.spanWith (uid, cls, []) lab + return $ extractSpaces (B.spanWith (uid, cls, [])) lab Just url' -> do mbBaseHref <- baseHref <$> getState let url = case (parseURIReference url', mbBaseHref) of (Just rel, Just bs) -> show (rel `nonStrictRelativeTo` bs) _ -> url' - return $ B.linkWith (uid, cls, []) (escapeURI url) title lab + return $ extractSpaces (B.linkWith (uid, cls, []) (escapeURI url) title) lab pImage :: PandocMonad m => TagParser m Inlines pImage = do diff --git a/test/command/4845.md b/test/command/4845.md new file mode 100644 index 000000000..093161ac7 --- /dev/null +++ b/test/command/4845.md @@ -0,0 +1,6 @@ +``` +% pandoc -f html -t native +x leading trailing space x +^D +[Plain [Str "x",Space,Link ("",[],[]) [Str "leading",Space,Str "trailing",Space,Str "space"] ("/foo",""),Space,Str "x"]] +``` -- cgit v1.2.3 From 4dddfbc4351cfa267946210c9aea59adbaa62f3b Mon Sep 17 00:00:00 2001 From: Antonio Terceiro Date: Fri, 24 Aug 2018 13:43:29 -0300 Subject: PDF: fix reference to rsvg-convert (#4855) When rsvg-convert is not available, pandoc would tell the user to check for rsvg2pdf instead --- src/Text/Pandoc/PDF.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs index 65de3e45a..3484699c0 100644 --- a/src/Text/Pandoc/PDF.hs +++ b/src/Text/Pandoc/PDF.hs @@ -188,7 +188,7 @@ convertImage tmpdir fname = then return $ Right pdfOut else return $ Left "conversion from SVG failed") (\(e :: E.SomeException) -> return $ Left $ - "check that rsvg2pdf is in path.\n" ++ + "check that rsvg-convert is in path.\n" ++ show e) _ -> JP.readImage fname >>= \res -> case res of -- cgit v1.2.3 From a2c4261b32d3ed3fd6562a5260d25a82d9f75e9b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 24 Aug 2018 18:04:00 -0700 Subject: HTML reader: allow enabling `raw_tex` extension. This now allows raw LaTeX environments, `\ref`, and `\eqref` to be parsed (which is helpful for translation HTML documents using MathJaX). Closes #1126. --- MANUAL.txt | 3 ++- src/Text/Pandoc/Readers/HTML.hs | 31 ++++++++++++++++++++++++++++--- test/command/1126.md | 29 +++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 test/command/1126.md (limited to 'src/Text/Pandoc') diff --git a/MANUAL.txt b/MANUAL.txt index 7ba9e188e..4c68bfa86 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -1917,7 +1917,8 @@ This extension can be enabled/disabled for the following formats (in addition to `markdown`): input formats -: `latex`, `org`, `textile` +: `latex`, `org`, `textile`, `html` (environments, `\ref`, and + `\eqref` only) output formats : `textile`, `commonmark` diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs index 697ab89e9..ea62bfcbf 100644 --- a/src/Text/Pandoc/Readers/HTML.hs +++ b/src/Text/Pandoc/Readers/HTML.hs @@ -68,11 +68,13 @@ import qualified Text.Pandoc.Builder as B import Text.Pandoc.Class (PandocMonad (..)) import Text.Pandoc.CSS (foldOrElse, pickStyleAttrProps) import Text.Pandoc.Definition +import Text.Pandoc.Readers.LaTeX (rawLaTeXInline) +import Text.Pandoc.Readers.LaTeX.Types (Macro) import Text.Pandoc.Error import Text.Pandoc.Logging import Text.Pandoc.Options ( Extension (Ext_epub_html_exts, Ext_empty_paragraphs, Ext_native_divs, - Ext_native_spans, Ext_raw_html, Ext_line_blocks), + Ext_native_spans, Ext_raw_html, Ext_line_blocks, Ext_raw_tex), ReaderOptions (readerExtensions, readerStripComments), extensionEnabled) import Text.Pandoc.Parsing hiding ((<|>)) @@ -102,7 +104,8 @@ readHtml opts inp = do (m:_) -> messageString m result <- flip runReaderT def $ runParserT parseDoc - (HTMLState def{ stateOptions = opts } [] Nothing Set.empty M.empty []) + (HTMLState def{ stateOptions = opts } + [] Nothing Set.empty M.empty [] M.empty) "source" tags case result of Right doc -> return doc @@ -124,7 +127,8 @@ data HTMLState = baseHref :: Maybe URI, identifiers :: Set.Set String, headerMap :: M.Map Inlines String, - logMessages :: [LogMessage] + logMessages :: [LogMessage], + macros :: M.Map Text Macro } data HTMLLocal = HTMLLocal { quoteContext :: QuoteContext @@ -907,9 +911,25 @@ pTagContents = <|> pStr <|> pSpace <|> smartPunctuation pTagContents + <|> pRawTeX <|> pSymbol <|> pBad +pRawTeX :: PandocMonad m => InlinesParser m Inlines +pRawTeX = do + lookAhead $ try $ do + char '\\' + choice $ map (try . string) ["begin", "eqref", "ref"] + guardEnabled Ext_raw_tex + inp <- getInput + st <- getState + res <- lift $ runParserT (withRaw rawLaTeXInline) st "chunk" (T.unpack inp) + case res of + Left _ -> mzero + Right (contents, raw) -> do + _ <- count (length raw) anyChar + return $ B.rawInline "tex" contents + pStr :: PandocMonad m => InlinesParser m Inlines pStr = do result <- many1 $ satisfy $ \c -> @@ -923,6 +943,7 @@ isSpecial '\'' = True isSpecial '.' = True isSpecial '-' = True isSpecial '$' = True +isSpecial '\\' = True isSpecial '\8216' = True isSpecial '\8217' = True isSpecial '\8220' = True @@ -1249,6 +1270,10 @@ isSpace _ = False -- Instances +instance HasMacros HTMLState where + extractMacros = macros + updateMacros f st = st{ macros = f $ macros st } + instance HasIdentifierList HTMLState where extractIdentifierList = identifiers updateIdentifierList f s = s{ identifiers = f (identifiers s) } diff --git a/test/command/1126.md b/test/command/1126.md new file mode 100644 index 000000000..014a8ae2d --- /dev/null +++ b/test/command/1126.md @@ -0,0 +1,29 @@ +``` +% pandoc -f html -t latex +\begin{eqnarray} +A&=&B,\\ +C&=&D +\end{eqnarray} +^D +\textbackslash{}begin\{eqnarray\} +A\&=\&B,\textbackslash{}\textbackslash{} C\&=\&D +\textbackslash{}end\{eqnarray\} +``` + +``` +% pandoc -f html+raw_tex -t latex +

See \eqref{myeq}.

+\begin{eqnarray} +A&=&B,\\ +C&=&D +\\label{myeq} +\end{eqnarray} +^D +See \eqref{myeq}. + +\begin{eqnarray} +A&=&B,\\ +C&=&D +\\label{myeq} +\end{eqnarray} +``` -- cgit v1.2.3 From 347242f5308cda8431045c5112967c49293b21ff Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 24 Aug 2018 21:07:47 -0700 Subject: FB2 writer: put coverpage element between title and date... ...rather than in document-info element. Closes #4854. --- src/Text/Pandoc/Writers/FB2.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 3227aaed8..6158052bb 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -135,8 +135,9 @@ description meta' = do Just (MetaString s) -> coverimage s _ -> return [] return $ el "description" - [ el "title-info" (genre : (as ++ bt ++ annotation ++ dd ++ lang)) - , el "document-info" (el "program-used" "pandoc" : coverpage) + [ el "title-info" (genre : + (as ++ bt ++ annotation ++ dd ++ coverpage ++ lang)) + , el "document-info" [el "program-used" "pandoc"] ] booktitle :: PandocMonad m => Meta -> FBM m [Content] -- cgit v1.2.3 From 7318bc91ce58bb6c39e556e334f278e590439c3f Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 28 Aug 2018 12:34:49 -0700 Subject: EPUB writer: set epub:type on body element intelligently. epub:type of first section epub:type of body -------------------------- ------------------ prologue frontmatter abstract frontmatter acknowledgments frontmatter copyright-page frontmatter dedication frontmatter foreword frontmatter halftitle, frontmatter introduction frontmatter preface frontmatter seriespage frontmatter titlepage frontmatter afterword backmatter appendix backmatter colophon backmatter conclusion backmatter epigraph backmatter Otherwise body will have epub:type 'bodymatter'. This only affects epub3. See http://www.idpf.org/epub/profiles/edu/structure/#h.l0bzsloklt10 Closes #4823. --- data/templates/default.epub3 | 2 +- src/Text/Pandoc/Writers/EPUB.hs | 28 ++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/data/templates/default.epub3 b/data/templates/default.epub3 index b22714963..6428e984c 100644 --- a/data/templates/default.epub3 +++ b/data/templates/default.epub3 @@ -26,7 +26,7 @@ $for(header-includes)$ $header-includes$ $endfor$ - + $if(titlepage)$
$for(title)$ diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 3c6ab69b9..4c5e73d81 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -461,6 +461,7 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do -- title page tpContent <- lift $ writeHtml opts'{ writerVariables = ("titlepage","true"): + ("body-type", "frontmatter"): ("pagetitle", escapeStringForXML plainTitle): cssvars True ++ vars } (Pandoc meta []) @@ -565,13 +566,28 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do let chapToEntry num (Chapter mbnum bs) = mkEntry ("text/" ++ showChapter num) =<< writeHtml opts'{ writerNumberOffset = fromMaybe [] mbnum - , writerVariables = cssvars True ++ vars } - (case bs of - (Header _ _ xs : _) -> + , writerVariables = ("body-type", bodyType) : + cssvars True ++ vars } pdoc + where (pdoc, bodyType) = + case bs of + (Header _ (_,_,kvs) xs : _) -> -- remove notes or we get doubled footnotes - Pandoc (setMeta "title" (walk removeNote $ fromList xs) - nullMeta) bs - _ -> Pandoc nullMeta bs) + (Pandoc (setMeta "title" + (walk removeNote $ fromList xs) nullMeta) bs, + case lookup "epub:type" kvs of + Nothing -> "bodymatter" + Just x + | x `elem` frontMatterTypes -> "frontmatter" + | x `elem` backMatterTypes -> "backmatter" + | otherwise -> "bodymatter") + _ -> (Pandoc nullMeta bs, "bodymatter") + frontMatterTypes = ["prologue", "abstract", "acknowledgments", + "copyright-page", "dedication", + "foreword", "halftitle", + "introduction", "preface", + "seriespage", "titlepage"] + backMatterTypes = ["afterword", "appendix", "colophon", + "conclusion", "epigraph"] chapterEntries <- zipWithM chapToEntry [1..] chapters -- cgit v1.2.3 From 85ed24e849975051f370dd8bf98c6c62ca92447a Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 29 Aug 2018 14:40:04 -0700 Subject: RSTR reader: don't skip link definitions after comments. Closes #4860. --- src/Text/Pandoc/Readers/RST.hs | 1 + test/command/4860.md | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 test/command/4860.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index 576c3b77c..6a9e7cb95 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -172,6 +172,7 @@ parseRST = do docMinusKeys <- concat <$> manyTill (referenceKey <|> anchorDef <|> noteBlock <|> citationBlock <|> + (snd <$> withRaw comment) <|> headerBlock <|> lineClump) eof setInput docMinusKeys setPosition startPos diff --git a/test/command/4860.md b/test/command/4860.md new file mode 100644 index 000000000..9198f68d7 --- /dev/null +++ b/test/command/4860.md @@ -0,0 +1,9 @@ +``` +% pandoc -f rst -t native +This is broken_. + +.. ***** REFERENCES FOLLOW ***** +.. _broken: http://google.com +^D +[Para [Str "This",Space,Str "is",Space,Link ("",[],[]) [Str "broken"] ("http://google.com",""),Str "."]] +``` -- cgit v1.2.3 From 889254e1d5c7b683b93f623207347a773e25776b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 29 Aug 2018 15:50:51 -0700 Subject: LaTeX reader: fixed parsing of \texorpdfstring. We were returning the wrong argument as the content. --- src/Text/Pandoc/Readers/LaTeX.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 56f14752a..9fcaa2b09 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1690,7 +1690,7 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("(", mathInline . toksToString <$> manyTill anyTok (controlSeq ")")) , ("[", mathDisplay . toksToString <$> manyTill anyTok (controlSeq "]")) , ("ensuremath", mathInline . toksToString <$> braced) - , ("texorpdfstring", (\_ x -> x) <$> tok <*> tok) + , ("texorpdfstring", (\x _ -> x) <$> tok <*> tok) , ("P", lit "¶") , ("S", lit "§") , ("$", lit "$") -- cgit v1.2.3 From cc8e115b7245361d024377ef9a068d612ad29643 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Thu, 30 Aug 2018 16:03:01 +0300 Subject: Muse reader: hlint --- src/Text/Pandoc/Readers/Muse.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 01f9be41f..2c21d377e 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -964,11 +964,11 @@ explicitLink = try $ do image :: PandocMonad m => MuseParser m (F Inlines) image = try $ do string "[[" - (url, (ext, width, align)) <- manyUntil (noneOf "]") $ (imageExtensionAndOptions <* char ']') + (url, (ext, width, align)) <- manyUntil (noneOf "]") (imageExtensionAndOptions <* char ']') content <- optionMaybe linkContent char ']' let widthAttr = case align of - Just 'f' -> [("width", (fromMaybe "100" width) ++ "%"), ("height", "75%")] + Just 'f' -> [("width", fromMaybe "100" width ++ "%"), ("height", "75%")] _ -> maybeToList (("width",) . (++ "%") <$> width) let alignClass = case align of Just 'r' -> ["align-right"] -- cgit v1.2.3 From 56685e8735e62af2855ae5703a10829979f32a46 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 31 Aug 2018 15:57:58 +0300 Subject: Muse reader: parse tag in one pass instead of using parseFromString. This change makes it possible to have verbatim tag inside verse. --- src/Text/Pandoc/Readers/Muse.hs | 19 +++++++++++-------- test/Tests/Readers/Muse.hs | 6 ++++++ 2 files changed, 17 insertions(+), 8 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 2c21d377e..2b55251e8 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -462,16 +462,19 @@ verseLine = do rest <- manyTill (choice inlineList) newline return $ trimInlinesF $ mconcat (pure indent : rest) -verseLines :: PandocMonad m => MuseParser m (F Blocks) -verseLines = do - lns <- many verseLine - return $ B.lineBlock <$> sequence lns - -- | Parse @\@ tag. verseTag :: PandocMonad m => MuseParser m (F Blocks) -verseTag = do - (_, content) <- htmlBlock "verse" - parseFromString verseLines (intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content) +verseTag = try $ do + many spaceChar + pos <- getPosition + (TagOpen _ _, _) <- htmlTag (~== TagOpen "verse" []) + manyTill spaceChar eol + let indent = count (sourceColumn pos - 1) spaceChar + content <- sequence <$> manyTill (indent >> verseLine) (try $ indent >> endtag) + manyTill spaceChar eol + return $ B.lineBlock <$> content + where + endtag = void $ htmlTag (~== TagClose "verse") -- | Parse @\@ tag. commentTag :: PandocMonad m => MuseParser m (F Blocks) diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs index a2c9cbc7e..20603b8fb 100644 --- a/test/Tests/Readers/Muse.hs +++ b/test/Tests/Readers/Muse.hs @@ -407,6 +407,12 @@ tests = , "" ] =?> lineBlock [ "" ] + , "Verse tag with verbatim close tag inside" =: + T.unlines [ "" + , "" + , "" + ] =?> + lineBlock [ "" ] , testGroup "Example" [ "Braces on separate lines" =: T.unlines [ "{{{" -- cgit v1.2.3 From 3ddb7c9d3e337bf692c6328ca6466f3b1930e6c3 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 31 Aug 2018 18:51:16 +0300 Subject: Muse writer: simplify inline list rendering --- src/Text/Pandoc/Writers/Muse.hs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 3681fcc0d..123ca94e4 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -424,7 +424,7 @@ renderInlineList (x:xs) = do start <- asks envInlineStart afterSpace <- asks envAfterSpace topLevel <- asks envTopLevel - r <- inlineToMuse x + r <- local (\env -> env { envInlineStart = False }) $ inlineToMuse x opts <- asks envOptions let isNewline = (x == SoftBreak && writerWrapText opts == WrapPreserve) || x == LineBreak lst' <- local (\env -> env { envInlineStart = isNewline @@ -435,23 +435,20 @@ renderInlineList (x:xs) = do else pure (r <> lst') -- | Normalize and convert list of Pandoc inline elements to Muse. -inlineListToMuse'' :: PandocMonad m - => Bool - -> [Inline] - -> Muse m Doc -inlineListToMuse'' start lst = do +inlineListToMuse :: PandocMonad m + => [Inline] + -> Muse m Doc +inlineListToMuse lst = do lst' <- (normalizeInlineList . fixNotes) <$> preprocessInlineList (map (removeKeyValues . replaceSmallCaps) lst) - topLevel <- asks envTopLevel - afterSpace <- asks envAfterSpace - local (\env -> env { envInlineStart = start - , envAfterSpace = afterSpace || (start && not topLevel) - }) $ renderInlineList lst' + renderInlineList lst' inlineListToMuse' :: PandocMonad m => [Inline] -> Muse m Doc -inlineListToMuse' = inlineListToMuse'' True - -inlineListToMuse :: PandocMonad m => [Inline] -> Muse m Doc -inlineListToMuse = inlineListToMuse'' False +inlineListToMuse' lst = do + topLevel <- asks envTopLevel + afterSpace <- asks envAfterSpace + local (\env -> env { envInlineStart = True + , envAfterSpace = afterSpace || not topLevel + }) $ inlineListToMuse lst -- | Convert Pandoc inline element to Muse. inlineToMuse :: PandocMonad m -- cgit v1.2.3 From e27ded9c385958295b28ed88cd6e6888a1c541b2 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sat, 1 Sep 2018 15:51:39 +0300 Subject: Muse writer: separate "shouldEscapeString" function --- src/Text/Pandoc/Writers/Muse.hs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 123ca94e4..7f3b64ea7 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -321,14 +321,19 @@ containsFootnotes = p s (_:xs) = p xs s [] = False +-- | Return True if string should be escaped with tags +shouldEscapeString :: Bool -> String -> Bool +shouldEscapeString isInsideLinkDescription s = + any (`elem` ("#*<=|" :: String)) s || + "::" `isInfixOf` s || + "~~" `isInfixOf` s || + "[[" `isInfixOf` s || + ("]" `isInfixOf` s && isInsideLinkDescription) || + containsFootnotes s + conditionalEscapeString :: Bool -> String -> String conditionalEscapeString isInsideLinkDescription s = - if any (`elem` ("#*<=|" :: String)) s || - "::" `isInfixOf` s || - "~~" `isInfixOf` s || - "[[" `isInfixOf` s || - ("]" `isInfixOf` s && isInsideLinkDescription) || - containsFootnotes s + if shouldEscapeString isInsideLinkDescription s then escapeString s else s -- cgit v1.2.3 From db44ddfbde16d8aff0d62550014ac72b684b3eef Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sat, 1 Sep 2018 16:14:06 +0300 Subject: Muse writer: wrap conditionalEscapeString result into "Muse" type This removes the need to pass envInsideLinkDescription to it. --- src/Text/Pandoc/Writers/Muse.hs | 50 +++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 22 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 7f3b64ea7..beb289d02 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -322,20 +322,26 @@ containsFootnotes = p s [] = False -- | Return True if string should be escaped with tags -shouldEscapeString :: Bool -> String -> Bool -shouldEscapeString isInsideLinkDescription s = - any (`elem` ("#*<=|" :: String)) s || - "::" `isInfixOf` s || - "~~" `isInfixOf` s || - "[[" `isInfixOf` s || - ("]" `isInfixOf` s && isInsideLinkDescription) || - containsFootnotes s - -conditionalEscapeString :: Bool -> String -> String -conditionalEscapeString isInsideLinkDescription s = - if shouldEscapeString isInsideLinkDescription s - then escapeString s - else s +shouldEscapeString :: PandocMonad m + => String + -> Muse m Bool +shouldEscapeString s = do + insideLink <- asks envInsideLinkDescription + return $ any (`elem` ("#*<=|" :: String)) s || + "::" `isInfixOf` s || + "~~" `isInfixOf` s || + "[[" `isInfixOf` s || + ("]" `isInfixOf` s && insideLink) || + containsFootnotes s + +conditionalEscapeString :: PandocMonad m + => String + -> Muse m String +conditionalEscapeString s = do + shouldEscape <- shouldEscapeString s + if shouldEscape + then return $ escapeString s + else return $ s -- Expand Math and Cite before normalizing inline list preprocessInlineList :: PandocMonad m @@ -459,9 +465,8 @@ inlineListToMuse' lst = do inlineToMuse :: PandocMonad m => Inline -> Muse m Doc -inlineToMuse (Str str) = do - insideLink <- asks envInsideLinkDescription - return $ text $ conditionalEscapeString insideLink str +inlineToMuse (Str str) = + text <$> conditionalEscapeString str inlineToMuse (Emph lst) = do contents <- inlineListToMuse lst return $ "" <> contents <> "" @@ -516,11 +521,12 @@ inlineToMuse (Image attr alt (source,'f':'i':'g':':':title)) = inlineToMuse (Image attr@(_, classes, _) inlines (source, title)) = do opts <- asks envOptions alt <- local (\env -> env { envInsideLinkDescription = True }) $ inlineListToMuse inlines - let title' = if null title - then if null inlines - then "" - else "[" <> alt <> "]" - else "[" <> text (conditionalEscapeString True title) <> "]" + title' <- if null title + then if null inlines + then return "" + else return $ "[" <> alt <> "]" + else do s <- local (\env -> env { envInsideLinkDescription = True }) $ conditionalEscapeString title + return $ "[" <> text s <> "]" let width = case dimension Width attr of Just (Percent x) | isEnabled Ext_amuse opts -> " " ++ show (round x :: Integer) _ -> "" -- cgit v1.2.3 From 23ed97f081d2a5f1ba1d9525e74dfcfbdcfe6a20 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 2 Sep 2018 00:35:26 +0300 Subject: Muse reader: allow newline after opening "*" or "**" Emacs Muse allows this. --- src/Text/Pandoc/Readers/Muse.hs | 10 +++++++++- test/Tests/Readers/Muse.hs | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 2b55251e8..045feedb3 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -58,7 +58,7 @@ import Text.Pandoc.Class (PandocMonad (..)) import Text.Pandoc.Definition import Text.Pandoc.Logging import Text.Pandoc.Options -import Text.Pandoc.Parsing hiding (F) +import Text.Pandoc.Parsing hiding (F, enclosed) import Text.Pandoc.Readers.HTML (htmlTag) import Text.Pandoc.Shared (crFilter, underlineSpan) @@ -839,6 +839,14 @@ br = try $ do emphasisBetween :: (PandocMonad m, Show a) => MuseParser m a -> MuseParser m (F Inlines) emphasisBetween c = try $ enclosedInlines c c +-- | Parses material enclosed between start and end parsers. +enclosed :: (Show end, Stream s m Char) => ParserT s st m t -- ^ start parser + -> ParserT s st m end -- ^ end parser + -> ParserT s st m a -- ^ content parser (to be used repeatedly) + -> ParserT s st m [a] +enclosed start end parser = try $ + start >> notFollowedBy spaceChar >> many1Till parser end + enclosedInlines :: (PandocMonad m, Show a, Show b) => MuseParser m a -> MuseParser m b diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs index 20603b8fb..ca3324e34 100644 --- a/test/Tests/Readers/Muse.hs +++ b/test/Tests/Readers/Muse.hs @@ -62,6 +62,14 @@ tests = "*Foo bar*" =?> para (emph . spcSep $ ["Foo", "bar"]) + -- Emacs Muse allows this + , "Newline in the beginning of emphasis" =: + "*\nFoo bar*" =?> + para (emph ("Foo" <> space <> "bar")) + , "Newline in the end of emphasis" =: + "*Foo bar\n*" =?> + para (emph ("Foo" <> space <> "bar")) + , "Comma after closing *" =: "Foo *bar*, baz" =?> para ("Foo " <> emph "bar" <> ", baz") -- cgit v1.2.3 From bd2bd9aeaab8a49372ba73d884a29f9ad1c8e9b7 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sat, 1 Sep 2018 17:44:17 +0300 Subject: Muse writer: escape empty strings This guarantees that conditionalEscapeString never returns empty string. --- src/Text/Pandoc/Writers/Muse.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index beb289d02..cedd376e8 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -327,7 +327,8 @@ shouldEscapeString :: PandocMonad m -> Muse m Bool shouldEscapeString s = do insideLink <- asks envInsideLinkDescription - return $ any (`elem` ("#*<=|" :: String)) s || + return $ null s || + any (`elem` ("#*<=|" :: String)) s || "::" `isInfixOf` s || "~~" `isInfixOf` s || "[[" `isInfixOf` s || -- cgit v1.2.3 From 746c30971ebbf9c1b02a3d7b7c5d94e67f8ee9ed Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sat, 1 Sep 2018 15:43:17 +0300 Subject: Muse writer: add more comments --- src/Text/Pandoc/Writers/Muse.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index cedd376e8..a21bf5fc0 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -70,9 +70,9 @@ data WriterEnv = WriterEnv { envOptions :: WriterOptions , envTopLevel :: Bool , envInsideBlock :: Bool - , envInlineStart :: Bool + , envInlineStart :: Bool -- ^ True if there is only whitespace since last newline , envInsideLinkDescription :: Bool -- ^ Escape ] if True - , envAfterSpace :: Bool + , envAfterSpace :: Bool -- ^ There is whitespace (not just newline) before , envOneLine :: Bool -- ^ True if newlines are not allowed } -- cgit v1.2.3 From 6ea6011ca66c3127ff42cd5d0d39b3bd40e56e76 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Thu, 30 Aug 2018 17:10:46 +0300 Subject: Muse writer: use lightweight markup when possible --- src/Text/Pandoc/Writers/Muse.hs | 142 ++++++++++++++++++++++++++++++++++------ test/Tests/Writers/Muse.hs | 50 ++++++++++---- test/writer.muse | 75 ++++++++++----------- 3 files changed, 198 insertions(+), 69 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index a21bf5fc0..b9f9381c3 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -46,7 +46,7 @@ module Text.Pandoc.Writers.Muse (writeMuse) where import Prelude import Control.Monad.Reader import Control.Monad.State.Strict -import Data.Char (isSpace, isDigit, isAsciiUpper, isAsciiLower) +import Data.Char (isSpace, isAlphaNum, isDigit, isAsciiUpper, isAsciiLower) import Data.Default import Data.Text (Text) import Data.List (intersperse, transpose, isInfixOf) @@ -74,16 +74,20 @@ data WriterEnv = , envInsideLinkDescription :: Bool -- ^ Escape ] if True , envAfterSpace :: Bool -- ^ There is whitespace (not just newline) before , envOneLine :: Bool -- ^ True if newlines are not allowed + , envInsideAsterisks :: Bool -- ^ True if outer element is emphasis with asterisks + , envNearAsterisks :: Bool -- ^ Rendering inline near asterisks } data WriterState = WriterState { stNotes :: Notes , stIds :: Set.Set String + , stUseTags :: Bool -- ^ Use tags for emphasis, for example because previous character is a letter } instance Default WriterState where def = WriterState { stNotes = [] , stIds = Set.empty + , stUseTags = False } evalMuse :: PandocMonad m => Muse m a -> WriterEnv -> WriterState -> m a @@ -103,6 +107,8 @@ writeMuse opts document = , envInsideLinkDescription = False , envAfterSpace = False , envOneLine = False + , envInsideAsterisks = False + , envNearAsterisks = False } -- | Return Muse representation of document. @@ -212,6 +218,7 @@ blockToMuse (BulletList items) = do => [Block] -> Muse m Doc bulletListItemToMuse item = do + modify $ \st -> st { stUseTags = False } contents <- blockListToMuse item return $ hang 2 "- " contents blockToMuse (DefinitionList items) = do @@ -223,6 +230,7 @@ blockToMuse (DefinitionList items) = do => ([Inline], [[Block]]) -> Muse m Doc definitionListItemToMuse (label, defs) = do + modify $ \st -> st { stUseTags = False } label' <- local (\env -> env { envOneLine = True, envAfterSpace = True }) $ inlineListToMuse' label contents <- vcat <$> mapM descriptionToMuse defs let ind = offset label' @@ -401,6 +409,17 @@ fixNotes (Space : n@Note{} : rest) = Str " " : n : fixNotes rest fixNotes (SoftBreak : n@Note{} : rest) = Str " " : n : fixNotes rest fixNotes (x:xs) = x : fixNotes xs +startsWithSpace :: [Inline] -> Bool +startsWithSpace (Space:_) = True +startsWithSpace (SoftBreak:_) = True +startsWithSpace _ = False + +endsWithSpace :: [Inline] -> Bool +endsWithSpace [Space] = True +endsWithSpace [SoftBreak] = True +endsWithSpace (_:xs) = endsWithSpace xs +endsWithSpace [] = False + urlEscapeBrackets :: String -> String urlEscapeBrackets (']':xs) = '%':'5':'D':urlEscapeBrackets xs urlEscapeBrackets (x:xs) = x:urlEscapeBrackets xs @@ -409,9 +428,9 @@ urlEscapeBrackets [] = [] isHorizontalRule :: String -> Bool isHorizontalRule s = length s >= 4 && all (== '-') s -startsWithSpace :: String -> Bool -startsWithSpace (x:_) = isSpace x -startsWithSpace [] = False +stringStartsWithSpace :: String -> Bool +stringStartsWithSpace (x:_) = isSpace x +stringStartsWithSpace [] = False fixOrEscape :: Bool -> Inline -> Bool fixOrEscape sp (Str "-") = sp @@ -420,11 +439,19 @@ fixOrEscape _ (Str ">") = True fixOrEscape sp (Str s) = (sp && (startsWithMarker isDigit s || startsWithMarker isAsciiLower s || startsWithMarker isAsciiUpper s)) - || isHorizontalRule s || startsWithSpace s + || isHorizontalRule s || stringStartsWithSpace s fixOrEscape _ Space = True fixOrEscape _ SoftBreak = True fixOrEscape _ _ = False +inlineListStartsWithAlnum :: PandocMonad m + => [Inline] + -> Muse m Bool +inlineListStartsWithAlnum (Str s:_) = do + esc <- shouldEscapeString s + return $ esc || isAlphaNum (head s) +inlineListStartsWithAlnum _ = return False + -- | Convert list of Pandoc inline elements to Muse renderInlineList :: PandocMonad m => [Inline] @@ -436,11 +463,22 @@ renderInlineList (x:xs) = do start <- asks envInlineStart afterSpace <- asks envAfterSpace topLevel <- asks envTopLevel - r <- local (\env -> env { envInlineStart = False }) $ inlineToMuse x + insideAsterisks <- asks envInsideAsterisks + nearAsterisks <- asks envNearAsterisks + useTags <- gets stUseTags + alnumNext <- inlineListStartsWithAlnum xs + let newUseTags = useTags || alnumNext + modify $ \st -> st { stUseTags = newUseTags } + + r <- local (\env -> env { envInlineStart = False + , envInsideAsterisks = False + , envNearAsterisks = nearAsterisks || (null xs && insideAsterisks) + }) $ inlineToMuse x opts <- asks envOptions let isNewline = (x == SoftBreak && writerWrapText opts == WrapPreserve) || x == LineBreak lst' <- local (\env -> env { envInlineStart = isNewline , envAfterSpace = x == Space || (not topLevel && isNewline) + , envNearAsterisks = False }) $ renderInlineList xs if start && fixOrEscape afterSpace x then pure (text "" <> r <> lst') @@ -452,7 +490,9 @@ inlineListToMuse :: PandocMonad m -> Muse m Doc inlineListToMuse lst = do lst' <- (normalizeInlineList . fixNotes) <$> preprocessInlineList (map (removeKeyValues . replaceSmallCaps) lst) - renderInlineList lst' + insideAsterisks <- asks envInsideAsterisks + modify $ \st -> st { stUseTags = False } -- Previous character is likely a '>' or some other markup + local (\env -> env { envNearAsterisks = insideAsterisks }) $ renderInlineList lst' inlineListToMuse' :: PandocMonad m => [Inline] -> Muse m Doc inlineListToMuse' lst = do @@ -466,52 +506,112 @@ inlineListToMuse' lst = do inlineToMuse :: PandocMonad m => Inline -> Muse m Doc -inlineToMuse (Str str) = - text <$> conditionalEscapeString str +inlineToMuse (Str str) = do + escapedStr <- conditionalEscapeString str + let useTags = isAlphaNum $ last escapedStr -- escapedStr is never empty because empty strings are escaped + modify $ \st -> st { stUseTags = useTags } + return $ text escapedStr +inlineToMuse (Emph [Strong lst]) = do + useTags <- gets stUseTags + if useTags + then do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + modify $ \st -> st { stUseTags = False } + return $ "**" <> contents <> "**" + else if null lst || startsWithSpace lst || endsWithSpace lst + then do + contents <- local (\env -> env { envInsideAsterisks = False }) $ inlineListToMuse lst + modify $ \st -> st { stUseTags = True } + return $ "*" <> contents <> "*" + else do + contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + modify $ \st -> st { stUseTags = True } + return $ "***" <> contents <> "***" inlineToMuse (Emph lst) = do - contents <- inlineListToMuse lst - return $ "" <> contents <> "" + useTags <- gets stUseTags + if useTags || null lst || startsWithSpace lst || endsWithSpace lst + then do contents <- inlineListToMuse lst + return $ "" <> contents <> "" + else do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + modify $ \st -> st { stUseTags = True } + return $ "*" <> contents <> "*" +inlineToMuse (Strong [Emph lst]) = do + useTags <- gets stUseTags + if useTags + then do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + modify $ \st -> st { stUseTags = False } + return $ "*" <> contents <> "*" + else if null lst || startsWithSpace lst || endsWithSpace lst + then do + contents <- local (\env -> env { envInsideAsterisks = False }) $ inlineListToMuse lst + modify $ \st -> st { stUseTags = True } + return $ "**" <> contents <> "**" + else do + contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + modify $ \st -> st { stUseTags = True } + return $ "***" <> contents <> "***" inlineToMuse (Strong lst) = do - contents <- inlineListToMuse lst - return $ "" <> contents <> "" + useTags <- gets stUseTags + if useTags || null lst || startsWithSpace lst || endsWithSpace lst + then do contents <- inlineListToMuse lst + modify $ \st -> st { stUseTags = False } + return $ "" <> contents <> "" + else do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + modify $ \st -> st { stUseTags = True } + return $ "**" <> contents <> "**" inlineToMuse (Strikeout lst) = do contents <- inlineListToMuse lst + modify $ \st -> st { stUseTags = False } return $ "" <> contents <> "" inlineToMuse (Superscript lst) = do contents <- inlineListToMuse lst + modify $ \st -> st { stUseTags = False } return $ "" <> contents <> "" inlineToMuse (Subscript lst) = do contents <- inlineListToMuse lst + modify $ \st -> st { stUseTags = False } return $ "" <> contents <> "" inlineToMuse SmallCaps {} = fail "SmallCaps should be expanded before normalization" inlineToMuse (Quoted SingleQuote lst) = do contents <- inlineListToMuse lst + modify $ \st -> st { stUseTags = False } return $ "‘" <> contents <> "’" inlineToMuse (Quoted DoubleQuote lst) = do contents <- inlineListToMuse lst + modify $ \st -> st { stUseTags = False } return $ "“" <> contents <> "”" inlineToMuse Cite {} = fail "Citations should be expanded before normalization" -inlineToMuse (Code _ str) = return $ - "" <> text (substitute "" "</code>" str) <> "" +inlineToMuse (Code _ str) = do + useTags <- gets stUseTags + modify $ \st -> st { stUseTags = False } + return $ if useTags || null str || '=' `elem` str || isSpace (head str) || isSpace (last str) + then "" <> text (substitute "" "</code>" str) <> "" + else "=" <> text str <> "=" inlineToMuse Math{} = fail "Math should be expanded before normalization" -inlineToMuse (RawInline (Format f) str) = +inlineToMuse (RawInline (Format f) str) = do + modify $ \st -> st { stUseTags = False } return $ " text f <> "\">" <> text str <> "" inlineToMuse LineBreak = do oneline <- asks envOneLine + modify $ \st -> st { stUseTags = False } return $ if oneline then "
" else "
" <> cr -inlineToMuse Space = return space +inlineToMuse Space = do + modify $ \st -> st { stUseTags = False } + return space inlineToMuse SoftBreak = do oneline <- asks envOneLine wrapText <- asks $ writerWrapText . envOptions + modify $ \st -> st { stUseTags = False } return $ if not oneline && wrapText == WrapPreserve then cr else space inlineToMuse (Link _ txt (src, _)) = case txt of - [Str x] | escapeURI x == src -> + [Str x] | escapeURI x == src -> do + modify $ \st -> st { stUseTags = False } return $ "[[" <> text (escapeLink x) <> "]]" _ -> do contents <- local (\env -> env { envInsideLinkDescription = True }) $ inlineListToMuse txt + modify $ \st -> st { stUseTags = False } return $ "[[" <> text (escapeLink src) <> "][" <> contents <> "]]" where escapeLink lnk = if isImageUrl lnk then "URL:" ++ urlEscapeBrackets lnk else urlEscapeBrackets lnk -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el @@ -537,11 +637,14 @@ inlineToMuse (Image attr@(_, classes, _) inlines (source, title)) = do let rightalign = if "align-right" `elem` classes then " r" else "" + modify $ \st -> st { stUseTags = False } return $ "[[" <> text (urlEscapeBrackets source ++ width ++ leftalign ++ rightalign) <> "]" <> title' <> "]" inlineToMuse (Note contents) = do -- add to notes in state notes <- gets stNotes - modify $ \st -> st { stNotes = contents:notes } + modify $ \st -> st { stNotes = contents:notes + , stUseTags = False + } let ref = show $ length notes + 1 return $ "[" <> text ref <> "]" inlineToMuse (Span (anchor,names,_) inlines) = do @@ -549,6 +652,7 @@ inlineToMuse (Span (anchor,names,_) inlines) = do let anchorDoc = if null anchor then mempty else text ('#':anchor) <> space + modify $ \st -> st { stUseTags = False } return $ anchorDoc <> (if null inlines && not (null anchor) then mempty else (if null names diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs index 50c0e78eb..f44097f9e 100644 --- a/test/Tests/Writers/Muse.hs +++ b/test/Tests/Writers/Muse.hs @@ -354,23 +354,51 @@ tests = [ testGroup "block elements" , "do not escape ; inside paragraph" =: text "foo ; bar" =?> "foo ; bar" ] , testGroup "emphasis" - [ "emph" =: emph (text "foo") =?> "foo" - , "strong" =: strong (text "foo") =?> "foo" + [ "emphasis" =: emph (text "foo") =?> "*foo*" + , "emphasis inside word" =: text "foo" <> emph (text "bar") <> text "baz" =?> "foobarbaz" + , "emphasis before comma" =: emph (text "foo") <> text ", bar" =?> "*foo*, bar" + , "emphasis before period" =: emph (text "foobar") <> text "." =?> "*foobar*." + , "empty emphasis" =: emph mempty =?> "" + , "empty strong" =: strong mempty =?> "" + , "empty strong emphasis" =: strong (emph mempty) =?> "****" + , "empty emphasized strong" =: emph (strong mempty) =?> "**" + , "strong" =: strong (text "foo") =?> "**foo**" + , "strong inside word" =: text "foo" <> strong (text "bar") <> text "baz" =?> "foobarbaz" + , "strong emphasis" =: strong (emph (text "foo")) =?> "***foo***" + , "strong after emphasis" =: emph (text "foo") <> strong (text "bar") =?> "*foo*bar" + , "strong emphasis after emphasis" =: emph (text "foo") <> strong (emph (text "bar")) =?> "*foo**bar*" + , "strong in the end of emphasis" =: emph (text "foo" <> strong (text "bar")) =?> "*foobar*" , "strikeout" =: strikeout (text "foo") =?> "foo" + , "space at the beginning of emphasis" =: emph (text " foo") =?> " foo" + , "space at the end of emphasis" =: emph (text "foo ") =?> "foo " + , "space at the beginning of strong" =: strong (text " foo") =?> " foo" + , "space at the end of strong" =: strong (text "foo ") =?> "foo " + , "space at the beginning of strong emphasis" =: strong (emph (text " foo")) =?> "** foo**" + , "space at the end of strong emphasis" =: strong (emph (text "foo ")) =?> "**foo **" + , "space at the beginning of emphasiszed strong" =: emph (strong (text " foo")) =?> "* foo*" + , "space at the end of emphasized strong" =: emph (strong (text "foo ")) =?> "*foo *" ] , "superscript" =: superscript (text "foo") =?> "foo" , "subscript" =: subscript (text "foo") =?> "foo" - , "smallcaps" =: smallcaps (text "foo") =?> "foo" - , "smallcaps near emphasis" =: emph (str "foo") <> smallcaps (str "bar") =?> "foobar" + , "smallcaps" =: smallcaps (text "foo") =?> "*foo*" + , "smallcaps near emphasis" =: emph (str "foo") <> smallcaps (str "bar") =?> "*foobar*" , "single quoted" =: singleQuoted (text "foo") =?> "‘foo’" , "double quoted" =: doubleQuoted (text "foo") =?> "“foo”" -- Cite is trivial , testGroup "code" - [ "simple" =: code "foo" =?> "foo" + [ "simple" =: code "foo" =?> "=foo=" + , "empty" =: code "" =?> "" + , "space" =: code " " =?> " " + , "space at the beginning" =: code " foo" =?> " foo" + , "space at the end" =: code "foo " =?> "foo " + , "use tags for =" =: code "foo = bar" =?> "foo = bar" , "escape tag" =: code "foo = bar baz" =?> "foo = bar</code> baz" - , "normalization with attributes" =: codeWith ("",["haskell"],[]) "foo" <> code "bar" =?> "foobar" - , "normalization" =: code " code "de>" =?> "</code>" - , "normalization with empty string" =: code " str "" <> code "de>" =?> "</code>" + , "normalization with attributes" =: codeWith ("",["haskell"],[]) "foo" <> code "bar" =?> "=foobar=" + , "code tag" =: code "foo" =?> "=foo=" + , "normalization" =: code " code "de>" <> code "=" =?> "</code>=" + , "normalization with empty string" =: code " str "" <> code "de>" <> code "=" =?> "</code>=" + , "emphasized code" =: emph (code "foo") =?> "*=foo=*" + , "strong code" =: strong (code "foo") =?> "**=foo=**" ] , testGroup "spaces" [ "space" =: text "a" <> space <> text "b" =?> "a b" @@ -385,7 +413,7 @@ tests = [ testGroup "block elements" , testGroup "math" [ "inline math" =: math "2^3" =?> "23" , "display math" =: displayMath "2^3" =?> "23" - , "multiple letters in inline math" =: math "abc" =?> "abc" + , "multiple letters in inline math" =: math "abc" =?> "*abc*" , "expand math before normalization" =: math "[" <> str "2]" =?> "[2]" , "multiple math expressions inside one inline list" =: math "5_4" <> text ", " <> displayMath "3^2" =?> "54, 32" ] @@ -461,7 +489,7 @@ tests = [ testGroup "block elements" "foobar" , "emph quoted" =: para (doubleQuoted (emph (text "foo"))) =?> - "“foo”" + "“*foo*”" , "strong word before" =: para (text "foo" <> strong (text "bar")) =?> "foobar" @@ -470,7 +498,7 @@ tests = [ testGroup "block elements" "foobar" , "strong quoted" =: para (singleQuoted (strong (text "foo"))) =?> - "‘foo’" + "‘**foo**’" ] ] ] diff --git a/test/writer.muse b/test/writer.muse index 5993ec357..35d43a751 100644 --- a/test/writer.muse +++ b/test/writer.muse @@ -11,7 +11,7 @@ markdown test suite. ** Level 2 with an [[/url][embedded link]] -*** Level 3 with emphasis +*** Level 3 with *emphasis* **** Level 4 @@ -19,7 +19,7 @@ markdown test suite. * Level 1 -** Level 2 with emphasis +** Level 2 with *emphasis* *** Level 3 @@ -271,18 +271,18 @@ Loose: Multiple blocks with italics: - apple :: red fruit + *apple* :: red fruit - contains seeds, crisp, pleasant to taste - orange :: orange fruit + contains seeds, crisp, pleasant to taste + *orange* :: orange fruit - - { orange code block } - + + { orange code block } + - - orange block quote - + + orange block quote + Multiple definitions, tight: @@ -331,7 +331,7 @@ Interpreted markdown in a table: -This is emphasized +This is *emphasized* @@ -341,7 +341,7 @@ This is emphasized -And this is strong +And this is **strong** @@ -461,27 +461,25 @@ Hr’s: * Inline Markup -This is emphasized, and so is this. +This is *emphasized*, and so *is this*. -This is strong, and so is this. +This is **strong**, and so **is this**. -An [[/url][emphasized link]]. +An *[[/url][emphasized link]]*. -This is strong and em. +***This is strong and em.*** -So is this word. +So is ***this*** word. -This is strong and em. +***This is strong and em.*** -So is this word. +So is ***this*** word. -This is code: >, $, \, \$, -. +This is code: =>=, =$=, =\=, =\$=, ==. -This is strikeout. +This is *strikeout*. -Superscripts: abcd ahello -ahello there. +Superscripts: abcd a*hello* ahello there. Subscripts: H2O, H23O, Hmany of themO. @@ -500,8 +498,8 @@ spaces: a^b c^d, a~b c~d. ‘He said, “I want to go.”’ Were you alive in the 70’s? -Here is some quoted ‘code’ and a -“[[http://example.com/?foo=1&bar=2][quoted link]]”. +Here is some quoted ‘=code=’ and a “[[http://example.com/?foo=1&bar=2][quoted +link]]”. Some dashes: one—two — three—four — five. @@ -515,22 +513,21 @@ Ellipses…and…and…. - \cite[22-23]{smith.1899} - 2 + 2 = 4 - - x ∈ y - - α ∧ ω + - *x* ∈ *y* + - *α* ∧ *ω* - 223 - - p-Tree + - *p*-Tree - Here’s some display math: $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$ - - Here’s one that has a line break in it: - α + ω × x2. + - Here’s one that has a line break in it: *α* + *ω* × *x*2. 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 + - $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$. + - Escaped =$=: $73 *this should be emphasized* 23$. Here’s a LaTeX table: @@ -669,7 +666,7 @@ An e-mail address: [[mailto:nobody@nowhere.net][nobody@nowhere.net]] Blockquoted: [[http://example.com/]] -Auto-links should not occur here: +Auto-links should not occur here: == or here: @@ -689,7 +686,7 @@ Here is a movie [[movie.jpg][movie]] icon. * Footnotes -Here is a footnote reference,[1] and another.[2] This should not be a +Here is a footnote reference,[1] and another.[2] This should *not* be a footnote reference, because it contains a space.[^my note] Here is an inline note.[3] @@ -716,9 +713,9 @@ This paragraph should not be part of the note, as it is not indented. If you want, you can indent every line, but you can also be lazy and just indent the first line of each block. -[3] This is easier to type. Inline notes may contain - [[http://google.com][links]] and ] verbatim characters, as - well as [bracketed text]. +[3] This is *easier* to type. Inline notes may contain + [[http://google.com][links]] and =]= verbatim characters, as well as + [bracketed text]. [4] In quote. -- cgit v1.2.3 From afd3f21218cf4279cc718ff050b4ab9c747e72e1 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 2 Sep 2018 03:29:47 +0300 Subject: Muse writer: hlint --- src/Text/Pandoc/Writers/Muse.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index b9f9381c3..627358839 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -348,9 +348,9 @@ conditionalEscapeString :: PandocMonad m -> Muse m String conditionalEscapeString s = do shouldEscape <- shouldEscapeString s - if shouldEscape - then return $ escapeString s - else return $ s + return $ if shouldEscape + then escapeString s + else s -- Expand Math and Cite before normalizing inline list preprocessInlineList :: PandocMonad m @@ -489,7 +489,7 @@ inlineListToMuse :: PandocMonad m => [Inline] -> Muse m Doc inlineListToMuse lst = do - lst' <- (normalizeInlineList . fixNotes) <$> preprocessInlineList (map (removeKeyValues . replaceSmallCaps) lst) + lst' <- normalizeInlineList . fixNotes <$> preprocessInlineList (map (removeKeyValues . replaceSmallCaps) lst) insideAsterisks <- asks envInsideAsterisks modify $ \st -> st { stUseTags = False } -- Previous character is likely a '>' or some other markup local (\env -> env { envNearAsterisks = insideAsterisks }) $ renderInlineList lst' -- cgit v1.2.3 From 1630a731ec35d3e8538561b7824c135303fe4bdb Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 2 Sep 2018 14:38:04 +0300 Subject: Muse reader: move duplicate code into "headingStart" function --- src/Text/Pandoc/Readers/Muse.hs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 045feedb3..b251f2237 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -361,15 +361,20 @@ separator = try $ do eol return $ return B.horizontalRule --- | Parse a single-line heading. -emacsHeading :: PandocMonad m => MuseParser m (F Blocks) -emacsHeading = try $ do - guardDisabled Ext_amuse +headingStart :: PandocMonad m => MuseParser m (String, Int) +headingStart = do anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol) getPosition >>= \pos -> guard (sourceColumn pos == 1) level <- fmap length $ many1 $ char '*' guard $ level <= 5 spaceChar + return (anchorId, level) + +-- | Parse a single-line heading. +emacsHeading :: PandocMonad m => MuseParser m (F Blocks) +emacsHeading = try $ do + guardDisabled Ext_amuse + (anchorId, level) <- headingStart content <- trimInlinesF . mconcat <$> manyTill inline eol attr <- registerHeader (anchorId, [], []) (runF content def) return $ B.headerWith attr level <$> content @@ -381,11 +386,7 @@ amuseHeadingUntil :: PandocMonad m -> MuseParser m (F Blocks, a) amuseHeadingUntil end = try $ do guardEnabled Ext_amuse - anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol) - getPosition >>= \pos -> guard (sourceColumn pos == 1) - level <- fmap length $ many1 $ char '*' - guard $ level <= 5 - spaceChar + (anchorId, level) <- headingStart (content, e) <- paraContentsUntil end attr <- registerHeader (anchorId, [], []) (runF content def) return (B.headerWith attr level <$> content, e) -- cgit v1.2.3 From 02e68859ebe964002b42d76ecbd3eea51a3e1f33 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 2 Sep 2018 17:26:43 +0300 Subject: Muse reader: autonumber sections in the correct order Parsing now stops at each section header to ensure the header is registered before parsing of the next section starts. --- src/Text/Pandoc/Readers/Muse.hs | 20 ++++++++++++++++---- test/Tests/Readers/Muse.hs | 12 ++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index b251f2237..0b5d3dc1f 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -123,7 +123,9 @@ instance HasLogMessages MuseState where parseMuse :: PandocMonad m => MuseParser m Pandoc parseMuse = do many directive - blocks <- parseBlocks + firstSection <- parseBlocks + rest <- many parseSection + let blocks = mconcat $ (firstSection : rest) st <- getState let doc = runF (do Pandoc _ bs <- B.doc <$> blocks meta <- museMeta st @@ -252,17 +254,20 @@ directive = do -- ** Block parsers +-- | Parse section contents until EOF or next header parseBlocks :: PandocMonad m => MuseParser m (F Blocks) parseBlocks = try (parseEnd <|> + nextSection <|> blockStart <|> listStart <|> paraStart) where + nextSection = mempty <$ lookAhead headingStart parseEnd = mempty <$ eof - blockStart = ((B.<>) <$> (emacsHeading <|> blockElements <|> emacsNoteBlock) - <*> parseBlocks) <|> (uncurry (B.<>) <$> amuseHeadingUntil parseBlocks) + blockStart = ((B.<>) <$> (blockElements <|> emacsNoteBlock) + <*> parseBlocks) listStart = do updateState (\st -> st { museInPara = False }) uncurry (B.<>) <$> (anyListUntil parseBlocks <|> amuseNoteBlockUntil parseBlocks) @@ -271,6 +276,13 @@ parseBlocks = uncurry (B.<>) . first (p indent) <$> paraUntil parseBlocks where p indent = if indent >= 2 && indent < 6 then fmap B.blockQuote else id +-- | Parse section that starts with a header +parseSection :: PandocMonad m + => MuseParser m (F Blocks) +parseSection = + ((B.<>) <$> emacsHeading <*> parseBlocks) <|> + ((uncurry (B.<>)) <$> amuseHeadingUntil parseBlocks) + parseBlocksTill :: PandocMonad m => MuseParser m a -> MuseParser m (F Blocks) @@ -362,7 +374,7 @@ separator = try $ do return $ return B.horizontalRule headingStart :: PandocMonad m => MuseParser m (String, Int) -headingStart = do +headingStart = try $ do anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol) getPosition >>= \pos -> guard (sourceColumn pos == 1) level <- fmap length $ many1 $ char '*' diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs index ca3324e34..edb8ba21a 100644 --- a/test/Tests/Readers/Muse.hs +++ b/test/Tests/Readers/Muse.hs @@ -625,6 +625,18 @@ tests = T.unlines [ "* Foo" , "bar" ] =?> header 1 "Foo\nbar" + , test (purely $ readMuse def { readerExtensions = extensionsFromList [Ext_amuse, Ext_auto_identifiers]}) + "Auto identifiers" + (T.unlines [ "* foo" + , "** Foo" + , "* bar" + , "** foo" + , "* foo" + ] =?> headerWith ("foo",[],[]) 1 "foo" <> + headerWith ("foo-1",[],[]) 2 "Foo" <> + headerWith ("bar",[],[]) 1 "bar" <> + headerWith ("foo-2",[],[]) 2 "foo" <> + headerWith ("foo-3",[],[]) 1 "foo") ] , testGroup "Directives" [ "Title" =: -- cgit v1.2.3 From c5572fc07e13b978acae53cd2af066d9b365993e Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 4 Sep 2018 11:21:13 +0300 Subject: hlint some writers --- src/Text/Pandoc/Writers/AsciiDoc.hs | 4 ++-- src/Text/Pandoc/Writers/ConTeXt.hs | 3 +-- src/Text/Pandoc/Writers/EPUB.hs | 2 +- src/Text/Pandoc/Writers/FB2.hs | 2 +- src/Text/Pandoc/Writers/Haddock.hs | 4 ++-- src/Text/Pandoc/Writers/Man.hs | 4 ++-- src/Text/Pandoc/Writers/Ms.hs | 2 +- src/Text/Pandoc/Writers/Texinfo.hs | 17 +++++++---------- src/Text/Pandoc/Writers/Textile.hs | 8 ++++---- 9 files changed, 21 insertions(+), 25 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs index df1b9c8d0..ffe5b7473 100644 --- a/src/Text/Pandoc/Writers/AsciiDoc.hs +++ b/src/Text/Pandoc/Writers/AsciiDoc.hs @@ -285,7 +285,7 @@ blockToAsciiDoc opts (DefinitionList items) = do contents <- mapM (definitionListItemToAsciiDoc opts) items return $ cat contents <> blankline blockToAsciiDoc opts (Div (ident,_,_) bs) = do - let identifier = if null ident then empty else ("[[" <> text ident <> "]]") + let identifier = if null ident then empty else "[[" <> text ident <> "]]" contents <- blockListToAsciiDoc opts bs return $ identifier $$ contents @@ -492,6 +492,6 @@ inlineToAsciiDoc opts (Note [Plain inlines]) = do -- asciidoc can't handle blank lines in notes inlineToAsciiDoc _ (Note _) = return "[multiblock footnote omitted]" inlineToAsciiDoc opts (Span (ident,_,_) ils) = do - let identifier = if null ident then empty else ("[[" <> text ident <> "]]") + let identifier = if null ident then empty else "[[" <> text ident <> "]]" contents <- inlineListToAsciiDoc opts ils return $ identifier <> contents diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs index 594812294..763f1a370 100644 --- a/src/Text/Pandoc/Writers/ConTeXt.hs +++ b/src/Text/Pandoc/Writers/ConTeXt.hs @@ -329,8 +329,7 @@ alignToConTeXt align = case align of AlignDefault -> empty listItemToConTeXt :: PandocMonad m => [Block] -> WM m Doc -listItemToConTeXt list = blockListToConTeXt list >>= - return . ("\\item" $$) . nest 2 +listItemToConTeXt list = (("\\item" $$) . nest 2) <$> blockListToConTeXt list defListItemToConTeXt :: PandocMonad m => ([Inline], [[Block]]) -> WM m Doc defListItemToConTeXt (term, defs) = do diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs index 4c5e73d81..6099f0223 100644 --- a/src/Text/Pandoc/Writers/EPUB.hs +++ b/src/Text/Pandoc/Writers/EPUB.hs @@ -801,7 +801,7 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do [ unode "a" ! [("href", "text/cover.xhtml") ,("epub:type", "cover")] $ "Cover"] | - epubCoverImage metadata /= Nothing + isJust (epubCoverImage metadata) ] ++ [ unode "li" [ unode "a" ! [("href", "#toc") diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs index 6158052bb..a139de5cd 100644 --- a/src/Text/Pandoc/Writers/FB2.hs +++ b/src/Text/Pandoc/Writers/FB2.hs @@ -119,7 +119,7 @@ description meta' = do let as = authors meta' dd <- docdate meta' annotation <- case lookupMeta "abstract" meta' of - Just (MetaBlocks bs) -> (list . el "annotation") <$> (cMapM blockToXml $ map unPlain bs) + Just (MetaBlocks bs) -> (list . el "annotation") <$> cMapM blockToXml (map unPlain bs) _ -> pure mempty let lang = case lookupMeta "lang" meta' of Just (MetaInlines [Str s]) -> [el "lang" $ iso639 s] diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs index 6cb720489..80e092b6a 100644 --- a/src/Text/Pandoc/Writers/Haddock.hs +++ b/src/Text/Pandoc/Writers/Haddock.hs @@ -207,13 +207,13 @@ blockListToHaddock :: PandocMonad m -> [Block] -- ^ List of block elements -> StateT WriterState m Doc blockListToHaddock opts blocks = - mapM (blockToHaddock opts) blocks >>= return . cat + cat <$> mapM (blockToHaddock opts) blocks -- | Convert list of Pandoc inline elements to haddock. inlineListToHaddock :: PandocMonad m => WriterOptions -> [Inline] -> StateT WriterState m Doc inlineListToHaddock opts lst = - mapM (inlineToHaddock opts) lst >>= return . cat + cat <$> mapM (inlineToHaddock opts) lst -- | Convert Pandoc inline element to haddock. inlineToHaddock :: PandocMonad m diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs index 912231a88..be490bf22 100644 --- a/src/Text/Pandoc/Writers/Man.hs +++ b/src/Text/Pandoc/Writers/Man.hs @@ -325,11 +325,11 @@ blockListToMan :: PandocMonad m -> [Block] -- ^ List of block elements -> StateT WriterState m Doc blockListToMan opts blocks = - mapM (blockToMan opts) blocks >>= (return . vcat) + vcat <$> mapM (blockToMan opts) blocks -- | Convert list of Pandoc inline elements to man. inlineListToMan :: PandocMonad m => WriterOptions -> [Inline] -> StateT WriterState m Doc -inlineListToMan opts lst = mapM (inlineToMan opts) lst >>= (return . hcat) +inlineListToMan opts lst = hcat <$> mapM (inlineToMan opts) lst -- | Convert Pandoc inline element to man. inlineToMan :: PandocMonad m => WriterOptions -> Inline -> StateT WriterState m Doc diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs index 16a66c85b..3dcf816b8 100644 --- a/src/Text/Pandoc/Writers/Ms.hs +++ b/src/Text/Pandoc/Writers/Ms.hs @@ -434,7 +434,7 @@ blockListToMs :: PandocMonad m -> [Block] -- ^ List of block elements -> MS m Doc blockListToMs opts blocks = - mapM (blockToMs opts) blocks >>= (return . vcat) + vcat <$> mapM (blockToMs opts) blocks -- | Convert list of Pandoc inline elements to ms. inlineListToMs :: PandocMonad m => WriterOptions -> [Inline] -> MS m Doc diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs index 9c73eb9ca..21d1f4eca 100644 --- a/src/Text/Pandoc/Writers/Texinfo.hs +++ b/src/Text/Pandoc/Writers/Texinfo.hs @@ -346,12 +346,9 @@ collectNodes :: Int -> [Block] -> [Block] collectNodes _ [] = [] collectNodes level (x:xs) = case x of - (Header hl _ _) -> - if hl < level - then [] - else if hl == level - then x : collectNodes level xs - else collectNodes level xs + (Header hl _ _) | hl < level -> [] + | hl == level -> x : collectNodes level xs + | otherwise -> collectNodes level xs _ -> collectNodes level xs @@ -389,7 +386,7 @@ defListItemToTexinfo (term, defs) = do inlineListToTexinfo :: PandocMonad m => [Inline] -- ^ Inlines to convert -> TI m Doc -inlineListToTexinfo lst = mapM inlineToTexinfo lst >>= return . hcat +inlineListToTexinfo lst = hcat <$> mapM inlineToTexinfo lst -- | Convert list of inline elements to Texinfo acceptable for a node name. inlineListForNode :: PandocMonad m @@ -411,10 +408,10 @@ inlineToTexinfo (Span _ lst) = inlineListToTexinfo lst inlineToTexinfo (Emph lst) = - inlineListToTexinfo lst >>= return . inCmd "emph" + inCmd "emph" <$> inlineListToTexinfo lst inlineToTexinfo (Strong lst) = - inlineListToTexinfo lst >>= return . inCmd "strong" + inCmd "strong" <$> inlineListToTexinfo lst inlineToTexinfo (Strikeout lst) = do modify $ \st -> st{ stStrikeout = True } @@ -430,7 +427,7 @@ inlineToTexinfo (Subscript lst) = do return $ text "@sub{" <> contents <> char '}' inlineToTexinfo (SmallCaps lst) = - inlineListToTexinfo lst >>= return . inCmd "sc" + inCmd "sc" <$> inlineListToTexinfo lst inlineToTexinfo (Code _ str) = return $ text $ "@code{" ++ stringToTexinfo str ++ "}" diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs index 0ed79d2df..d1724f438 100644 --- a/src/Text/Pandoc/Writers/Textile.hs +++ b/src/Text/Pandoc/Writers/Textile.hs @@ -73,7 +73,7 @@ pandocToTextile opts (Pandoc meta blocks) = do (inlineListToTextile opts) meta body <- blockListToTextile opts blocks notes <- gets $ unlines . reverse . stNotes - let main = pack $ body ++ if null notes then "" else ("\n\n" ++ notes) + let main = pack $ body ++ if null notes then "" else "\n\n" ++ notes let context = defField "body" main metadata case writerTemplate opts of Nothing -> return main @@ -154,7 +154,7 @@ blockToTextile _ HorizontalRule = return "
\n" blockToTextile opts (Header level (ident,classes,keyvals) inlines) = do contents <- inlineListToTextile opts inlines - let identAttr = if null ident then "" else ('#':ident) + let identAttr = if null ident then "" else '#':ident let attribs = if null identAttr && null classes then "" else "(" ++ unwords classes ++ identAttr ++ ")" @@ -382,13 +382,13 @@ blockListToTextile :: PandocMonad m -> [Block] -- ^ List of block elements -> TW m String blockListToTextile opts blocks = - mapM (blockToTextile opts) blocks >>= return . vcat + vcat <$> mapM (blockToTextile opts) blocks -- | Convert list of Pandoc inline elements to Textile. inlineListToTextile :: PandocMonad m => WriterOptions -> [Inline] -> TW m String inlineListToTextile opts lst = - mapM (inlineToTextile opts) lst >>= return . concat + concat <$> mapM (inlineToTextile opts) lst -- | Convert Pandoc inline element to Textile. inlineToTextile :: PandocMonad m => WriterOptions -> Inline -> TW m String -- cgit v1.2.3 From ceec26f6471d3c1cbd971cf7701144ccd5bbfdca Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Wed, 5 Sep 2018 14:26:06 +0200 Subject: Org reader: strip planning info from output Planning info is parsed, but not included in the output (as is the default with Emacs Org-mode). Fixes: #4867 --- src/Text/Pandoc/Readers/Org/DocumentTree.hs | 36 ++++++++++++++++++++++++++++- test/Tests/Readers/Org/Block/Header.hs | 25 ++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Org/DocumentTree.hs b/src/Text/Pandoc/Readers/Org/DocumentTree.hs index c9465581a..8e2f080f2 100644 --- a/src/Text/Pandoc/Readers/Org/DocumentTree.hs +++ b/src/Text/Pandoc/Readers/Org/DocumentTree.hs @@ -70,6 +70,7 @@ documentTree blocks inline = do , headlineTodoMarker = Nothing , headlineText = B.fromList title' , headlineTags = mempty + , headlinePlanning = emptyPlanning , headlineProperties = mempty , headlineContents = initialBlocks' , headlineChildren = headlines' @@ -117,6 +118,7 @@ data Headline = Headline , headlineTodoMarker :: Maybe TodoMarker , headlineText :: Inlines , headlineTags :: [Tag] + , headlinePlanning :: PlanningInfo -- ^ subtree planning information , headlineProperties :: Properties , headlineContents :: Blocks , headlineChildren :: [Headline] @@ -136,6 +138,7 @@ headline blocks inline lvl = try $ do title <- trimInlinesF . mconcat <$> manyTill inline endOfTitle tags <- option [] headerTags newline + planning <- option emptyPlanning planningInfo properties <- option mempty propertiesDrawer contents <- blocks children <- many (headline blocks inline (level + 1)) @@ -148,6 +151,7 @@ headline blocks inline lvl = try $ do , headlineTodoMarker = todoKw , headlineText = title' , headlineTags = tags + , headlinePlanning = planning , headlineProperties = properties , headlineContents = contents' , headlineChildren = children' @@ -277,9 +281,39 @@ tagsToInlines tags = tagSpan :: Tag -> Inlines -> Inlines tagSpan t = B.spanWith ("", ["tag"], [("tag-name", fromTag t)]) +-- | An Org timestamp, including repetition marks. TODO: improve +type Timestamp = String + +timestamp :: Monad m => OrgParser m Timestamp +timestamp = try $ do + openChar <- oneOf "<[" + let isActive = openChar == '<' + let closeChar = if isActive then '>' else ']' + content <- many1Till anyChar (char closeChar) + return (openChar : content ++ [closeChar]) + +-- | Planning information for a subtree/headline. +data PlanningInfo = PlanningInfo + { planningClosed :: Maybe Timestamp + , planningDeadline :: Maybe Timestamp + , planningScheduled :: Maybe Timestamp + } +emptyPlanning :: PlanningInfo +emptyPlanning = PlanningInfo Nothing Nothing Nothing - +-- | Read a single planning-related and timestamped line. +planningInfo :: Monad m => OrgParser m PlanningInfo +planningInfo = try $ do + updaters <- many1 planningDatum <* skipSpaces <* newline + return $ foldr ($) emptyPlanning updaters + where + planningDatum = skipSpaces *> choice + [ updateWith (\s p -> p { planningScheduled = Just s}) "SCHEDULED" + , updateWith (\d p -> p { planningDeadline = Just d}) "DEADLINE" + , updateWith (\c p -> p { planningClosed = Just c}) "CLOSED" + ] + updateWith fn cs = fn <$> (string cs *> char ':' *> skipSpaces *> timestamp) -- | Read a :PROPERTIES: drawer and return the key/value pairs contained -- within. diff --git a/test/Tests/Readers/Org/Block/Header.hs b/test/Tests/Readers/Org/Block/Header.hs index 3b0d7dda9..6f38714cd 100644 --- a/test/Tests/Readers/Org/Block/Header.hs +++ b/test/Tests/Readers/Org/Block/Header.hs @@ -181,4 +181,29 @@ tests = , " :END:" ] =?> headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered" + + , testGroup "planning information" + [ "Planning info is not included in output" =: + T.unlines [ "* important" + , T.unwords + [ "CLOSED: [2018-09-05 Wed 13:58]" + , "DEADLINE: <2018-09-17 Mon>" + , "SCHEDULED: <2018-09-10 Mon>" + ] + ] =?> + headerWith ("important", [], []) 1 "important" + + , "Properties after planning info are recognized" =: + T.unlines [ "* important " + , " " <> T.unwords + [ "CLOSED: [2018-09-05 Wed 13:58]" + , "DEADLINE: <2018-09-17 Mon>" + , "SCHEDULED: <2018-09-10 Mon>" + ] + , " :PROPERTIES:" + , " :custom_id: look" + , " :END:" + ] =?> + headerWith ("look", [], []) 1 "important" + ] ] -- cgit v1.2.3 From aac3d752e1f059d2727863a4705feef4e5a05f3e Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Thu, 6 Sep 2018 20:53:57 +0200 Subject: Org reader internals: disable some GHC extensions The RecordWildCards and ViewPatterns language extensions can be used to shorten code, but usually also makes it harder to read. The DocumentTree module was hence refactored and no longer relies on these extensions. --- src/Text/Pandoc/Readers/Org/DocumentTree.hs | 58 ++++++++++++++++------------- 1 file changed, 32 insertions(+), 26 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Org/DocumentTree.hs b/src/Text/Pandoc/Readers/Org/DocumentTree.hs index 8e2f080f2..6dd78560f 100644 --- a/src/Text/Pandoc/Readers/Org/DocumentTree.hs +++ b/src/Text/Pandoc/Readers/Org/DocumentTree.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE NoImplicitPrelude #-} {- Copyright (C) 2014-2018 Albert Krewinkel @@ -17,8 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} {-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ViewPatterns #-} +{-# LANGUAGE NoImplicitPrelude #-} {- | Module : Text.Pandoc.Readers.Org.DocumentTree Copyright : Copyright (C) 2014-2018 Albert Krewinkel @@ -167,14 +165,17 @@ headline blocks inline lvl = try $ do -- | Convert an Org mode headline (i.e. a document tree) into pandoc's Blocks headlineToBlocks :: Monad m => Headline -> OrgParser m Blocks -headlineToBlocks hdln@Headline {..} = do - maxHeadlineLevels <- getExportSetting exportHeadlineLevels +headlineToBlocks hdln = do + maxLevel <- getExportSetting exportHeadlineLevels + let tags = headlineTags hdln + let text = headlineText hdln + let level = headlineLevel hdln case () of - _ | any isNoExportTag headlineTags -> return mempty - _ | any isArchiveTag headlineTags -> archivedHeadlineToBlocks hdln - _ | isCommentTitle headlineText -> return mempty - _ | headlineLevel >= maxHeadlineLevels -> headlineToHeaderWithList hdln - _ | otherwise -> headlineToHeaderWithContents hdln + _ | any isNoExportTag tags -> return mempty + _ | any isArchiveTag tags -> archivedHeadlineToBlocks hdln + _ | isCommentTitle text -> return mempty + _ | maxLevel <= level -> headlineToHeaderWithList hdln + _ | otherwise -> headlineToHeaderWithContents hdln isNoExportTag :: Tag -> Bool isNoExportTag = (== toTag "noexport") @@ -186,8 +187,9 @@ isArchiveTag = (== toTag "ARCHIVE") -- FIXME: This accesses builder internals not intended for use in situations -- like these. Replace once keyword parsing is supported. isCommentTitle :: Inlines -> Bool -isCommentTitle (B.toList -> (Str "COMMENT":_)) = True -isCommentTitle _ = False +isCommentTitle inlns = case B.toList inlns of + (Str "COMMENT":_) -> True + _ -> False archivedHeadlineToBlocks :: Monad m => Headline -> OrgParser m Blocks archivedHeadlineToBlocks hdln = do @@ -198,17 +200,21 @@ archivedHeadlineToBlocks hdln = do ArchivedTreesHeadlineOnly -> headlineToHeader hdln headlineToHeaderWithList :: Monad m => Headline -> OrgParser m Blocks -headlineToHeaderWithList hdln@Headline {..} = do +headlineToHeaderWithList hdln = do maxHeadlineLevels <- getExportSetting exportHeadlineLevels header <- headlineToHeader hdln - listElements <- mapM headlineToBlocks headlineChildren + listElements <- mapM headlineToBlocks (headlineChildren hdln) let listBlock = if null listElements then mempty else B.orderedList listElements - let headerText = if maxHeadlineLevels == headlineLevel + let headerText = if maxHeadlineLevels == headlineLevel hdln then header else flattenHeader header - return $ headerText <> headlineContents <> listBlock + return . mconcat $ + [ headerText + , headlineContents hdln + , listBlock + ] where flattenHeader :: Blocks -> Blocks flattenHeader blks = @@ -217,27 +223,27 @@ headlineToHeaderWithList hdln@Headline {..} = do _ -> mempty headlineToHeaderWithContents :: Monad m => Headline -> OrgParser m Blocks -headlineToHeaderWithContents hdln@Headline {..} = do +headlineToHeaderWithContents hdln = do header <- headlineToHeader hdln - childrenBlocks <- mconcat <$> mapM headlineToBlocks headlineChildren - return $ header <> headlineContents <> childrenBlocks + childrenBlocks <- mconcat <$> mapM headlineToBlocks (headlineChildren hdln) + return $ header <> headlineContents hdln <> childrenBlocks headlineToHeader :: Monad m => Headline -> OrgParser m Blocks -headlineToHeader Headline {..} = do +headlineToHeader hdln = do exportTodoKeyword <- getExportSetting exportWithTodoKeywords exportTags <- getExportSetting exportWithTags let todoText = if exportTodoKeyword - then case headlineTodoMarker of + then case headlineTodoMarker hdln of Just kw -> todoKeywordToInlines kw <> B.space Nothing -> mempty else mempty - let text = todoText <> headlineText <> + let text = todoText <> headlineText hdln <> if exportTags - then tagsToInlines headlineTags + then tagsToInlines (headlineTags hdln) else mempty - let propAttr = propertiesToAttr headlineProperties - attr <- registerHeader propAttr headlineText - return $ B.headerWith attr headlineLevel text + let propAttr = propertiesToAttr (headlineProperties hdln) + attr <- registerHeader propAttr (headlineText hdln) + return $ B.headerWith attr (headlineLevel hdln) text todoKeyword :: Monad m => OrgParser m TodoMarker todoKeyword = try $ do -- cgit v1.2.3 From 275afec38a9feb1143344af19d5ebfbf4ef4fb32 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Thu, 6 Sep 2018 20:57:21 +0200 Subject: Org reader: respect export option `p` for planning info Inclusion of planning info (*DEADLINE*, *SCHEDULED*, and *CLOSED*) can be controlled via the `p` export option: setting the option to `t` will add all planning information in a *Plain* block below the respective headline. --- src/Text/Pandoc/Readers/Org/DocumentTree.hs | 26 +++++++++++++++++++++++++- src/Text/Pandoc/Readers/Org/ExportSettings.hs | 2 +- src/Text/Pandoc/Readers/Org/ParserState.hs | 2 ++ test/Tests/Readers/Org/Block/Header.hs | 13 +++++++++++++ test/Tests/Readers/Org/Directive.hs | 23 +++++++++++++++++++++++ 5 files changed, 64 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Org/DocumentTree.hs b/src/Text/Pandoc/Readers/Org/DocumentTree.hs index 6dd78560f..c7a5f22c4 100644 --- a/src/Text/Pandoc/Readers/Org/DocumentTree.hs +++ b/src/Text/Pandoc/Readers/Org/DocumentTree.hs @@ -204,6 +204,7 @@ headlineToHeaderWithList hdln = do maxHeadlineLevels <- getExportSetting exportHeadlineLevels header <- headlineToHeader hdln listElements <- mapM headlineToBlocks (headlineChildren hdln) + planningBlock <- planningToBlock (headlinePlanning hdln) let listBlock = if null listElements then mempty else B.orderedList listElements @@ -213,6 +214,7 @@ headlineToHeaderWithList hdln = do return . mconcat $ [ headerText , headlineContents hdln + , planningBlock , listBlock ] where @@ -225,8 +227,9 @@ headlineToHeaderWithList hdln = do headlineToHeaderWithContents :: Monad m => Headline -> OrgParser m Blocks headlineToHeaderWithContents hdln = do header <- headlineToHeader hdln + planningBlock <- planningToBlock (headlinePlanning hdln) childrenBlocks <- mconcat <$> mapM headlineToBlocks (headlineChildren hdln) - return $ header <> headlineContents hdln <> childrenBlocks + return $ header <> planningBlock <> headlineContents hdln <> childrenBlocks headlineToHeader :: Monad m => Headline -> OrgParser m Blocks headlineToHeader hdln = do @@ -287,6 +290,27 @@ tagsToInlines tags = tagSpan :: Tag -> Inlines -> Inlines tagSpan t = B.spanWith ("", ["tag"], [("tag-name", fromTag t)]) +-- | Render planning info as a block iff the respective export setting is +-- enabled. +planningToBlock :: Monad m => PlanningInfo -> OrgParser m Blocks +planningToBlock planning = do + includePlanning <- getExportSetting exportWithPlanning + return $ + if includePlanning + then B.plain . mconcat . intersperse B.space . filter (/= mempty) $ + [ datumInlines planningClosed "CLOSED" + , datumInlines planningDeadline "DEADLINE" + , datumInlines planningScheduled "SCHEDULED" + ] + else mempty + where + datumInlines field name = + case field planning of + Nothing -> mempty + Just time -> B.strong (B.str name <> B.str ":") + <> B.space + <> B.emph (B.str time) + -- | An Org timestamp, including repetition marks. TODO: improve type Timestamp = String diff --git a/src/Text/Pandoc/Readers/Org/ExportSettings.hs b/src/Text/Pandoc/Readers/Org/ExportSettings.hs index d02eb37c5..f79ee0d64 100644 --- a/src/Text/Pandoc/Readers/Org/ExportSettings.hs +++ b/src/Text/Pandoc/Readers/Org/ExportSettings.hs @@ -69,7 +69,7 @@ exportSetting = choice , integerSetting "H" (\val es -> es { exportHeadlineLevels = val }) , ignoredSetting "inline" , ignoredSetting "num" - , ignoredSetting "p" + , booleanSetting "p" (\val es -> es { exportWithPlanning = val }) , ignoredSetting "pri" , ignoredSetting "prop" , ignoredSetting "stat" diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs index 4cb5bb626..d33602575 100644 --- a/src/Text/Pandoc/Readers/Org/ParserState.hs +++ b/src/Text/Pandoc/Readers/Org/ParserState.hs @@ -260,6 +260,7 @@ data ExportSettings = ExportSettings , exportWithAuthor :: Bool -- ^ Include author in final meta-data , exportWithCreator :: Bool -- ^ Include creator in final meta-data , exportWithEmail :: Bool -- ^ Include email in final meta-data + , exportWithPlanning :: Bool -- ^ Keep planning info after headlines , exportWithTags :: Bool -- ^ Keep tags as part of headlines , exportWithTodoKeywords :: Bool -- ^ Keep TODO keywords in headers } @@ -280,6 +281,7 @@ defaultExportSettings = ExportSettings , exportWithAuthor = True , exportWithCreator = True , exportWithEmail = True + , exportWithPlanning = False , exportWithTags = True , exportWithTodoKeywords = True } diff --git a/test/Tests/Readers/Org/Block/Header.hs b/test/Tests/Readers/Org/Block/Header.hs index 6f38714cd..913c830d6 100644 --- a/test/Tests/Readers/Org/Block/Header.hs +++ b/test/Tests/Readers/Org/Block/Header.hs @@ -205,5 +205,18 @@ tests = , " :END:" ] =?> headerWith ("look", [], []) 1 "important" + + , "Planning info followed by test" =: + T.unlines [ "* important " + , " " <> T.unwords + [ "CLOSED: [2018-09-05 Wed 13:58]" + , "DEADLINE: <2018-09-17 Mon>" + , "SCHEDULED: <2018-09-10 Mon>" + ] + , " :PROPERTIES:" + , " :custom_id: look" + , " :END:" + ] =?> + headerWith ("look", [], []) 1 "important" ] ] diff --git a/test/Tests/Readers/Org/Directive.hs b/test/Tests/Readers/Org/Directive.hs index bb9c52e69..87abb714d 100644 --- a/test/Tests/Readers/Org/Directive.hs +++ b/test/Tests/Readers/Org/Directive.hs @@ -150,6 +150,29 @@ tests = , "* Headline :hello:world:" ] =?> headerWith ("headline", [], mempty) 1 "Headline" + + , testGroup "planning information" + [ "include planning info after headlines" =: + T.unlines [ "#+OPTIONS: p:t" + , "* important" + , " DEADLINE: <2018-10-01 Mon> SCHEDULED: <2018-09-15 Sat>" + ] =?> + mconcat [ headerWith ("important", mempty, mempty) 1 "important" + , plain $ strong "DEADLINE:" + <> space + <> emph (str "<2018-10-01 Mon>") + <> space + <> strong "SCHEDULED:" + <> space + <> emph (str "<2018-09-15 Sat>") + ] + + , "empty planning info is not included" =: + T.unlines [ "#+OPTIONS: p:t" + , "* Wichtig" + ] =?> + headerWith ("wichtig", mempty, mempty) 1 "Wichtig" + ] ] , testGroup "Include" -- cgit v1.2.3 From a211edc8192f2abc9787c1012a3cf3cb3f96952c Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 6 Sep 2018 17:05:04 -0700 Subject: HTML reader: parse ` +^D +[Plain [Str "My",Space,Math InlineMath "\\mathcal{D}"]] +``` + +``` +% pandoc -f html -t native + +^D +[Plain [Math DisplayMath "\\mathcal{D}"]] +``` -- cgit v1.2.3 From 12cec8f08233ea5836af77aff27771b800a35ce7 Mon Sep 17 00:00:00 2001 From: Nils Carlson Date: Fri, 7 Sep 2018 23:37:21 +0000 Subject: Fix percentage image scaling in ODT (#4881) Image scaling in ODT was broken when a width was set to a percentage. The width was passed to the svg:width field as a pecentage, which is not correct according to the ODT standard. Instead the real dimensions should be passed as width and height and the style:rel-width attribute should be set to the percentage while style:rel-heigh attribute should be set to "scale". The converse is true if a percentage height is given. This is now fixed and documents produced are now properly scaled. --- src/Text/Pandoc/Writers/ODT.hs | 4 ++-- src/Text/Pandoc/Writers/OpenDocument.hs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs index 7aecb3da5..1c9481630 100644 --- a/src/Text/Pandoc/Writers/ODT.hs +++ b/src/Text/Pandoc/Writers/ODT.hs @@ -189,8 +189,8 @@ transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = catchError let dims = case (getDim Width, getDim Height) of (Just w, Just h) -> [("width", show w), ("height", show h)] - (Just w@(Percent p), Nothing) -> [("width", show w), ("height", show (p / ratio) ++ "%")] - (Nothing, Just h@(Percent p)) -> [("width", show (p * ratio) ++ "%"), ("height", show h)] + (Just w@(Percent _), Nothing) -> [("rel-width", show w),("rel-height", "scale"),("width", show ptX ++ "pt"),("height", show ptY ++ "pt")] + (Nothing, Just h@(Percent _)) -> [("rel-width", "scale"),("rel-height", show h),("width", show ptX ++ "pt"),("height", show ptY ++ "pt")] (Just w@(Inch i), Nothing) -> [("width", show w), ("height", show (i / ratio) ++ "in")] (Nothing, Just h@(Inch i)) -> [("width", show (i * ratio) ++ "in"), ("height", show h)] _ -> [("width", show ptX ++ "pt"), ("height", show ptY ++ "pt")] diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index 21d709f98..d6ab73aa4 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -506,7 +506,9 @@ inlineToOpenDocument o ils modify (\st -> st{ stImageId = id' + 1 }) let getDims [] = [] getDims (("width", w) :xs) = ("svg:width", w) : getDims xs + getDims (("rel-width", w):xs) = ("style:rel-width", w) : getDims xs getDims (("height", h):xs) = ("svg:height", h) : getDims xs + getDims (("rel-height", w):xs) = ("style:rel-height", w) : getDims xs getDims (_:xs) = getDims xs return $ inTags False "draw:frame" (("draw:name", "img" ++ show id') : getDims kvs) $ -- cgit v1.2.3 From 0b486e867264c2bac02226766055b05d3c51de7e Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 9 Sep 2018 13:11:53 -0700 Subject: Org writer: don't escape literal `_`, `^`. Org doesn't recognize these escapes. Closes #4882. --- src/Text/Pandoc/Writers/Org.hs | 2 +- test/writer.org | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs index 1dd825b79..12a54fd71 100644 --- a/src/Text/Pandoc/Writers/Org.hs +++ b/src/Text/Pandoc/Writers/Org.hs @@ -109,7 +109,7 @@ escapeString = escapeStringUsing $ , ('\x2013',"--") , ('\x2019',"'") , ('\x2026',"...") - ] ++ backslashEscapes "^_" + ] isRawFormat :: Format -> Bool isRawFormat f = diff --git a/test/writer.org b/test/writer.org index 1ae0ca8f3..32fcfc404 100644 --- a/test/writer.org +++ b/test/writer.org @@ -584,7 +584,7 @@ Superscripts: a^{bc}d a^{/hello/} a^{hello there}. Subscripts: H_{2}O, H_{23}O, H_{many of them}O. These should not be superscripts or subscripts, because of the unescaped -spaces: a\^b c\^d, a~b c~d. +spaces: a^b c^d, a~b c~d. -------------- @@ -674,7 +674,7 @@ Backtick: ` Asterisk: * -Underscore: \_ +Underscore: _ Left brace: { @@ -724,7 +724,7 @@ Just a [[/url/][URL]]. [[/url/][URL and title]] -[[/url/with_underscore][with\_underscore]] +[[/url/with_underscore][with_underscore]] [[mailto:nobody@nowhere.net][Email link]] @@ -816,7 +816,7 @@ Here is a movie [[file:movie.jpg]] icon. :END: Here is a footnote reference,[fn:1] and another.[fn:2] This should /not/ be a -footnote reference, because it contains a space.[\^my note] Here is an inline +footnote reference, because it contains a space.[^my note] Here is an inline note.[fn:3] #+BEGIN_QUOTE -- cgit v1.2.3 From fa4ebd71a33a3ca1b435bda34fce91f4a13055f5 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 9 Sep 2018 22:53:18 -0700 Subject: LaTeX reader: resolve `\ref` for figure numbers. --- src/Text/Pandoc/Readers/LaTeX.hs | 53 +++++++++++++++++++++++++++++++--------- test/command/refs.md | 45 +++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 13 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 9fcaa2b09..7346e9398 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -137,15 +137,15 @@ resolveRefs _ x = x -- Left e -> error (show e) -- Right r -> return r -newtype HeaderNum = HeaderNum [Int] +newtype DottedNum = DottedNum [Int] deriving (Show) -renderHeaderNum :: HeaderNum -> String -renderHeaderNum (HeaderNum xs) = +renderDottedNum :: DottedNum -> String +renderDottedNum (DottedNum xs) = intercalate "." (map show xs) -incrementHeaderNum :: Int -> HeaderNum -> HeaderNum -incrementHeaderNum level (HeaderNum ns) = HeaderNum $ +incrementDottedNum :: Int -> DottedNum -> DottedNum +incrementDottedNum level (DottedNum ns) = DottedNum $ case reverse (take level (ns ++ repeat 0)) of (x:xs) -> reverse (x+1 : xs) [] -> [] -- shouldn't happen @@ -162,7 +162,8 @@ data LaTeXState = LaTeXState{ sOptions :: ReaderOptions , sCaption :: (Maybe Inlines, Maybe String) , sInListItem :: Bool , sInTableCell :: Bool - , sLastHeaderNum :: HeaderNum + , sLastHeaderNum :: DottedNum + , sLastFigureNum :: DottedNum , sLabels :: M.Map String [Inline] , sHasChapters :: Bool , sToggles :: M.Map String Bool @@ -182,7 +183,8 @@ defaultLaTeXState = LaTeXState{ sOptions = def , sCaption = (Nothing, Nothing) , sInListItem = False , sInTableCell = False - , sLastHeaderNum = HeaderNum [] + , sLastHeaderNum = DottedNum [] + , sLastFigureNum = DottedNum [] , sLabels = M.empty , sHasChapters = False , sToggles = M.empty @@ -2431,11 +2433,11 @@ section (ident, classes, kvs) lvl = do hn <- sLastHeaderNum <$> getState hasChapters <- sHasChapters <$> getState let lvl' = lvl + if hasChapters then 1 else 0 - let num = incrementHeaderNum lvl' hn - updateState $ \st -> st{ sLastHeaderNum = num } - updateState $ \st -> st{ sLabels = M.insert lab - [Str (renderHeaderNum num)] - (sLabels st) } + let num = incrementDottedNum lvl' hn + updateState $ \st -> st{ sLastHeaderNum = num + , sLabels = M.insert lab + [Str (renderDottedNum num)] + (sLabels st) } attr' <- registerHeader (lab, classes, kvs) contents return $ headerWith attr' lvl contents @@ -2722,6 +2724,33 @@ addImageCaption = walkM go attr' = case mblab of Just lab -> (lab, cls, kvs) Nothing -> attr + case attr' of + ("", _, _) -> return () + (ident, _, _) -> do + st <- getState + let chapnum = + case (sHasChapters st, sLastHeaderNum st) of + (True, DottedNum (n:_)) -> Just n + _ -> Nothing + let num = case sLastFigureNum st of + DottedNum [m,n] -> + case chapnum of + Just m' | m' == m -> DottedNum [m, n+1] + | otherwise -> DottedNum [m', 1] + Nothing -> DottedNum [1] + -- shouldn't happen + DottedNum [n] -> + case chapnum of + Just m -> DottedNum [m, 1] + Nothing -> DottedNum [n + 1] + _ -> + case chapnum of + Just n -> DottedNum [n, 1] + Nothing -> DottedNum [1] + setState $ + st{ sLastFigureNum = num + , sLabels = M.insert ident + [Str (renderDottedNum num)] (sLabels st) } return $ Image attr' alt' (src, tit') go x = return x diff --git a/test/command/refs.md b/test/command/refs.md index dd62fa33d..8b58ea6d7 100644 --- a/test/command/refs.md +++ b/test/command/refs.md @@ -43,9 +43,52 @@ Accuracy~\eqref{eq:Accuracy} is the proportion, measuring true results among all Figure \ref{fig:Logo} illustrated the SVG logo ^D [Para [Image ("fig:Logo",[],[]) [Str "Logo",Span ("",[],[("label","fig:Logo")]) []] ("command/SVG_logo.svg","fig:")] -,Para [Str "Figure",Space,Link ("",[],[("reference-type","ref"),("reference","fig:Logo")]) [Str "[fig:Logo]"] ("#fig:Logo",""),Space,Str "illustrated",Space,Str "the",Space,Str "SVG",Space,Str "logo"]] +,Para [Str "Figure",Space,Link ("",[],[("reference-type","ref"),("reference","fig:Logo")]) [Str "1"] ("#fig:Logo",""),Space,Str "illustrated",Space,Str "the",Space,Str "SVG",Space,Str "logo"]] ``` +``` +% pandoc -f latex -t native +\chapter{One} +\begin{figure} + \includegraphics{command/SVG_logo.svg} + \caption{Logo} + \label{fig:Logo} +\end{figure} + +\begin{figure} + \includegraphics{command/SVG_logo2.svg} + \caption{Logo2} + \label{fig:Logo2} +\end{figure} + +\chapter{Two} + +\section{Subone} + +\begin{figure} + \includegraphics{command/SVG_logo3.svg} + \caption{Logo3} + \label{fig:Logo3} +\end{figure} + +Figure \ref{fig:Logo} illustrated the SVG logo + +Figure \ref{fig:Logo2} illustrated the SVG logo + +Figure \ref{fig:Logo3} illustrated the SVG logo +^D +[Header 1 ("one",[],[]) [Str "One"] +,Para [Image ("fig:Logo",[],[]) [Str "Logo",Span ("",[],[("label","fig:Logo")]) []] ("command/SVG_logo.svg","fig:")] +,Para [Image ("fig:Logo2",[],[]) [Str "Logo2",Span ("",[],[("label","fig:Logo2")]) []] ("command/SVG_logo2.svg","fig:")] +,Header 1 ("two",[],[]) [Str "Two"] +,Header 2 ("subone",[],[]) [Str "Subone"] +,Para [Image ("fig:Logo3",[],[]) [Str "Logo3",Span ("",[],[("label","fig:Logo3")]) []] ("command/SVG_logo3.svg","fig:")] +,Para [Str "Figure",Space,Link ("",[],[("reference-type","ref"),("reference","fig:Logo")]) [Str "1.1"] ("#fig:Logo",""),Space,Str "illustrated",Space,Str "the",Space,Str "SVG",Space,Str "logo"] +,Para [Str "Figure",Space,Link ("",[],[("reference-type","ref"),("reference","fig:Logo2")]) [Str "1.2"] ("#fig:Logo2",""),Space,Str "illustrated",Space,Str "the",Space,Str "SVG",Space,Str "logo"] +,Para [Str "Figure",Space,Link ("",[],[("reference-type","ref"),("reference","fig:Logo3")]) [Str "2.1"] ("#fig:Logo3",""),Space,Str "illustrated",Space,Str "the",Space,Str "SVG",Space,Str "logo"]] +``` + + ``` % pandoc -f latex -t native \label{section} Section \ref{section} -- cgit v1.2.3 From c2b97c4b8026694d9c59d7b9f6d333d204f669ce Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 11 Sep 2018 00:38:55 +0300 Subject: Muse writer: use tags instead of lightweight markup for empty strings --- src/Text/Pandoc/Writers/Muse.hs | 13 +++++++++---- test/Tests/Writers/Muse.hs | 4 ++++ 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 627358839..87c6c58da 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -420,6 +420,11 @@ endsWithSpace [SoftBreak] = True endsWithSpace (_:xs) = endsWithSpace xs endsWithSpace [] = False +emptyInlines :: [Inline] -> Bool +emptyInlines [] = True +emptyInlines (Str "":xs) = emptyInlines xs +emptyInlines _ = False + urlEscapeBrackets :: String -> String urlEscapeBrackets (']':xs) = '%':'5':'D':urlEscapeBrackets xs urlEscapeBrackets (x:xs) = x:urlEscapeBrackets xs @@ -517,7 +522,7 @@ inlineToMuse (Emph [Strong lst]) = do then do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst modify $ \st -> st { stUseTags = False } return $ "**" <> contents <> "**" - else if null lst || startsWithSpace lst || endsWithSpace lst + else if emptyInlines lst || startsWithSpace lst || endsWithSpace lst then do contents <- local (\env -> env { envInsideAsterisks = False }) $ inlineListToMuse lst modify $ \st -> st { stUseTags = True } @@ -528,7 +533,7 @@ inlineToMuse (Emph [Strong lst]) = do return $ "***" <> contents <> "***" inlineToMuse (Emph lst) = do useTags <- gets stUseTags - if useTags || null lst || startsWithSpace lst || endsWithSpace lst + if useTags || emptyInlines lst || startsWithSpace lst || endsWithSpace lst then do contents <- inlineListToMuse lst return $ "" <> contents <> "" else do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst @@ -540,7 +545,7 @@ inlineToMuse (Strong [Emph lst]) = do then do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst modify $ \st -> st { stUseTags = False } return $ "*" <> contents <> "*" - else if null lst || startsWithSpace lst || endsWithSpace lst + else if emptyInlines lst || startsWithSpace lst || endsWithSpace lst then do contents <- local (\env -> env { envInsideAsterisks = False }) $ inlineListToMuse lst modify $ \st -> st { stUseTags = True } @@ -551,7 +556,7 @@ inlineToMuse (Strong [Emph lst]) = do return $ "***" <> contents <> "***" inlineToMuse (Strong lst) = do useTags <- gets stUseTags - if useTags || null lst || startsWithSpace lst || endsWithSpace lst + if useTags || emptyInlines lst || startsWithSpace lst || endsWithSpace lst then do contents <- inlineListToMuse lst modify $ \st -> st { stUseTags = False } return $ "" <> contents <> "" diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs index 29f771cf5..c747578bf 100644 --- a/test/Tests/Writers/Muse.hs +++ b/test/Tests/Writers/Muse.hs @@ -362,6 +362,10 @@ tests = [ testGroup "block elements" , "empty strong" =: strong mempty =?> "" , "empty strong emphasis" =: strong (emph mempty) =?> "****" , "empty emphasized strong" =: emph (strong mempty) =?> "**" + , "emphasized empty string" =: emph (str "") =?> "" + , "strong empty string" =: strong (str "") =?> "" + , "strong emphasized empty string" =: strong (emph (str "")) =?> "****" + , "emphasized strong empty string" =: emph (strong (str "")) =?> "**" , "strong" =: strong (text "foo") =?> "**foo**" , "strong inside word" =: text "foo" <> strong (text "bar") <> text "baz" =?> "foobarbaz" , "strong emphasis" =: strong (emph (text "foo")) =?> "***foo***" -- cgit v1.2.3 From 00b2b0feb660bbe4ec50b3a33131e75cf0341e4c Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 11 Sep 2018 01:36:11 +0300 Subject: Muse writer: normalize inline list before testing if tags should be used --- src/Text/Pandoc/Writers/Muse.hs | 37 ++++++++++++++++++------------------- test/Tests/Writers/Muse.hs | 1 + 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 87c6c58da..7dbe3a53f 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -420,11 +420,6 @@ endsWithSpace [SoftBreak] = True endsWithSpace (_:xs) = endsWithSpace xs endsWithSpace [] = False -emptyInlines :: [Inline] -> Bool -emptyInlines [] = True -emptyInlines (Str "":xs) = emptyInlines xs -emptyInlines _ = False - urlEscapeBrackets :: String -> String urlEscapeBrackets (']':xs) = '%':'5':'D':urlEscapeBrackets xs urlEscapeBrackets (x:xs) = x:urlEscapeBrackets xs @@ -518,49 +513,53 @@ inlineToMuse (Str str) = do return $ text escapedStr inlineToMuse (Emph [Strong lst]) = do useTags <- gets stUseTags + let lst' = normalizeInlineList lst if useTags - then do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + then do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst' modify $ \st -> st { stUseTags = False } return $ "**" <> contents <> "**" - else if emptyInlines lst || startsWithSpace lst || endsWithSpace lst + else if null lst' || startsWithSpace lst' || endsWithSpace lst' then do - contents <- local (\env -> env { envInsideAsterisks = False }) $ inlineListToMuse lst + contents <- local (\env -> env { envInsideAsterisks = False }) $ inlineListToMuse lst' modify $ \st -> st { stUseTags = True } return $ "*" <> contents <> "*" else do - contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst' modify $ \st -> st { stUseTags = True } return $ "***" <> contents <> "***" inlineToMuse (Emph lst) = do useTags <- gets stUseTags - if useTags || emptyInlines lst || startsWithSpace lst || endsWithSpace lst - then do contents <- inlineListToMuse lst + let lst' = normalizeInlineList lst + if useTags || null lst' || startsWithSpace lst' || endsWithSpace lst' + then do contents <- inlineListToMuse lst' return $ "" <> contents <> "" - else do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + else do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst' modify $ \st -> st { stUseTags = True } return $ "*" <> contents <> "*" inlineToMuse (Strong [Emph lst]) = do useTags <- gets stUseTags + let lst' = normalizeInlineList lst if useTags - then do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + then do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst' modify $ \st -> st { stUseTags = False } return $ "*" <> contents <> "*" - else if emptyInlines lst || startsWithSpace lst || endsWithSpace lst + else if null lst' || startsWithSpace lst' || endsWithSpace lst' then do - contents <- local (\env -> env { envInsideAsterisks = False }) $ inlineListToMuse lst + contents <- local (\env -> env { envInsideAsterisks = False }) $ inlineListToMuse lst' modify $ \st -> st { stUseTags = True } return $ "**" <> contents <> "**" else do - contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst' modify $ \st -> st { stUseTags = True } return $ "***" <> contents <> "***" inlineToMuse (Strong lst) = do useTags <- gets stUseTags - if useTags || emptyInlines lst || startsWithSpace lst || endsWithSpace lst - then do contents <- inlineListToMuse lst + let lst' = normalizeInlineList lst + if useTags || null lst' || startsWithSpace lst' || endsWithSpace lst' + then do contents <- inlineListToMuse lst' modify $ \st -> st { stUseTags = False } return $ "" <> contents <> "" - else do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst + else do contents <- local (\env -> env { envInsideAsterisks = True }) $ inlineListToMuse lst' modify $ \st -> st { stUseTags = True } return $ "**" <> contents <> "**" inlineToMuse (Strikeout lst) = do diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs index c747578bf..776884760 100644 --- a/test/Tests/Writers/Muse.hs +++ b/test/Tests/Writers/Muse.hs @@ -366,6 +366,7 @@ tests = [ testGroup "block elements" , "strong empty string" =: strong (str "") =?> "" , "strong emphasized empty string" =: strong (emph (str "")) =?> "****" , "emphasized strong empty string" =: emph (strong (str "")) =?> "**" + , "emphasized space between empty strings" =: emph (str "" <> space <> str "") =?> " " , "strong" =: strong (text "foo") =?> "**foo**" , "strong inside word" =: text "foo" <> strong (text "bar") <> text "baz" =?> "foobarbaz" , "strong emphasis" =: strong (emph (text "foo")) =?> "***foo***" -- cgit v1.2.3 From c899b4e89dcd61f91f7383e2a81a13ef0da080b8 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 11 Sep 2018 03:50:59 +0300 Subject: Muse writer: escape list markers in the beginning of notes --- src/Text/Pandoc/Writers/Muse.hs | 5 ++++- test/Tests/Writers/Muse.hs | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 7dbe3a53f..413b71659 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -292,7 +292,10 @@ noteToMuse :: PandocMonad m -> [Block] -> Muse m Doc noteToMuse num note = - hang (length marker) (text marker) <$> blockListToMuse note + hang (length marker) (text marker) <$> + (local (\env -> env { envInlineStart = True + , envAfterSpace = True + }) $ blockListToMuse note) where marker = "[" ++ show num ++ "] " diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs index 776884760..7821f4e96 100644 --- a/test/Tests/Writers/Muse.hs +++ b/test/Tests/Writers/Muse.hs @@ -348,6 +348,12 @@ tests = [ testGroup "block elements" , "" , " - bar" ] + , "escape - inside a note" =: + note (para (text "- foo")) =?> + unlines [ "[1]" + , "" + , "[1] - foo" + ] , "escape ; to avoid accidental comments" =: text "; foo" =?> "; foo" , "escape ; after softbreak" =: text "foo" <> softbreak <> text "; bar" =?> "foo\n; bar" , "escape ; after linebreak" =: text "foo" <> linebreak <> text "; bar" =?> "foo
\n; bar" -- cgit v1.2.3 From cb28cab489279c48f0afd7113a75ccd96f43eaba Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 11 Sep 2018 11:35:25 +0300 Subject: Muse writer: escape -, ; and > in the beginning of strings --- src/Text/Pandoc/Writers/Muse.hs | 9 ++++++--- test/Tests/Writers/Muse.hs | 10 ++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 413b71659..262d4fb50 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -437,12 +437,15 @@ stringStartsWithSpace [] = False fixOrEscape :: Bool -> Inline -> Bool fixOrEscape sp (Str "-") = sp -fixOrEscape sp (Str ";") = not sp -fixOrEscape _ (Str ">") = True +fixOrEscape sp (Str s@('-':x:_)) = (sp && isSpace x) || isHorizontalRule s +fixOrEscape sp (Str (";")) = not sp +fixOrEscape sp (Str (';':x:_)) = not sp && isSpace x +fixOrEscape _ (Str (">")) = True +fixOrEscape _ (Str ('>':x:_)) = isSpace x fixOrEscape sp (Str s) = (sp && (startsWithMarker isDigit s || startsWithMarker isAsciiLower s || startsWithMarker isAsciiUpper s)) - || isHorizontalRule s || stringStartsWithSpace s + || stringStartsWithSpace s fixOrEscape _ Space = True fixOrEscape _ SoftBreak = True fixOrEscape _ _ = False diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs index 7821f4e96..a8ccd6d87 100644 --- a/test/Tests/Writers/Muse.hs +++ b/test/Tests/Writers/Muse.hs @@ -283,6 +283,7 @@ tests = [ testGroup "block elements" , "don't escape horizontal inside paragraph" =: para (text "foo ---- bar") =?> "foo ---- bar" , "escape nonbreaking space" =: para (text "~~") =?> "~~" , "escape > in the beginning of line" =: para (text "> foo bar") =?> "> foo bar" + , "escape string with > and space in the beginning of line" =: para (str "> foo bar") =?> "> foo bar" , testGroup "tables" [ "table without header" =: let rows = [[para $ text "Para 1.1", para $ text "Para 1.2"] @@ -348,6 +349,14 @@ tests = [ testGroup "block elements" , "" , " - bar" ] + , "escape strings starting with - inside a list" =: + bulletList [ para (str "foo") <> + para (str "- bar") + ] =?> + unlines [ " - foo" + , "" + , " - bar" + ] , "escape - inside a note" =: note (para (text "- foo")) =?> unlines [ "[1]" @@ -355,6 +364,7 @@ tests = [ testGroup "block elements" , "[1] - foo" ] , "escape ; to avoid accidental comments" =: text "; foo" =?> "; foo" + , "escape strings starting with ; and space" =: str "; foo" =?> "; foo" , "escape ; after softbreak" =: text "foo" <> softbreak <> text "; bar" =?> "foo\n; bar" , "escape ; after linebreak" =: text "foo" <> linebreak <> text "; bar" =?> "foo
\n; bar" , "do not escape ; inside paragraph" =: text "foo ; bar" =?> "foo ; bar" -- cgit v1.2.3 From 165a61095c08794d1639a683f1c6f1a82387c8d5 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 11 Sep 2018 11:49:11 +0300 Subject: Muse writer: check for whitespace in the beginning and end of Str's --- src/Text/Pandoc/Writers/Muse.hs | 2 ++ test/Tests/Writers/Muse.hs | 3 +++ 2 files changed, 5 insertions(+) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 262d4fb50..025114a47 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -415,11 +415,13 @@ fixNotes (x:xs) = x : fixNotes xs startsWithSpace :: [Inline] -> Bool startsWithSpace (Space:_) = True startsWithSpace (SoftBreak:_) = True +startsWithSpace (Str s:_) = stringStartsWithSpace s startsWithSpace _ = False endsWithSpace :: [Inline] -> Bool endsWithSpace [Space] = True endsWithSpace [SoftBreak] = True +endsWithSpace [Str s] = stringStartsWithSpace $ reverse s endsWithSpace (_:xs) = endsWithSpace xs endsWithSpace [] = False diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs index a8ccd6d87..4cb7618f3 100644 --- a/test/Tests/Writers/Muse.hs +++ b/test/Tests/Writers/Muse.hs @@ -382,6 +382,9 @@ tests = [ testGroup "block elements" , "strong empty string" =: strong (str "") =?> "" , "strong emphasized empty string" =: strong (emph (str "")) =?> "****" , "emphasized strong empty string" =: emph (strong (str "")) =?> "**" + , "emphasized string with space" =: emph (str " ") =?> " " + , "emphasized string ending with space" =: emph (str "foo ") =?> "foo " + , "emphasized string with tab" =: emph (str "\t") =?> "\t" , "emphasized space between empty strings" =: emph (str "" <> space <> str "") =?> " " , "strong" =: strong (text "foo") =?> "**foo**" , "strong inside word" =: text "foo" <> strong (text "bar") <> text "baz" =?> "foobarbaz" -- cgit v1.2.3 From 97f6833ee58667defbf4f203ebd69f5062232563 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 11 Sep 2018 11:49:30 +0300 Subject: Muse writer: use "" instead of [] for empty String --- src/Text/Pandoc/Writers/Muse.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 025114a47..26349493b 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -435,7 +435,7 @@ isHorizontalRule s = length s >= 4 && all (== '-') s stringStartsWithSpace :: String -> Bool stringStartsWithSpace (x:_) = isSpace x -stringStartsWithSpace [] = False +stringStartsWithSpace "" = False fixOrEscape :: Bool -> Inline -> Bool fixOrEscape sp (Str "-") = sp -- cgit v1.2.3 From e6ba0cc8936a0520bee96de6c2eb42973caa4058 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 11 Sep 2018 13:12:00 +0300 Subject: HTML writer: always output
element, even if it is empty Fixes #4883 --- src/Text/Pandoc/Writers/HTML.hs | 4 +--- test/Tests/Writers/HTML.hs | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 25f3163c2..a0b622c83 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -830,9 +830,7 @@ blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do return $ foldl (!) l attribs blockToHtml opts (DefinitionList lst) = do contents <- mapM (\(term, defs) -> - do term' <- if null term - then return mempty - else liftM H.dt $ inlineListToHtml opts term + do term' <- liftM H.dt $ inlineListToHtml opts term defs' <- mapM (liftM (\x -> H.dd (x >> nl opts)) . blockListToHtml opts) defs return $ mconcat $ nl opts : term' : nl opts : diff --git a/test/Tests/Writers/HTML.hs b/test/Tests/Writers/HTML.hs index e771255b3..dfacda608 100644 --- a/test/Tests/Writers/HTML.hs +++ b/test/Tests/Writers/HTML.hs @@ -43,4 +43,9 @@ tests = [ testGroup "inline code" image "/url" "title" ("my " <> emph "image") =?> "\"my" ] + , testGroup "blocks" + [ "definition list with empty
" =: + definitionList [(mempty, [para $ text "foo bar"])] + =?> "

foo bar

" + ] ] -- cgit v1.2.3 From 1aac754359d44a96e30e96f61f38c58d6aea29b4 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Tue, 11 Sep 2018 14:10:20 +0300 Subject: Muse writer: set envInsideBlock = True when rendering notes --- src/Text/Pandoc/Writers/Muse.hs | 3 ++- test/Tests/Writers/Muse.hs | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 26349493b..13c9c23b7 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -293,7 +293,8 @@ noteToMuse :: PandocMonad m -> Muse m Doc noteToMuse num note = hang (length marker) (text marker) <$> - (local (\env -> env { envInlineStart = True + (local (\env -> env { envInsideBlock = True + , envInlineStart = True , envAfterSpace = True }) $ blockListToMuse note) where diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs index 4cb7618f3..614e9dbc6 100644 --- a/test/Tests/Writers/Muse.hs +++ b/test/Tests/Writers/Muse.hs @@ -363,6 +363,13 @@ tests = [ testGroup "block elements" , "" , "[1] - foo" ] + , "escape - after softbreak in note" =: + note (para (str "foo" <> softbreak <> str "- bar")) =?> + unlines [ "[1]" + , "" + , "[1] foo" + , " - bar" + ] , "escape ; to avoid accidental comments" =: text "; foo" =?> "; foo" , "escape strings starting with ; and space" =: str "; foo" =?> "; foo" , "escape ; after softbreak" =: text "foo" <> softbreak <> text "; bar" =?> "foo\n; bar" -- cgit v1.2.3 From f8d3f3a999df1db6eb6828c6e8e254e4d4faca21 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 12 Sep 2018 14:03:24 +0300 Subject: Muse writer: never wrap definition list terms --- src/Text/Pandoc/Writers/Muse.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 13c9c23b7..8fafdba91 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -234,7 +234,7 @@ blockToMuse (DefinitionList items) = do label' <- local (\env -> env { envOneLine = True, envAfterSpace = True }) $ inlineListToMuse' label contents <- vcat <$> mapM descriptionToMuse defs let ind = offset label' - return $ hang ind label' contents + return $ hang ind (nowrap label') contents descriptionToMuse :: PandocMonad m => [Block] -> Muse m Doc -- cgit v1.2.3 From 700f7a141f94616734b08df291b44e7a7ae64991 Mon Sep 17 00:00:00 2001 From: mb21 Date: Sat, 15 Sep 2018 12:46:59 +0200 Subject: Markdown Reader: rename yamlToMeta to yamlToMetaValue --- src/Text/Pandoc/Readers/Markdown.hs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index a81942a9e..2ab61f90e 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -249,7 +249,7 @@ yamlMetaBlock = try $ do if ignorable k then return () else do - v' <- yamlToMeta v + v' <- yamlToMetaValue v let k' = T.unpack k updateState $ \st -> st{ stateMeta' = do m <- stateMeta' st @@ -309,9 +309,9 @@ checkBoolean t = then Just False else Nothing -yamlToMeta :: PandocMonad m - => YAML.Node -> MarkdownParser m (F MetaValue) -yamlToMeta (YAML.Scalar x) = +yamlToMetaValue :: PandocMonad m + => YAML.Node -> MarkdownParser m (F MetaValue) +yamlToMetaValue (YAML.Scalar x) = case x of YAML.SStr t -> toMetaValue t YAML.SBool b -> return $ return $ MetaBool b @@ -322,25 +322,25 @@ yamlToMeta (YAML.Scalar x) = Just b -> return $ return $ MetaBool b Nothing -> toMetaValue t YAML.SNull -> return $ return $ MetaString "" -yamlToMeta (YAML.Sequence _ xs) = do - xs' <- mapM yamlToMeta xs +yamlToMetaValue (YAML.Sequence _ xs) = do + xs' <- mapM yamlToMetaValue xs return $ do xs'' <- sequence xs' return $ B.toMetaValue xs'' -yamlToMeta (YAML.Mapping _ o) = +yamlToMetaValue (YAML.Mapping _ o) = foldM (\m (key, v) -> do k <- nodeToKey key if ignorable k then return m else do - v' <- yamlToMeta v + v' <- yamlToMetaValue v return $ do MetaMap m' <- m v'' <- v' return (MetaMap $ M.insert (T.unpack k) v'' m')) (return $ MetaMap M.empty) (M.toList o) -yamlToMeta _ = return $ return $ MetaString "" +yamlToMetaValue _ = return $ return $ MetaString "" stopLine :: PandocMonad m => MarkdownParser m () stopLine = try $ (string "---" <|> string "...") >> blankline >> return () -- cgit v1.2.3 From 51c122245797ee8d699698765bfb1ad92041cd05 Mon Sep 17 00:00:00 2001 From: mb21 Date: Sat, 15 Sep 2018 13:22:45 +0200 Subject: Markdown Reader: factor out yamlBsToMeta --- src/Text/Pandoc/Readers/Markdown.hs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 2ab61f90e..4efbd25eb 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -36,6 +36,7 @@ module Text.Pandoc.Readers.Markdown ( readMarkdown ) where import Prelude import Control.Monad import Control.Monad.Except (throwError) +import qualified Data.ByteString.Lazy as BS import Data.Char (isAlphaNum, isPunctuation, isSpace, toLower) import Data.List (intercalate, sortBy, transpose, elemIndex) import qualified Data.Map as M @@ -233,7 +234,6 @@ pandocTitleBlock = try $ do yamlMetaBlock :: PandocMonad m => MarkdownParser m (F Blocks) yamlMetaBlock = try $ do guardEnabled Ext_yaml_metadata_block - pos <- getPosition string "---" blankline notFollowedBy blankline -- if --- is followed by a blank it's an HRULE @@ -241,8 +241,13 @@ yamlMetaBlock = try $ do -- by including --- and ..., we allow yaml blocks with just comments: let rawYaml = unlines ("---" : (rawYamlLines ++ ["..."])) optional blanklines - case YAML.decodeNode' YAML.failsafeSchemaResolver False False - (UTF8.fromStringLazy rawYaml) of + yamlBsToMeta $ UTF8.fromStringLazy rawYaml + return mempty + +yamlBsToMeta :: PandocMonad m => BS.ByteString -> MarkdownParser m () +yamlBsToMeta bstr = do + pos <- getPosition + case YAML.decodeNode' YAML.failsafeSchemaResolver False False bstr of Right [YAML.Doc (YAML.Mapping _ hashmap)] -> mapM_ (\(key, v) -> do k <- nodeToKey key @@ -271,7 +276,6 @@ yamlMetaBlock = try $ do logMessage $ CouldNotParseYamlMetadata err' pos return () - return mempty nodeToKey :: Monad m => YAML.Node -> m Text nodeToKey (YAML.Scalar (YAML.SStr t)) = return t -- cgit v1.2.3 From 73fa70c3974fa37aeb9a9d1535c1e09fb549bbcf Mon Sep 17 00:00:00 2001 From: mb21 Date: Sat, 15 Sep 2018 14:35:04 +0200 Subject: Markdown Reader: factor out yamlMap --- src/Text/Pandoc/Readers/Markdown.hs | 67 +++++++++++++++---------------------- 1 file changed, 27 insertions(+), 40 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 4efbd25eb..50780b379 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -241,51 +241,33 @@ yamlMetaBlock = try $ do -- by including --- and ..., we allow yaml blocks with just comments: let rawYaml = unlines ("---" : (rawYamlLines ++ ["..."])) optional blanklines - yamlBsToMeta $ UTF8.fromStringLazy rawYaml + newMetaF <- yamlBsToMeta $ UTF8.fromStringLazy rawYaml + -- Since `<>` is left-biased, existing values are not touched: + updateState $ \st -> st{ stateMeta' = (stateMeta' st) <> newMetaF } return mempty -yamlBsToMeta :: PandocMonad m => BS.ByteString -> MarkdownParser m () +yamlBsToMeta :: PandocMonad m => BS.ByteString -> MarkdownParser m (F Meta) yamlBsToMeta bstr = do pos <- getPosition case YAML.decodeNode' YAML.failsafeSchemaResolver False False bstr of - Right [YAML.Doc (YAML.Mapping _ hashmap)] -> - mapM_ (\(key, v) -> do - k <- nodeToKey key - if ignorable k - then return () - else do - v' <- yamlToMetaValue v - let k' = T.unpack k - updateState $ \st -> st{ stateMeta' = - do m <- stateMeta' st - -- if there's already a value, leave it unchanged - case lookupMeta k' m of - Just _ -> return m - Nothing -> do - v'' <- v' - return $ B.setMeta (T.unpack k) v'' m}) - (M.toList hashmap) - Right [] -> return () - Right [YAML.Doc (YAML.Scalar YAML.SNull)] -> return () + Right [YAML.Doc (YAML.Mapping _ o)] -> (fmap Meta) <$> yamlMap o + Right [] -> return . return $ mempty + Right [YAML.Doc (YAML.Scalar YAML.SNull)] -> return . return $ mempty Right _ -> do logMessage $ CouldNotParseYamlMetadata "not an object" pos - return () + return . return $ mempty Left err' -> do logMessage $ CouldNotParseYamlMetadata err' pos - return () + return . return $ mempty nodeToKey :: Monad m => YAML.Node -> m Text nodeToKey (YAML.Scalar (YAML.SStr t)) = return t nodeToKey (YAML.Scalar (YAML.SUnknown _ t)) = return t nodeToKey _ = fail "Non-string key in YAML mapping" --- ignore fields ending with _ -ignorable :: Text -> Bool -ignorable t = (T.pack "_") `T.isSuffixOf` t - toMetaValue :: PandocMonad m => Text -> MarkdownParser m (F MetaValue) toMetaValue x = @@ -331,21 +313,26 @@ yamlToMetaValue (YAML.Sequence _ xs) = do return $ do xs'' <- sequence xs' return $ B.toMetaValue xs'' -yamlToMetaValue (YAML.Mapping _ o) = - foldM (\m (key, v) -> do - k <- nodeToKey key - if ignorable k - then return m - else do - v' <- yamlToMetaValue v - return $ do - MetaMap m' <- m - v'' <- v' - return (MetaMap $ M.insert (T.unpack k) v'' m')) - (return $ MetaMap M.empty) - (M.toList o) +yamlToMetaValue (YAML.Mapping _ o) = fmap B.toMetaValue <$> yamlMap o yamlToMetaValue _ = return $ return $ MetaString "" +yamlMap :: PandocMonad m + => M.Map YAML.Node YAML.Node + -> MarkdownParser m (F (M.Map String MetaValue)) +yamlMap o = do + kvs <- forM (M.toList o) $ \(key, v) -> do + k <- nodeToKey key + return (k, v) + let kvs' = filter (not . ignorable . fst) kvs + (fmap M.fromList . sequence) <$> mapM toMeta kvs' + where + ignorable t = (T.pack "_") `T.isSuffixOf` t + toMeta (k, v) = do + fv <- yamlToMetaValue v + return $ do + v' <- fv + return (T.unpack k, v') + stopLine :: PandocMonad m => MarkdownParser m () stopLine = try $ (string "---" <|> string "...") >> blankline >> return () -- cgit v1.2.3 From 6aa5fcac13ea702de19ee1a605631e3ac75d7e05 Mon Sep 17 00:00:00 2001 From: mb21 Date: Fri, 30 Mar 2018 21:48:14 +0200 Subject: introduce --metadata-file option closes #1960 API change: Text.Pandoc.Readers.Markdown exports now `yamlToMeta` --- MANUAL.txt | 14 +++++++++++++- src/Text/Pandoc/App.hs | 17 +++++++++++++++++ src/Text/Pandoc/Readers/Markdown.hs | 16 ++++++++++++++-- 3 files changed, 44 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/MANUAL.txt b/MANUAL.txt index b4033a5e3..2eda67cc4 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -578,6 +578,16 @@ Reader options printed in some output formats) and metadata values will be escaped when inserted into the template. +`--metadata-file=`*FILE* + +: Read metadata from the supplied YAML (or JSON) file. + This option can be used with every input format, but string + scalars in the YAML file will always be parsed as Markdown. + Generally, the input will be handled the same as in + [YAML metadata blocks][Extension: `yaml_metadata_block`]. + Metadata values specified inside the document, or by using `-M`, + overwrite values specified with this option. + `-p`, `--preserve-tabs` : Preserve tabs instead of converting them to spaces (the default). @@ -3061,7 +3071,9 @@ and pass it to pandoc as an argument, along with your Markdown files: pandoc chap1.md chap2.md chap3.md metadata.yaml -s -o book.html Just be sure that the YAML file begins with `---` and ends with `---` or -`...`.) +`...`.) Alternatively, you can use the `--metadata-file` option. Using +that approach however, you cannot reference content (like footnotes) +from the main markdown input document. Metadata will be taken from the fields of the YAML object and added to any existing document metadata. Metadata can contain lists and objects (nested diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index 44bb30223..cb1db4f89 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -89,6 +89,7 @@ import Text.Pandoc.Builder (setMeta, deleteMeta) import Text.Pandoc.Filter (Filter (JSONFilter, LuaFilter), applyFilters) import Text.Pandoc.Highlighting (highlightingStyles) import Text.Pandoc.PDF (makePDF) +import Text.Pandoc.Readers.Markdown (yamlToMeta) import Text.Pandoc.SelfContained (makeDataURI, makeSelfContained) import Text.Pandoc.Shared (eastAsianLineBreakFilter, stripEmptyParagraphs, headerShift, isURI, ordNub, safeRead, tabFilter, uriPathToPath) @@ -399,6 +400,10 @@ convertWithOpts opts = do ("application/xml", jatsCSL) return $ ("csl", jatsEncoded) : optMetadata opts else return $ optMetadata opts + metadataFromFile <- + case optMetadataFile opts of + Nothing -> return mempty + Just file -> readFileLazy file >>= yamlToMeta case lookup "lang" (optMetadata opts) of Just l -> case parseBCP47 l of @@ -491,6 +496,7 @@ convertWithOpts opts = do ( (if isJust (optExtractMedia opts) then fillMediaBag else return) + >=> return . addNonPresentMetadata metadataFromFile >=> return . addMetadata metadata >=> applyTransforms transforms >=> applyFilters readerOpts filters' [format] @@ -556,6 +562,7 @@ data Opt = Opt , optTemplate :: Maybe FilePath -- ^ Custom template , optVariables :: [(String,String)] -- ^ Template variables to set , optMetadata :: [(String, String)] -- ^ Metadata fields to set + , optMetadataFile :: Maybe FilePath -- ^ Name of YAML metadata file , optOutputFile :: Maybe FilePath -- ^ Name of output file , optInputFiles :: [FilePath] -- ^ Names of input files , optNumberSections :: Bool -- ^ Number sections in LaTeX @@ -628,6 +635,7 @@ defaultOpts = Opt , optTemplate = Nothing , optVariables = [] , optMetadata = [] + , optMetadataFile = Nothing , optOutputFile = Nothing , optInputFiles = [] , optNumberSections = False @@ -687,6 +695,9 @@ defaultOpts = Opt , optStripComments = False } +addNonPresentMetadata :: Text.Pandoc.Meta -> Pandoc -> Pandoc +addNonPresentMetadata newmeta (Pandoc meta bs) = Pandoc (meta <> newmeta) bs + addMetadata :: [(String, String)] -> Pandoc -> Pandoc addMetadata kvs pdc = foldr addMeta (removeMetaKeys kvs pdc) kvs @@ -963,6 +974,12 @@ options = "KEY[:VALUE]") "" + , Option "" ["metadata-file"] + (ReqArg + (\arg opt -> return opt{ optMetadataFile = Just arg }) + "FILE") + "" + , Option "V" ["variable"] (ReqArg (\arg opt -> do diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 50780b379..502abae9a 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Conversion of markdown-formatted plain text to 'Pandoc' document. -} -module Text.Pandoc.Readers.Markdown ( readMarkdown ) where +module Text.Pandoc.Readers.Markdown ( readMarkdown, yamlToMeta ) where import Prelude import Control.Monad @@ -246,11 +246,23 @@ yamlMetaBlock = try $ do updateState $ \st -> st{ stateMeta' = (stateMeta' st) <> newMetaF } return mempty +-- | Read a YAML string and convert it to pandoc metadata. +-- String scalars in the YAML are parsed as Markdown. +yamlToMeta :: PandocMonad m => BS.ByteString -> m Meta +yamlToMeta bstr = do + let parser = do + meta <- yamlBsToMeta bstr + return $ runF meta defaultParserState + parsed <- readWithM parser def "" + case parsed of + Right result -> return result + Left e -> throwError e + yamlBsToMeta :: PandocMonad m => BS.ByteString -> MarkdownParser m (F Meta) yamlBsToMeta bstr = do pos <- getPosition case YAML.decodeNode' YAML.failsafeSchemaResolver False False bstr of - Right [YAML.Doc (YAML.Mapping _ o)] -> (fmap Meta) <$> yamlMap o + Right ((YAML.Doc (YAML.Mapping _ o)):_) -> (fmap Meta) <$> yamlMap o Right [] -> return . return $ mempty Right [YAML.Doc (YAML.Scalar YAML.SNull)] -> return . return $ mempty Right _ -> do -- cgit v1.2.3 From f736dea4ba71f81b37ff28a218115871249b35ec Mon Sep 17 00:00:00 2001 From: Mauro Bieg Date: Sat, 15 Sep 2018 20:55:23 +0200 Subject: Docx writer: add MetaString case for abstract, subtitle (#4905) fixes #4900 --- src/Text/Pandoc/Writers/Docx.hs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 2055ee1da..5bd7e809b 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -763,11 +763,13 @@ writeOpenXML opts (Pandoc meta blocks) = do let abstract' = case lookupMeta "abstract" meta of Just (MetaBlocks bs) -> bs Just (MetaInlines ils) -> [Plain ils] + Just (MetaString s) -> [Plain [Str s]] _ -> [] let subtitle' = case lookupMeta "subtitle" meta of Just (MetaBlocks [Plain xs]) -> xs Just (MetaBlocks [Para xs]) -> xs Just (MetaInlines xs) -> xs + Just (MetaString s) -> [Str s] _ -> [] let includeTOC = writerTableOfContents opts || case lookupMeta "toc" meta of -- cgit v1.2.3 From b2cc2a24247e043fb8addd7237cd04b268253e33 Mon Sep 17 00:00:00 2001 From: Chris Martin Date: Sat, 15 Sep 2018 18:32:58 -0400 Subject: Fix haddock on 'Ext_footnotes' --- src/Text/Pandoc/Extensions.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Extensions.hs b/src/Text/Pandoc/Extensions.hs index ab510d92d..b60c57497 100644 --- a/src/Text/Pandoc/Extensions.hs +++ b/src/Text/Pandoc/Extensions.hs @@ -114,7 +114,7 @@ data Extension = | Ext_fenced_code_attributes -- ^ Allow attributes on fenced code blocks | Ext_fenced_code_blocks -- ^ Parse fenced code blocks | Ext_fenced_divs -- ^ Allow fenced div syntax ::: - | Ext_footnotes -- ^ Pandoc/PHP/MMD style footnotes + | Ext_footnotes -- ^ Pandoc\/PHP\/MMD style footnotes | Ext_four_space_rule -- ^ Require 4-space indent for list contents | Ext_gfm_auto_identifiers -- ^ Automatic identifiers for headers, using -- GitHub's method for generating identifiers -- cgit v1.2.3 From 25163bfe53301c0447f1f9fd69638cf26dcf9944 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 16 Sep 2018 09:29:08 +0300 Subject: Muse writer: output headers without asterisks if not on the top level --- src/Text/Pandoc/Writers/Muse.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 8fafdba91..1f081348e 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -241,6 +241,7 @@ blockToMuse (DefinitionList items) = do descriptionToMuse desc = hang 4 " :: " <$> blockListToMuse desc blockToMuse (Header level (ident,_,_) inlines) = do opts <- asks envOptions + topLevel <- asks envTopLevel contents <- local (\env -> env { envOneLine = True }) $ inlineListToMuse' inlines ids <- gets stIds let autoId = uniqueIdent inlines ids @@ -249,8 +250,8 @@ blockToMuse (Header level (ident,_,_) inlines) = do let attr' = if null ident || (isEnabled Ext_auto_identifiers opts && ident == autoId) then empty else "#" <> text ident <> cr - let header' = text $ replicate level '*' - return $ blankline <> attr' $$ nowrap (header' <> space <> contents) <> blankline + let header' = if topLevel then (text $ replicate level '*') <> space else mempty + return $ blankline <> attr' $$ nowrap (header' <> contents) <> blankline -- https://www.gnu.org/software/emacs-muse/manual/muse.html#Horizontal-Rules-and-Anchors blockToMuse HorizontalRule = return $ blankline $$ "----" $$ blankline blockToMuse (Table caption _ _ headers rows) = do -- cgit v1.2.3 From 71776661cd0ceceb896ce668b99f1df373f6e1b0 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sun, 16 Sep 2018 20:59:59 +0300 Subject: Muse writer: replace newlines in strings with spaces --- src/Text/Pandoc/Writers/Muse.hs | 8 +++++++- test/Tests/Writers/Muse.hs | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs index 1f081348e..18aebc364 100644 --- a/src/Text/Pandoc/Writers/Muse.hs +++ b/src/Text/Pandoc/Writers/Muse.hs @@ -308,6 +308,12 @@ escapeString s = substitute "" "</verbatim>" s ++ "" +-- | Replace newlines with spaces +replaceNewlines :: String -> String +replaceNewlines ('\n':xs) = ' ':replaceNewlines xs +replaceNewlines (x:xs) = x:replaceNewlines xs +replaceNewlines [] = [] + startsWithMarker :: (Char -> Bool) -> String -> Bool startsWithMarker f (' ':xs) = startsWithMarker f xs startsWithMarker f (x:xs) = @@ -517,7 +523,7 @@ inlineToMuse :: PandocMonad m => Inline -> Muse m Doc inlineToMuse (Str str) = do - escapedStr <- conditionalEscapeString str + escapedStr <- conditionalEscapeString $ replaceNewlines str let useTags = isAlphaNum $ last escapedStr -- escapedStr is never empty because empty strings are escaped modify $ \st -> st { stUseTags = useTags } return $ text escapedStr diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs index 614e9dbc6..f7287d57d 100644 --- a/test/Tests/Writers/Muse.hs +++ b/test/Tests/Writers/Muse.hs @@ -375,6 +375,7 @@ tests = [ testGroup "block elements" , "escape ; after softbreak" =: text "foo" <> softbreak <> text "; bar" =?> "foo\n; bar" , "escape ; after linebreak" =: text "foo" <> linebreak <> text "; bar" =?> "foo
\n; bar" , "do not escape ; inside paragraph" =: text "foo ; bar" =?> "foo ; bar" + , "escape newlines" =: str "foo\nbar" =?> "foo bar" ] , testGroup "emphasis" [ "emphasis" =: emph (text "foo") =?> "*foo*" -- cgit v1.2.3 From 44e4f7b29278897814f1b1913d3d9a863d9070f8 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 16 Sep 2018 20:32:42 -0700 Subject: Markdown reader: example_lists should work without startnum. Closes #4908. --- src/Text/Pandoc/Readers/Markdown.hs | 4 +++- test/command/4908.md | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 test/command/4908.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 502abae9a..5f6788887 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -970,7 +970,9 @@ orderedList = try $ do <|> return (style == Example) items <- fmap sequence $ many1 $ listItem fourSpaceRule (orderedListStart (Just (style, delim))) - start' <- (start <$ guardEnabled Ext_startnum) <|> return 1 + start' <- if style == Example + then return start + else (start <$ guardEnabled Ext_startnum) <|> return 1 return $ B.orderedListWith (start', style, delim) <$> fmap compactify items bulletList :: PandocMonad m => MarkdownParser m (F Blocks) diff --git a/test/command/4908.md b/test/command/4908.md new file mode 100644 index 000000000..2ff1a4603 --- /dev/null +++ b/test/command/4908.md @@ -0,0 +1,16 @@ +``` +% pandoc -f markdown_mmd+fancy_lists+example_lists -t native -t plain +(@) Example one +(@) Example two + +some text + +(@) Example three +^D +(1) Example one +(2) Example two + +some text + +(3) Example three +``` -- cgit v1.2.3 From db2a68d089e06bbf298b939252f826c84b6b6702 Mon Sep 17 00:00:00 2001 From: danse Date: Tue, 18 Sep 2018 13:24:24 +0200 Subject: parse rST inlines containing newlines closing #4912 this eliminates a regression error introduced after pandoc 2.1.1, affecting rST inline parsing. see the issue for details --- src/Text/Pandoc/Readers/RST.hs | 2 +- test/Tests/Readers/RST.hs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index 6a9e7cb95..274c9da7a 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -1315,7 +1315,6 @@ table = gridTable False <|> simpleTable False <|> inline :: PandocMonad m => RSTParser m Inlines inline = choice [ note -- can start with whitespace, so try before ws , link - , endline , strong , emph , code @@ -1328,6 +1327,7 @@ inline = choice [ note -- can start with whitespace, so try before ws inlineContent :: PandocMonad m => RSTParser m Inlines inlineContent = choice [ whitespace , str + , endline , smart , hyphens , escapedChar diff --git a/test/Tests/Readers/RST.hs b/test/Tests/Readers/RST.hs index 8916eed6f..963e7530d 100644 --- a/test/Tests/Readers/RST.hs +++ b/test/Tests/Readers/RST.hs @@ -198,5 +198,8 @@ tests = [ "line block with blank line" =: , "bare URI parsing disabled inside emphasis (#4561)" =: "*http://location*" =?> para (emph (text "http://location")) + , "include newlines" =: + "**before\nafter**" =?> + para (strong (text "before\nafter")) ] ] -- cgit v1.2.3 From 1feb62cb24a8fda5ce8ea823ec102abc0bd6e2ec Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 19 Sep 2018 13:22:25 +0300 Subject: Muse reader: add openTag and closeTag functions --- src/Text/Pandoc/Readers/Muse.hs | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 0b5d3dc1f..ea45ea9fc 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -179,16 +179,22 @@ someUntil p end = first <$> ((:) <$> p) <*> manyUntil p end -- ** HTML parsers +openTag :: PandocMonad m => String -> MuseParser m Attr +openTag tag = do + (TagOpen _ attr, _) <- htmlTag(~== TagOpen tag []) + return $ htmlAttrToPandoc attr + +closeTag :: PandocMonad m => String -> MuseParser m () +closeTag tag = void $ htmlTag (~== TagClose tag) + -- | Parse HTML tag, returning its attributes and literal contents. htmlElement :: PandocMonad m => String -- ^ Tag name -> MuseParser m (Attr, String) htmlElement tag = try $ do - (TagOpen _ attr, _) <- htmlTag (~== TagOpen tag []) - content <- manyTill anyChar endtag - return (htmlAttrToPandoc attr, content) - where - endtag = void $ htmlTag (~== TagClose tag) + attr <- openTag tag + content <- manyTill anyChar $ closeTag tag + return (attr, content) htmlBlock :: PandocMonad m => String -- ^ Tag name @@ -213,13 +219,11 @@ parseHtmlContent :: PandocMonad m parseHtmlContent tag = try $ do many spaceChar pos <- getPosition - (TagOpen _ attr, _) <- htmlTag (~== TagOpen tag []) + attr <- openTag tag manyTill spaceChar eol - content <- parseBlocksTill $ try $ count (sourceColumn pos - 1) spaceChar >> endtag + content <- parseBlocksTill $ try $ count (sourceColumn pos - 1) spaceChar >> closeTag tag manyTill spaceChar eol -- closing tag must be followed by optional whitespace and newline - return (htmlAttrToPandoc attr, content) - where - endtag = void $ htmlTag (~== TagClose tag) + return (attr, content) -- ** Directive parsers @@ -423,13 +427,12 @@ exampleTag = try $ do literalTag :: PandocMonad m => MuseParser m (F Blocks) literalTag = try $ do many spaceChar - (TagOpen _ attr, _) <- htmlTag (~== TagOpen "literal" []) + attr <- openTag "literal" manyTill spaceChar eol - content <- manyTill anyChar endtag + content <- manyTill anyChar $ closeTag "literal" manyTill spaceChar eol - return $ return $ rawBlock (htmlAttrToPandoc attr, content) + return $ return $ rawBlock (attr, content) where - endtag = void $ htmlTag (~== TagClose "literal") -- FIXME: Emacs Muse inserts without style into all output formats, but we assume HTML format (_, _, kvs) = fromMaybe "html" $ lookup "style" kvs rawBlock (attrs, content) = B.rawBlock (format attrs) $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content @@ -480,14 +483,12 @@ verseTag :: PandocMonad m => MuseParser m (F Blocks) verseTag = try $ do many spaceChar pos <- getPosition - (TagOpen _ _, _) <- htmlTag (~== TagOpen "verse" []) + openTag "verse" manyTill spaceChar eol let indent = count (sourceColumn pos - 1) spaceChar - content <- sequence <$> manyTill (indent >> verseLine) (try $ indent >> endtag) + content <- sequence <$> manyTill (indent >> verseLine) (try $ indent >> closeTag "verse") manyTill spaceChar eol return $ B.lineBlock <$> content - where - endtag = void $ htmlTag (~== TagClose "verse") -- | Parse @\@ tag. commentTag :: PandocMonad m => MuseParser m (F Blocks) -- cgit v1.2.3 From 94b9561e056f44eea891f394bde6547bf05dcb1b Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 19 Sep 2018 14:05:55 +0300 Subject: Muse reader: make openTag return association list --- src/Text/Pandoc/Readers/Muse.hs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index ea45ea9fc..4c6d78d1b 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -179,10 +179,10 @@ someUntil p end = first <$> ((:) <$> p) <*> manyUntil p end -- ** HTML parsers -openTag :: PandocMonad m => String -> MuseParser m Attr +openTag :: PandocMonad m => String -> MuseParser m [(String, String)] openTag tag = do (TagOpen _ attr, _) <- htmlTag(~== TagOpen tag []) - return $ htmlAttrToPandoc attr + return $ attr closeTag :: PandocMonad m => String -> MuseParser m () closeTag tag = void $ htmlTag (~== TagClose tag) @@ -194,7 +194,7 @@ htmlElement :: PandocMonad m htmlElement tag = try $ do attr <- openTag tag content <- manyTill anyChar $ closeTag tag - return (attr, content) + return (htmlAttrToPandoc attr, content) htmlBlock :: PandocMonad m => String -- ^ Tag name @@ -223,7 +223,7 @@ parseHtmlContent tag = try $ do manyTill spaceChar eol content <- parseBlocksTill $ try $ count (sourceColumn pos - 1) spaceChar >> closeTag tag manyTill spaceChar eol -- closing tag must be followed by optional whitespace and newline - return (attr, content) + return (htmlAttrToPandoc attr, content) -- ** Directive parsers @@ -427,7 +427,7 @@ exampleTag = try $ do literalTag :: PandocMonad m => MuseParser m (F Blocks) literalTag = try $ do many spaceChar - attr <- openTag "literal" + attr <- htmlAttrToPandoc <$> openTag "literal" manyTill spaceChar eol content <- manyTill anyChar $ closeTag "literal" manyTill spaceChar eol -- cgit v1.2.3 From 6be2e4339753a3dc6e00a4f07b9315e131fad5be Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 19 Sep 2018 14:06:14 +0300 Subject: Muse reader: use openTag and closeTag everywhere --- src/Text/Pandoc/Readers/Muse.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 4c6d78d1b..7f0bd374f 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -873,8 +873,8 @@ inlineTag :: PandocMonad m => String -- ^ Tag name -> MuseParser m (F Inlines) inlineTag tag = try $ do - htmlTag (~== TagOpen tag []) - mconcat <$> manyTill inline (void $ htmlTag (~== TagClose tag)) + openTag tag + mconcat <$> manyTill inline (closeTag tag) -- | Parse strong inline markup, indicated by @**@. strong :: PandocMonad m => MuseParser m (F Inlines) @@ -918,8 +918,8 @@ verbatimTag = return . B.text . snd <$> htmlElement "verbatim" -- | Parse @\@ tag. classTag :: PandocMonad m => MuseParser m (F Inlines) classTag = do - (TagOpen _ attrs, _) <- htmlTag (~== TagOpen "class" []) - res <- manyTill inline (void $ htmlTag (~== TagClose "class")) + attrs <- openTag "class" + res <- manyTill inline $ closeTag "class" let classes = maybe [] words $ lookup "name" attrs return $ B.spanWith ("", classes, []) <$> mconcat res -- cgit v1.2.3 From 1b8c22de1df43a88c13f6d0d0c7c08f9bf84c7a5 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 19 Sep 2018 15:02:25 +0300 Subject: Muse reader: get rid of HTML parser dependency --- src/Text/Pandoc/Readers/Muse.hs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 7f0bd374f..024ede456 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -59,7 +59,6 @@ import Text.Pandoc.Definition import Text.Pandoc.Logging import Text.Pandoc.Options import Text.Pandoc.Parsing hiding (F, enclosed) -import Text.Pandoc.Readers.HTML (htmlTag) import Text.Pandoc.Shared (crFilter, underlineSpan) -- | Read Muse from an input string and return a Pandoc document. @@ -180,12 +179,21 @@ someUntil p end = first <$> ((:) <$> p) <*> manyUntil p end -- ** HTML parsers openTag :: PandocMonad m => String -> MuseParser m [(String, String)] -openTag tag = do - (TagOpen _ attr, _) <- htmlTag(~== TagOpen tag []) - return $ attr +openTag tag = try $ do + char '<' + string tag + attrs <- manyTill attr (char '>') + return attrs + where + attr = try $ do + many1 spaceChar + key <- many1 (noneOf "=\n") + string "=\"" + value <- manyTill (noneOf "\"") (char '"') + return (key, value) closeTag :: PandocMonad m => String -> MuseParser m () -closeTag tag = void $ htmlTag (~== TagClose tag) +closeTag tag = try $ string "> string tag >> void (char '>') -- | Parse HTML tag, returning its attributes and literal contents. htmlElement :: PandocMonad m -- cgit v1.2.3 From 841784fb57b05a404646a608447ba5ac903a3a31 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 19 Sep 2018 15:26:21 +0300 Subject: hlint Muse reader --- src/Text/Pandoc/Readers/Muse.hs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 024ede456..a1f0e19ac 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -124,7 +124,7 @@ parseMuse = do many directive firstSection <- parseBlocks rest <- many parseSection - let blocks = mconcat $ (firstSection : rest) + let blocks = mconcat (firstSection : rest) st <- getState let doc = runF (do Pandoc _ bs <- B.doc <$> blocks meta <- museMeta st @@ -182,8 +182,7 @@ openTag :: PandocMonad m => String -> MuseParser m [(String, String)] openTag tag = try $ do char '<' string tag - attrs <- manyTill attr (char '>') - return attrs + manyTill attr (char '>') where attr = try $ do many1 spaceChar @@ -278,8 +277,8 @@ parseBlocks = where nextSection = mempty <$ lookAhead headingStart parseEnd = mempty <$ eof - blockStart = ((B.<>) <$> (blockElements <|> emacsNoteBlock) - <*> parseBlocks) + blockStart = (B.<>) <$> (blockElements <|> emacsNoteBlock) + <*> parseBlocks listStart = do updateState (\st -> st { museInPara = False }) uncurry (B.<>) <$> (anyListUntil parseBlocks <|> amuseNoteBlockUntil parseBlocks) @@ -293,7 +292,7 @@ parseSection :: PandocMonad m => MuseParser m (F Blocks) parseSection = ((B.<>) <$> emacsHeading <*> parseBlocks) <|> - ((uncurry (B.<>)) <$> amuseHeadingUntil parseBlocks) + (uncurry (B.<>) <$> amuseHeadingUntil parseBlocks) parseBlocksTill :: PandocMonad m => MuseParser m a -- cgit v1.2.3 From 8f841297df2aa4dcb1789843e562d4404baf1bf0 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 19 Sep 2018 16:34:14 +0300 Subject: Muse reader: parse Text instead of String Benchmark shows 7% improvement --- src/Text/Pandoc/Readers/Muse.hs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index a1f0e19ac..a0069827a 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -56,10 +56,11 @@ import Text.Pandoc.Builder (Blocks, Inlines) import qualified Text.Pandoc.Builder as B import Text.Pandoc.Class (PandocMonad (..)) import Text.Pandoc.Definition +import Text.Pandoc.Error (PandocError (PandocParsecError)) import Text.Pandoc.Logging import Text.Pandoc.Options import Text.Pandoc.Parsing hiding (F, enclosed) -import Text.Pandoc.Shared (crFilter, underlineSpan) +import Text.Pandoc.Shared (crFilter, underlineSpan, mapLeft) -- | Read Muse from an input string and return a Pandoc document. readMuse :: PandocMonad m @@ -67,7 +68,8 @@ readMuse :: PandocMonad m -> Text -> m Pandoc readMuse opts s = do - res <- readWithM parseMuse def{ museOptions = opts } (unpack (crFilter s)) + let input = crFilter s + res <- mapLeft (PandocParsecError $ unpack input) `liftM` runParserT parseMuse def{ museOptions = opts } "source" input case res of Left e -> throwError e Right d -> return d @@ -97,7 +99,7 @@ instance Default MuseState where , museInPara = False } -type MuseParser = ParserT String MuseState +type MuseParser = ParserT Text MuseState instance HasReaderOptions MuseState where extractReaderOptions = museOptions -- cgit v1.2.3 From 4264a1b1437f4b5885cf907aede821c8d611dff9 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Wed, 19 Sep 2018 21:05:36 +0200 Subject: Lua filter: cleanup filter execution code --- src/Text/Pandoc/Lua/Filter.hs | 124 +++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 51 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Lua/Filter.hs b/src/Text/Pandoc/Lua/Filter.hs index 264066305..6cbb10c6b 100644 --- a/src/Text/Pandoc/Lua/Filter.hs +++ b/src/Text/Pandoc/Lua/Filter.hs @@ -1,6 +1,33 @@ -{-# LANGUAGE NoImplicitPrelude #-} +{- +Copyright © 2012-2018 John MacFarlane + 2017-2018 Albert Krewinkel + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-} {-# LANGUAGE FlexibleContexts #-} - +{-# LANGUAGE NoImplicitPrelude #-} +{- | +Module : Text.Pandoc.Lua.Filter +Copyright : © 2012–2018 John MacFarlane, + © 2017-2018 Albert Krewinkel +License : GNU GPL, version 2 or above +Maintainer : Albert Krewinkel +Stability : alpha + +Types and functions for running Lua filters. +-} module Text.Pandoc.Lua.Filter ( LuaFilterFunction , LuaFilter , tryFilter @@ -12,60 +39,56 @@ module Text.Pandoc.Lua.Filter ( LuaFilterFunction , inlineElementNames ) where import Prelude -import Control.Monad (mplus, unless, when, (>=>)) +import Control.Monad (mplus, (>=>)) import Control.Monad.Catch (finally) -import Text.Pandoc.Definition -import Data.Foldable (foldrM) -import Data.Map (Map) -import qualified Data.Map as Map -import qualified Foreign.Lua as Lua -import Foreign.Lua (FromLuaStack (peek), Lua, StackIndex, - Status (OK), ToLuaStack (push)) -import Text.Pandoc.Walk (walkM, Walkable) import Data.Data (Data, DataType, dataTypeConstrs, dataTypeName, dataTypeOf, showConstr, toConstr, tyconUQname) -import Text.Pandoc.Lua.StackInstances() +import Data.Foldable (foldrM) +import Data.Map (Map) +import Foreign.Lua (Lua, FromLuaStack, ToLuaStack) +import Text.Pandoc.Definition +import Text.Pandoc.Lua.StackInstances () import Text.Pandoc.Lua.Util (typeCheck) +import Text.Pandoc.Walk (walkM, Walkable) -type FunctionMap = Map String LuaFilterFunction - -newtype LuaFilterFunction = LuaFilterFunction { functionIndex :: Int } - -instance ToLuaStack LuaFilterFunction where - push = pushFilterFunction +import qualified Data.Map.Strict as Map +import qualified Foreign.Lua as Lua -instance FromLuaStack LuaFilterFunction where - peek = registerFilterFunction +-- | Filter function stored at the given index in the registry +newtype LuaFilterFunction = LuaFilterFunction Int -newtype LuaFilter = LuaFilter FunctionMap +-- | Collection of filter functions (at most one function per element +-- constructor) +newtype LuaFilter = LuaFilter (Map String LuaFilterFunction) instance FromLuaStack LuaFilter where - peek idx = - let constrs = metaFilterName : pandocFilterNames - ++ blockElementNames - ++ inlineElementNames - fn c acc = do - Lua.getfield idx c - filterFn <- Lua.tryLua (peek (-1)) - Lua.pop 1 + peek idx = do + let constrs = metaFilterName + : pandocFilterNames + ++ blockElementNames + ++ inlineElementNames + let go constr acc = do + Lua.getfield idx constr + filterFn <- registerFilterFunction return $ case filterFn of - Left _ -> acc - Right f -> (c, f) : acc - in LuaFilter . Map.fromList <$> foldrM fn [] constrs - --- | Push the filter function to the top of the stack. + Nothing -> acc + Just fn -> Map.insert constr fn acc + LuaFilter <$> foldrM go Map.empty constrs + +-- | Register the function at the top of the stack as a filter function in the +-- registry. +registerFilterFunction :: Lua (Maybe LuaFilterFunction) +registerFilterFunction = do + isFn <- Lua.isfunction Lua.stackTop + if isFn + then Just . LuaFilterFunction <$> Lua.ref Lua.registryindex + else Nothing <$ Lua.pop 1 + +-- | Retrieve filter function from registry and push it to the top of the stack. pushFilterFunction :: LuaFilterFunction -> Lua () -pushFilterFunction lf = - -- The function is stored in a lua registry table, retrieve it from there. - Lua.rawgeti Lua.registryindex (functionIndex lf) - -registerFilterFunction :: StackIndex -> Lua LuaFilterFunction -registerFilterFunction idx = do - isFn <- Lua.isfunction idx - unless isFn . Lua.throwLuaError $ "Not a function at index " ++ show idx - Lua.pushvalue idx - refIdx <- Lua.ref Lua.registryindex - return $ LuaFilterFunction refIdx +pushFilterFunction (LuaFilterFunction fnRef) = + Lua.rawgeti Lua.registryindex fnRef + elementOrList :: FromLuaStack a => a -> Lua [a] elementOrList x = do @@ -98,12 +121,11 @@ tryFilter (LuaFilter fnMap) x = -- element is left unchanged. runFilterFunction :: ToLuaStack a => LuaFilterFunction -> a -> Lua () runFilterFunction lf x = do - pushFilterFunction lf - push x - z <- Lua.pcall 1 1 Nothing - when (z /= OK) $ do - let addPrefix = ("Error while running filter function: " ++) - Lua.throwTopMessageAsError' addPrefix + let errorPrefix = "Error while running filter function:\n" + (`Lua.modifyLuaError` (errorPrefix <>)) $ do + pushFilterFunction lf + Lua.push x + Lua.call 1 1 walkMWithLuaFilter :: LuaFilter -> Pandoc -> Lua Pandoc walkMWithLuaFilter f = -- cgit v1.2.3 From 136bf901aa088eaf4e5c996c71e0a36c171f1587 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 19 Sep 2018 14:49:46 -0700 Subject: Markdown reader: distinguish autolinks in the AST. With this change, autolinks are parsed as Links with the `uri` class. (The same is true for bare links, if the `autolink_bare_uris` extension is enabled.) Email autolinks are parsed as Links with the `email` class. This allows the distinction to be represented in the URI. Formerly the `uri` class was added to autolinks by the HTML writer, but it had to guess what was an autolink and could not distinguish `[http://example.com](http://example.com)` from ``. It also incorrectly recognized `[pandoc](pandoc)` as an autolink. Now the HTML writer simply passes through the `uri` attribute if it is present, but does not add anything. The Textile writer has been modified so that the `uri` class is not explicitly added for autolinks, even if it is present. Closes #4913. --- src/Text/Pandoc/Readers/Markdown.hs | 12 +++++++----- src/Text/Pandoc/Writers/HTML.hs | 7 ++----- src/Text/Pandoc/Writers/Textile.hs | 6 +++--- test/Tests/Readers/Markdown.hs | 8 +++++--- test/command/3716.md | 2 +- test/command/4913.md | 34 ++++++++++++++++++++++++++++++++++ test/markdown-reader-more.native | 8 ++++---- test/testsuite.native | 8 ++++---- test/writer.docbook4 | 6 +++--- test/writer.docbook5 | 6 +++--- test/writer.html4 | 2 +- test/writer.html5 | 2 +- test/writer.native | 8 ++++---- test/writer.textile | 2 +- 14 files changed, 73 insertions(+), 38 deletions(-) create mode 100644 test/command/4913.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs index 5f6788887..d1ea7a1a5 100644 --- a/src/Text/Pandoc/Readers/Markdown.hs +++ b/src/Text/Pandoc/Readers/Markdown.hs @@ -1,6 +1,7 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RelaxedPolyRec #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} {- Copyright (C) 2006-2018 John MacFarlane @@ -1879,23 +1880,24 @@ bareURL :: PandocMonad m => MarkdownParser m (F Inlines) bareURL = try $ do guardEnabled Ext_autolink_bare_uris getState >>= guard . stateAllowLinks - (orig, src) <- uri <|> emailAddress + (cls, (orig, src)) <- (("uri",) <$> uri) <|> (("email",) <$> emailAddress) notFollowedBy $ try $ spaces >> htmlTag (~== TagClose "a") - return $ return $ B.link src "" (B.str orig) + return $ return $ B.linkWith ("",[cls],[]) src "" (B.str orig) autoLink :: PandocMonad m => MarkdownParser m (F Inlines) autoLink = try $ do getState >>= guard . stateAllowLinks char '<' - (orig, src) <- uri <|> emailAddress + (cls, (orig, src)) <- (("uri",) <$> uri) <|> (("email",) <$> emailAddress) -- in rare cases, something may remain after the uri parser -- is finished, because the uri parser tries to avoid parsing -- final punctuation. for example: in ``, -- the URI parser will stop before the dashes. extra <- fromEntities <$> manyTill nonspaceChar (char '>') - attr <- option nullAttr $ try $ + attr <- option ("", [cls], []) $ try $ guardEnabled Ext_link_attributes >> attributes - return $ return $ B.linkWith attr (src ++ escapeURI extra) "" (B.str $ orig ++ extra) + return $ return $ B.linkWith attr (src ++ escapeURI extra) "" + (B.str $ orig ++ extra) image :: PandocMonad m => MarkdownParser m (F Inlines) image = try $ do diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index a0b622c83..851b48956 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -56,7 +56,7 @@ import Data.String (fromString) import Data.Text (Text) import qualified Data.Text.Lazy as TL import Network.HTTP (urlEncode) -import Network.URI (URI (..), parseURIReference, unEscapeString) +import Network.URI (URI (..), parseURIReference) import Numeric (showHex) import Text.Blaze.Internal (customLeaf, customParent, MarkupM(Empty)) #if MIN_VERSION_blaze_markup(0,6,3) @@ -1084,10 +1084,7 @@ inlineToHtml opts inline = do in '#' : prefix ++ xs _ -> s let link = H.a ! A.href (toValue s') $ linkText - let attr = if txt == [Str (unEscapeString s)] - then (ident, "uri" : classes, kvs) - else (ident, classes, kvs) - link' <- addAttrs opts attr link + link' <- addAttrs opts (ident, classes, kvs) link return $ if null tit then link' else link' ! A.title (toValue tit) diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs index d1724f438..c7d96454a 100644 --- a/src/Text/Pandoc/Writers/Textile.hs +++ b/src/Text/Pandoc/Writers/Textile.hs @@ -463,15 +463,15 @@ inlineToTextile _ SoftBreak = return " " inlineToTextile _ Space = return " " inlineToTextile opts (Link (_, cls, _) txt (src, _)) = do - let classes = if null cls - then "" - else "(" ++ unwords cls ++ ")" label <- case txt of [Code _ s] | s == src -> return "$" [Str s] | s == src -> return "$" _ -> inlineListToTextile opts txt + let classes = if null cls || cls == ["uri"] && label == "$" + then "" + else "(" ++ unwords cls ++ ")" return $ "\"" ++ classes ++ label ++ "\":" ++ src inlineToTextile opts (Image attr@(_, cls, _) alt (source, tit)) = do diff --git a/test/Tests/Readers/Markdown.hs b/test/Tests/Readers/Markdown.hs index bc8e55615..be89e708e 100644 --- a/test/Tests/Readers/Markdown.hs +++ b/test/Tests/Readers/Markdown.hs @@ -39,7 +39,7 @@ testBareLink (inp, ils) = (unpack inp) (inp, doc $ para ils) autolink :: String -> Inlines -autolink = autolinkWith nullAttr +autolink = autolinkWith ("",["uri"],[]) autolinkWith :: Attr -> String -> Inlines autolinkWith attr s = linkWith attr s "" (str s) @@ -72,10 +72,12 @@ bareLinkTests = , ("http://en.wikipedia.org/wiki/Sprite_(computer_graphics)", autolink "http://en.wikipedia.org/wiki/Sprite_(computer_graphics)") , ("http://en.wikipedia.org/wiki/Sprite_[computer_graphics]", - link "http://en.wikipedia.org/wiki/Sprite_%5Bcomputer_graphics%5D" "" + linkWith ("",["uri"],[]) + "http://en.wikipedia.org/wiki/Sprite_%5Bcomputer_graphics%5D" "" (str "http://en.wikipedia.org/wiki/Sprite_[computer_graphics]")) , ("http://en.wikipedia.org/wiki/Sprite_{computer_graphics}", - link "http://en.wikipedia.org/wiki/Sprite_%7Bcomputer_graphics%7D" "" + linkWith ("",["uri"],[]) + "http://en.wikipedia.org/wiki/Sprite_%7Bcomputer_graphics%7D" "" (str "http://en.wikipedia.org/wiki/Sprite_{computer_graphics}")) , ("http://example.com/Notification_Center-GitHub-20101108-140050.jpg", autolink "http://example.com/Notification_Center-GitHub-20101108-140050.jpg") diff --git a/test/command/3716.md b/test/command/3716.md index 7e00819da..81e4a9568 100644 --- a/test/command/3716.md +++ b/test/command/3716.md @@ -2,5 +2,5 @@ % pandoc {.foo} ^D -

http://example.com

+

http://example.com

``` diff --git a/test/command/4913.md b/test/command/4913.md new file mode 100644 index 000000000..6492b80ce --- /dev/null +++ b/test/command/4913.md @@ -0,0 +1,34 @@ +``` +% pandoc -f markdown -t html +[https://pandoc.org](https://pandoc.org) +^D +

https://pandoc.org

+``` + +``` +% pandoc -f markdown -t markdown +[https://pandoc.org](https://pandoc.org) +^D + +``` + +``` +% pandoc -f markdown -t html + +^D +

https://pandoc.org

+``` + +``` +% pandoc -f markdown -t html +{.foo} +^D +

https://pandoc.org

+``` + +``` +% pandoc -f markdown -t html + +^D +

+``` diff --git a/test/markdown-reader-more.native b/test/markdown-reader-more.native index 799f4ffa7..9c128ab94 100644 --- a/test/markdown-reader-more.native +++ b/test/markdown-reader-more.native @@ -45,9 +45,9 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "Author",S ,Para [Str "`hi"] ,Para [Str "there`"] ,Header 2 ("multilingual-urls",[],[]) [Str "Multilingual",Space,Str "URLs"] -,Para [Link ("",[],[]) [Str "http://\27979.com?\27979=\27979"] ("http://\27979.com?\27979=\27979","")] +,Para [Link ("",["uri"],[]) [Str "http://\27979.com?\27979=\27979"] ("http://\27979.com?\27979=\27979","")] ,Para [Link ("",[],[]) [Str "foo"] ("/bar/\27979?x=\27979","title")] -,Para [Link ("",[],[]) [Str "\27979@foo.\27979.baz"] ("mailto:\27979@foo.\27979.baz","")] +,Para [Link ("",["email"],[]) [Str "\27979@foo.\27979.baz"] ("mailto:\27979@foo.\27979.baz","")] ,Header 2 ("numbered-examples",[],[]) [Str "Numbered",Space,Str "examples"] ,OrderedList (1,Example,TwoParens) [[Plain [Str "First",Space,Str "example."]] @@ -176,8 +176,8 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "Author",S ,[]]] ,Header 2 ("entities-in-links-and-titles",[],[]) [Str "Entities",Space,Str "in",Space,Str "links",Space,Str "and",Space,Str "titles"] ,Para [Link ("",[],[]) [Str "link"] ("/\252rl","\246\246!")] -,Para [Link ("",[],[]) [Str "http://g\246\246gle.com"] ("http://g\246\246gle.com","")] -,Para [Link ("",[],[]) [Str "me@ex\228mple.com"] ("mailto:me@ex\228mple.com","")] +,Para [Link ("",["uri"],[]) [Str "http://g\246\246gle.com"] ("http://g\246\246gle.com","")] +,Para [Link ("",["email"],[]) [Str "me@ex\228mple.com"] ("mailto:me@ex\228mple.com","")] ,Para [Link ("",[],[]) [Str "foobar"] ("/\252rl","\246\246!")] ,Header 2 ("parentheses-in-urls",[],[]) [Str "Parentheses",Space,Str "in",Space,Str "URLs"] ,Para [Link ("",[],[]) [Str "link"] ("/hi(there)","")] diff --git a/test/testsuite.native b/test/testsuite.native index fcd189eb0..73fcc0633 100644 --- a/test/testsuite.native +++ b/test/testsuite.native @@ -384,14 +384,14 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa ,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."] ,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."] ,Header 2 ("autolinks",[],[]) [Str "Autolinks"] -,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")] +,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",["uri"],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")] ,BulletList [[Plain [Str "In",Space,Str "a",Space,Str "list?"]] - ,[Plain [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]] + ,[Plain [Link ("",["uri"],[]) [Str "http://example.com/"] ("http://example.com/","")]] ,[Plain [Str "It",Space,Str "should."]]] -,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Link ("",[],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")] +,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Link ("",["email"],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")] ,BlockQuote - [Para [Str "Blockquoted:",Space,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]] + [Para [Str "Blockquoted:",Space,Link ("",["uri"],[]) [Str "http://example.com/"] ("http://example.com/","")]] ,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) ""] ,CodeBlock ("",[],[]) "or here: " ,HorizontalRule diff --git a/test/writer.docbook4 b/test/writer.docbook4 index 163255974..38b3cc1ee 100644 --- a/test/writer.docbook4 +++ b/test/writer.docbook4 @@ -1298,7 +1298,7 @@ These should not be escaped: \$ \\ \> \[ \{ Autolinks With an ampersand: - http://example.com/?foo=1&bar=2 + http://example.com/?foo=1&bar=2 @@ -1308,7 +1308,7 @@ These should not be escaped: \$ \\ \> \[ \{ - http://example.com/ + http://example.com/ @@ -1323,7 +1323,7 @@ These should not be escaped: \$ \\ \> \[ \{
Blockquoted: - http://example.com/ + http://example.com/
diff --git a/test/writer.docbook5 b/test/writer.docbook5 index 992cd8b63..9a9eff0c5 100644 --- a/test/writer.docbook5 +++ b/test/writer.docbook5 @@ -1273,7 +1273,7 @@ These should not be escaped: \$ \\ \> \[ \{ Autolinks With an ampersand: - http://example.com/?foo=1&bar=2 + http://example.com/?foo=1&bar=2 @@ -1283,7 +1283,7 @@ These should not be escaped: \$ \\ \> \[ \{ - http://example.com/ + http://example.com/ @@ -1298,7 +1298,7 @@ These should not be escaped: \$ \\ \> \[ \{
Blockquoted: - http://example.com/ + http://example.com/
diff --git a/test/writer.html4 b/test/writer.html4 index dc889f07a..bed6617a0 100644 --- a/test/writer.html4 +++ b/test/writer.html4 @@ -508,7 +508,7 @@ Blah
  • http://example.com/
  • It should.
  • -

    An e-mail address: nobody@nowhere.net

    +

    An e-mail address:

    Blockquoted: http://example.com/

    diff --git a/test/writer.html5 b/test/writer.html5 index 4f80231db..46105d0a6 100644 --- a/test/writer.html5 +++ b/test/writer.html5 @@ -511,7 +511,7 @@ Blah
  • http://example.com/
  • It should.
  • -

    An e-mail address: nobody@nowhere.net

    +

    An e-mail address:

    Blockquoted: http://example.com/

    diff --git a/test/writer.native b/test/writer.native index fcd189eb0..73fcc0633 100644 --- a/test/writer.native +++ b/test/writer.native @@ -384,14 +384,14 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa ,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."] ,Para [Str "Here\8217s",Space,Str "an",Space,Link ("",[],[]) [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."] ,Header 2 ("autolinks",[],[]) [Str "Autolinks"] -,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",[],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")] +,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link ("",["uri"],[]) [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")] ,BulletList [[Plain [Str "In",Space,Str "a",Space,Str "list?"]] - ,[Plain [Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]] + ,[Plain [Link ("",["uri"],[]) [Str "http://example.com/"] ("http://example.com/","")]] ,[Plain [Str "It",Space,Str "should."]]] -,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Link ("",[],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")] +,Para [Str "An",Space,Str "e-mail",Space,Str "address:",Space,Link ("",["email"],[]) [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")] ,BlockQuote - [Para [Str "Blockquoted:",Space,Link ("",[],[]) [Str "http://example.com/"] ("http://example.com/","")]] + [Para [Str "Blockquoted:",Space,Link ("",["uri"],[]) [Str "http://example.com/"] ("http://example.com/","")]] ,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) ""] ,CodeBlock ("",[],[]) "or here: " ,HorizontalRule diff --git a/test/writer.textile b/test/writer.textile index d19b698f9..78e659091 100644 --- a/test/writer.textile +++ b/test/writer.textile @@ -660,7 +660,7 @@ With an ampersand: "$":http://example.com/?foo=1&bar=2 * "$":http://example.com/ * It should. -An e-mail address: "nobody@nowhere.net":mailto:nobody@nowhere.net +An e-mail address: "(email)nobody@nowhere.net":mailto:nobody@nowhere.net bq. Blockquoted: "$":http://example.com/ -- cgit v1.2.3 From 5b1fdeaf41d6ee4b6b82cbeb4e7f7508182b3566 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 20 Sep 2018 09:35:43 -0700 Subject: ConTeXt writer: change `\` to `/` in Windows image paths. We do this in the LaTeX writer, and it avoids problems. Note that `/` works as a LaTeX path separator on Windows. Closes #4918. --- src/Text/Pandoc/Writers/ConTeXt.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs index 763f1a370..4947d7f79 100644 --- a/src/Text/Pandoc/Writers/ConTeXt.hs +++ b/src/Text/Pandoc/Writers/ConTeXt.hs @@ -453,7 +453,12 @@ inlineToConTeXt (Image attr@(_,cls,_) _ (src, _)) = do clas = if null cls then empty else brackets $ text $ toLabel $ head cls - src' = if isURI src + -- Use / for path separators on Windows; see #4918 + fixPathSeparators = map $ \c -> case c of + '\\' -> '/' + c -> c + src' = fixPathSeparators $ + if isURI src then src else unEscapeString src return $ braces $ "\\externalfigure" <> brackets (text src') <> dims <> clas -- cgit v1.2.3 From 37c6f6adfe5f292bccd42046842e5cb2cc7484d0 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 20 Sep 2018 11:15:03 -0700 Subject: RST reader: fix bug with internal link targets. They were gobbling up indented content underneath. Closes #4919. --- src/Text/Pandoc/Readers/RST.hs | 2 +- test/command/4919.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/command/4919.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs index 274c9da7a..28fa7b83e 100644 --- a/src/Text/Pandoc/Readers/RST.hs +++ b/src/Text/Pandoc/Readers/RST.hs @@ -1090,7 +1090,7 @@ referenceKey = do targetURI :: Monad m => ParserT [Char] st m [Char] targetURI = do skipSpaces - optional newline + optional $ try $ newline >> notFollowedBy blankline contents <- trim <$> many1 (satisfy (/='\n') <|> try (newline >> many1 spaceChar >> noneOf " \t\n")) diff --git a/test/command/4919.md b/test/command/4919.md new file mode 100644 index 000000000..029d1beff --- /dev/null +++ b/test/command/4919.md @@ -0,0 +1,14 @@ +``` +% pandoc -f rst -t native +.. _`tgtmath`: + + .. math:: + :name: + + V = \frac{K}{r^2} +^D +[Div ("tgtmath",[],[]) + [BlockQuote + [Para [Math DisplayMath "V = \\frac{K}{r^2}"]]]] +``` + -- cgit v1.2.3 From fedf1f213fec089736fce041bb344f86a403c5cb Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 21 Sep 2018 02:57:06 +0300 Subject: Muse reader: simplify lchop --- src/Text/Pandoc/Readers/Muse.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index a0069827a..a749b87b8 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -145,9 +145,8 @@ commonPrefix (x:xs) (y:ys) -- | Trim up to one newline from the beginning of the string. lchop :: String -> String -lchop s = case s of - '\n':ss -> ss - _ -> s +lchop ('\n':xs) = xs +lchop s = s -- | Trim up to one newline from the end of the string. rchop :: String -> String -- cgit v1.2.3 From 095fff7da127c27e5b46c9425c332750c2de4db0 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 21 Sep 2018 03:03:20 +0300 Subject: Muse reader: cleanup and conversion to applicative style --- src/Text/Pandoc/Readers/Muse.hs | 170 ++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 95 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index a749b87b8..9432ecc1c 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -180,38 +180,31 @@ someUntil p end = first <$> ((:) <$> p) <*> manyUntil p end -- ** HTML parsers openTag :: PandocMonad m => String -> MuseParser m [(String, String)] -openTag tag = try $ do - char '<' - string tag - manyTill attr (char '>') +openTag tag = try $ + char '<' *> string tag *> manyTill attr (char '>') where - attr = try $ do - many1 spaceChar - key <- many1 (noneOf "=\n") - string "=\"" - value <- manyTill (noneOf "\"") (char '"') - return (key, value) + attr = try $ (,) + <$ many1 spaceChar + <*> many1 (noneOf "=\n") + <* string "=\"" + <*> manyTill (noneOf "\"") (char '"') closeTag :: PandocMonad m => String -> MuseParser m () -closeTag tag = try $ string "> string tag >> void (char '>') +closeTag tag = try $ string " string tag *> void (char '>') -- | Parse HTML tag, returning its attributes and literal contents. htmlElement :: PandocMonad m => String -- ^ Tag name -> MuseParser m (Attr, String) -htmlElement tag = try $ do - attr <- openTag tag - content <- manyTill anyChar $ closeTag tag - return (htmlAttrToPandoc attr, content) +htmlElement tag = try $ (,) + <$> (htmlAttrToPandoc <$> openTag tag) + <*> manyTill anyChar (closeTag tag) htmlBlock :: PandocMonad m => String -- ^ Tag name -> MuseParser m (Attr, String) -htmlBlock tag = try $ do - many spaceChar - res <- htmlElement tag - manyTill spaceChar eol - return res +htmlBlock tag = try $ + many spaceChar *> htmlElement tag <* manyTill spaceChar eol -- | Convert HTML attributes to Pandoc 'Attr' htmlAttrToPandoc :: [Attribute String] -> Attr @@ -229,7 +222,7 @@ parseHtmlContent tag = try $ do pos <- getPosition attr <- openTag tag manyTill spaceChar eol - content <- parseBlocksTill $ try $ count (sourceColumn pos - 1) spaceChar >> closeTag tag + content <- parseBlocksTill $ try $ count (sourceColumn pos - 1) spaceChar *> closeTag tag manyTill spaceChar eol -- closing tag must be followed by optional whitespace and newline return (htmlAttrToPandoc attr, content) @@ -240,21 +233,19 @@ parseDirectiveKey :: PandocMonad m => MuseParser m String parseDirectiveKey = char '#' *> many (letter <|> char '-') parseEmacsDirective :: PandocMonad m => MuseParser m (String, F Inlines) -parseEmacsDirective = do - key <- parseDirectiveKey - spaceChar - value <- trimInlinesF . mconcat <$> manyTill (choice inlineList) eol - return (key, value) +parseEmacsDirective = (,) + <$> parseDirectiveKey + <* spaceChar + <*> (trimInlinesF . mconcat <$> manyTill (choice inlineList) eol) parseAmuseDirective :: PandocMonad m => MuseParser m (String, F Inlines) -parseAmuseDirective = do - key <- parseDirectiveKey - many1 spaceChar - value <- trimInlinesF . mconcat <$> many1Till inline endOfDirective - many blankline - return (key, value) +parseAmuseDirective = (,) + <$> parseDirectiveKey + <* many1 spaceChar + <*> (trimInlinesF . mconcat <$> many1Till inline endOfDirective) + <* many blankline where - endOfDirective = lookAhead $ eof <|> try (newline >> (void blankline <|> void parseDirectiveKey)) + endOfDirective = lookAhead $ eof <|> try (newline *> (void blankline <|> void parseDirectiveKey)) directive :: PandocMonad m => MuseParser m () directive = do @@ -372,18 +363,17 @@ comment :: PandocMonad m => MuseParser m (F Blocks) comment = try $ do getPosition >>= \pos -> guard (sourceColumn pos == 1) char ';' - optional (spaceChar >> many (noneOf "\n")) + optional (spaceChar *> many (noneOf "\n")) eol return mempty -- | Parse a horizontal rule, consisting of 4 or more @\'-\'@ characters. separator :: PandocMonad m => MuseParser m (F Blocks) -separator = try $ do - string "----" - many $ char '-' - many spaceChar - eol - return $ return B.horizontalRule +separator = try $ pure B.horizontalRule + <$ string "----" + <* many (char '-') + <* many spaceChar + <* eol headingStart :: PandocMonad m => MuseParser m (String, Int) headingStart = try $ do @@ -418,11 +408,10 @@ amuseHeadingUntil end = try $ do -- | Parse an example between @{{{@ and @}}}@. -- It is an Amusewiki extension influenced by Creole wiki, as described in @Text::Amuse@ documentation. example :: PandocMonad m => MuseParser m (F Blocks) -example = try $ do - string "{{{" - optional blankline - contents <- manyTill anyChar $ try (optional blankline >> string "}}}") - return $ return $ B.codeBlock contents +example = try $ pure . B.codeBlock + <$ string "{{{" + <* optional blankline + <*> manyTill anyChar (try (optional blankline *> string "}}}")) -- | Parse an @\@ tag. exampleTag :: PandocMonad m => MuseParser m (F Blocks) @@ -482,7 +471,7 @@ playTag = do verseLine :: PandocMonad m => MuseParser m (F Inlines) verseLine = do - indent <- (B.str <$> many1 (char ' ' >> pure '\160')) <|> pure mempty + indent <- (B.str <$> many1 ('\160' <$ char ' ')) <|> pure mempty rest <- manyTill (choice inlineList) newline return $ trimInlinesF $ mconcat (pure indent : rest) @@ -494,13 +483,13 @@ verseTag = try $ do openTag "verse" manyTill spaceChar eol let indent = count (sourceColumn pos - 1) spaceChar - content <- sequence <$> manyTill (indent >> verseLine) (try $ indent >> closeTag "verse") + content <- sequence <$> manyTill (indent *> verseLine) (try $ indent *> closeTag "verse") manyTill spaceChar eol return $ B.lineBlock <$> content -- | Parse @\@ tag. commentTag :: PandocMonad m => MuseParser m (F Blocks) -commentTag = htmlBlock "comment" >> return mempty +commentTag = mempty <$ htmlBlock "comment" -- | Parse paragraph contents. paraContentsUntil :: PandocMonad m @@ -508,7 +497,7 @@ paraContentsUntil :: PandocMonad m -> MuseParser m (F Inlines, a) paraContentsUntil end = do updateState (\st -> st { museInPara = True }) - (l, e) <- someUntil inline $ try (manyTill spaceChar eol >> end) + (l, e) <- someUntil inline $ try (manyTill spaceChar eol *> end) updateState (\st -> st { museInPara = False }) return (trimInlinesF $ mconcat l, e) @@ -522,9 +511,10 @@ paraUntil end = do first (fmap B.para) <$> paraContentsUntil end noteMarker :: PandocMonad m => MuseParser m String -noteMarker = try $ do - char '[' - (:) <$> oneOf "123456789" <*> manyTill digit (char ']') +noteMarker = try $ (:) + <$ char '[' + <*> oneOf "123456789" + <*> manyTill digit (char ']') -- Amusewiki version of note -- Parsing is similar to list item, except that note marker is used instead of list marker @@ -567,16 +557,15 @@ emacsNoteBlock = try $ do lineVerseLine :: PandocMonad m => MuseParser m (F Inlines) lineVerseLine = try $ do string "> " - indent <- many (char ' ' >> pure '\160') + indent <- many ('\160' <$ char ' ') let indentEl = if null indent then mempty else B.str indent rest <- manyTill (choice inlineList) eol return $ trimInlinesF $ mconcat (pure indentEl : rest) blanklineVerseLine :: PandocMonad m => MuseParser m (F Inlines) -blanklineVerseLine = try $ do - char '>' - blankline - pure mempty +blanklineVerseLine = try $ mempty + <$ char '>' + <* blankline -- | Parse a line block indicated by @\'>\'@ characters. lineBlock :: PandocMonad m => MuseParser m (F Blocks) @@ -596,7 +585,7 @@ bulletListItemsUntil indent end = try $ do char '-' void spaceChar <|> lookAhead eol updateState (\st -> st { museInPara = False }) - (x, (xs, e)) <- listItemContentsUntil (indent + 2) (try (optional blankline >> indentWith indent >> bulletListItemsUntil indent end)) (([],) <$> end) + (x, (xs, e)) <- listItemContentsUntil (indent + 2) (try (optional blankline *> indentWith indent *> bulletListItemsUntil indent end)) (([],) <$> end) return (x:xs, e) -- | Parse a bullet list. @@ -643,7 +632,7 @@ orderedListItemsUntil indent style end = pos <- getPosition void spaceChar <|> lookAhead eol updateState (\st -> st { museInPara = False }) - (x, (xs, e)) <- listItemContentsUntil (sourceColumn pos) (try (optional blankline >> indentWith indent >> museOrderedListMarker style >> continuation)) (([],) <$> end) + (x, (xs, e)) <- listItemContentsUntil (sourceColumn pos) (try (optional blankline *> indentWith indent *> museOrderedListMarker style *> continuation)) (([],) <$> end) return (x:xs, e) -- | Parse an ordered list. @@ -667,7 +656,7 @@ descriptionsUntil :: PandocMonad m descriptionsUntil indent end = do void spaceChar <|> lookAhead eol updateState (\st -> st { museInPara = False }) - (x, (xs, e)) <- listItemContentsUntil indent (try (optional blankline >> indentWith indent >> manyTill spaceChar (string "::") >> descriptionsUntil indent end)) (([],) <$> end) + (x, (xs, e)) <- listItemContentsUntil indent (try (optional blankline *> indentWith indent *> manyTill spaceChar (string "::") *> descriptionsUntil indent end)) (([],) <$> end) return (x:xs, e) definitionListItemsUntil :: PandocMonad m @@ -680,7 +669,7 @@ definitionListItemsUntil indent end = continuation = try $ do pos <- getPosition term <- trimInlinesF . mconcat <$> manyTill (choice inlineList) (try $ string "::") - (x, (xs, e)) <- descriptionsUntil (sourceColumn pos) (try (optional blankline >> indentWith indent >> continuation) <|> (([],) <$> end)) + (x, (xs, e)) <- descriptionsUntil (sourceColumn pos) (try (optional blankline *> indentWith indent *> continuation) <|> (([],) <$> end)) let xx = (,) <$> term <*> sequence x return (xx:xs, e) @@ -736,7 +725,7 @@ museAppendElement element tbl = tableCell :: PandocMonad m => MuseParser m (F Blocks) tableCell = try $ fmap B.plain . trimInlinesF . mconcat <$> manyTill inline (lookAhead cellEnd) - where cellEnd = try $ void (many1 spaceChar >> char '|') <|> eol + where cellEnd = try $ void (many1 spaceChar *> char '|') <|> eol tableElements :: PandocMonad m => MuseParser m (F [MuseTableElement]) tableElements = sequence <$> (tableParseElement `sepEndBy1` eol) @@ -758,11 +747,10 @@ tableParseElement = tableParseHeader tableParseRow :: PandocMonad m => Int -- ^ Number of separator characters -> MuseParser m (F [Blocks]) -tableParseRow n = try $ do - fields <- tableCell `sepBy2` fieldSep - return $ sequence fields - where p `sepBy2` sep = (:) <$> p <*> many1 (sep >> p) - fieldSep = many1 spaceChar >> count n (char '|') >> (void (many1 spaceChar) <|> void (lookAhead newline)) +tableParseRow n = try $ + sequence <$> (tableCell `sepBy2` fieldSep) + where p `sepBy2` sep = (:) <$> p <*> many1 (sep *> p) + fieldSep = many1 spaceChar *> count n (char '|') *> (void (many1 spaceChar) <|> void (lookAhead newline)) -- | Parse a table header row. tableParseHeader :: PandocMonad m => MuseParser m (F MuseTableElement) @@ -778,10 +766,10 @@ tableParseFooter = fmap MuseFooterRow <$> tableParseRow 3 -- | Parse table caption. tableParseCaption :: PandocMonad m => MuseParser m (F MuseTableElement) -tableParseCaption = try $ do - many spaceChar - string "|+" - fmap MuseCaption <$> (trimInlinesF . mconcat <$> many1Till inline (string "+|")) +tableParseCaption = try $ fmap MuseCaption . trimInlinesF . mconcat + <$ many spaceChar + <* string "|+" + <*> many1Till inline (string "+|") -- ** Inline parsers @@ -815,10 +803,7 @@ inline = endline <|> choice inlineList "inline" -- | Parse a soft break. endline :: PandocMonad m => MuseParser m (F Inlines) -endline = try $ do - newline - notFollowedBy blankline - return $ return B.softbreak +endline = try $ pure B.softbreak <$ newline <* notFollowedBy blankline parseAnchor :: PandocMonad m => MuseParser m String parseAnchor = try $ do @@ -848,15 +833,11 @@ footnote = try $ do return $ B.note contents' whitespace :: PandocMonad m => MuseParser m (F Inlines) -whitespace = try $ do - skipMany1 spaceChar - return $ return B.space +whitespace = try $ pure B.space <$ skipMany1 spaceChar -- | Parse @\
    @ tag. br :: PandocMonad m => MuseParser m (F Inlines) -br = try $ do - string "
    " - return $ return B.linebreak +br = try $ pure B.linebreak <$ string "
    " emphasisBetween :: (PandocMonad m, Show a) => MuseParser m a -> MuseParser m (F Inlines) emphasisBetween c = try $ enclosedInlines c c @@ -867,7 +848,7 @@ enclosed :: (Show end, Stream s m Char) => ParserT s st m t -- ^ start parser -> ParserT s st m a -- ^ content parser (to be used repeatedly) -> ParserT s st m [a] enclosed start end parser = try $ - start >> notFollowedBy spaceChar >> many1Till parser end + start *> notFollowedBy spaceChar *> many1Till parser end enclosedInlines :: (PandocMonad m, Show a, Show b) => MuseParser m a @@ -880,9 +861,9 @@ enclosedInlines start end = try $ inlineTag :: PandocMonad m => String -- ^ Tag name -> MuseParser m (F Inlines) -inlineTag tag = try $ do - openTag tag - mconcat <$> manyTill inline (closeTag tag) +inlineTag tag = try $ mconcat + <$ openTag tag + <*> manyTill inline (closeTag tag) -- | Parse strong inline markup, indicated by @**@. strong :: PandocMonad m => MuseParser m (F Inlines) @@ -933,9 +914,7 @@ classTag = do -- | Parse "~~" as nonbreaking space. nbsp :: PandocMonad m => MuseParser m (F Inlines) -nbsp = try $ do - string "~~" - return $ return $ B.str "\160" +nbsp = try $ pure (B.str "\160") <$ string "~~" -- | Parse code markup, indicated by @\'=\'@ characters. code :: PandocMonad m => MuseParser m (F Inlines) @@ -983,7 +962,9 @@ linkOrImage = try $ do return res linkContent :: PandocMonad m => MuseParser m (F Inlines) -linkContent = char '[' >> trimInlinesF . mconcat <$> manyTill inline (char ']') +linkContent = trimInlinesF . mconcat + <$ char '[' + <*> manyTill inline (char ']') -- | Parse a link starting with @URL:@ explicitLink :: PandocMonad m => MuseParser m (F Inlines) @@ -1016,12 +997,11 @@ image = try $ do ext <- imageExtension (width, align) <- option (Nothing, Nothing) imageAttrs return (ext, width, align) - imageAttrs = do - many1 spaceChar - width <- optionMaybe (many1 digit) - many spaceChar - align <- optionMaybe (oneOf "rlf") - return (width, align) + imageAttrs = (,) + <$ many1 spaceChar + <*> optionMaybe (many1 digit) + <* many spaceChar + <*> optionMaybe (oneOf "rlf") link :: PandocMonad m => MuseParser m (F Inlines) link = try $ do -- cgit v1.2.3 From f57a8aa655b5dc71c697db511a0155c684a1c754 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 21 Sep 2018 04:51:00 +0300 Subject: Muse reader: simplify tag parsers --- src/Text/Pandoc/Readers/Muse.hs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 9432ecc1c..6c7ab643f 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -422,17 +422,12 @@ exampleTag = try $ do -- | Parse a @\@ tag as a raw block. -- For 'RawInline' @\@ parser, see 'inlineLiteralTag'. literalTag :: PandocMonad m => MuseParser m (F Blocks) -literalTag = try $ do - many spaceChar - attr <- htmlAttrToPandoc <$> openTag "literal" - manyTill spaceChar eol - content <- manyTill anyChar $ closeTag "literal" - manyTill spaceChar eol - return $ return $ rawBlock (attr, content) - where - -- FIXME: Emacs Muse inserts without style into all output formats, but we assume HTML - format (_, _, kvs) = fromMaybe "html" $ lookup "style" kvs - rawBlock (attrs, content) = B.rawBlock (format attrs) $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content +literalTag = try $ fmap pure $ B.rawBlock + <$ many spaceChar + <*> (fromMaybe "html" . lookup "style" <$> openTag "literal") -- FIXME: Emacs Muse inserts without style into all output formats, but we assume HTML + <* manyTill spaceChar eol + <*> (rchop . intercalate "\n" . dropSpacePrefix . splitOn "\n" . lchop <$> manyTill anyChar (closeTag "literal")) + <* manyTill spaceChar eol -- | Parse @\
    @ tag. -- Currently it is ignored as Pandoc cannot represent centered blocks. @@ -938,12 +933,9 @@ mathTag = return . B.math . snd <$> htmlElement "math" -- | Parse inline @\@ tag as a raw inline. inlineLiteralTag :: PandocMonad m => MuseParser m (F Inlines) -inlineLiteralTag = - (return . rawInline) <$> htmlElement "literal" - where - -- FIXME: Emacs Muse inserts without style into all output formats, but we assume HTML - format (_, _, kvs) = fromMaybe "html" $ lookup "style" kvs - rawInline (attrs, content) = B.rawInline (format attrs) content +inlineLiteralTag = try $ fmap pure $ B.rawInline + <$> (fromMaybe "html" . lookup "style" <$> openTag "literal") -- FIXME: Emacs Muse inserts without style into all output formats, but we assume HTML + <*> manyTill anyChar (closeTag "literal") str :: PandocMonad m => MuseParser m (F Inlines) str = return . B.str <$> many1 alphaNum <* updateLastStrPos -- cgit v1.2.3 From b7b93d76097b55515d62b2c2e131cb439a41c0f0 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 20 Sep 2018 21:29:08 -0700 Subject: Fix compiler warning. --- src/Text/Pandoc/Writers/ConTeXt.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs index 4947d7f79..1f9760442 100644 --- a/src/Text/Pandoc/Writers/ConTeXt.hs +++ b/src/Text/Pandoc/Writers/ConTeXt.hs @@ -456,7 +456,7 @@ inlineToConTeXt (Image attr@(_,cls,_) _ (src, _)) = do -- Use / for path separators on Windows; see #4918 fixPathSeparators = map $ \c -> case c of '\\' -> '/' - c -> c + _ -> c src' = fixPathSeparators $ if isURI src then src -- cgit v1.2.3 From e26313dd62e1513a9bc2f75f2198a8dd8e9097ea Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 21 Sep 2018 11:50:51 +0300 Subject: Muse reader: refactoring --- src/Text/Pandoc/Readers/Muse.hs | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 6c7ab643f..ee93c6777 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -165,6 +165,9 @@ atStart p = do guard $ museLastStrPos st /= Just pos p +firstColumn :: PandocMonad m => MuseParser m () +firstColumn = getPosition >>= \pos -> guard (sourceColumn pos == 1) + -- * Parsers -- | Parse end-of-line, which can be either a newline or end-of-file. @@ -360,12 +363,11 @@ blockElements = do -- | Parse a line comment, starting with @;@ in the first column. comment :: PandocMonad m => MuseParser m (F Blocks) -comment = try $ do - getPosition >>= \pos -> guard (sourceColumn pos == 1) - char ';' - optional (spaceChar *> many (noneOf "\n")) - eol - return mempty +comment = try $ mempty + <$ firstColumn + <* char ';' + <* optional (spaceChar *> many (noneOf "\n")) + <* eol -- | Parse a horizontal rule, consisting of 4 or more @\'-\'@ characters. separator :: PandocMonad m => MuseParser m (F Blocks) @@ -378,7 +380,7 @@ separator = try $ pure B.horizontalRule headingStart :: PandocMonad m => MuseParser m (String, Int) headingStart = try $ do anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol) - getPosition >>= \pos -> guard (sourceColumn pos == 1) + firstColumn level <- fmap length $ many1 $ char '*' guard $ level <= 5 spaceChar @@ -801,10 +803,11 @@ endline :: PandocMonad m => MuseParser m (F Inlines) endline = try $ pure B.softbreak <$ newline <* notFollowedBy blankline parseAnchor :: PandocMonad m => MuseParser m String -parseAnchor = try $ do - getPosition >>= \pos -> guard (sourceColumn pos == 1) - char '#' - (:) <$> letter <*> many (letter <|> digit <|> char '-') +parseAnchor = try $ (:) + <$ firstColumn + <* char '#' + <*> letter + <*> many (letter <|> digit <|> char '-') anchor :: PandocMonad m => MuseParser m (F Inlines) anchor = try $ do @@ -849,8 +852,9 @@ enclosedInlines :: (PandocMonad m, Show a, Show b) => MuseParser m a -> MuseParser m b -> MuseParser m (F Inlines) -enclosedInlines start end = try $ - trimInlinesF . mconcat <$> (enclosed (atStart start) end inline <* notFollowedBy (satisfy ((||) <$> isLetter <*> isDigit))) +enclosedInlines start end = try $ trimInlinesF . mconcat + <$> enclosed (atStart start) end inline + <* notFollowedBy (satisfy ((||) <$> isLetter <*> isDigit)) -- | Parse an inline tag, such as @\@ and @\@. inlineTag :: PandocMonad m @@ -871,9 +875,9 @@ emph = fmap B.emph <$> emphasisBetween (char '*') -- | Parse underline inline markup, indicated by @_@. -- Supported only in Emacs Muse mode, not Text::Amuse. underlined :: PandocMonad m => MuseParser m (F Inlines) -underlined = do - guardDisabled Ext_amuse -- Supported only by Emacs Muse - fmap underlineSpan <$> emphasisBetween (char '_') +underlined = fmap underlineSpan + <$ guardDisabled Ext_amuse -- Supported only by Emacs Muse + <*> emphasisBetween (char '_') -- | Parse @\@ tag. strongTag :: PandocMonad m => MuseParser m (F Inlines) @@ -902,9 +906,8 @@ verbatimTag = return . B.text . snd <$> htmlElement "verbatim" -- | Parse @\@ tag. classTag :: PandocMonad m => MuseParser m (F Inlines) classTag = do - attrs <- openTag "class" + classes <- maybe [] words . lookup "name" <$> openTag "class" res <- manyTill inline $ closeTag "class" - let classes = maybe [] words $ lookup "name" attrs return $ B.spanWith ("", classes, []) <$> mconcat res -- | Parse "~~" as nonbreaking space. -- cgit v1.2.3 From 23725f3a20f488547aa4d2d2601d34c8e2b628bf Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 21 Sep 2018 12:26:29 +0300 Subject: Muse reader: rewrite headingStart in applicative style and remove heading level limit --- src/Text/Pandoc/Readers/Muse.hs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index ee93c6777..6cb732c42 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -378,13 +378,11 @@ separator = try $ pure B.horizontalRule <* eol headingStart :: PandocMonad m => MuseParser m (String, Int) -headingStart = try $ do - anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol) - firstColumn - level <- fmap length $ many1 $ char '*' - guard $ level <= 5 - spaceChar - return (anchorId, level) +headingStart = try $ (,) + <$> option "" (try (parseAnchor <* manyTill spaceChar eol)) + <* firstColumn + <*> fmap length (many1 $ char '*') + <* spaceChar -- | Parse a single-line heading. emacsHeading :: PandocMonad m => MuseParser m (F Blocks) -- cgit v1.2.3 From ca0bb5123e52b89b39033a54120626062e824ca5 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 21 Sep 2018 12:46:36 +0300 Subject: Muse reader: simplify ordered list parsing --- src/Text/Pandoc/Readers/Muse.hs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 6cb732c42..9c6c24f08 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -595,13 +595,6 @@ bulletListUntil end = try $ do (items, e) <- bulletListItemsUntil indent end return (B.bulletList <$> sequence items, e) --- | Parses an ordered list marker and returns list attributes. -anyMuseOrderedListMarker :: PandocMonad m => MuseParser m ListAttributes -anyMuseOrderedListMarker = do - (style, start) <- decimal <|> lowerRoman <|> upperRoman <|> lowerAlpha <|> upperAlpha - char '.' - return (start, style, Period) - museOrderedListMarker :: PandocMonad m => ListNumberStyle -> MuseParser m Int @@ -639,10 +632,10 @@ orderedListUntil end = try $ do pos <- getPosition let indent = sourceColumn pos - 1 guard $ indent /= 0 - p@(_, style, _) <- anyMuseOrderedListMarker - guard $ style `elem` [Decimal, LowerAlpha, UpperAlpha, LowerRoman, UpperRoman] - (items, e) <- orderedListItemsUntil indent style end - return (B.orderedListWith p <$> sequence items, e) + (style, start) <- decimal <|> lowerRoman <|> upperRoman <|> lowerAlpha <|> upperAlpha + char '.' + first (fmap (B.orderedListWith (start, style, Period)) . sequence) + <$> orderedListItemsUntil indent style end descriptionsUntil :: PandocMonad m => Int -- cgit v1.2.3 From dd5d234c6a0be60d313863b08c8d12bdb97fff8f Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 21 Sep 2018 13:07:56 +0300 Subject: Muse reader: do not allow code markup to be followed by digit --- src/Text/Pandoc/Readers/Muse.hs | 4 ++-- test/Tests/Readers/Muse.hs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 9c6c24f08..3f93fcc12 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -43,7 +43,7 @@ import Prelude import Control.Monad import Control.Monad.Except (throwError) import Data.Bifunctor -import Data.Char (isLetter, isDigit) +import Data.Char (isLetter, isDigit, isAlphaNum) import Data.Default import Data.List (intercalate) import Data.List.Split (splitOn) @@ -913,7 +913,7 @@ code = try $ do guard $ not $ null contents guard $ head contents `notElem` " \t\n" guard $ last contents `notElem` " \t\n" - notFollowedBy $ satisfy isLetter + notFollowedBy $ satisfy isAlphaNum return $ return $ B.code contents -- | Parse @\@ tag. diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs index e88cfa5f1..80540b697 100644 --- a/test/Tests/Readers/Muse.hs +++ b/test/Tests/Readers/Muse.hs @@ -150,6 +150,10 @@ tests = "Foo =bar=, baz" =?> para (text "Foo " <> code "bar" <> text ", baz") + , "Not code if followed by digit" =: + "Foo =bar=0 baz" =?> + para (text "Foo =bar=0 baz") + , "One character code" =: "=c=" =?> para (code "c") , "Three = characters is not a code" =: "===" =?> para "===" -- cgit v1.2.3 From 3067e57bd4462835a45b2505160d1ba9951b1267 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 21 Sep 2018 13:10:20 +0300 Subject: Muse reader: use isAlphaNum instead of isLetter and isDigit --- src/Text/Pandoc/Readers/Muse.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 3f93fcc12..8a065196f 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -43,7 +43,7 @@ import Prelude import Control.Monad import Control.Monad.Except (throwError) import Data.Bifunctor -import Data.Char (isLetter, isDigit, isAlphaNum) +import Data.Char (isAlphaNum) import Data.Default import Data.List (intercalate) import Data.List.Split (splitOn) @@ -845,7 +845,7 @@ enclosedInlines :: (PandocMonad m, Show a, Show b) -> MuseParser m (F Inlines) enclosedInlines start end = try $ trimInlinesF . mconcat <$> enclosed (atStart start) end inline - <* notFollowedBy (satisfy ((||) <$> isLetter <*> isDigit)) + <* notFollowedBy (satisfy isAlphaNum) -- | Parse an inline tag, such as @\@ and @\@. inlineTag :: PandocMonad m -- cgit v1.2.3 From 111e6ffa55e17b5e0399adac484a9510a80d3a3b Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 21 Sep 2018 13:54:52 +0300 Subject: Muse reader: simplify tag parsers --- src/Text/Pandoc/Readers/Muse.hs | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 8a065196f..e8e309115 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -195,20 +195,6 @@ openTag tag = try $ closeTag :: PandocMonad m => String -> MuseParser m () closeTag tag = try $ string " string tag *> void (char '>') --- | Parse HTML tag, returning its attributes and literal contents. -htmlElement :: PandocMonad m - => String -- ^ Tag name - -> MuseParser m (Attr, String) -htmlElement tag = try $ (,) - <$> (htmlAttrToPandoc <$> openTag tag) - <*> manyTill anyChar (closeTag tag) - -htmlBlock :: PandocMonad m - => String -- ^ Tag name - -> MuseParser m (Attr, String) -htmlBlock tag = try $ - many spaceChar *> htmlElement tag <* manyTill spaceChar eol - -- | Convert HTML attributes to Pandoc 'Attr' htmlAttrToPandoc :: [Attribute String] -> Attr htmlAttrToPandoc attrs = (ident, classes, keyvals) @@ -415,9 +401,11 @@ example = try $ pure . B.codeBlock -- | Parse an @\@ tag. exampleTag :: PandocMonad m => MuseParser m (F Blocks) -exampleTag = try $ do - (attr, contents) <- htmlBlock "example" - return $ return $ B.codeBlockWith attr $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop contents +exampleTag = try $ fmap pure $ B.codeBlockWith + <$ many spaceChar + <*> (htmlAttrToPandoc <$> openTag "example") + <*> (rchop . intercalate "\n" . dropSpacePrefix . splitOn "\n" . lchop <$> manyTill anyChar (closeTag "example")) + <* manyTill spaceChar eol -- | Parse a @\@ tag as a raw block. -- For 'RawInline' @\@ parser, see 'inlineLiteralTag'. @@ -484,7 +472,11 @@ verseTag = try $ do -- | Parse @\@ tag. commentTag :: PandocMonad m => MuseParser m (F Blocks) -commentTag = mempty <$ htmlBlock "comment" +commentTag = try $ mempty + <$ many spaceChar + <* openTag "comment" + <* manyTill anyChar (closeTag "comment") + <* manyTill spaceChar eol -- | Parse paragraph contents. paraContentsUntil :: PandocMonad m @@ -892,7 +884,9 @@ strikeoutTag = fmap B.strikeout <$> inlineTag "del" -- | Parse @\@ tag. verbatimTag :: PandocMonad m => MuseParser m (F Inlines) -verbatimTag = return . B.text . snd <$> htmlElement "verbatim" +verbatimTag = return . B.text + <$ openTag "verbatim" + <*> manyTill anyChar (closeTag "verbatim") -- | Parse @\@ tag. classTag :: PandocMonad m => MuseParser m (F Inlines) @@ -918,12 +912,16 @@ code = try $ do -- | Parse @\@ tag. codeTag :: PandocMonad m => MuseParser m (F Inlines) -codeTag = return . uncurry B.codeWith <$> htmlElement "code" +codeTag = fmap pure $ B.codeWith + <$> (htmlAttrToPandoc <$> openTag "code") + <*> manyTill anyChar (closeTag "code") -- | Parse @\@ tag. -- @\@ tag is an Emacs Muse extension enabled by @(require 'muse-latex2png)@ mathTag :: PandocMonad m => MuseParser m (F Inlines) -mathTag = return . B.math . snd <$> htmlElement "math" +mathTag = return . B.math + <$ openTag "math" + <*> manyTill anyChar (closeTag "math") -- | Parse inline @\@ tag as a raw inline. inlineLiteralTag :: PandocMonad m => MuseParser m (F Inlines) -- cgit v1.2.3 From 4bc2b7eb5b9e71eef141c3b5022fc3cd18560a80 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 22 Sep 2018 20:39:42 -0700 Subject: LaTeX writer: fix a use of `last` that might take empty list. If you ran with `--biblatex` and have an empty document (metadata but no blocks), pandoc would previously raise an error because of the use of `last` on an empty list. --- src/Text/Pandoc/Writers/LaTeX.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 3db643503..6042f2765 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -176,9 +176,9 @@ pandocToLaTeX options (Pandoc meta blocks) = do modify $ \s -> s{stCsquotes = True} let (blocks'', lastHeader) = if writerCiteMethod options == Citeproc then (blocks', []) - else case last blocks' of - Header 1 _ il -> (init blocks', il) - _ -> (blocks', []) + else case reverse blocks' of + Header 1 _ il : _ -> (init blocks', il) + _ -> (blocks', []) beamer <- gets stBeamer blocks''' <- if beamer then toSlides blocks'' -- cgit v1.2.3 From ce6e9e8817fa7c09625a3c587095bffc8a5eb598 Mon Sep 17 00:00:00 2001 From: Nils Carlson Date: Thu, 20 Sep 2018 21:30:32 +0000 Subject: ODT Writer: Improve table header row style handling This changes the way styles for cells in the header row and normal rows are handled in ODT tables. Previously a new (but identical) style was generated for every table, specifying the style of the cells within the table. After this change there are two style definitions for table cells, one for the cells in the header row, one for all other cells. This doesn't change the actual styles, but makes post-processing changes to the table styles much simpler as it is no longer necessary to introduce new styles for header rows and there are now only two styles where there was previously one per table. --- src/Text/Pandoc/Writers/OpenDocument.hs | 34 +++--- test/tables.opendocument | 184 ++++++++++++++++---------------- 2 files changed, 113 insertions(+), 105 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index d6ab73aa4..6f6f58ae6 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -403,8 +403,8 @@ blockToOpenDocument o bs else withParagraphStyle o "Table" [Para c] th <- if all null h then return empty - else colHeadsToOpenDocument o name (map fst paraHStyles) h - tr <- mapM (tableRowToOpenDocument o name (map fst paraStyles)) r + else colHeadsToOpenDocument o (map fst paraHStyles) h + tr <- mapM (tableRowToOpenDocument o (map fst paraStyles)) r return $ inTags True "table:table" [ ("table:name" , name) , ("table:style-name", name) ] (vcat columns $$ th $$ vcat tr) $$ captionDoc @@ -416,24 +416,24 @@ blockToOpenDocument o bs return $ imageDoc $$ captionDoc colHeadsToOpenDocument :: PandocMonad m - => WriterOptions -> String -> [String] -> [[Block]] + => WriterOptions -> [String] -> [[Block]] -> OD m Doc -colHeadsToOpenDocument o tn ns hs = +colHeadsToOpenDocument o ns hs = inTagsIndented "table:table-header-rows" . inTagsIndented "table:table-row" . vcat <$> - mapM (tableItemToOpenDocument o tn) (zip ns hs) + mapM (tableItemToOpenDocument o "TableHeaderRowCell") (zip ns hs) tableRowToOpenDocument :: PandocMonad m - => WriterOptions -> String -> [String] -> [[Block]] + => WriterOptions -> [String] -> [[Block]] -> OD m Doc -tableRowToOpenDocument o tn ns cs = +tableRowToOpenDocument o ns cs = inTagsIndented "table:table-row" . vcat <$> - mapM (tableItemToOpenDocument o tn) (zip ns cs) + mapM (tableItemToOpenDocument o "TableRowCell") (zip ns cs) tableItemToOpenDocument :: PandocMonad m => WriterOptions -> String -> (String,[Block]) -> OD m Doc -tableItemToOpenDocument o tn (n,i) = - let a = [ ("table:style-name" , tn ++ ".A1" ) +tableItemToOpenDocument o s (n,i) = + let a = [ ("table:style-name" , s ) , ("office:value-type", "string" ) ] in inTags True "table:table-cell" a <$> @@ -584,13 +584,21 @@ tableStyle num wcs = , ("style:family", "table-column" )] $ selfClosingTag "style:table-column-properties" [("style:rel-column-width", printf "%d*" (floor $ w * 65535 :: Integer))] - cellStyle = inTags True "style:style" - [ ("style:name" , tableId ++ ".A1") + headerRowCellStyle = inTags True "style:style" + [ ("style:name" , "TableHeaderRowCell") , ("style:family", "table-cell" )] $ selfClosingTag "style:table-cell-properties" [ ("fo:border", "none")] + rowCellStyle = inTags True "style:style" + [ ("style:name" , "TableRowCell") + , ("style:family", "table-cell" )] $ + selfClosingTag "style:table-cell-properties" + [ ("fo:border", "none")] + cellStyles = if num == 0 + then headerRowCellStyle $$ rowCellStyle + else empty columnStyles = map colStyle wcs - in table $$ vcat columnStyles $$ cellStyle + in cellStyles $$ table $$ vcat columnStyles paraStyle :: PandocMonad m => [(String,String)] -> OD m Int paraStyle attrs = do diff --git a/test/tables.opendocument b/test/tables.opendocument index c331ecc43..c04afd492 100644 --- a/test/tables.opendocument +++ b/test/tables.opendocument @@ -6,59 +6,59 @@ - + Right - + Left - + Center - + Default - + 12 - + 12 - + 12 - + 12 - + 123 - + 123 - + 123 - + 123 - + 1 - + 1 - + 1 - + 1 @@ -73,59 +73,59 @@ caption: - + Right - + Left - + Center - + Default - + 12 - + 12 - + 12 - + 12 - + 123 - + 123 - + 123 - + 123 - + 1 - + 1 - + 1 - + 1 @@ -139,59 +139,59 @@ spaces: - + Right - + Left - + Center - + Default - + 12 - + 12 - + 12 - + 12 - + 123 - + 123 - + 123 - + 123 - + 1 - + 1 - + 1 - + 1 @@ -206,46 +206,46 @@ caption: - + Centered Header - + Left Aligned - + Right Aligned - + Default aligned - + First - + row - + 12.0 - + Example of a row that spans multiple lines. - + Second - + row - + 5.0 - + Here’s another one. Note the blank line between rows. @@ -262,46 +262,46 @@ caption: - + Centered Header - + Left Aligned - + Right Aligned - + Default aligned - + First - + row - + 12.0 - + Example of a row that spans multiple lines. - + Second - + row - + 5.0 - + Here’s another one. Note the blank line between rows. @@ -315,44 +315,44 @@ headers: - + 12 - + 12 - + 12 - + 12 - + 123 - + 123 - + 123 - + 123 - + 1 - + 1 - + 1 - + 1 @@ -365,31 +365,31 @@ headers: - + First - + row - + 12.0 - + Example of a row that spans multiple lines. - + Second - + row - + 5.0 - + Here’s another one. Note the blank line between rows. -- cgit v1.2.3 From 6d16ea9c76799e1303dde6cea13406ea62c10439 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 24 Sep 2018 10:57:45 +0300 Subject: Muse reader: replace `optionMaybe` and `fromMaybe` with `option` --- src/Text/Pandoc/Readers/Muse.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index e8e309115..e5b0f5f33 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -963,7 +963,7 @@ image :: PandocMonad m => MuseParser m (F Inlines) image = try $ do string "[[" (url, (ext, width, align)) <- manyUntil (noneOf "]") (imageExtensionAndOptions <* char ']') - content <- optionMaybe linkContent + content <- option mempty linkContent char ']' let widthAttr = case align of Just 'f' -> [("width", fromMaybe "100" width ++ "%"), ("height", "75%")] @@ -973,7 +973,7 @@ image = try $ do Just 'l' -> ["align-left"] Just 'f' -> [] _ -> [] - return $ B.imageWith ("", alignClass, widthAttr) (url ++ ext) mempty <$> fromMaybe (return mempty) content + return $ B.imageWith ("", alignClass, widthAttr) (url ++ ext) mempty <$> content where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"] imageExtension = choice (try . string <$> imageExtensions) -- cgit v1.2.3 From cd610da8ccf3af925dd5d501902590a634c22b34 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 24 Sep 2018 14:37:54 +0300 Subject: Muse reader: replace inlineList with inline' --- src/Text/Pandoc/Readers/Muse.hs | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index e5b0f5f33..6475669ce 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -225,7 +225,7 @@ parseEmacsDirective :: PandocMonad m => MuseParser m (String, F Inlines) parseEmacsDirective = (,) <$> parseDirectiveKey <* spaceChar - <*> (trimInlinesF . mconcat <$> manyTill (choice inlineList) eol) + <*> (trimInlinesF . mconcat <$> manyTill inline' eol) parseAmuseDirective :: PandocMonad m => MuseParser m (String, F Inlines) parseAmuseDirective = (,) @@ -455,7 +455,7 @@ playTag = do verseLine :: PandocMonad m => MuseParser m (F Inlines) verseLine = do indent <- (B.str <$> many1 ('\160' <$ char ' ')) <|> pure mempty - rest <- manyTill (choice inlineList) newline + rest <- manyTill inline' newline return $ trimInlinesF $ mconcat (pure indent : rest) -- | Parse @\@ tag. @@ -546,7 +546,7 @@ lineVerseLine = try $ do string "> " indent <- many ('\160' <$ char ' ') let indentEl = if null indent then mempty else B.str indent - rest <- manyTill (choice inlineList) eol + rest <- manyTill inline' eol return $ trimInlinesF $ mconcat (pure indentEl : rest) blanklineVerseLine :: PandocMonad m => MuseParser m (F Inlines) @@ -648,7 +648,7 @@ definitionListItemsUntil indent end = where continuation = try $ do pos <- getPosition - term <- trimInlinesF . mconcat <$> manyTill (choice inlineList) (try $ string "::") + term <- trimInlinesF . mconcat <$> manyTill inline' (try $ string "::") (x, (xs, e)) <- descriptionsUntil (sourceColumn pos) (try (optional blankline *> indentWith indent *> continuation) <|> (([],) <$> end)) let xx = (,) <$> term <*> sequence x return (xx:xs, e) @@ -753,33 +753,33 @@ tableParseCaption = try $ fmap MuseCaption . trimInlinesF . mconcat -- ** Inline parsers -inlineList :: PandocMonad m => [MuseParser m (F Inlines)] -inlineList = [ whitespace - , br - , anchor - , footnote - , strong - , strongTag - , emph - , emphTag - , underlined - , superscriptTag - , subscriptTag - , strikeoutTag - , verbatimTag - , classTag - , nbsp - , linkOrImage - , code - , codeTag - , mathTag - , inlineLiteralTag - , str - , symbol - ] +inline' :: PandocMonad m => MuseParser m (F Inlines) +inline' = whitespace + <|> br + <|> anchor + <|> footnote + <|> strong + <|> strongTag + <|> emph + <|> emphTag + <|> underlined + <|> superscriptTag + <|> subscriptTag + <|> strikeoutTag + <|> verbatimTag + <|> classTag + <|> nbsp + <|> linkOrImage + <|> code + <|> codeTag + <|> mathTag + <|> inlineLiteralTag + <|> str + <|> symbol + "inline" inline :: PandocMonad m => MuseParser m (F Inlines) -inline = endline <|> choice inlineList "inline" +inline = endline <|> inline' -- | Parse a soft break. endline :: PandocMonad m => MuseParser m (F Inlines) -- cgit v1.2.3 From f15c8d1ab48bd1bb0b3911468ce87a10fb88ce24 Mon Sep 17 00:00:00 2001 From: Jonas Scholl Date: Mon, 24 Sep 2018 14:58:26 +0200 Subject: RTF writer: Fix build failure with ghc-8.6.1 caused by missing MonadFail instance. --- src/Text/Pandoc/Writers/RTF.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs index 3045c1c10..ed8dc9ae4 100644 --- a/src/Text/Pandoc/Writers/RTF.hs +++ b/src/Text/Pandoc/Writers/RTF.hs @@ -341,8 +341,10 @@ listItemToRTF :: PandocMonad m listItemToRTF alignment indent marker [] = return $ rtfCompact (indent + listIncrement) (negate listIncrement) alignment (marker ++ "\\tx" ++ show listIncrement ++ "\\tab ") -listItemToRTF alignment indent marker list = do - (first:rest) <- mapM (blockToRTF (indent + listIncrement) alignment) list +listItemToRTF alignment indent marker (listFirst:listRest) = do + let f = blockToRTF (indent + listIncrement) alignment + first <- f listFirst + rest <- mapM f listRest let listMarker = "\\fi" ++ show (negate listIncrement) ++ " " ++ marker ++ "\\tx" ++ show listIncrement ++ "\\tab" let insertListMarker ('\\':'f':'i':'-':d:xs) | isDigit d = -- cgit v1.2.3 From 56fe5b559e9dbda97840a45c9f3a0713e2913bb5 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Mon, 24 Sep 2018 20:11:00 +0200 Subject: Use hslua v1.0.0 --- pandoc.cabal | 6 +- src/Text/Pandoc/Lua.hs | 11 +- src/Text/Pandoc/Lua/Filter.hs | 27 ++--- src/Text/Pandoc/Lua/Init.hs | 13 ++- src/Text/Pandoc/Lua/Module/MediaBag.hs | 2 +- src/Text/Pandoc/Lua/Module/Pandoc.hs | 28 ++--- src/Text/Pandoc/Lua/Module/Utils.hs | 24 ++-- src/Text/Pandoc/Lua/Packages.hs | 32 ++---- src/Text/Pandoc/Lua/StackInstances.hs | 194 ++++++++++++++------------------- src/Text/Pandoc/Lua/Util.hs | 88 ++++++--------- src/Text/Pandoc/Writers/Custom.hs | 143 ++++++++++++------------ stack.lts9.yaml | 4 +- stack.yaml | 2 + test/Tests/Lua.hs | 10 +- 14 files changed, 266 insertions(+), 318 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index 591c1960c..1c27e0b97 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -372,8 +372,8 @@ library blaze-html >= 0.9 && < 0.10, blaze-markup >= 0.8 && < 0.9, vector >= 0.10 && < 0.13, - hslua >= 0.9.5 && < 0.9.6, - hslua-module-text >= 0.1.2 && < 0.2, + hslua >= 1.0 && < 1.1, + hslua-module-text >= 0.2 && < 0.3, binary >= 0.5 && < 0.10, SHA >= 1.6 && < 1.7, haddock-library >= 1.6 && < 1.7, @@ -615,7 +615,7 @@ test-suite test-pandoc time >= 1.5 && < 1.10, directory >= 1 && < 1.4, filepath >= 1.1 && < 1.5, - hslua >= 0.9.5 && < 0.9.6, + hslua >= 1.0 && < 1.1, process >= 1.2.3 && < 1.7, temporary >= 1.1 && < 1.4, Diff >= 0.2 && < 0.4, diff --git a/src/Text/Pandoc/Lua.hs b/src/Text/Pandoc/Lua.hs index be448cf48..c4e5791b6 100644 --- a/src/Text/Pandoc/Lua.hs +++ b/src/Text/Pandoc/Lua.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2017–2018 Albert Krewinkel @@ -16,6 +15,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} +{-# LANGUAGE NoImplicitPrelude #-} {- | Module : Text.Pandoc.Lua Copyright : Copyright © 2017–2018 Albert Krewinkel @@ -34,12 +34,11 @@ module Text.Pandoc.Lua import Prelude import Control.Monad ((>=>)) -import Foreign.Lua (Lua, LuaException (..)) +import Foreign.Lua (Lua) import Text.Pandoc.Class (PandocIO) import Text.Pandoc.Definition (Pandoc) import Text.Pandoc.Lua.Filter (LuaFilter, walkMWithLuaFilter) -import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath) -import Text.Pandoc.Lua.Util (popValue) +import Text.Pandoc.Lua.Init (LuaException (..), runPandocLua, registerScriptPath) import Text.Pandoc.Options (ReaderOptions) import qualified Foreign.Lua as Lua @@ -61,14 +60,14 @@ runLuaFilter' ropts filterPath format pd = do top <- Lua.gettop stat <- Lua.dofile filterPath if stat /= Lua.OK - then Lua.throwTopMessageAsError + then Lua.throwTopMessage else do newtop <- Lua.gettop -- Use the returned filters, or the implicitly defined global filter if -- nothing was returned. luaFilters <- if newtop - top >= 1 then Lua.peek Lua.stackTop - else Lua.getglobal "_G" *> fmap (:[]) popValue + else Lua.pushglobaltable *> fmap (:[]) Lua.popValue runAll luaFilters pd where registerFormat = do diff --git a/src/Text/Pandoc/Lua/Filter.hs b/src/Text/Pandoc/Lua/Filter.hs index 6cbb10c6b..9b5f5f40a 100644 --- a/src/Text/Pandoc/Lua/Filter.hs +++ b/src/Text/Pandoc/Lua/Filter.hs @@ -45,23 +45,22 @@ import Data.Data (Data, DataType, dataTypeConstrs, dataTypeName, dataTypeOf, showConstr, toConstr, tyconUQname) import Data.Foldable (foldrM) import Data.Map (Map) -import Foreign.Lua (Lua, FromLuaStack, ToLuaStack) +import Foreign.Lua (Lua, Peekable, Pushable) import Text.Pandoc.Definition import Text.Pandoc.Lua.StackInstances () -import Text.Pandoc.Lua.Util (typeCheck) import Text.Pandoc.Walk (walkM, Walkable) import qualified Data.Map.Strict as Map import qualified Foreign.Lua as Lua --- | Filter function stored at the given index in the registry -newtype LuaFilterFunction = LuaFilterFunction Int +-- | Filter function stored in the registry +newtype LuaFilterFunction = LuaFilterFunction Lua.Reference -- | Collection of filter functions (at most one function per element -- constructor) newtype LuaFilter = LuaFilter (Map String LuaFilterFunction) -instance FromLuaStack LuaFilter where +instance Peekable LuaFilter where peek idx = do let constrs = metaFilterName : pandocFilterNames @@ -87,10 +86,10 @@ registerFilterFunction = do -- | Retrieve filter function from registry and push it to the top of the stack. pushFilterFunction :: LuaFilterFunction -> Lua () pushFilterFunction (LuaFilterFunction fnRef) = - Lua.rawgeti Lua.registryindex fnRef + Lua.getref Lua.registryindex fnRef -elementOrList :: FromLuaStack a => a -> Lua [a] +elementOrList :: Peekable a => a -> Lua [a] elementOrList x = do let topOfStack = Lua.stackTop elementUnchanged <- Lua.isnil topOfStack @@ -100,12 +99,10 @@ elementOrList x = do mbres <- Lua.peekEither topOfStack case mbres of Right res -> [res] <$ Lua.pop 1 - Left _ -> do - typeCheck Lua.stackTop Lua.TypeTable - Lua.toList topOfStack `finally` Lua.pop 1 + Left _ -> Lua.peekList topOfStack `finally` Lua.pop 1 -- | Try running a filter for the given element -tryFilter :: (Data a, FromLuaStack a, ToLuaStack a) +tryFilter :: (Data a, Peekable a, Pushable a) => LuaFilter -> a -> Lua [a] tryFilter (LuaFilter fnMap) x = let filterFnName = showConstr (toConstr x) @@ -119,10 +116,10 @@ tryFilter (LuaFilter fnMap) x = -- called with given element as argument and is expected to return an element. -- Alternatively, the function can return nothing or nil, in which case the -- element is left unchanged. -runFilterFunction :: ToLuaStack a => LuaFilterFunction -> a -> Lua () +runFilterFunction :: Pushable a => LuaFilterFunction -> a -> Lua () runFilterFunction lf x = do let errorPrefix = "Error while running filter function:\n" - (`Lua.modifyLuaError` (errorPrefix <>)) $ do + Lua.withExceptionMessage (errorPrefix <>) $ do pushFilterFunction lf Lua.push x Lua.call 1 1 @@ -178,7 +175,7 @@ metaFilterName = "Meta" pandocFilterNames :: [String] pandocFilterNames = ["Pandoc", "Doc"] -singleElement :: FromLuaStack a => a -> Lua a +singleElement :: Peekable a => a -> Lua a singleElement x = do elementUnchanged <- Lua.isnil (-1) if elementUnchanged @@ -189,6 +186,6 @@ singleElement x = do Right res -> res <$ Lua.pop 1 Left err -> do Lua.pop 1 - Lua.throwLuaError $ + Lua.throwException $ "Error while trying to get a filter's return " ++ "value from lua stack.\n" ++ err diff --git a/src/Text/Pandoc/Lua/Init.hs b/src/Text/Pandoc/Lua/Init.hs index 15f90664e..35611d481 100644 --- a/src/Text/Pandoc/Lua/Init.hs +++ b/src/Text/Pandoc/Lua/Init.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2017-2018 Albert Krewinkel @@ -16,6 +15,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} +{-# LANGUAGE NoImplicitPrelude #-} {- | Module : Text.Pandoc.Lua Copyright : Copyright © 2017-2018 Albert Krewinkel @@ -40,7 +40,7 @@ import Control.Monad.Trans (MonadIO (..)) import Data.Data (Data, dataTypeConstrs, dataTypeOf, showConstr) import Data.IORef (newIORef, readIORef) import Data.Version (Version (versionBranch)) -import Foreign.Lua (Lua, LuaException (..)) +import Foreign.Lua (Lua) import GHC.IO.Encoding (getForeignEncoding, setForeignEncoding, utf8) import Paths_pandoc (version) import Text.Pandoc.Class (PandocIO, getCommonState, getUserDataDir, getMediaBag, @@ -54,17 +54,22 @@ import qualified Foreign.Lua as Lua import qualified Foreign.Lua.Module.Text as Lua import qualified Text.Pandoc.Definition as Pandoc +-- | Lua error message +newtype LuaException = LuaException String deriving (Show) + -- | Run the lua interpreter, using pandoc's default way of environment -- initialization. runPandocLua :: Lua a -> PandocIO (Either LuaException a) runPandocLua luaOp = do luaPkgParams <- luaPackageParams enc <- liftIO $ getForeignEncoding <* setForeignEncoding utf8 - res <- liftIO $ Lua.runLuaEither (initLuaState luaPkgParams *> luaOp) + res <- liftIO $ Lua.runEither (initLuaState luaPkgParams *> luaOp) liftIO $ setForeignEncoding enc newMediaBag <- liftIO (readIORef (luaPkgMediaBag luaPkgParams)) setMediaBag newMediaBag - return res + return $ case res of + Left (Lua.Exception msg) -> Left (LuaException msg) + Right x -> Right x -- | Generate parameters required to setup pandoc's lua environment. luaPackageParams :: PandocIO LuaPackageParams diff --git a/src/Text/Pandoc/Lua/Module/MediaBag.hs b/src/Text/Pandoc/Lua/Module/MediaBag.hs index f48fe56c5..150c06cc8 100644 --- a/src/Text/Pandoc/Lua/Module/MediaBag.hs +++ b/src/Text/Pandoc/Lua/Module/MediaBag.hs @@ -87,7 +87,7 @@ mediaDirectoryFn mbRef = do zipWithM_ addEntry [1..] dirContents return 1 where - addEntry :: Int -> (FilePath, MimeType, Int) -> Lua () + addEntry :: Lua.Integer -> (FilePath, MimeType, Int) -> Lua () addEntry idx (fp, mimeType, contentLength) = do Lua.newtable Lua.push "path" *> Lua.push fp *> Lua.rawset (-3) diff --git a/src/Text/Pandoc/Lua/Module/Pandoc.hs b/src/Text/Pandoc/Lua/Module/Pandoc.hs index ca337941f..769b04b9e 100644 --- a/src/Text/Pandoc/Lua/Module/Pandoc.hs +++ b/src/Text/Pandoc/Lua/Module/Pandoc.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2017-2018 Albert Krewinkel @@ -17,6 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NoImplicitPrelude #-} {- | Module : Text.Pandoc.Lua.Module.Pandoc Copyright : Copyright © 2017-2018 Albert Krewinkel @@ -36,13 +36,12 @@ import Control.Monad (when) import Data.Default (Default (..)) import Data.Maybe (fromMaybe) import Data.Text (pack) -import Foreign.Lua (ToLuaStack, FromLuaStack, Lua, NumResults, Optional, liftIO) +import Foreign.Lua (Lua, NumResults, Optional, Peekable, Pushable) import System.Exit (ExitCode (..)) import Text.Pandoc.Class (runIO) import Text.Pandoc.Definition (Block, Inline) import Text.Pandoc.Lua.Filter (walkInlines, walkBlocks, LuaFilter) import Text.Pandoc.Lua.StackInstances () -import Text.Pandoc.Lua.Util (addFunction, loadScriptFromDataDir) import Text.Pandoc.Walk (Walkable) import Text.Pandoc.Options (ReaderOptions (readerExtensions)) import Text.Pandoc.Process (pipeProcess) @@ -57,14 +56,14 @@ import qualified Text.Pandoc.Lua.Util as LuaUtil -- loaded. pushModule :: Maybe FilePath -> Lua NumResults pushModule datadir = do - loadScriptFromDataDir datadir "pandoc.lua" - addFunction "read" readDoc - addFunction "pipe" pipeFn - addFunction "walk_block" walkBlock - addFunction "walk_inline" walkInline + LuaUtil.loadScriptFromDataDir datadir "pandoc.lua" + LuaUtil.addFunction "read" readDoc + LuaUtil.addFunction "pipe" pipeFn + LuaUtil.addFunction "walk_block" walkBlock + LuaUtil.addFunction "walk_inline" walkInline return 1 -walkElement :: (ToLuaStack a, Walkable [Inline] a, Walkable [Block] a) +walkElement :: (Pushable a, Walkable [Inline] a, Walkable [Block] a) => a -> LuaFilter -> Lua a walkElement x f = walkInlines f x >>= walkBlocks f @@ -82,7 +81,8 @@ readDoc content formatSpecOrNil = do Right (reader, es) -> case reader of TextReader r -> do - res <- liftIO $ runIO $ r def{ readerExtensions = es } (pack content) + res <- Lua.liftIO . runIO $ + r def{ readerExtensions = es } (pack content) case res of Right pd -> (1 :: NumResults) <$ Lua.push pd -- success, push Pandoc Left s -> Lua.raiseError (show s) -- error while reading @@ -94,7 +94,7 @@ pipeFn :: String -> BL.ByteString -> Lua NumResults pipeFn command args input = do - (ec, output) <- liftIO $ pipeProcess Nothing command args input + (ec, output) <- Lua.liftIO $ pipeProcess Nothing command args input case ec of ExitSuccess -> 1 <$ Lua.push output ExitFailure n -> Lua.raiseError (PipeError command n output) @@ -105,14 +105,14 @@ data PipeError = PipeError , pipeErrorOutput :: BL.ByteString } -instance FromLuaStack PipeError where +instance Peekable PipeError where peek idx = PipeError <$> (Lua.getfield idx "command" *> Lua.peek (-1) <* Lua.pop 1) <*> (Lua.getfield idx "error_code" *> Lua.peek (-1) <* Lua.pop 1) <*> (Lua.getfield idx "output" *> Lua.peek (-1) <* Lua.pop 1) -instance ToLuaStack PipeError where +instance Pushable PipeError where push pipeErr = do Lua.newtable LuaUtil.addField "command" (pipeErrorCommand pipeErr) @@ -124,7 +124,7 @@ instance ToLuaStack PipeError where pushPipeErrorMetaTable :: Lua () pushPipeErrorMetaTable = do v <- Lua.newmetatable "pandoc pipe error" - when v $ addFunction "__tostring" pipeErrorMessage + when v $ LuaUtil.addFunction "__tostring" pipeErrorMessage pipeErrorMessage :: PipeError -> Lua BL.ByteString pipeErrorMessage (PipeError cmd errorCode output) = return $ mconcat diff --git a/src/Text/Pandoc/Lua/Module/Utils.hs b/src/Text/Pandoc/Lua/Module/Utils.hs index 7016c7ebd..030d6af95 100644 --- a/src/Text/Pandoc/Lua/Module/Utils.hs +++ b/src/Text/Pandoc/Lua/Module/Utils.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2017-2018 Albert Krewinkel @@ -16,6 +15,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} +{-# LANGUAGE NoImplicitPrelude #-} {- | Module : Text.Pandoc.Lua.Module.Utils Copyright : Copyright © 2017-2018 Albert Krewinkel @@ -33,11 +33,11 @@ module Text.Pandoc.Lua.Module.Utils import Prelude import Control.Applicative ((<|>)) import Data.Default (def) -import Foreign.Lua (FromLuaStack, Lua, LuaInteger, NumResults) +import Foreign.Lua (Peekable, Lua, NumResults) import Text.Pandoc.Class (runIO, setUserDataDir) import Text.Pandoc.Definition (Pandoc, Meta, MetaValue, Block, Inline) import Text.Pandoc.Lua.StackInstances () -import Text.Pandoc.Lua.Util (addFunction, popValue) +import Text.Pandoc.Lua.Util (addFunction) import qualified Data.Digest.Pure.SHA as SHA import qualified Data.ByteString.Lazy as BSL @@ -89,7 +89,7 @@ runJSONFilter mbDatadir doc filterFile optArgs = do Just x -> return x Nothing -> do Lua.getglobal "FORMAT" - (:[]) <$> popValue + (:[]) <$> Lua.popValue filterRes <- Lua.liftIO . runIO $ do setUserDataDir mbDatadir JSONFilter.apply def args filterFile doc @@ -121,18 +121,18 @@ data AstElement | MetaValueElement MetaValue deriving (Show) -instance FromLuaStack AstElement where +instance Peekable AstElement where peek idx = do - res <- Lua.tryLua $ (PandocElement <$> Lua.peek idx) - <|> (InlineElement <$> Lua.peek idx) - <|> (BlockElement <$> Lua.peek idx) - <|> (MetaElement <$> Lua.peek idx) - <|> (MetaValueElement <$> Lua.peek idx) + res <- Lua.try $ (PandocElement <$> Lua.peek idx) + <|> (InlineElement <$> Lua.peek idx) + <|> (BlockElement <$> Lua.peek idx) + <|> (MetaElement <$> Lua.peek idx) + <|> (MetaValueElement <$> Lua.peek idx) case res of Right x -> return x - Left _ -> Lua.throwLuaError + Left _ -> Lua.throwException "Expected an AST element, but could not parse value as such." -- | Convert a number < 4000 to uppercase roman numeral. -toRomanNumeral :: LuaInteger -> Lua String +toRomanNumeral :: Lua.Integer -> Lua String toRomanNumeral = return . Shared.toRomanNumeral . fromIntegral diff --git a/src/Text/Pandoc/Lua/Packages.hs b/src/Text/Pandoc/Lua/Packages.hs index 59637826e..5cf11f5c5 100644 --- a/src/Text/Pandoc/Lua/Packages.hs +++ b/src/Text/Pandoc/Lua/Packages.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2017-2018 Albert Krewinkel @@ -16,8 +15,9 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE ScopedTypeVariables #-} {- | Module : Text.Pandoc.Lua.Packages Copyright : Copyright © 2017-2018 Albert Krewinkel @@ -35,12 +35,11 @@ module Text.Pandoc.Lua.Packages import Prelude import Control.Monad (forM_) -import Data.ByteString.Char8 (unpack) +import Data.ByteString (ByteString) import Data.IORef (IORef) import Foreign.Lua (Lua, NumResults, liftIO) import Text.Pandoc.Class (CommonState, readDataFile, runIO, setUserDataDir) import Text.Pandoc.MediaBag (MediaBag) -import Text.Pandoc.Lua.Util (dostring') import qualified Foreign.Lua as Lua import Text.Pandoc.Lua.Module.Pandoc as Pandoc @@ -57,14 +56,10 @@ data LuaPackageParams = LuaPackageParams -- | Insert pandoc's package loader as the first loader, making it the default. installPandocPackageSearcher :: LuaPackageParams -> Lua () installPandocPackageSearcher luaPkgParams = do - luaVersion <- Lua.getglobal "_VERSION" *> Lua.peek (-1) - if luaVersion == "Lua 5.1" - then Lua.getglobal' "package.loaders" - else Lua.getglobal' "package.searchers" + Lua.getglobal' "package.searchers" shiftArray Lua.pushHaskellFunction (pandocPackageSearcher luaPkgParams) - Lua.wrapHaskellFunction - Lua.rawseti (-2) 1 + Lua.rawseti (Lua.nthFromTop 2) 1 Lua.pop 1 -- remove 'package.searchers' from stack where shiftArray = forM_ [4, 3, 2, 1] $ \i -> do @@ -86,7 +81,6 @@ pandocPackageSearcher luaPkgParams pkgName = where pushWrappedHsFun f = do Lua.pushHaskellFunction f - Lua.wrapHaskellFunction return 1 searchPureLuaLoader = do let filename = pkgName ++ ".lua" @@ -97,21 +91,19 @@ pandocPackageSearcher luaPkgParams pkgName = Lua.push ("no file '" ++ filename ++ "' in pandoc's datadir") return 1 -loadStringAsPackage :: String -> String -> Lua NumResults +loadStringAsPackage :: String -> ByteString -> Lua NumResults loadStringAsPackage pkgName script = do - status <- dostring' script + status <- Lua.dostring script if status == Lua.OK then return (1 :: NumResults) else do - msg <- Lua.peek (-1) <* Lua.pop 1 - Lua.push ("Error while loading ``" ++ pkgName ++ "`.\n" ++ msg) - Lua.lerror - return (2 :: NumResults) + msg <- Lua.popValue + Lua.raiseError ("Error while loading `" <> pkgName <> "`.\n" <> msg) --- | Get the string representation of the pandoc module -dataDirScript :: Maybe FilePath -> FilePath -> IO (Maybe String) +-- | Get the ByteString representation of the pandoc module. +dataDirScript :: Maybe FilePath -> FilePath -> IO (Maybe ByteString) dataDirScript datadir moduleFile = do res <- runIO $ setUserDataDir datadir >> readDataFile moduleFile return $ case res of Left _ -> Nothing - Right s -> Just (unpack s) + Right s -> Just s diff --git a/src/Text/Pandoc/Lua/StackInstances.hs b/src/Text/Pandoc/Lua/StackInstances.hs index 9c3b40f12..220dfccfa 100644 --- a/src/Text/Pandoc/Lua/StackInstances.hs +++ b/src/Text/Pandoc/Lua/StackInstances.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2012-2018 John MacFarlane 2017-2018 Albert Krewinkel @@ -19,6 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {- | @@ -37,67 +37,59 @@ module Text.Pandoc.Lua.StackInstances () where import Prelude import Control.Applicative ((<|>)) import Control.Monad (when) -import Control.Monad.Catch (finally) import Data.Data (showConstr, toConstr) -import Data.Foldable (forM_) -import Foreign.Lua (FromLuaStack (peek), Lua, LuaInteger, LuaNumber, StackIndex, - ToLuaStack (push), Type (..), throwLuaError, tryLua) +import Foreign.Lua (Lua, Peekable, Pushable, StackIndex) import Text.Pandoc.Definition import Text.Pandoc.Extensions (Extensions) -import Text.Pandoc.Lua.Util (pushViaConstructor, typeCheck) +import Text.Pandoc.Lua.Util (defineHowTo, pushViaConstructor) import Text.Pandoc.Options (ReaderOptions (..), TrackChanges) -import Text.Pandoc.Shared (Element (Blk, Sec), safeRead) +import Text.Pandoc.Shared (Element (Blk, Sec)) -import qualified Foreign.Lua as Lua import qualified Data.Set as Set +import qualified Foreign.Lua as Lua import qualified Text.Pandoc.Lua.Util as LuaUtil -defineHowTo :: String -> Lua a -> Lua a -defineHowTo ctx op = op `Lua.modifyLuaError` (("Could not " ++ ctx ++ ": ") ++) - -instance ToLuaStack Pandoc where +instance Pushable Pandoc where push (Pandoc meta blocks) = pushViaConstructor "Pandoc" blocks meta -instance FromLuaStack Pandoc where +instance Peekable Pandoc where peek idx = defineHowTo "get Pandoc value" $ do - typeCheck idx Lua.TypeTable blocks <- LuaUtil.rawField idx "blocks" - meta <- Lua.getfield idx "meta" *> (Lua.peek Lua.stackTop `finally` Lua.pop 1) + meta <- LuaUtil.rawField idx "meta" return $ Pandoc meta blocks -instance ToLuaStack Meta where +instance Pushable Meta where push (Meta mmap) = pushViaConstructor "Meta" mmap -instance FromLuaStack Meta where - peek idx = defineHowTo "get Meta value" $ do - typeCheck idx Lua.TypeTable - Meta <$> peek idx +instance Peekable Meta where + peek idx = defineHowTo "get Meta value" $ + Meta <$> Lua.peek idx -instance ToLuaStack MetaValue where +instance Pushable MetaValue where push = pushMetaValue -instance FromLuaStack MetaValue where +instance Peekable MetaValue where peek = peekMetaValue -instance ToLuaStack Block where +instance Pushable Block where push = pushBlock -instance FromLuaStack Block where +instance Peekable Block where peek = peekBlock -- Inline -instance ToLuaStack Inline where +instance Pushable Inline where push = pushInline -instance FromLuaStack Inline where +instance Peekable Inline where peek = peekInline -- Citation -instance ToLuaStack Citation where +instance Pushable Citation where push (Citation cid prefix suffix mode noteNum hash) = pushViaConstructor "Citation" cid mode prefix suffix noteNum hash -instance FromLuaStack Citation where +instance Peekable Citation where peek idx = do id' <- LuaUtil.rawField idx "id" prefix <- LuaUtil.rawField idx "prefix" @@ -107,78 +99,63 @@ instance FromLuaStack Citation where hash <- LuaUtil.rawField idx "hash" return $ Citation id' prefix suffix mode num hash -instance ToLuaStack Alignment where - push = push . show -instance FromLuaStack Alignment where - peek idx = safeRead' =<< peek idx - -instance ToLuaStack CitationMode where - push = push . show -instance FromLuaStack CitationMode where - peek idx = safeRead' =<< peek idx - -instance ToLuaStack Format where - push (Format f) = push f -instance FromLuaStack Format where - peek idx = Format <$> peek idx - -instance ToLuaStack ListNumberDelim where - push = push . show -instance FromLuaStack ListNumberDelim where - peek idx = safeRead' =<< peek idx - -instance ToLuaStack ListNumberStyle where - push = push . show -instance FromLuaStack ListNumberStyle where - peek idx = safeRead' =<< peek idx - -instance ToLuaStack MathType where - push = push . show -instance FromLuaStack MathType where - peek idx = safeRead' =<< peek idx - -instance ToLuaStack QuoteType where - push = push . show -instance FromLuaStack QuoteType where - peek idx = safeRead' =<< peek idx - -instance ToLuaStack Double where - push = push . (realToFrac :: Double -> LuaNumber) -instance FromLuaStack Double where - peek = fmap (realToFrac :: LuaNumber -> Double) . peek - -instance ToLuaStack Int where - push = push . (fromIntegral :: Int -> LuaInteger) -instance FromLuaStack Int where - peek = fmap (fromIntegral :: LuaInteger-> Int) . peek - -safeRead' :: Read a => String -> Lua a -safeRead' s = case safeRead s of - Nothing -> throwLuaError ("Could not read: " ++ s) - Just x -> return x +instance Pushable Alignment where + push = Lua.push . show +instance Peekable Alignment where + peek = Lua.peekRead + +instance Pushable CitationMode where + push = Lua.push . show +instance Peekable CitationMode where + peek = Lua.peekRead + +instance Pushable Format where + push (Format f) = Lua.push f +instance Peekable Format where + peek idx = Format <$> Lua.peek idx + +instance Pushable ListNumberDelim where + push = Lua.push . show +instance Peekable ListNumberDelim where + peek = Lua.peekRead + +instance Pushable ListNumberStyle where + push = Lua.push . show +instance Peekable ListNumberStyle where + peek = Lua.peekRead + +instance Pushable MathType where + push = Lua.push . show +instance Peekable MathType where + peek = Lua.peekRead + +instance Pushable QuoteType where + push = Lua.push . show +instance Peekable QuoteType where + peek = Lua.peekRead -- | Push an meta value element to the top of the lua stack. pushMetaValue :: MetaValue -> Lua () pushMetaValue = \case MetaBlocks blcks -> pushViaConstructor "MetaBlocks" blcks - MetaBool bool -> push bool + MetaBool bool -> Lua.push bool MetaInlines inlns -> pushViaConstructor "MetaInlines" inlns MetaList metalist -> pushViaConstructor "MetaList" metalist MetaMap metamap -> pushViaConstructor "MetaMap" metamap - MetaString str -> push str + MetaString str -> Lua.push str -- | Interpret the value at the given stack index as meta value. peekMetaValue :: StackIndex -> Lua MetaValue peekMetaValue idx = defineHowTo "get MetaValue" $ do -- Get the contents of an AST element. - let elementContent :: FromLuaStack a => Lua a - elementContent = peek idx + let elementContent :: Peekable a => Lua a + elementContent = Lua.peek idx luatype <- Lua.ltype idx case luatype of - TypeBoolean -> MetaBool <$> peek idx - TypeString -> MetaString <$> peek idx - TypeTable -> do - tag <- tryLua $ LuaUtil.getTag idx + Lua.TypeBoolean -> MetaBool <$> Lua.peek idx + Lua.TypeString -> MetaString <$> Lua.peek idx + Lua.TypeTable -> do + tag <- Lua.try $ LuaUtil.getTag idx case tag of Right "MetaBlocks" -> MetaBlocks <$> elementContent Right "MetaBool" -> MetaBool <$> elementContent @@ -186,16 +163,16 @@ peekMetaValue idx = defineHowTo "get MetaValue" $ do Right "MetaInlines" -> MetaInlines <$> elementContent Right "MetaList" -> MetaList <$> elementContent Right "MetaString" -> MetaString <$> elementContent - Right t -> throwLuaError ("Unknown meta tag: " ++ t) + Right t -> Lua.throwException ("Unknown meta tag: " <> t) Left _ -> do -- no meta value tag given, try to guess. len <- Lua.rawlen idx if len <= 0 - then MetaMap <$> peek idx - else (MetaInlines <$> peek idx) - <|> (MetaBlocks <$> peek idx) - <|> (MetaList <$> peek idx) - _ -> throwLuaError "could not get meta value" + then MetaMap <$> Lua.peek idx + else (MetaInlines <$> Lua.peek idx) + <|> (MetaBlocks <$> Lua.peek idx) + <|> (MetaList <$> Lua.peek idx) + _ -> Lua.throwException "could not get meta value" -- | Push an block element to the top of the lua stack. pushBlock :: Block -> Lua () @@ -219,7 +196,6 @@ pushBlock = \case -- | Return the value at the given index as block if possible. peekBlock :: StackIndex -> Lua Block peekBlock idx = defineHowTo "get Block value" $ do - typeCheck idx Lua.TypeTable tag <- LuaUtil.getTag idx case tag of "BlockQuote" -> BlockQuote <$> elementContent @@ -239,10 +215,10 @@ peekBlock idx = defineHowTo "get Block value" $ do "Table" -> (\(capt, aligns, widths, headers, body) -> Table capt aligns widths headers body) <$> elementContent - _ -> throwLuaError ("Unknown block type: " ++ tag) + _ -> Lua.throwException ("Unknown block type: " <> tag) where -- Get the contents of an AST element. - elementContent :: FromLuaStack a => Lua a + elementContent :: Peekable a => Lua a elementContent = LuaUtil.rawField idx "c" -- | Push an inline element to the top of the lua stack. @@ -271,7 +247,6 @@ pushInline = \case -- | Return the value at the given index as inline if possible. peekInline :: StackIndex -> Lua Inline peekInline idx = defineHowTo "get Inline value" $ do - typeCheck idx Lua.TypeTable tag <- LuaUtil.getTag idx case tag of "Cite" -> uncurry Cite <$> elementContent @@ -295,10 +270,10 @@ peekInline idx = defineHowTo "get Inline value" $ do "Strong" -> Strong <$> elementContent "Subscript" -> Subscript <$> elementContent "Superscript"-> Superscript <$> elementContent - _ -> throwLuaError ("Unknown inline type: " ++ tag) + _ -> Lua.throwException ("Unknown inline type: " <> tag) where -- Get the contents of an AST element. - elementContent :: FromLuaStack a => Lua a + elementContent :: Peekable a => Lua a elementContent = LuaUtil.rawField idx "c" withAttr :: (Attr -> a -> b) -> (LuaAttr, a) -> b @@ -307,18 +282,18 @@ withAttr f (attributes, x) = f (fromLuaAttr attributes) x -- | Wrapper for Attr newtype LuaAttr = LuaAttr { fromLuaAttr :: Attr } -instance ToLuaStack LuaAttr where +instance Pushable LuaAttr where push (LuaAttr (id', classes, kv)) = pushViaConstructor "Attr" id' classes kv -instance FromLuaStack LuaAttr where - peek idx = defineHowTo "get Attr value" (LuaAttr <$> peek idx) +instance Peekable LuaAttr where + peek idx = defineHowTo "get Attr value" (LuaAttr <$> Lua.peek idx) -- -- Hierarchical elements -- -instance ToLuaStack Element where - push (Blk blk) = push blk +instance Pushable Element where + push (Blk blk) = Lua.push blk push (Sec lvl num attr label contents) = do Lua.newtable LuaUtil.addField "level" lvl @@ -342,18 +317,13 @@ instance ToLuaStack Element where -- -- Reader Options -- -instance ToLuaStack Extensions where - push exts = push (show exts) +instance Pushable Extensions where + push exts = Lua.push (show exts) -instance ToLuaStack TrackChanges where - push = push . showConstr . toConstr - -instance ToLuaStack a => ToLuaStack (Set.Set a) where - push set = do - Lua.newtable - forM_ set (`LuaUtil.addValue` True) +instance Pushable TrackChanges where + push = Lua.push . showConstr . toConstr -instance ToLuaStack ReaderOptions where +instance Pushable ReaderOptions where push ro = do let ReaderOptions (extensions :: Extensions) diff --git a/src/Text/Pandoc/Lua/Util.hs b/src/Text/Pandoc/Lua/Util.hs index c12884a10..46e11da24 100644 --- a/src/Text/Pandoc/Lua/Util.hs +++ b/src/Text/Pandoc/Lua/Util.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2012-2018 John MacFarlane 2017-2018 Albert Krewinkel @@ -18,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE NoImplicitPrelude #-} {- | Module : Text.Pandoc.Lua.Util Copyright : © 2012–2018 John MacFarlane, @@ -35,39 +36,35 @@ module Text.Pandoc.Lua.Util , addField , addFunction , addValue - , typeCheck - , popValue - , PushViaCall - , pushViaCall , pushViaConstructor , loadScriptFromDataDir - , dostring' + , defineHowTo + , throwTopMessageAsError' ) where import Prelude -import Control.Monad (when) -import Control.Monad.Catch (finally) -import Data.ByteString.Char8 (unpack) -import Foreign.Lua (FromLuaStack, Lua, NumArgs, StackIndex, Status, - ToLuaStack, ToHaskellFunction) +import Control.Monad (unless, when) +import Foreign.Lua ( Lua, NumArgs, Peekable, Pushable, StackIndex + , ToHaskellFunction ) import Text.Pandoc.Class (readDataFile, runIOorExplode, setUserDataDir) import qualified Foreign.Lua as Lua +import qualified Text.Pandoc.UTF8 as UTF8 -- | Get value behind key from table at given index. -rawField :: FromLuaStack a => StackIndex -> String -> Lua a +rawField :: Peekable a => StackIndex -> String -> Lua a rawField idx key = do absidx <- Lua.absindex idx Lua.push key Lua.rawget absidx - popValue + Lua.popValue -- | Add a value to the table at the top of the stack at a string-index. -addField :: ToLuaStack a => String -> a -> Lua () +addField :: Pushable a => String -> a -> Lua () addField = addValue -- | Add a key-value pair to the table at the top of the stack. -addValue :: (ToLuaStack a, ToLuaStack b) => a -> b -> Lua () +addValue :: (Pushable a, Pushable b) => a -> b -> Lua () addValue key value = do Lua.push key Lua.push value @@ -78,26 +75,8 @@ addFunction :: ToHaskellFunction a => String -> a -> Lua () addFunction name fn = do Lua.push name Lua.pushHaskellFunction fn - Lua.wrapHaskellFunction Lua.rawset (-3) -typeCheck :: StackIndex -> Lua.Type -> Lua () -typeCheck idx expected = do - actual <- Lua.ltype idx - when (actual /= expected) $ do - expName <- Lua.typename expected - actName <- Lua.typename actual - Lua.throwLuaError $ "expected " ++ expName ++ " but got " ++ actName ++ "." - --- | Get, then pop the value at the top of the stack. -popValue :: FromLuaStack a => Lua a -popValue = do - resOrError <- Lua.peekEither (-1) - Lua.pop 1 - case resOrError of - Left err -> Lua.throwLuaError err - Right x -> return x - -- | Helper class for pushing a single value to the stack via a lua function. -- See @pushViaCall@. class PushViaCall a where @@ -110,7 +89,7 @@ instance PushViaCall (Lua ()) where pushArgs Lua.call num 1 -instance (ToLuaStack a, PushViaCall b) => PushViaCall (a -> b) where +instance (Pushable a, PushViaCall b) => PushViaCall (a -> b) where pushViaCall' fn pushArgs num x = pushViaCall' fn (pushArgs *> Lua.push x) (num + 1) @@ -127,26 +106,11 @@ pushViaConstructor pandocFn = pushViaCall ("pandoc." ++ pandocFn) -- | Load a file from pandoc's data directory. loadScriptFromDataDir :: Maybe FilePath -> FilePath -> Lua () loadScriptFromDataDir datadir scriptFile = do - script <- fmap unpack . Lua.liftIO . runIOorExplode $ + script <- Lua.liftIO . runIOorExplode $ setUserDataDir datadir >> readDataFile scriptFile - status <- dostring' script - when (status /= Lua.OK) . - Lua.throwTopMessageAsError' $ \msg -> - "Couldn't load '" ++ scriptFile ++ "'.\n" ++ msg - --- | Load a string and immediately perform a full garbage collection. This is --- important to keep the program from hanging: If the program containes a call --- to @require@, then a new loader function is created which then becomes --- garbage. If that function is collected at an inopportune time, i.e. when the --- Lua API is called via a function that doesn't allow calling back into Haskell --- (getraw, setraw, …), then the function's finalizer, and the full program, --- will hang. -dostring' :: String -> Lua Status -dostring' script = do - loadRes <- Lua.loadstring script - if loadRes == Lua.OK - then Lua.pcall 0 1 Nothing <* Lua.gc Lua.GCCOLLECT 0 - else return loadRes + status <- Lua.dostring script + when (status /= Lua.OK) $ + throwTopMessageAsError' (("Couldn't load '" ++ scriptFile ++ "'.\n") ++) -- | Get the tag of a value. This is an optimized and specialized version of -- @Lua.getfield idx "tag"@. It only checks for the field on the table at index @@ -155,7 +119,21 @@ dostring' script = do getTag :: StackIndex -> Lua String getTag idx = do -- push metatable or just the table - Lua.getmetatable idx >>= \hasMT -> when (not hasMT) (Lua.pushvalue idx) + Lua.getmetatable idx >>= \hasMT -> unless hasMT (Lua.pushvalue idx) Lua.push "tag" Lua.rawget (Lua.nthFromTop 2) - Lua.peek Lua.stackTop `finally` Lua.pop 2 + Lua.tostring Lua.stackTop <* Lua.pop 2 >>= \case + Nothing -> Lua.throwException "untagged value" + Just x -> return (UTF8.toString x) + +-- | Modify the message at the top of the stack before throwing it as an +-- Exception. +throwTopMessageAsError' :: (String -> String) -> Lua a +throwTopMessageAsError' modifier = do + msg <- Lua.tostring' Lua.stackTop + Lua.pop 2 -- remove error and error string pushed by tostring' + Lua.throwException (modifier (UTF8.toString msg)) + + +defineHowTo :: String -> Lua a -> Lua a +defineHowTo ctx = Lua.withExceptionMessage (("Could not " <> ctx <> ": ") <>) diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs index 866df85be..1d1261baf 100644 --- a/src/Text/Pandoc/Writers/Custom.hs +++ b/src/Text/Pandoc/Writers/Custom.hs @@ -1,6 +1,6 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE DeriveDataTypeable #-} -{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE NoImplicitPrelude #-} {- Copyright (C) 2012-2018 John MacFarlane This program is free software; you can redistribute it and/or modify @@ -35,25 +35,26 @@ import Prelude import Control.Arrow ((***)) import Control.Exception import Control.Monad (when) -import Control.Monad.Trans (MonadIO (liftIO)) import Data.Char (toLower) import Data.List (intersperse) import qualified Data.Map as M import Data.Text (Text, pack) import Data.Typeable -import Foreign.Lua (Lua, ToLuaStack (..), callFunc) -import Foreign.Lua.Api +import Foreign.Lua (Lua, Pushable) import Text.Pandoc.Class (PandocIO) import Text.Pandoc.Definition import Text.Pandoc.Error -import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath) +import Text.Pandoc.Lua.Init (LuaException (LuaException), runPandocLua, + registerScriptPath) import Text.Pandoc.Lua.StackInstances () -import Text.Pandoc.Lua.Util (addField, addValue, dostring') +import Text.Pandoc.Lua.Util (addField) import Text.Pandoc.Options import Text.Pandoc.Templates import qualified Text.Pandoc.UTF8 as UTF8 import Text.Pandoc.Writers.Shared +import qualified Foreign.Lua as Lua + attrToMap :: Attr -> M.Map String String attrToMap (id',classes,keyvals) = M.fromList $ ("id", id') @@ -62,26 +63,26 @@ attrToMap (id',classes,keyvals) = M.fromList newtype Stringify a = Stringify a -instance ToLuaStack (Stringify Format) where - push (Stringify (Format f)) = push (map toLower f) +instance Pushable (Stringify Format) where + push (Stringify (Format f)) = Lua.push (map toLower f) -instance ToLuaStack (Stringify [Inline]) where - push (Stringify ils) = push =<< inlineListToCustom ils +instance Pushable (Stringify [Inline]) where + push (Stringify ils) = Lua.push =<< inlineListToCustom ils -instance ToLuaStack (Stringify [Block]) where - push (Stringify blks) = push =<< blockListToCustom blks +instance Pushable (Stringify [Block]) where + push (Stringify blks) = Lua.push =<< blockListToCustom blks -instance ToLuaStack (Stringify MetaValue) where - push (Stringify (MetaMap m)) = push (fmap Stringify m) - push (Stringify (MetaList xs)) = push (map Stringify xs) - push (Stringify (MetaBool x)) = push x - push (Stringify (MetaString s)) = push s - push (Stringify (MetaInlines ils)) = push (Stringify ils) - push (Stringify (MetaBlocks bs)) = push (Stringify bs) +instance Pushable (Stringify MetaValue) where + push (Stringify (MetaMap m)) = Lua.push (fmap Stringify m) + push (Stringify (MetaList xs)) = Lua.push (map Stringify xs) + push (Stringify (MetaBool x)) = Lua.push x + push (Stringify (MetaString s)) = Lua.push s + push (Stringify (MetaInlines ils)) = Lua.push (Stringify ils) + push (Stringify (MetaBlocks bs)) = Lua.push (Stringify bs) -instance ToLuaStack (Stringify Citation) where +instance Pushable (Stringify Citation) where push (Stringify cit) = do - createtable 6 0 + Lua.createtable 6 0 addField "citationId" $ citationId cit addField "citationPrefix" . Stringify $ citationPrefix cit addField "citationSuffix" . Stringify $ citationSuffix cit @@ -93,10 +94,12 @@ instance ToLuaStack (Stringify Citation) where -- associated value. newtype KeyValue a b = KeyValue (a, b) -instance (ToLuaStack a, ToLuaStack b) => ToLuaStack (KeyValue a b) where +instance (Pushable a, Pushable b) => Pushable (KeyValue a b) where push (KeyValue (k, v)) = do - newtable - addValue k v + Lua.newtable + Lua.push k + Lua.push v + Lua.rawset (Lua.nthFromTop 3) data PandocLuaException = PandocLuaException String deriving (Show, Typeable) @@ -106,14 +109,13 @@ instance Exception PandocLuaException -- | Convert Pandoc to custom markup. writeCustom :: FilePath -> WriterOptions -> Pandoc -> PandocIO Text writeCustom luaFile opts doc@(Pandoc meta _) = do - luaScript <- liftIO $ UTF8.readFile luaFile res <- runPandocLua $ do registerScriptPath luaFile - stat <- dostring' luaScript + stat <- Lua.dofile luaFile -- check for error in lua script (later we'll change the return type -- to handle this more gracefully): - when (stat /= OK) $ - tostring (-1) >>= throw . PandocLuaException . UTF8.toString + when (stat /= Lua.OK) $ + Lua.tostring' (-1) >>= throw . PandocLuaException . UTF8.toString -- TODO - call hierarchicalize, so we have that info rendered <- docToCustom opts doc context <- metaToJSON opts @@ -122,7 +124,7 @@ writeCustom luaFile opts doc@(Pandoc meta _) = do meta return (rendered, context) let (body, context) = case res of - Left e -> throw (PandocLuaException (show e)) + Left (LuaException msg) -> throw (PandocLuaException msg) Right x -> x case writerTemplate opts of Nothing -> return $ pack body @@ -134,7 +136,7 @@ writeCustom luaFile opts doc@(Pandoc meta _) = do docToCustom :: WriterOptions -> Pandoc -> Lua String docToCustom opts (Pandoc (Meta metamap) blocks) = do body <- blockListToCustom blocks - callFunc "Doc" body (fmap Stringify metamap) (writerVariables opts) + Lua.callFunc "Doc" body (fmap Stringify metamap) (writerVariables opts) -- | Convert Pandoc block element to Custom. blockToCustom :: Block -- ^ Block element @@ -142,52 +144,55 @@ blockToCustom :: Block -- ^ Block element blockToCustom Null = return "" -blockToCustom (Plain inlines) = callFunc "Plain" (Stringify inlines) +blockToCustom (Plain inlines) = Lua.callFunc "Plain" (Stringify inlines) blockToCustom (Para [Image attr txt (src,tit)]) = - callFunc "CaptionedImage" src tit (Stringify txt) (attrToMap attr) + Lua.callFunc "CaptionedImage" src tit (Stringify txt) (attrToMap attr) -blockToCustom (Para inlines) = callFunc "Para" (Stringify inlines) +blockToCustom (Para inlines) = Lua.callFunc "Para" (Stringify inlines) -blockToCustom (LineBlock linesList) = callFunc "LineBlock" (map Stringify linesList) +blockToCustom (LineBlock linesList) = + Lua.callFunc "LineBlock" (map Stringify linesList) blockToCustom (RawBlock format str) = - callFunc "RawBlock" (Stringify format) str + Lua.callFunc "RawBlock" (Stringify format) str -blockToCustom HorizontalRule = callFunc "HorizontalRule" +blockToCustom HorizontalRule = Lua.callFunc "HorizontalRule" blockToCustom (Header level attr inlines) = - callFunc "Header" level (Stringify inlines) (attrToMap attr) + Lua.callFunc "Header" level (Stringify inlines) (attrToMap attr) blockToCustom (CodeBlock attr str) = - callFunc "CodeBlock" str (attrToMap attr) + Lua.callFunc "CodeBlock" str (attrToMap attr) -blockToCustom (BlockQuote blocks) = callFunc "BlockQuote" (Stringify blocks) +blockToCustom (BlockQuote blocks) = + Lua.callFunc "BlockQuote" (Stringify blocks) blockToCustom (Table capt aligns widths headers rows) = let aligns' = map show aligns capt' = Stringify capt headers' = map Stringify headers rows' = map (map Stringify) rows - in callFunc "Table" capt' aligns' widths headers' rows' + in Lua.callFunc "Table" capt' aligns' widths headers' rows' -blockToCustom (BulletList items) = callFunc "BulletList" (map Stringify items) +blockToCustom (BulletList items) = + Lua.callFunc "BulletList" (map Stringify items) blockToCustom (OrderedList (num,sty,delim) items) = - callFunc "OrderedList" (map Stringify items) num (show sty) (show delim) + Lua.callFunc "OrderedList" (map Stringify items) num (show sty) (show delim) blockToCustom (DefinitionList items) = - callFunc "DefinitionList" - (map (KeyValue . (Stringify *** map Stringify)) items) + Lua.callFunc "DefinitionList" + (map (KeyValue . (Stringify *** map Stringify)) items) blockToCustom (Div attr items) = - callFunc "Div" (Stringify items) (attrToMap attr) + Lua.callFunc "Div" (Stringify items) (attrToMap attr) -- | Convert list of Pandoc block elements to Custom. blockListToCustom :: [Block] -- ^ List of block elements -> Lua String blockListToCustom xs = do - blocksep <- callFunc "Blocksep" + blocksep <- Lua.callFunc "Blocksep" bs <- mapM blockToCustom xs return $ mconcat $ intersperse blocksep bs @@ -200,51 +205,51 @@ inlineListToCustom lst = do -- | Convert Pandoc inline element to Custom. inlineToCustom :: Inline -> Lua String -inlineToCustom (Str str) = callFunc "Str" str +inlineToCustom (Str str) = Lua.callFunc "Str" str -inlineToCustom Space = callFunc "Space" +inlineToCustom Space = Lua.callFunc "Space" -inlineToCustom SoftBreak = callFunc "SoftBreak" +inlineToCustom SoftBreak = Lua.callFunc "SoftBreak" -inlineToCustom (Emph lst) = callFunc "Emph" (Stringify lst) +inlineToCustom (Emph lst) = Lua.callFunc "Emph" (Stringify lst) -inlineToCustom (Strong lst) = callFunc "Strong" (Stringify lst) +inlineToCustom (Strong lst) = Lua.callFunc "Strong" (Stringify lst) -inlineToCustom (Strikeout lst) = callFunc "Strikeout" (Stringify lst) +inlineToCustom (Strikeout lst) = Lua.callFunc "Strikeout" (Stringify lst) -inlineToCustom (Superscript lst) = callFunc "Superscript" (Stringify lst) +inlineToCustom (Superscript lst) = Lua.callFunc "Superscript" (Stringify lst) -inlineToCustom (Subscript lst) = callFunc "Subscript" (Stringify lst) +inlineToCustom (Subscript lst) = Lua.callFunc "Subscript" (Stringify lst) -inlineToCustom (SmallCaps lst) = callFunc "SmallCaps" (Stringify lst) +inlineToCustom (SmallCaps lst) = Lua.callFunc "SmallCaps" (Stringify lst) -inlineToCustom (Quoted SingleQuote lst) = callFunc "SingleQuoted" (Stringify lst) +inlineToCustom (Quoted SingleQuote lst) = Lua.callFunc "SingleQuoted" (Stringify lst) -inlineToCustom (Quoted DoubleQuote lst) = callFunc "DoubleQuoted" (Stringify lst) +inlineToCustom (Quoted DoubleQuote lst) = Lua.callFunc "DoubleQuoted" (Stringify lst) -inlineToCustom (Cite cs lst) = callFunc "Cite" (Stringify lst) (map Stringify cs) +inlineToCustom (Cite cs lst) = Lua.callFunc "Cite" (Stringify lst) (map Stringify cs) inlineToCustom (Code attr str) = - callFunc "Code" str (attrToMap attr) + Lua.callFunc "Code" str (attrToMap attr) inlineToCustom (Math DisplayMath str) = - callFunc "DisplayMath" str + Lua.callFunc "DisplayMath" str inlineToCustom (Math InlineMath str) = - callFunc "InlineMath" str + Lua.callFunc "InlineMath" str inlineToCustom (RawInline format str) = - callFunc "RawInline" (Stringify format) str + Lua.callFunc "RawInline" (Stringify format) str -inlineToCustom LineBreak = callFunc "LineBreak" +inlineToCustom LineBreak = Lua.callFunc "LineBreak" inlineToCustom (Link attr txt (src,tit)) = - callFunc "Link" (Stringify txt) src tit (attrToMap attr) + Lua.callFunc "Link" (Stringify txt) src tit (attrToMap attr) inlineToCustom (Image attr alt (src,tit)) = - callFunc "Image" (Stringify alt) src tit (attrToMap attr) + Lua.callFunc "Image" (Stringify alt) src tit (attrToMap attr) -inlineToCustom (Note contents) = callFunc "Note" (Stringify contents) +inlineToCustom (Note contents) = Lua.callFunc "Note" (Stringify contents) inlineToCustom (Span attr items) = - callFunc "Span" (Stringify items) (attrToMap attr) + Lua.callFunc "Span" (Stringify items) (attrToMap attr) diff --git a/stack.lts9.yaml b/stack.lts9.yaml index a21841e08..a58946210 100644 --- a/stack.lts9.yaml +++ b/stack.lts9.yaml @@ -12,8 +12,8 @@ packages: - '.' extra-deps: - pandoc-citeproc-0.14.4 -- hslua-0.9.5.1 -- hslua-module-text-0.1.2.1 +- hslua-1.0.0 +- hslua-module-text-0.2.0 - ansi-terminal-0.8.0.2 - cmark-gfm-0.1.3 - QuickCheck-2.11.3 diff --git a/stack.yaml b/stack.yaml index a70e3e87d..36c5ee105 100644 --- a/stack.yaml +++ b/stack.yaml @@ -24,6 +24,8 @@ extra-deps: - HsYAML-0.1.1.1 - texmath-0.11.1 - yaml-0.9.0 +- hslua-1.0.0 +- hslua-module-text-0.2.0 ghc-options: "$locals": -fhide-source-paths -XNoImplicitPrelude resolver: lts-12.6 diff --git a/test/Tests/Lua.hs b/test/Tests/Lua.hs index 361b25297..3fe9c1121 100644 --- a/test/Tests/Lua.hs +++ b/test/Tests/Lua.hs @@ -164,11 +164,11 @@ tests = map (localOption (QuickCheckTests 20)) , testCase "informative error messages" . runPandocLua' $ do Lua.pushboolean True - err <- Lua.peekEither Lua.stackTop :: Lua.Lua (Either String Pandoc) - case err of + err <- Lua.peekEither Lua.stackTop + case (err :: Either String Pandoc) of Left msg -> do let expectedMsg = "Could not get Pandoc value: " - ++ "expected table but got boolean." + <> "table expected, got boolean" Lua.liftIO $ assertEqual "unexpected error message" expectedMsg msg Right _ -> error "Getting a Pandoc element from a bool should fail." ] @@ -182,10 +182,10 @@ assertFilterConversion msg filterPath docIn docExpected = do Left exception -> assertFailure (show exception) Right docRes -> assertEqual msg docExpected docRes -roundtripEqual :: (Eq a, Lua.FromLuaStack a, Lua.ToLuaStack a) => a -> IO Bool +roundtripEqual :: (Eq a, Lua.Peekable a, Lua.Pushable a) => a -> IO Bool roundtripEqual x = (x ==) <$> roundtripped where - roundtripped :: (Lua.FromLuaStack a, Lua.ToLuaStack a) => IO a + roundtripped :: (Lua.Peekable a, Lua.Pushable a) => IO a roundtripped = runPandocLua' $ do oldSize <- Lua.gettop Lua.push x -- cgit v1.2.3 From 72363cd2fc3941d921eea892d48ef5e9a4654888 Mon Sep 17 00:00:00 2001 From: Brian Leung Date: Tue, 25 Sep 2018 20:49:13 -0700 Subject: Add support for multiprenote and multipostnote arguments in LaTeX. (#4930) * Add support for multiprenote and multipostnote arguments. The multiprenotes occur before the first prefix of a multicite, and the multipostnotes follow the last suffix. * Add test for multiprenote and multipostnote. --- src/Text/Pandoc/Readers/LaTeX.hs | 35 ++++++++++++++++++++++++++++- test/command/4928.md | 48 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 test/command/4928.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 7346e9398..4a7f2f978 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -662,6 +662,11 @@ bracketed parser = try $ do symbol '[' mconcat <$> manyTill parser (symbol ']') +parenWrapped :: PandocMonad m => Monoid a => LP m a -> LP m a +parenWrapped parser = try $ do + symbol '(' + mconcat <$> manyTill parser (symbol ')') + dimenarg :: PandocMonad m => LP m Text dimenarg = try $ do ch <- option False $ True <$ symbol '=' @@ -1470,7 +1475,21 @@ citationLabel = do cites :: PandocMonad m => CitationMode -> Bool -> LP m [Citation] cites mode multi = try $ do cits <- if multi - then many1 simpleCiteArgs + then do + multiprenote <- optionMaybe $ toList <$> paropt + multipostnote <- optionMaybe $ toList <$> paropt + let (pre, suf) = case (multiprenote, multipostnote) of + (Just s , Nothing) -> (mempty, s) + (Nothing , Just t) -> (mempty, t) + (Just s , Just t ) -> (s, t) + _ -> (mempty, mempty) + tempCits <- many1 simpleCiteArgs + case tempCits of + (k:ks) -> case ks of + (_:_) -> return $ ((addMprenote pre k):init ks) ++ + [addMpostnote suf (last ks)] + _ -> return [addMprenote pre (addMpostnote suf k)] + _ -> return [[]] else count 1 simpleCiteArgs let cs = concat cits return $ case mode of @@ -1478,6 +1497,17 @@ cites mode multi = try $ do (c:rest) -> c {citationMode = mode} : rest [] -> [] _ -> map (\a -> a {citationMode = mode}) cs + where mprenote (k:ks) = (k:ks) ++ [Space] + mprenote _ = mempty + mpostnote (k:ks) = [Str ",", Space] ++ (k:ks) + mpostnote _ = mempty + addMprenote mpn (k:ks) = + let mpnfinal = case citationPrefix k of + (_:_) -> mprenote mpn + _ -> mpn + in addPrefix mpnfinal (k:ks) + addMprenote _ _ = [] + addMpostnote = addSuffix . mpostnote citation :: PandocMonad m => String -> CitationMode -> Bool -> LP m Inlines citation name mode multi = do @@ -1548,6 +1578,9 @@ singleChar = try $ do opt :: PandocMonad m => LP m Inlines opt = bracketed inline <|> (str . T.unpack <$> rawopt) +paropt :: PandocMonad m => LP m Inlines +paropt = parenWrapped inline + rawopt :: PandocMonad m => LP m Text rawopt = do inner <- untokenize <$> bracketedToks diff --git a/test/command/4928.md b/test/command/4928.md new file mode 100644 index 000000000..d1e2b6db7 --- /dev/null +++ b/test/command/4928.md @@ -0,0 +1,48 @@ +``` +% pandoc -f latex -t native +\cites(Multiprenote)(multipostnote)[23][42]{Knu86}[65]{Nie72} +^D +[Para [Cite [Citation {citationId = "Knu86", citationPrefix = [Str "Multiprenote",Space,Str "23"], citationSuffix = [Str "42"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "Nie72", citationPrefix = [], citationSuffix = [Str "65",Str ",",Space,Str "multipostnote"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cites(Multiprenote)(multipostnote)[23][42]{Knu86}[65]{Nie72}"]]] +``` + +``` +% pandoc -f latex -t native +\cites(Multiprenote)()[23][42]{Knu86}[65]{Nie72} +^D +[Para [Cite [Citation {citationId = "Knu86", citationPrefix = [Str "Multiprenote",Space,Str "23"], citationSuffix = [Str "42"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "Nie72", citationPrefix = [], citationSuffix = [Str "65"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cites(Multiprenote)()[23][42]{Knu86}[65]{Nie72}"]]] +``` + +``` +% pandoc -f latex -t native +\cites()(multipostnote)[23][42]{Knu86}[65]{Nie72} +^D +[Para [Cite [Citation {citationId = "Knu86", citationPrefix = [Str "23"], citationSuffix = [Str "42"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "Nie72", citationPrefix = [], citationSuffix = [Str "65",Str ",",Space,Str "multipostnote"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cites()(multipostnote)[23][42]{Knu86}[65]{Nie72}"]]] +``` + +``` +% pandoc -f latex -t native +\cites()()[23][42]{Knu86}[65]{Nie72} +^D +[Para [Cite [Citation {citationId = "Knu86", citationPrefix = [Str "23"], citationSuffix = [Str "42"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "Nie72", citationPrefix = [], citationSuffix = [Str "65"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cites()()[23][42]{Knu86}[65]{Nie72}"]]] +``` + +``` +% pandoc -f latex -t native +\cites(multipostnote)[23][42]{Knu86}[65]{Nie72} +^D +[Para [Cite [Citation {citationId = "Knu86", citationPrefix = [Str "23"], citationSuffix = [Str "42"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "Nie72", citationPrefix = [], citationSuffix = [Str "65",Str ",",Space,Str "multipostnote"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cites(multipostnote)[23][42]{Knu86}[65]{Nie72}"]]] +``` + +``` +% pandoc -f latex -t native +\cites(Multiprenote)(multipostnote){Knu86} +^D +[Para [Cite [Citation {citationId = "Knu86", citationPrefix = [Str "Multiprenote"], citationSuffix = [Str ",",Space,Str "multipostnote"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\cites(Multiprenote)(multipostnote){Knu86}"]]] +``` + +``` +% pandoc -f latex -t native +\footcites(Multiprenote)(multipostnote)[23][42]{Knu86}[65]{Nie72} +^D +[Para [Note [Para [Cite [Citation {citationId = "Knu86", citationPrefix = [Str "Multiprenote",Space,Str "23"], citationSuffix = [Str "42"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0},Citation {citationId = "Nie72", citationPrefix = [], citationSuffix = [Str "65",Str ",",Space,Str "multipostnote"], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [RawInline (Format "latex") "\\footcites(Multiprenote)(multipostnote)[23][42]{Knu86}[65]{Nie72}"],Str "."]]]] +``` -- cgit v1.2.3 From 6e8f31dab16472cb7cf14aac88cf2e383bdbc5ec Mon Sep 17 00:00:00 2001 From: leungbk Date: Tue, 25 Sep 2018 18:21:03 -0700 Subject: Force inline code blocks to honor export options. `exportsCode` is moved from `Blocks.hs` to `Shared.hs` and exported accordingly. --- src/Text/Pandoc/Readers/Org/Blocks.hs | 5 +---- src/Text/Pandoc/Readers/Org/Inlines.hs | 5 +++-- src/Text/Pandoc/Readers/Org/Shared.hs | 4 ++++ test/command/4885.md | 8 ++++++++ 4 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 test/command/4885.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs index d2a749efb..1c52c3477 100644 --- a/src/Text/Pandoc/Readers/Org/Blocks.hs +++ b/src/Text/Pandoc/Readers/Org/Blocks.hs @@ -40,7 +40,7 @@ import Text.Pandoc.Readers.Org.Meta (metaExport, metaKey, metaLine) import Text.Pandoc.Readers.Org.ParserState import Text.Pandoc.Readers.Org.Parsing import Text.Pandoc.Readers.Org.Shared (cleanLinkString, isImageFilename, - originalLang, translateLang) + originalLang, translateLang, exportsCode) import Text.Pandoc.Builder (Blocks, Inlines) import Text.Pandoc.Class (PandocMonad) @@ -314,9 +314,6 @@ codeBlock blockAttrs blockType = do labelledBlock :: F Inlines -> F Blocks labelledBlock = fmap (B.plain . B.spanWith ("", ["label"], [])) - exportsCode :: [(String, String)] -> Bool - exportsCode = maybe True (`elem` ["code", "both"]) . lookup "exports" - exportsResults :: [(String, String)] -> Bool exportsResults = maybe False (`elem` ["results", "both"]) . lookup "exports" diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs index b7378e3e4..b9a589f03 100644 --- a/src/Text/Pandoc/Readers/Org/Inlines.hs +++ b/src/Text/Pandoc/Readers/Org/Inlines.hs @@ -39,7 +39,7 @@ import Text.Pandoc.Readers.Org.BlockStarts (endOfBlock, noteMarker) import Text.Pandoc.Readers.Org.ParserState import Text.Pandoc.Readers.Org.Parsing import Text.Pandoc.Readers.Org.Shared (cleanLinkString, isImageFilename, - originalLang, translateLang) + originalLang, translateLang, exportsCode) import Text.Pandoc.Builder (Inlines) import qualified Text.Pandoc.Builder as B @@ -529,7 +529,8 @@ inlineCodeBlock = try $ do inlineCode <- enclosedByPair '{' '}' (noneOf "\n\r") let attrClasses = [translateLang lang] let attrKeyVal = originalLang lang <> opts - returnF $ B.codeWith ("", attrClasses, attrKeyVal) inlineCode + let codeInlineBlck = B.codeWith ("", attrClasses, attrKeyVal) inlineCode + returnF $ (if exportsCode opts then codeInlineBlck else mempty) where inlineBlockOption :: PandocMonad m => OrgParser m (String, String) inlineBlockOption = try $ do diff --git a/src/Text/Pandoc/Readers/Org/Shared.hs b/src/Text/Pandoc/Readers/Org/Shared.hs index 17fe34738..71d1dd517 100644 --- a/src/Text/Pandoc/Readers/Org/Shared.hs +++ b/src/Text/Pandoc/Readers/Org/Shared.hs @@ -32,6 +32,7 @@ module Text.Pandoc.Readers.Org.Shared , isImageFilename , originalLang , translateLang + , exportsCode ) where import Prelude @@ -96,3 +97,6 @@ translateLang cs = "sh" -> "bash" "sqlite" -> "sql" _ -> cs + +exportsCode :: [(String, String)] -> Bool +exportsCode = maybe True (`elem` ["code", "both"]) . lookup "exports" diff --git a/test/command/4885.md b/test/command/4885.md new file mode 100644 index 000000000..8611097c2 --- /dev/null +++ b/test/command/4885.md @@ -0,0 +1,8 @@ +``` +% pandoc -f org -t markdown +This won't show the command. +src_maxima[:exports none :results raw]{tex('integrate(sin((e^x)/pi),x,0,inf));} $$\int_{0}^{\infty }{\sin \left({{e^{x}}\over{\pi}}\right)\;dx}$$ +^D +This won\'t show the command. +$$\int_{0}^{\infty }{\sin \left({{e^{x}}\over{\pi}}\right)\;dx}$$ +``` -- cgit v1.2.3 From 99aae5d7cd4170b0d7c7d9cd635b3d138bffd85f Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 27 Sep 2018 09:19:32 -0700 Subject: HTML writer: omit unknown attributes in EPUB2 output. This allows users to include `epub:type` attributes, which will be passed through to epub3 but not epub2. --- src/Text/Pandoc/Writers/HTML.hs | 148 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 140 insertions(+), 8 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 851b48956..272454290 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -50,7 +50,7 @@ import Prelude import Control.Monad.State.Strict import Data.Char (ord, toLower) import Data.List (intercalate, intersperse, isPrefixOf, partition) -import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing) +import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing, mapMaybe) import qualified Data.Set as Set import Data.String (fromString) import Data.Text (Text) @@ -577,13 +577,23 @@ toAttrs :: PandocMonad m => [(String, String)] -> StateT WriterState m [Attribute] toAttrs kvs = do html5 <- gets stHtml5 - return $ map (\(x,y) -> - customAttribute - (fromString (if not html5 || x `Set.member` html5Attributes - || "epub:" `isPrefixOf` x - || "data-" `isPrefixOf` x - then x - else "data-" ++ x)) (toValue y)) kvs + mbEpubVersion <- gets stEPUBVersion + return $ mapMaybe (\(x,y) -> + if html5 + then + if x `Set.member` html5Attributes + || ':' `elem` x -- e.g. epub: namespace + || "data-" `isPrefixOf` x + then Just $ customAttribute (fromString x) (toValue y) + else Just $ customAttribute (fromString ("data-" ++ x)) + (toValue y) + else + if mbEpubVersion == Just EPUB2 && + not (x `Set.member` html4Attributes || + "xml:" `isPrefixOf` x) + then Nothing + else Just $ customAttribute (fromString x) (toValue y)) + kvs attrsToHtml :: PandocMonad m => WriterOptions -> Attr -> StateT WriterState m [Attribute] @@ -1419,3 +1429,125 @@ html5Attributes = Set.fromList , "workertype" , "wrap" ] + +html4Attributes :: Set.Set String +html4Attributes = Set.fromList + [ "abbr" + , "accept" + , "accept-charset" + , "accesskey" + , "action" + , "align" + , "alink" + , "alt" + , "archive" + , "axis" + , "background" + , "bgcolor" + , "border" + , "cellpadding" + , "cellspacing" + , "char" + , "charoff" + , "charset" + , "checked" + , "cite" + , "class" + , "classid" + , "clear" + , "code" + , "codebase" + , "codetype" + , "color" + , "cols" + , "colspan" + , "compact" + , "content" + , "coords" + , "data" + , "datetime" + , "declare" + , "defer" + , "dir" + , "disabled" + , "enctype" + , "face" + , "for" + , "frame" + , "frameborder" + , "headers" + , "height" + , "href" + , "hreflang" + , "hspace" + , "http-equiv" + , "id" + , "ismap" + , "label" + , "lang" + , "language" + , "link" + , "longdesc" + , "marginheight" + , "marginwidth" + , "maxlength" + , "media" + , "method" + , "multiple" + , "name" + , "nohref" + , "noresize" + , "noshade" + , "nowrap" + , "object" + , "onblur" + , "onchange" + , "onclick" + , "ondblclick" + , "onfocus" + , "onkeydown" + , "onkeypress" + , "onkeyup" + , "onload" + , "onmousedown" + , "onmousemove" + , "onmouseout" + , "onmouseover" + , "onmouseup" + , "onreset" + , "onselect" + , "onsubmit" + , "onunload" + , "profile" + , "prompt" + , "readonly" + , "rel" + , "rev" + , "rows" + , "rowspan" + , "rules" + , "scheme" + , "scope" + , "scrolling" + , "selected" + , "shape" + , "size" + , "span" + , "src" + , "standby" + , "start" + , "style" + , "summary" + , "tabindex" + , "target" + , "text" + , "title" + , "usemap" + , "valign" + , "value" + , "valuetype" + , "version" + , "vlink" + , "vspace" + , "width" + ] -- cgit v1.2.3 From 53657798cdd3b64165a2c2885bb4eefbf3ddafdf Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 27 Sep 2018 13:18:06 -0700 Subject: JATS writer: remove 'role' attribute on 'bold' and 'sc' elements. The JATS spec does not allow these. Closes #4937. --- src/Text/Pandoc/Writers/JATS.hs | 5 ++--- test/writer.jats | 13 ++++++------- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/JATS.hs b/src/Text/Pandoc/Writers/JATS.hs index fb3236bd9..f55a49d4e 100644 --- a/src/Text/Pandoc/Writers/JATS.hs +++ b/src/Text/Pandoc/Writers/JATS.hs @@ -344,7 +344,7 @@ inlineToJATS _ (Str str) = return $ text $ escapeStringForXML str inlineToJATS opts (Emph lst) = inTagsSimple "italic" <$> inlinesToJATS opts lst inlineToJATS opts (Strong lst) = - inTags False "bold" [("role", "strong")] <$> inlinesToJATS opts lst + inTagsSimple "bold" <$> inlinesToJATS opts lst inlineToJATS opts (Strikeout lst) = inTagsSimple "strike" <$> inlinesToJATS opts lst inlineToJATS opts (Superscript lst) = @@ -352,8 +352,7 @@ inlineToJATS opts (Superscript lst) = inlineToJATS opts (Subscript lst) = inTagsSimple "sub" <$> inlinesToJATS opts lst inlineToJATS opts (SmallCaps lst) = - inTags False "sc" [("role", "smallcaps")] <$> - inlinesToJATS opts lst + inTagsSimple "sc" <$> inlinesToJATS opts lst inlineToJATS opts (Quoted SingleQuote lst) = do contents <- inlinesToJATS opts lst return $ char '‘' <> contents <> char '’' diff --git a/test/writer.jats b/test/writer.jats index b51addf3b..f87b2325a 100644 --- a/test/writer.jats +++ b/test/writer.jats @@ -583,7 +583,7 @@ These should not be escaped: \$ \\ \> \[ \{

    Interpreted markdown in a table:

    This is emphasized

    -

    And this is strong

    +

    And this is strong

    Here’s a simple block:

    foo

    @@ -614,14 +614,13 @@ These should not be escaped: \$ \\ \> \[ \{ Inline Markup

    This is emphasized, and so is this.

    -

    This is strong, and so is - this.

    +

    This is strong, and so is this.

    An emphasized link.

    -

    This is strong and em.

    -

    So is this word.

    -

    This is strong and em.

    -

    So is this word.

    +

    This is strong and em.

    +

    So is this word.

    +

    This is strong and em.

    +

    So is this word.

    This is code: >, $, \, \$, <html>.

    -- cgit v1.2.3 From 0b3e885a00d4b56f0f100d7f852e9c08d9858598 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 27 Sep 2018 20:59:48 -0700 Subject: HTML writer: avoid adding extra section nestings for revealjs. Previously revealjs title slides at level (slidelevel - 1) were nested under an extra section element, even when the section contained no additional (vertical) content. That caused problems for some transition effects. See hakimel/reveal.js#1947. --- src/Text/Pandoc/Writers/HTML.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 272454290..c7f25197f 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -461,7 +461,7 @@ elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elemen t <- addAttrs opts attr $ secttag header' return $ - (if slideVariant == RevealJsSlides + (if slideVariant == RevealJsSlides && not (null innerContents) then H5.section else id) $ mconcat $ t : innerContents else if writerSectionDivs opts || slide -- cgit v1.2.3 From 4f9ab7e03268e576d86e697f7110869434d08557 Mon Sep 17 00:00:00 2001 From: leungbk Date: Thu, 27 Sep 2018 15:04:56 -0700 Subject: Parse empty argument array in inline src blocks. `enclosedByPair` alone does not the handle the empty array properly since it uses `many1Till`. --- src/Text/Pandoc/Readers/Org/Inlines.hs | 3 ++- test/Tests/Readers/Org/Inline.hs | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs index b9a589f03..a5335ca57 100644 --- a/src/Text/Pandoc/Readers/Org/Inlines.hs +++ b/src/Text/Pandoc/Readers/Org/Inlines.hs @@ -525,7 +525,8 @@ inlineCodeBlock :: PandocMonad m => OrgParser m (F Inlines) inlineCodeBlock = try $ do string "src_" lang <- many1 orgArgWordChar - opts <- option [] $ enclosedByPair '[' ']' inlineBlockOption + opts <- option [] $ try (enclosedByPair '[' ']' inlineBlockOption) + <|> (mempty <$ string "[]") inlineCode <- enclosedByPair '{' '}' (noneOf "\n\r") let attrClasses = [translateLang lang] let attrKeyVal = originalLang lang <> opts diff --git a/test/Tests/Readers/Org/Inline.hs b/test/Tests/Readers/Org/Inline.hs index 7dfa001e3..9cfcda79f 100644 --- a/test/Tests/Readers/Org/Inline.hs +++ b/test/Tests/Readers/Org/Inline.hs @@ -280,6 +280,13 @@ tests = ) "echo 'Hello, World'") + , "Inline code block with a blank argument array" =: + "src_sh[]{echo 'Hello, World'}" =?> + para (codeWith ( "" + , [ "bash" ] + , [ ("org-language", "sh") ]) + "echo 'Hello, World'") + , "Inline code block with toggle" =: "src_sh[:toggle]{echo $HOME}" =?> para (codeWith ( "" -- cgit v1.2.3 From 9dac993835603a1a92136f07e80a6561b1598754 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 28 Sep 2018 10:33:32 -0700 Subject: Added Text.Pandoc.Readers.LaTeX.Parsing (unexported). This collects some of the general-purpose code from the LaTeX reader, with the aim of making the module smaller. (We've been having out-of-memory issues compiling this module on CI.) --- pandoc.cabal | 1 + src/Text/Pandoc/Readers/LaTeX.hs | 560 +------------------------- src/Text/Pandoc/Readers/LaTeX/Parsing.hs | 663 +++++++++++++++++++++++++++++++ 3 files changed, 667 insertions(+), 557 deletions(-) create mode 100644 src/Text/Pandoc/Readers/LaTeX/Parsing.hs (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index 6edbc8ba0..75c34f039 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -508,6 +508,7 @@ library Text.Pandoc.Readers.Docx.Util, Text.Pandoc.Readers.Docx.StyleMap, Text.Pandoc.Readers.Docx.Fields, + Text.Pandoc.Readers.LaTeX.Parsing, Text.Pandoc.Readers.Odt.Base, Text.Pandoc.Readers.Odt.Namespaces, Text.Pandoc.Readers.Odt.StyleReader, diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 4a7f2f978..5065cc81c 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -47,8 +47,7 @@ import Prelude import Control.Applicative (many, optional, (<|>)) import Control.Monad import Control.Monad.Except (throwError) -import Control.Monad.Trans (lift) -import Data.Char (chr, isAlphaNum, isDigit, isLetter, ord, toLower, toUpper) +import Data.Char (isDigit, isLetter, toLower, toUpper) import Data.Default import Data.List (intercalate, isPrefixOf) import qualified Data.Map as M @@ -63,7 +62,7 @@ import Text.Pandoc.Builder import Text.Pandoc.Class (PandocMonad, PandocPure, getResourcePath, lookupEnv, readFileFromDirs, report, setResourcePath, setTranslations, translateTerm, trace) -import Text.Pandoc.Error (PandocError (PandocMacroLoop, PandocParseError, PandocParsecError)) +import Text.Pandoc.Error (PandocError ( PandocParseError, PandocParsecError)) import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension) import Text.Pandoc.ImageSize (numUnit, showFl) import Text.Pandoc.Logging @@ -72,10 +71,10 @@ import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline, optional, space, spaces, withRaw, (<|>)) import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..), ArgSpec (..), Tok (..), TokType (..)) +import Text.Pandoc.Readers.LaTeX.Parsing import Text.Pandoc.Shared import qualified Text.Pandoc.Translations as Translations import Text.Pandoc.Walk -import Text.Parsec.Pos import qualified Text.Pandoc.Builder as B -- for debugging: @@ -137,151 +136,6 @@ resolveRefs _ x = x -- Left e -> error (show e) -- Right r -> return r -newtype DottedNum = DottedNum [Int] - deriving (Show) - -renderDottedNum :: DottedNum -> String -renderDottedNum (DottedNum xs) = - intercalate "." (map show xs) - -incrementDottedNum :: Int -> DottedNum -> DottedNum -incrementDottedNum level (DottedNum ns) = DottedNum $ - case reverse (take level (ns ++ repeat 0)) of - (x:xs) -> reverse (x+1 : xs) - [] -> [] -- shouldn't happen - -data LaTeXState = LaTeXState{ sOptions :: ReaderOptions - , sMeta :: Meta - , sQuoteContext :: QuoteContext - , sMacros :: M.Map Text Macro - , sContainers :: [String] - , sHeaders :: M.Map Inlines String - , sLogMessages :: [LogMessage] - , sIdentifiers :: Set.Set String - , sVerbatimMode :: Bool - , sCaption :: (Maybe Inlines, Maybe String) - , sInListItem :: Bool - , sInTableCell :: Bool - , sLastHeaderNum :: DottedNum - , sLastFigureNum :: DottedNum - , sLabels :: M.Map String [Inline] - , sHasChapters :: Bool - , sToggles :: M.Map String Bool - } - deriving Show - -defaultLaTeXState :: LaTeXState -defaultLaTeXState = LaTeXState{ sOptions = def - , sMeta = nullMeta - , sQuoteContext = NoQuote - , sMacros = M.empty - , sContainers = [] - , sHeaders = M.empty - , sLogMessages = [] - , sIdentifiers = Set.empty - , sVerbatimMode = False - , sCaption = (Nothing, Nothing) - , sInListItem = False - , sInTableCell = False - , sLastHeaderNum = DottedNum [] - , sLastFigureNum = DottedNum [] - , sLabels = M.empty - , sHasChapters = False - , sToggles = M.empty - } - -instance PandocMonad m => HasQuoteContext LaTeXState m where - getQuoteContext = sQuoteContext <$> getState - withQuoteContext context parser = do - oldState <- getState - let oldQuoteContext = sQuoteContext oldState - setState oldState { sQuoteContext = context } - result <- parser - newState <- getState - setState newState { sQuoteContext = oldQuoteContext } - return result - -instance HasLogMessages LaTeXState where - addLogMessage msg st = st{ sLogMessages = msg : sLogMessages st } - getLogMessages st = reverse $ sLogMessages st - -instance HasIdentifierList LaTeXState where - extractIdentifierList = sIdentifiers - updateIdentifierList f st = st{ sIdentifiers = f $ sIdentifiers st } - -instance HasIncludeFiles LaTeXState where - getIncludeFiles = sContainers - addIncludeFile f s = s{ sContainers = f : sContainers s } - dropLatestIncludeFile s = s { sContainers = drop 1 $ sContainers s } - -instance HasHeaderMap LaTeXState where - extractHeaderMap = sHeaders - updateHeaderMap f st = st{ sHeaders = f $ sHeaders st } - -instance HasMacros LaTeXState where - extractMacros st = sMacros st - updateMacros f st = st{ sMacros = f (sMacros st) } - -instance HasReaderOptions LaTeXState where - extractReaderOptions = sOptions - -instance HasMeta LaTeXState where - setMeta field val st = - st{ sMeta = setMeta field val $ sMeta st } - deleteMeta field st = - st{ sMeta = deleteMeta field $ sMeta st } - -instance Default LaTeXState where - def = defaultLaTeXState - -type LP m = ParserT [Tok] LaTeXState m - -withVerbatimMode :: PandocMonad m => LP m a -> LP m a -withVerbatimMode parser = do - updateState $ \st -> st{ sVerbatimMode = True } - result <- parser - updateState $ \st -> st{ sVerbatimMode = False } - return result - -rawLaTeXParser :: (PandocMonad m, HasMacros s, HasReaderOptions s) - => Bool -> LP m a -> LP m a -> ParserT String s m (a, String) -rawLaTeXParser retokenize parser valParser = do - inp <- getInput - let toks = tokenize "source" $ T.pack inp - pstate <- getState - let lstate = def{ sOptions = extractReaderOptions pstate } - let lstate' = lstate { sMacros = extractMacros pstate } - let rawparser = (,) <$> withRaw valParser <*> getState - res' <- lift $ runParserT (snd <$> withRaw parser) lstate "chunk" toks - case res' of - Left _ -> mzero - Right toks' -> do - res <- lift $ runParserT (do when retokenize $ do - -- retokenize, applying macros - doMacros 0 - ts <- many (satisfyTok (const True)) - setInput ts - rawparser) - lstate' "chunk" toks' - case res of - Left _ -> mzero - Right ((val, raw), st) -> do - updateState (updateMacros (sMacros st <>)) - _ <- takeP (T.length (untokenize toks')) - return (val, T.unpack (untokenize raw)) - -applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s) - => String -> ParserT String s m String -applyMacros s = (guardDisabled Ext_latex_macros >> return s) <|> - do let retokenize = doMacros 0 *> - (toksToString <$> many (satisfyTok (const True))) - pstate <- getState - let lstate = def{ sOptions = extractReaderOptions pstate - , sMacros = extractMacros pstate } - res <- runParserT retokenize lstate "math" (tokenize "math" (T.pack s)) - case res of - Left e -> fail (show e) - Right s' -> return s' rawLaTeXBlock :: (PandocMonad m, HasMacros s, HasReaderOptions s) => ParserT String s m String @@ -326,358 +180,6 @@ inlineCommand = do lookAhead (try (char '\\' >> letter)) fst <$> rawLaTeXParser True (inlineEnvironment <|> inlineCommand') inlines -tokenize :: SourceName -> Text -> [Tok] -tokenize sourcename = totoks (initialPos sourcename) - -totoks :: SourcePos -> Text -> [Tok] -totoks pos t = - case T.uncons t of - Nothing -> [] - Just (c, rest) - | c == '\n' -> - Tok pos Newline "\n" - : totoks (setSourceColumn (incSourceLine pos 1) 1) rest - | isSpaceOrTab c -> - let (sps, rest') = T.span isSpaceOrTab t - in Tok pos Spaces sps - : totoks (incSourceColumn pos (T.length sps)) - rest' - | isAlphaNum c -> - let (ws, rest') = T.span isAlphaNum t - in Tok pos Word ws - : totoks (incSourceColumn pos (T.length ws)) rest' - | c == '%' -> - let (cs, rest') = T.break (== '\n') rest - in Tok pos Comment ("%" <> cs) - : totoks (incSourceColumn pos (1 + T.length cs)) rest' - | c == '\\' -> - case T.uncons rest of - Nothing -> [Tok pos (CtrlSeq " ") "\\"] - Just (d, rest') - | isLetterOrAt d -> - -- \makeatletter is common in macro defs; - -- ideally we should make tokenization sensitive - -- to \makeatletter and \makeatother, but this is - -- probably best for now - let (ws, rest'') = T.span isLetterOrAt rest - (ss, rest''') = T.span isSpaceOrTab rest'' - in Tok pos (CtrlSeq ws) ("\\" <> ws <> ss) - : totoks (incSourceColumn pos - (1 + T.length ws + T.length ss)) rest''' - | isSpaceOrTab d || d == '\n' -> - let (w1, r1) = T.span isSpaceOrTab rest - (w2, (w3, r3)) = case T.uncons r1 of - Just ('\n', r2) - -> (T.pack "\n", - T.span isSpaceOrTab r2) - _ -> (mempty, (mempty, r1)) - ws = "\\" <> w1 <> w2 <> w3 - in case T.uncons r3 of - Just ('\n', _) -> - Tok pos (CtrlSeq " ") ("\\" <> w1) - : totoks (incSourceColumn pos (T.length ws)) - r1 - _ -> - Tok pos (CtrlSeq " ") ws - : totoks (incSourceColumn pos (T.length ws)) - r3 - | otherwise -> - Tok pos (CtrlSeq (T.singleton d)) (T.pack [c,d]) - : totoks (incSourceColumn pos 2) rest' - | c == '#' -> - let (t1, t2) = T.span (\d -> d >= '0' && d <= '9') rest - in case safeRead (T.unpack t1) of - Just i -> - Tok pos (Arg i) ("#" <> t1) - : totoks (incSourceColumn pos (1 + T.length t1)) t2 - Nothing -> - Tok pos Symbol "#" - : totoks (incSourceColumn pos 1) t2 - | c == '^' -> - case T.uncons rest of - Just ('^', rest') -> - case T.uncons rest' of - Just (d, rest'') - | isLowerHex d -> - case T.uncons rest'' of - Just (e, rest''') | isLowerHex e -> - Tok pos Esc2 (T.pack ['^','^',d,e]) - : totoks (incSourceColumn pos 4) rest''' - _ -> - Tok pos Esc1 (T.pack ['^','^',d]) - : totoks (incSourceColumn pos 3) rest'' - | d < '\128' -> - Tok pos Esc1 (T.pack ['^','^',d]) - : totoks (incSourceColumn pos 3) rest'' - _ -> Tok pos Symbol "^" : - Tok (incSourceColumn pos 1) Symbol "^" : - totoks (incSourceColumn pos 2) rest' - _ -> Tok pos Symbol "^" - : totoks (incSourceColumn pos 1) rest - | otherwise -> - Tok pos Symbol (T.singleton c) : totoks (incSourceColumn pos 1) rest - -isSpaceOrTab :: Char -> Bool -isSpaceOrTab ' ' = True -isSpaceOrTab '\t' = True -isSpaceOrTab _ = False - -isLetterOrAt :: Char -> Bool -isLetterOrAt '@' = True -isLetterOrAt c = isLetter c - -isLowerHex :: Char -> Bool -isLowerHex x = x >= '0' && x <= '9' || x >= 'a' && x <= 'f' - -untokenize :: [Tok] -> Text -untokenize = mconcat . map untoken - -untoken :: Tok -> Text -untoken (Tok _ _ t) = t - -satisfyTok :: PandocMonad m => (Tok -> Bool) -> LP m Tok -satisfyTok f = - try $ do - res <- tokenPrim (T.unpack . untoken) updatePos matcher - doMacros 0 -- apply macros on remaining input stream - return res - where matcher t | f t = Just t - | otherwise = Nothing - updatePos :: SourcePos -> Tok -> [Tok] -> SourcePos - updatePos _spos _ (Tok pos _ _ : _) = pos - updatePos spos _ [] = incSourceColumn spos 1 - -doMacros :: PandocMonad m => Int -> LP m () -doMacros n = do - verbatimMode <- sVerbatimMode <$> getState - unless verbatimMode $ do - inp <- getInput - case inp of - Tok spos (CtrlSeq "begin") _ : Tok _ Symbol "{" : - Tok _ Word name : Tok _ Symbol "}" : ts - -> handleMacros spos name ts - Tok spos (CtrlSeq "end") _ : Tok _ Symbol "{" : - Tok _ Word name : Tok _ Symbol "}" : ts - -> handleMacros spos ("end" <> name) ts - Tok _ (CtrlSeq "expandafter") _ : t : ts - -> do setInput ts - doMacros n - getInput >>= setInput . combineTok t - Tok spos (CtrlSeq name) _ : ts - -> handleMacros spos name ts - _ -> return () - where combineTok (Tok spos (CtrlSeq name) x) (Tok _ Word w : ts) - | T.all isLetterOrAt w = - Tok spos (CtrlSeq (name <> w)) (x1 <> w <> x2) : ts - where (x1, x2) = T.break isSpaceOrTab x - combineTok t ts = t:ts - handleMacros spos name ts = do - macros <- sMacros <$> getState - case M.lookup name macros of - Nothing -> return () - Just (Macro expansionPoint argspecs optarg newtoks) -> do - setInput ts - let matchTok (Tok _ toktype txt) = - satisfyTok (\(Tok _ toktype' txt') -> - toktype == toktype' && - txt == txt') - let matchPattern toks = try $ mapM_ matchTok toks - let getargs argmap [] = return argmap - getargs argmap (Pattern toks : rest) = try $ do - matchPattern toks - getargs argmap rest - getargs argmap (ArgNum i : Pattern toks : rest) = - try $ do - x <- mconcat <$> manyTill - (braced <|> ((:[]) <$> anyTok)) - (matchPattern toks) - getargs (M.insert i x argmap) rest - getargs argmap (ArgNum i : rest) = do - x <- try $ spaces >> bracedOrToken - getargs (M.insert i x argmap) rest - args <- case optarg of - Nothing -> getargs M.empty argspecs - Just o -> do - x <- option o bracketedToks - getargs (M.singleton 1 x) argspecs - -- first boolean param is true if we're tokenizing - -- an argument (in which case we don't want to - -- expand #1 etc.) - let addTok False (Tok _ (Arg i) _) acc = - case M.lookup i args of - Nothing -> mzero - Just xs -> foldr (addTok True) acc xs - -- see #4007 - addTok _ (Tok _ (CtrlSeq x) txt) - acc@(Tok _ Word _ : _) - | not (T.null txt) && - isLetter (T.last txt) = - Tok spos (CtrlSeq x) (txt <> " ") : acc - addTok _ t acc = setpos spos t : acc - ts' <- getInput - setInput $ foldr (addTok False) ts' newtoks - case expansionPoint of - ExpandWhenUsed -> - if n > 20 -- detect macro expansion loops - then throwError $ PandocMacroLoop (T.unpack name) - else doMacros (n + 1) - ExpandWhenDefined -> return () - - -setpos :: SourcePos -> Tok -> Tok -setpos spos (Tok _ tt txt) = Tok spos tt txt - -anyControlSeq :: PandocMonad m => LP m Tok -anyControlSeq = satisfyTok isCtrlSeq - -isCtrlSeq :: Tok -> Bool -isCtrlSeq (Tok _ (CtrlSeq _) _) = True -isCtrlSeq _ = False - -anySymbol :: PandocMonad m => LP m Tok -anySymbol = satisfyTok isSymbolTok - -isSymbolTok :: Tok -> Bool -isSymbolTok (Tok _ Symbol _) = True -isSymbolTok _ = False - -spaces :: PandocMonad m => LP m () -spaces = skipMany (satisfyTok (tokTypeIn [Comment, Spaces, Newline])) - -spaces1 :: PandocMonad m => LP m () -spaces1 = skipMany1 (satisfyTok (tokTypeIn [Comment, Spaces, Newline])) - -tokTypeIn :: [TokType] -> Tok -> Bool -tokTypeIn toktypes (Tok _ tt _) = tt `elem` toktypes - -controlSeq :: PandocMonad m => Text -> LP m Tok -controlSeq name = satisfyTok isNamed - where isNamed (Tok _ (CtrlSeq n) _) = n == name - isNamed _ = False - -symbol :: PandocMonad m => Char -> LP m Tok -symbol c = satisfyTok isc - where isc (Tok _ Symbol d) = case T.uncons d of - Just (c',_) -> c == c' - _ -> False - isc _ = False - -symbolIn :: PandocMonad m => [Char] -> LP m Tok -symbolIn cs = satisfyTok isInCs - where isInCs (Tok _ Symbol d) = case T.uncons d of - Just (c,_) -> c `elem` cs - _ -> False - isInCs _ = False - -sp :: PandocMonad m => LP m () -sp = whitespace <|> endline - -whitespace :: PandocMonad m => LP m () -whitespace = () <$ satisfyTok isSpaceTok - -isSpaceTok :: Tok -> Bool -isSpaceTok (Tok _ Spaces _) = True -isSpaceTok _ = False - -newlineTok :: PandocMonad m => LP m () -newlineTok = () <$ satisfyTok isNewlineTok - -isNewlineTok :: Tok -> Bool -isNewlineTok (Tok _ Newline _) = True -isNewlineTok _ = False - -comment :: PandocMonad m => LP m () -comment = () <$ satisfyTok isCommentTok - -isCommentTok :: Tok -> Bool -isCommentTok (Tok _ Comment _) = True -isCommentTok _ = False - -anyTok :: PandocMonad m => LP m Tok -anyTok = satisfyTok (const True) - -endline :: PandocMonad m => LP m () -endline = try $ do - newlineTok - lookAhead anyTok - notFollowedBy blankline - -blankline :: PandocMonad m => LP m () -blankline = try $ skipMany whitespace *> newlineTok - -primEscape :: PandocMonad m => LP m Char -primEscape = do - Tok _ toktype t <- satisfyTok (tokTypeIn [Esc1, Esc2]) - case toktype of - Esc1 -> case T.uncons (T.drop 2 t) of - Just (c, _) - | c >= '\64' && c <= '\127' -> return (chr (ord c - 64)) - | otherwise -> return (chr (ord c + 64)) - Nothing -> fail "Empty content of Esc1" - Esc2 -> case safeRead ('0':'x':T.unpack (T.drop 2 t)) of - Just x -> return (chr x) - Nothing -> fail $ "Could not read: " ++ T.unpack t - _ -> fail "Expected an Esc1 or Esc2 token" -- should not happen - -bgroup :: PandocMonad m => LP m Tok -bgroup = try $ do - skipMany sp - symbol '{' <|> controlSeq "bgroup" <|> controlSeq "begingroup" - -egroup :: PandocMonad m => LP m Tok -egroup = symbol '}' <|> controlSeq "egroup" <|> controlSeq "endgroup" - -grouped :: (PandocMonad m, Monoid a) => LP m a -> LP m a -grouped parser = try $ do - bgroup - -- first we check for an inner 'grouped', because - -- {{a,b}} should be parsed the same as {a,b} - try (grouped parser <* egroup) <|> (mconcat <$> manyTill parser egroup) - -braced' :: PandocMonad m => LP m Tok -> Int -> LP m [Tok] -braced' getTok n = - handleEgroup <|> handleBgroup <|> handleOther - where handleEgroup = do - t <- egroup - if n == 1 - then return [] - else (t:) <$> braced' getTok (n - 1) - handleBgroup = do - t <- bgroup - (t:) <$> braced' getTok (n + 1) - handleOther = do - t <- getTok - (t:) <$> braced' getTok n - -braced :: PandocMonad m => LP m [Tok] -braced = bgroup *> braced' anyTok 1 - --- URLs require special handling, because they can contain % --- characters. So we retonenize comments as we go... -bracedUrl :: PandocMonad m => LP m [Tok] -bracedUrl = bgroup *> braced' (retokenizeComment >> anyTok) 1 - -bracketed :: PandocMonad m => Monoid a => LP m a -> LP m a -bracketed parser = try $ do - symbol '[' - mconcat <$> manyTill parser (symbol ']') - -parenWrapped :: PandocMonad m => Monoid a => LP m a -> LP m a -parenWrapped parser = try $ do - symbol '(' - mconcat <$> manyTill parser (symbol ')') - -dimenarg :: PandocMonad m => LP m Text -dimenarg = try $ do - ch <- option False $ True <$ symbol '=' - Tok _ _ s <- satisfyTok isWordTok - guard $ T.take 2 (T.reverse s) `elem` - ["pt","pc","in","bp","cm","mm","dd","cc","sp"] - let num = T.take (T.length s - 2) s - guard $ T.length num > 0 - guard $ T.all isDigit num - return $ T.pack ['=' | ch] <> s - -- inline elements: word :: PandocMonad m => LP m Inlines @@ -689,13 +191,6 @@ regularSymbol = (str . T.unpack . untoken) <$> satisfyTok isRegularSymbol isRegularSymbol _ = False isSpecial c = c `Set.member` specialChars -specialChars :: Set.Set Char -specialChars = Set.fromList "#$%&~_^\\{}" - -isWordTok :: Tok -> Bool -isWordTok (Tok _ Word _) = True -isWordTok _ = False - inlineGroup :: PandocMonad m => LP m Inlines inlineGroup = do ils <- grouped inline @@ -1396,9 +891,6 @@ breve 'U' = "Ŭ" breve 'u' = "ŭ" breve c = [c] -toksToString :: [Tok] -> String -toksToString = T.unpack . untokenize - mathDisplay :: String -> Inlines mathDisplay = displayMath . trim @@ -1562,19 +1054,6 @@ tok = try $ spaces >> grouped inline <|> inlineCommand' <|> singleChar' Tok _ _ t <- singleChar return (str (T.unpack t)) -singleChar :: PandocMonad m => LP m Tok -singleChar = try $ do - Tok pos toktype t <- satisfyTok (tokTypeIn [Word, Symbol]) - guard $ not $ toktype == Symbol && - T.any (`Set.member` specialChars) t - if T.length t > 1 - then do - let (t1, t2) = (T.take 1 t, T.drop 1 t) - inp <- getInput - setInput $ Tok (incSourceColumn pos 1) toktype t2 : inp - return $ Tok pos toktype t1 - else return $ Tok pos toktype t - opt :: PandocMonad m => LP m Inlines opt = bracketed inline <|> (str . T.unpack <$> rawopt) @@ -1611,20 +1090,6 @@ overlayTok = Tok _ Symbol c -> c `elem` ["-","+","@","|",":",","] _ -> False) -ignore :: (Monoid a, PandocMonad m) => String -> ParserT s u m a -ignore raw = do - pos <- getPosition - report $ SkippedContent raw pos - return mempty - -withRaw :: PandocMonad m => LP m a -> LP m (a, [Tok]) -withRaw parser = do - inp <- getInput - result <- parser - nxt <- option (Tok (initialPos "source") Word "") (lookAhead anyTok) - let raw = takeWhile (/= nxt) inp - return (result, raw) - inBrackets :: Inlines -> Inlines inBrackets x = str "[" <> x <> str "]" @@ -1634,17 +1099,6 @@ unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs unescapeURL (x:xs) = x:unescapeURL xs unescapeURL [] = "" --- For handling URLs, which allow literal % characters... -retokenizeComment :: PandocMonad m => LP m () -retokenizeComment = (do - Tok pos Comment txt <- satisfyTok isCommentTok - let updPos (Tok pos' toktype' txt') = - Tok (incSourceColumn (incSourceLine pos' (sourceLine pos - 1)) - (sourceColumn pos)) toktype' txt' - let newtoks = map updPos $ tokenize (sourceName pos) $ T.tail txt - getInput >>= setInput . ((Tok pos Symbol "%" : newtoks) ++)) - <|> return () - mathEnvWith :: PandocMonad m => (Inlines -> a) -> Maybe Text -> Text -> LP m a mathEnvWith f innerEnv name = f . mathDisplay . inner <$> mathEnv name @@ -2364,9 +1818,6 @@ isArgTok :: Tok -> Bool isArgTok (Tok _ (Arg _) _) = True isArgTok _ = False -bracedOrToken :: PandocMonad m => LP m [Tok] -bracedOrToken = braced <|> ((:[]) <$> (anyControlSeq <|> singleChar)) - newcommand :: PandocMonad m => LP m (Text, Macro) newcommand = do pos <- getPosition @@ -2417,11 +1868,6 @@ newenvironment = do return (name, Macro ExpandWhenUsed argspecs optarg startcontents, Macro ExpandWhenUsed [] Nothing endcontents) -bracketedToks :: PandocMonad m => LP m [Tok] -bracketedToks = do - symbol '[' - mconcat <$> manyTill (braced <|> (:[]) <$> anyTok) (symbol ']') - bracketedNum :: PandocMonad m => LP m Int bracketedNum = do ds <- untokenize <$> bracketedToks diff --git a/src/Text/Pandoc/Readers/LaTeX/Parsing.hs b/src/Text/Pandoc/Readers/LaTeX/Parsing.hs new file mode 100644 index 000000000..81d83dab2 --- /dev/null +++ b/src/Text/Pandoc/Readers/LaTeX/Parsing.hs @@ -0,0 +1,663 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{- +Copyright (C) 2006-2018 John MacFarlane + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-} + +{- | + Module : Text.Pandoc.Readers.LaTeX.Parsing + Copyright : Copyright (C) 2006-2018 John MacFarlane + License : GNU GPL, version 2 or above + + Maintainer : John MacFarlane + Stability : alpha + Portability : portable + +General parsing types and functions for LaTeX. +-} +module Text.Pandoc.Readers.LaTeX.Parsing + ( DottedNum(..) + , renderDottedNum + , incrementDottedNum + , LaTeXState(..) + , defaultLaTeXState + , LP + , withVerbatimMode + , rawLaTeXParser + , applyMacros + , tokenize + , untokenize + , untoken + , totoks + , toksToString + , satisfyTok + , doMacros + , setpos + , anyControlSeq + , anySymbol + , isWordTok + , isNewlineTok + , spaces + , spaces1 + , tokTypeIn + , controlSeq + , symbol + , symbolIn + , sp + , whitespace + , newlineTok + , comment + , anyTok + , singleChar + , specialChars + , endline + , blankline + , primEscape + , bgroup + , egroup + , grouped + , braced + , braced' + , bracedUrl + , bracedOrToken + , bracketed + , bracketedToks + , parenWrapped + , dimenarg + , ignore + , withRaw + ) where + +import Prelude +import Control.Applicative (many, (<|>)) +import Control.Monad +import Control.Monad.Except (throwError) +import Control.Monad.Trans (lift) +import Data.Char (chr, isAlphaNum, isDigit, isLetter, ord) +import Data.Default +import Data.List (intercalate) +import qualified Data.Map as M +import qualified Data.Set as Set +import Data.Text (Text) +import qualified Data.Text as T +import Text.Pandoc.Builder +import Text.Pandoc.Class (PandocMonad, report) +import Text.Pandoc.Error (PandocError (PandocMacroLoop)) +import Text.Pandoc.Logging +import Text.Pandoc.Options +import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline, + optional, space, spaces, withRaw, (<|>)) +import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..), + ArgSpec (..), Tok (..), TokType (..)) +import Text.Pandoc.Shared +import Text.Parsec.Pos + +newtype DottedNum = DottedNum [Int] + deriving (Show) + +renderDottedNum :: DottedNum -> String +renderDottedNum (DottedNum xs) = + intercalate "." (map show xs) + +incrementDottedNum :: Int -> DottedNum -> DottedNum +incrementDottedNum level (DottedNum ns) = DottedNum $ + case reverse (take level (ns ++ repeat 0)) of + (x:xs) -> reverse (x+1 : xs) + [] -> [] -- shouldn't happen + +data LaTeXState = LaTeXState{ sOptions :: ReaderOptions + , sMeta :: Meta + , sQuoteContext :: QuoteContext + , sMacros :: M.Map Text Macro + , sContainers :: [String] + , sHeaders :: M.Map Inlines String + , sLogMessages :: [LogMessage] + , sIdentifiers :: Set.Set String + , sVerbatimMode :: Bool + , sCaption :: (Maybe Inlines, Maybe String) + , sInListItem :: Bool + , sInTableCell :: Bool + , sLastHeaderNum :: DottedNum + , sLastFigureNum :: DottedNum + , sLabels :: M.Map String [Inline] + , sHasChapters :: Bool + , sToggles :: M.Map String Bool + } + deriving Show + +defaultLaTeXState :: LaTeXState +defaultLaTeXState = LaTeXState{ sOptions = def + , sMeta = nullMeta + , sQuoteContext = NoQuote + , sMacros = M.empty + , sContainers = [] + , sHeaders = M.empty + , sLogMessages = [] + , sIdentifiers = Set.empty + , sVerbatimMode = False + , sCaption = (Nothing, Nothing) + , sInListItem = False + , sInTableCell = False + , sLastHeaderNum = DottedNum [] + , sLastFigureNum = DottedNum [] + , sLabels = M.empty + , sHasChapters = False + , sToggles = M.empty + } + +instance PandocMonad m => HasQuoteContext LaTeXState m where + getQuoteContext = sQuoteContext <$> getState + withQuoteContext context parser = do + oldState <- getState + let oldQuoteContext = sQuoteContext oldState + setState oldState { sQuoteContext = context } + result <- parser + newState <- getState + setState newState { sQuoteContext = oldQuoteContext } + return result + +instance HasLogMessages LaTeXState where + addLogMessage msg st = st{ sLogMessages = msg : sLogMessages st } + getLogMessages st = reverse $ sLogMessages st + +instance HasIdentifierList LaTeXState where + extractIdentifierList = sIdentifiers + updateIdentifierList f st = st{ sIdentifiers = f $ sIdentifiers st } + +instance HasIncludeFiles LaTeXState where + getIncludeFiles = sContainers + addIncludeFile f s = s{ sContainers = f : sContainers s } + dropLatestIncludeFile s = s { sContainers = drop 1 $ sContainers s } + +instance HasHeaderMap LaTeXState where + extractHeaderMap = sHeaders + updateHeaderMap f st = st{ sHeaders = f $ sHeaders st } + +instance HasMacros LaTeXState where + extractMacros st = sMacros st + updateMacros f st = st{ sMacros = f (sMacros st) } + +instance HasReaderOptions LaTeXState where + extractReaderOptions = sOptions + +instance HasMeta LaTeXState where + setMeta field val st = + st{ sMeta = setMeta field val $ sMeta st } + deleteMeta field st = + st{ sMeta = deleteMeta field $ sMeta st } + +instance Default LaTeXState where + def = defaultLaTeXState + +type LP m = ParserT [Tok] LaTeXState m + +withVerbatimMode :: PandocMonad m => LP m a -> LP m a +withVerbatimMode parser = do + updateState $ \st -> st{ sVerbatimMode = True } + result <- parser + updateState $ \st -> st{ sVerbatimMode = False } + return result + +rawLaTeXParser :: (PandocMonad m, HasMacros s, HasReaderOptions s) + => Bool -> LP m a -> LP m a -> ParserT String s m (a, String) +rawLaTeXParser retokenize parser valParser = do + inp <- getInput + let toks = tokenize "source" $ T.pack inp + pstate <- getState + let lstate = def{ sOptions = extractReaderOptions pstate } + let lstate' = lstate { sMacros = extractMacros pstate } + let rawparser = (,) <$> withRaw valParser <*> getState + res' <- lift $ runParserT (snd <$> withRaw parser) lstate "chunk" toks + case res' of + Left _ -> mzero + Right toks' -> do + res <- lift $ runParserT (do when retokenize $ do + -- retokenize, applying macros + doMacros 0 + ts <- many (satisfyTok (const True)) + setInput ts + rawparser) + lstate' "chunk" toks' + case res of + Left _ -> mzero + Right ((val, raw), st) -> do + updateState (updateMacros (sMacros st <>)) + _ <- takeP (T.length (untokenize toks')) + return (val, T.unpack (untokenize raw)) + +applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s) + => String -> ParserT String s m String +applyMacros s = (guardDisabled Ext_latex_macros >> return s) <|> + do let retokenize = doMacros 0 *> + (toksToString <$> many (satisfyTok (const True))) + pstate <- getState + let lstate = def{ sOptions = extractReaderOptions pstate + , sMacros = extractMacros pstate } + res <- runParserT retokenize lstate "math" (tokenize "math" (T.pack s)) + case res of + Left e -> fail (show e) + Right s' -> return s' +tokenize :: SourceName -> Text -> [Tok] +tokenize sourcename = totoks (initialPos sourcename) + +totoks :: SourcePos -> Text -> [Tok] +totoks pos t = + case T.uncons t of + Nothing -> [] + Just (c, rest) + | c == '\n' -> + Tok pos Newline "\n" + : totoks (setSourceColumn (incSourceLine pos 1) 1) rest + | isSpaceOrTab c -> + let (sps, rest') = T.span isSpaceOrTab t + in Tok pos Spaces sps + : totoks (incSourceColumn pos (T.length sps)) + rest' + | isAlphaNum c -> + let (ws, rest') = T.span isAlphaNum t + in Tok pos Word ws + : totoks (incSourceColumn pos (T.length ws)) rest' + | c == '%' -> + let (cs, rest') = T.break (== '\n') rest + in Tok pos Comment ("%" <> cs) + : totoks (incSourceColumn pos (1 + T.length cs)) rest' + | c == '\\' -> + case T.uncons rest of + Nothing -> [Tok pos (CtrlSeq " ") "\\"] + Just (d, rest') + | isLetterOrAt d -> + -- \makeatletter is common in macro defs; + -- ideally we should make tokenization sensitive + -- to \makeatletter and \makeatother, but this is + -- probably best for now + let (ws, rest'') = T.span isLetterOrAt rest + (ss, rest''') = T.span isSpaceOrTab rest'' + in Tok pos (CtrlSeq ws) ("\\" <> ws <> ss) + : totoks (incSourceColumn pos + (1 + T.length ws + T.length ss)) rest''' + | isSpaceOrTab d || d == '\n' -> + let (w1, r1) = T.span isSpaceOrTab rest + (w2, (w3, r3)) = case T.uncons r1 of + Just ('\n', r2) + -> (T.pack "\n", + T.span isSpaceOrTab r2) + _ -> (mempty, (mempty, r1)) + ws = "\\" <> w1 <> w2 <> w3 + in case T.uncons r3 of + Just ('\n', _) -> + Tok pos (CtrlSeq " ") ("\\" <> w1) + : totoks (incSourceColumn pos (T.length ws)) + r1 + _ -> + Tok pos (CtrlSeq " ") ws + : totoks (incSourceColumn pos (T.length ws)) + r3 + | otherwise -> + Tok pos (CtrlSeq (T.singleton d)) (T.pack [c,d]) + : totoks (incSourceColumn pos 2) rest' + | c == '#' -> + let (t1, t2) = T.span (\d -> d >= '0' && d <= '9') rest + in case safeRead (T.unpack t1) of + Just i -> + Tok pos (Arg i) ("#" <> t1) + : totoks (incSourceColumn pos (1 + T.length t1)) t2 + Nothing -> + Tok pos Symbol "#" + : totoks (incSourceColumn pos 1) t2 + | c == '^' -> + case T.uncons rest of + Just ('^', rest') -> + case T.uncons rest' of + Just (d, rest'') + | isLowerHex d -> + case T.uncons rest'' of + Just (e, rest''') | isLowerHex e -> + Tok pos Esc2 (T.pack ['^','^',d,e]) + : totoks (incSourceColumn pos 4) rest''' + _ -> + Tok pos Esc1 (T.pack ['^','^',d]) + : totoks (incSourceColumn pos 3) rest'' + | d < '\128' -> + Tok pos Esc1 (T.pack ['^','^',d]) + : totoks (incSourceColumn pos 3) rest'' + _ -> Tok pos Symbol "^" : + Tok (incSourceColumn pos 1) Symbol "^" : + totoks (incSourceColumn pos 2) rest' + _ -> Tok pos Symbol "^" + : totoks (incSourceColumn pos 1) rest + | otherwise -> + Tok pos Symbol (T.singleton c) : totoks (incSourceColumn pos 1) rest + +isSpaceOrTab :: Char -> Bool +isSpaceOrTab ' ' = True +isSpaceOrTab '\t' = True +isSpaceOrTab _ = False + +isLetterOrAt :: Char -> Bool +isLetterOrAt '@' = True +isLetterOrAt c = isLetter c + +isLowerHex :: Char -> Bool +isLowerHex x = x >= '0' && x <= '9' || x >= 'a' && x <= 'f' + +untokenize :: [Tok] -> Text +untokenize = mconcat . map untoken + +untoken :: Tok -> Text +untoken (Tok _ _ t) = t + +toksToString :: [Tok] -> String +toksToString = T.unpack . untokenize + +satisfyTok :: PandocMonad m => (Tok -> Bool) -> LP m Tok +satisfyTok f = + try $ do + res <- tokenPrim (T.unpack . untoken) updatePos matcher + doMacros 0 -- apply macros on remaining input stream + return res + where matcher t | f t = Just t + | otherwise = Nothing + updatePos :: SourcePos -> Tok -> [Tok] -> SourcePos + updatePos _spos _ (Tok pos _ _ : _) = pos + updatePos spos _ [] = incSourceColumn spos 1 + +doMacros :: PandocMonad m => Int -> LP m () +doMacros n = do + verbatimMode <- sVerbatimMode <$> getState + unless verbatimMode $ do + inp <- getInput + case inp of + Tok spos (CtrlSeq "begin") _ : Tok _ Symbol "{" : + Tok _ Word name : Tok _ Symbol "}" : ts + -> handleMacros spos name ts + Tok spos (CtrlSeq "end") _ : Tok _ Symbol "{" : + Tok _ Word name : Tok _ Symbol "}" : ts + -> handleMacros spos ("end" <> name) ts + Tok _ (CtrlSeq "expandafter") _ : t : ts + -> do setInput ts + doMacros n + getInput >>= setInput . combineTok t + Tok spos (CtrlSeq name) _ : ts + -> handleMacros spos name ts + _ -> return () + where combineTok (Tok spos (CtrlSeq name) x) (Tok _ Word w : ts) + | T.all isLetterOrAt w = + Tok spos (CtrlSeq (name <> w)) (x1 <> w <> x2) : ts + where (x1, x2) = T.break isSpaceOrTab x + combineTok t ts = t:ts + handleMacros spos name ts = do + macros <- sMacros <$> getState + case M.lookup name macros of + Nothing -> return () + Just (Macro expansionPoint argspecs optarg newtoks) -> do + setInput ts + let matchTok (Tok _ toktype txt) = + satisfyTok (\(Tok _ toktype' txt') -> + toktype == toktype' && + txt == txt') + let matchPattern toks = try $ mapM_ matchTok toks + let getargs argmap [] = return argmap + getargs argmap (Pattern toks : rest) = try $ do + matchPattern toks + getargs argmap rest + getargs argmap (ArgNum i : Pattern toks : rest) = + try $ do + x <- mconcat <$> manyTill + (braced <|> ((:[]) <$> anyTok)) + (matchPattern toks) + getargs (M.insert i x argmap) rest + getargs argmap (ArgNum i : rest) = do + x <- try $ spaces >> bracedOrToken + getargs (M.insert i x argmap) rest + args <- case optarg of + Nothing -> getargs M.empty argspecs + Just o -> do + x <- option o bracketedToks + getargs (M.singleton 1 x) argspecs + -- first boolean param is true if we're tokenizing + -- an argument (in which case we don't want to + -- expand #1 etc.) + let addTok False (Tok _ (Arg i) _) acc = + case M.lookup i args of + Nothing -> mzero + Just xs -> foldr (addTok True) acc xs + -- see #4007 + addTok _ (Tok _ (CtrlSeq x) txt) + acc@(Tok _ Word _ : _) + | not (T.null txt) && + isLetter (T.last txt) = + Tok spos (CtrlSeq x) (txt <> " ") : acc + addTok _ t acc = setpos spos t : acc + ts' <- getInput + setInput $ foldr (addTok False) ts' newtoks + case expansionPoint of + ExpandWhenUsed -> + if n > 20 -- detect macro expansion loops + then throwError $ PandocMacroLoop (T.unpack name) + else doMacros (n + 1) + ExpandWhenDefined -> return () + + +setpos :: SourcePos -> Tok -> Tok +setpos spos (Tok _ tt txt) = Tok spos tt txt + +anyControlSeq :: PandocMonad m => LP m Tok +anyControlSeq = satisfyTok isCtrlSeq + +isCtrlSeq :: Tok -> Bool +isCtrlSeq (Tok _ (CtrlSeq _) _) = True +isCtrlSeq _ = False + +anySymbol :: PandocMonad m => LP m Tok +anySymbol = satisfyTok isSymbolTok + +isSymbolTok :: Tok -> Bool +isSymbolTok (Tok _ Symbol _) = True +isSymbolTok _ = False + +isWordTok :: Tok -> Bool +isWordTok (Tok _ Word _) = True +isWordTok _ = False + +spaces :: PandocMonad m => LP m () +spaces = skipMany (satisfyTok (tokTypeIn [Comment, Spaces, Newline])) + +spaces1 :: PandocMonad m => LP m () +spaces1 = skipMany1 (satisfyTok (tokTypeIn [Comment, Spaces, Newline])) + +tokTypeIn :: [TokType] -> Tok -> Bool +tokTypeIn toktypes (Tok _ tt _) = tt `elem` toktypes + +controlSeq :: PandocMonad m => Text -> LP m Tok +controlSeq name = satisfyTok isNamed + where isNamed (Tok _ (CtrlSeq n) _) = n == name + isNamed _ = False + +symbol :: PandocMonad m => Char -> LP m Tok +symbol c = satisfyTok isc + where isc (Tok _ Symbol d) = case T.uncons d of + Just (c',_) -> c == c' + _ -> False + isc _ = False + +symbolIn :: PandocMonad m => [Char] -> LP m Tok +symbolIn cs = satisfyTok isInCs + where isInCs (Tok _ Symbol d) = case T.uncons d of + Just (c,_) -> c `elem` cs + _ -> False + isInCs _ = False + +sp :: PandocMonad m => LP m () +sp = whitespace <|> endline + +whitespace :: PandocMonad m => LP m () +whitespace = () <$ satisfyTok isSpaceTok + +isSpaceTok :: Tok -> Bool +isSpaceTok (Tok _ Spaces _) = True +isSpaceTok _ = False + +newlineTok :: PandocMonad m => LP m () +newlineTok = () <$ satisfyTok isNewlineTok + +isNewlineTok :: Tok -> Bool +isNewlineTok (Tok _ Newline _) = True +isNewlineTok _ = False + +comment :: PandocMonad m => LP m () +comment = () <$ satisfyTok isCommentTok + +isCommentTok :: Tok -> Bool +isCommentTok (Tok _ Comment _) = True +isCommentTok _ = False + +anyTok :: PandocMonad m => LP m Tok +anyTok = satisfyTok (const True) + +singleChar :: PandocMonad m => LP m Tok +singleChar = try $ do + Tok pos toktype t <- satisfyTok (tokTypeIn [Word, Symbol]) + guard $ not $ toktype == Symbol && + T.any (`Set.member` specialChars) t + if T.length t > 1 + then do + let (t1, t2) = (T.take 1 t, T.drop 1 t) + inp <- getInput + setInput $ Tok (incSourceColumn pos 1) toktype t2 : inp + return $ Tok pos toktype t1 + else return $ Tok pos toktype t + +specialChars :: Set.Set Char +specialChars = Set.fromList "#$%&~_^\\{}" + +endline :: PandocMonad m => LP m () +endline = try $ do + newlineTok + lookAhead anyTok + notFollowedBy blankline + +blankline :: PandocMonad m => LP m () +blankline = try $ skipMany whitespace *> newlineTok + +primEscape :: PandocMonad m => LP m Char +primEscape = do + Tok _ toktype t <- satisfyTok (tokTypeIn [Esc1, Esc2]) + case toktype of + Esc1 -> case T.uncons (T.drop 2 t) of + Just (c, _) + | c >= '\64' && c <= '\127' -> return (chr (ord c - 64)) + | otherwise -> return (chr (ord c + 64)) + Nothing -> fail "Empty content of Esc1" + Esc2 -> case safeRead ('0':'x':T.unpack (T.drop 2 t)) of + Just x -> return (chr x) + Nothing -> fail $ "Could not read: " ++ T.unpack t + _ -> fail "Expected an Esc1 or Esc2 token" -- should not happen + +bgroup :: PandocMonad m => LP m Tok +bgroup = try $ do + skipMany sp + symbol '{' <|> controlSeq "bgroup" <|> controlSeq "begingroup" + +egroup :: PandocMonad m => LP m Tok +egroup = symbol '}' <|> controlSeq "egroup" <|> controlSeq "endgroup" + +grouped :: (PandocMonad m, Monoid a) => LP m a -> LP m a +grouped parser = try $ do + bgroup + -- first we check for an inner 'grouped', because + -- {{a,b}} should be parsed the same as {a,b} + try (grouped parser <* egroup) <|> (mconcat <$> manyTill parser egroup) + +braced' :: PandocMonad m => LP m Tok -> Int -> LP m [Tok] +braced' getTok n = + handleEgroup <|> handleBgroup <|> handleOther + where handleEgroup = do + t <- egroup + if n == 1 + then return [] + else (t:) <$> braced' getTok (n - 1) + handleBgroup = do + t <- bgroup + (t:) <$> braced' getTok (n + 1) + handleOther = do + t <- getTok + (t:) <$> braced' getTok n + +braced :: PandocMonad m => LP m [Tok] +braced = bgroup *> braced' anyTok 1 + +-- URLs require special handling, because they can contain % +-- characters. So we retonenize comments as we go... +bracedUrl :: PandocMonad m => LP m [Tok] +bracedUrl = bgroup *> braced' (retokenizeComment >> anyTok) 1 + +-- For handling URLs, which allow literal % characters... +retokenizeComment :: PandocMonad m => LP m () +retokenizeComment = (do + Tok pos Comment txt <- satisfyTok isCommentTok + let updPos (Tok pos' toktype' txt') = + Tok (incSourceColumn (incSourceLine pos' (sourceLine pos - 1)) + (sourceColumn pos)) toktype' txt' + let newtoks = map updPos $ tokenize (sourceName pos) $ T.tail txt + getInput >>= setInput . ((Tok pos Symbol "%" : newtoks) ++)) + <|> return () + +bracedOrToken :: PandocMonad m => LP m [Tok] +bracedOrToken = braced <|> ((:[]) <$> (anyControlSeq <|> singleChar)) + +bracketed :: PandocMonad m => Monoid a => LP m a -> LP m a +bracketed parser = try $ do + symbol '[' + mconcat <$> manyTill parser (symbol ']') + +bracketedToks :: PandocMonad m => LP m [Tok] +bracketedToks = do + symbol '[' + mconcat <$> manyTill (braced <|> (:[]) <$> anyTok) (symbol ']') + +parenWrapped :: PandocMonad m => Monoid a => LP m a -> LP m a +parenWrapped parser = try $ do + symbol '(' + mconcat <$> manyTill parser (symbol ')') + +dimenarg :: PandocMonad m => LP m Text +dimenarg = try $ do + ch <- option False $ True <$ symbol '=' + Tok _ _ s <- satisfyTok isWordTok + guard $ T.take 2 (T.reverse s) `elem` + ["pt","pc","in","bp","cm","mm","dd","cc","sp"] + let num = T.take (T.length s - 2) s + guard $ T.length num > 0 + guard $ T.all isDigit num + return $ T.pack ['=' | ch] <> s + +ignore :: (Monoid a, PandocMonad m) => String -> ParserT s u m a +ignore raw = do + pos <- getPosition + report $ SkippedContent raw pos + return mempty + +withRaw :: PandocMonad m => LP m a -> LP m (a, [Tok]) +withRaw parser = do + inp <- getInput + result <- parser + nxt <- option (Tok (initialPos "source") Word "") (lookAhead anyTok) + let raw = takeWhile (/= nxt) inp + return (result, raw) -- cgit v1.2.3 From c6d56f026f27519e913f64d843450c7a32f957fb Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 29 Sep 2018 10:18:09 -0700 Subject: LaTeX reader: support breq math environments: dmath, dgroup, darray. --- src/Text/Pandoc/Readers/LaTeX.hs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 5065cc81c..8a8b7dfb6 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1136,6 +1136,12 @@ inlineEnvironments = M.fromList [ , ("align*", mathEnvWith id (Just "aligned") "align*") , ("alignat", mathEnvWith id (Just "aligned") "alignat") , ("alignat*", mathEnvWith id (Just "aligned") "alignat*") + , ("dmath", mathEnvWith id Nothing "dmath") + , ("dmath*", mathEnvWith id Nothing "dmath*") + , ("dgroup", mathEnvWith id (Just "aligned") "dgroup") + , ("dgroup*", mathEnvWith id (Just "aligned") "dgroup*") + , ("darray", mathEnvWith id (Just "aligned") "darray") + , ("darray*", mathEnvWith id (Just "aligned") "darray*") ] inlineCommands :: PandocMonad m => M.Map Text (LP m Inlines) -- cgit v1.2.3 From 190ee279c9c10c6e87248428dcdbd73ab9036373 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 29 Sep 2018 10:57:11 -0700 Subject: LaTeX reader: allow verbatim blocks ending with blank lines. Closes #4624. --- src/Text/Pandoc/Readers/LaTeX.hs | 15 ++++++++++++++- test/command/4624.md | 30 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 test/command/4624.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 8a8b7dfb6..17d1c4bc9 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -2145,7 +2145,20 @@ verbEnv name = withVerbatimMode $ do skipopts optional blankline res <- manyTill anyTok (end_ name) - return $ stripTrailingNewlines $ toksToString res + return $ T.unpack + $ stripTrailingNewline + $ untokenize + $ res + +-- Strip single final newline and any spaces following it. +-- Input is unchanged if it doesn't end with newline + +-- optional spaces. +stripTrailingNewline :: Text -> Text +stripTrailingNewline t = + let (b, e) = T.breakOnEnd "\n" t + in if T.all (== ' ') e + then T.dropEnd 1 b + else t fancyverbEnv :: PandocMonad m => Text -> LP m Blocks fancyverbEnv name = do diff --git a/test/command/4624.md b/test/command/4624.md new file mode 100644 index 000000000..f9aa45596 --- /dev/null +++ b/test/command/4624.md @@ -0,0 +1,30 @@ +``` +% pandoc -f latex -t native +\begin{Verbatim}[key1=value1] +code1 + +\end{Verbatim} + + +\begin{lstlisting}[key2=value2] +code2 + +\end{lstlisting} + +\begin{verbatim} +code3 +\end{verbatim} + +\begin{verbatim} +code4 + \end{verbatim} + +\begin{verbatim} +code5\end{verbatim} +^D +[CodeBlock ("",[],[("key1","value1")]) "code1\n" +,CodeBlock ("",[],[("key2","value2")]) "code2\n " +,CodeBlock ("",[],[]) "code3" +,CodeBlock ("",[],[]) "code4" +,CodeBlock ("",[],[]) "code5"] +``` -- cgit v1.2.3 From 966bd94ba268216f9d1492287638fd0b725dd503 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 29 Sep 2018 23:29:32 -0700 Subject: LaTeX writer: Fix description lists contining highlighted code. Closes #4662. --- src/Text/Pandoc/Writers/LaTeX.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 6042f2765..7be3fce28 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -870,9 +870,11 @@ defListItemToLaTeX (term, defs) = do else term' def' <- liftM vsep $ mapM blockListToLaTeX defs return $ case defs of - ((Header{} : _) : _) -> + ((Header{} : _) : _) -> "\\item" <> brackets term'' <> " ~ " $$ def' - _ -> + ((CodeBlock{} : _) : _) -> -- see #4662 + "\\item" <> brackets term'' <> " ~ " $$ def' + _ -> "\\item" <> brackets term'' $$ def' -- | Craft the section header, inserting the secton reference, if supplied. -- cgit v1.2.3 From aebe5fe99eecd132f29dedafe12fa8155f30045b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 30 Sep 2018 10:25:17 -0700 Subject: LaTeX reader: simplified accent code using unicode-transforms. New dependency on unicode-transforms package for normalization. --- pandoc.cabal | 1 + src/Text/Pandoc/Readers/LaTeX.hs | 355 ++++----------------------------------- 2 files changed, 34 insertions(+), 322 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index 75c34f039..9ebd86f6e 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -388,6 +388,7 @@ library http-client-tls >= 0.2.4 && < 0.4, http-types >= 0.8 && < 0.13, case-insensitive >= 1.2 && < 1.3, + unicode-transforms >= 0.3 && < 0.4, HsYAML >= 0.1.1.1 && < 0.2 if impl(ghc < 8.0) build-depends: semigroups == 0.18.*, diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 17d1c4bc9..1af82246e 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -76,6 +76,7 @@ import Text.Pandoc.Shared import qualified Text.Pandoc.Translations as Translations import Text.Pandoc.Walk import qualified Text.Pandoc.Builder as B +import qualified Data.Text.Normalize as Normalize -- for debugging: -- import Text.Pandoc.Extensions (getDefaultExtensions) @@ -589,308 +590,18 @@ keyval = try $ do keyvals :: PandocMonad m => LP m [(String, String)] keyvals = try $ symbol '[' >> manyTill keyval (symbol ']') -accent :: PandocMonad m => Char -> (Char -> String) -> LP m Inlines -accent c f = try $ do +accent :: PandocMonad m => Char -> Maybe Char -> LP m Inlines +accent combiningAccent fallBack = try $ do ils <- tok case toList ils of (Str (x:xs) : ys) -> return $ fromList $ - case f x of - [z] | z == x -> Str ([z,c] ++ xs) : ys -- combining accent - zs -> Str (zs ++ xs) : ys - [Space] -> return $ str [c] - [] -> return $ str [c] + -- try to normalize to the combined character: + Str (T.unpack + (Normalize.normalize Normalize.NFC + (T.pack [x, combiningAccent])) ++ xs) : ys + [Space] -> return $ str [fromMaybe combiningAccent fallBack] + [] -> return $ str [fromMaybe combiningAccent fallBack] _ -> return ils - -grave :: Char -> String -grave 'A' = "À" -grave 'E' = "È" -grave 'I' = "Ì" -grave 'O' = "Ò" -grave 'U' = "Ù" -grave 'a' = "à" -grave 'e' = "è" -grave 'i' = "ì" -grave 'o' = "ò" -grave 'u' = "ù" -grave c = [c] - -acute :: Char -> String -acute 'A' = "Á" -acute 'E' = "É" -acute 'I' = "Í" -acute 'O' = "Ó" -acute 'U' = "Ú" -acute 'Y' = "Ý" -acute 'a' = "á" -acute 'e' = "é" -acute 'i' = "í" -acute 'o' = "ó" -acute 'u' = "ú" -acute 'y' = "ý" -acute 'C' = "Ć" -acute 'c' = "ć" -acute 'L' = "Ĺ" -acute 'l' = "ĺ" -acute 'N' = "Ń" -acute 'n' = "ń" -acute 'R' = "Ŕ" -acute 'r' = "ŕ" -acute 'S' = "Ś" -acute 's' = "ś" -acute 'Z' = "Ź" -acute 'z' = "ź" -acute c = [c] - -circ :: Char -> String -circ 'A' = "Â" -circ 'E' = "Ê" -circ 'I' = "Î" -circ 'O' = "Ô" -circ 'U' = "Û" -circ 'a' = "â" -circ 'e' = "ê" -circ 'i' = "î" -circ 'o' = "ô" -circ 'u' = "û" -circ 'C' = "Ĉ" -circ 'c' = "ĉ" -circ 'G' = "Ĝ" -circ 'g' = "ĝ" -circ 'H' = "Ĥ" -circ 'h' = "ĥ" -circ 'J' = "Ĵ" -circ 'j' = "ĵ" -circ 'S' = "Ŝ" -circ 's' = "ŝ" -circ 'W' = "Ŵ" -circ 'w' = "ŵ" -circ 'Y' = "Ŷ" -circ 'y' = "ŷ" -circ c = [c] - -tilde :: Char -> String -tilde 'A' = "Ã" -tilde 'a' = "ã" -tilde 'O' = "Õ" -tilde 'o' = "õ" -tilde 'I' = "Ĩ" -tilde 'i' = "ĩ" -tilde 'U' = "Ũ" -tilde 'u' = "ũ" -tilde 'N' = "Ñ" -tilde 'n' = "ñ" -tilde c = [c] - -umlaut :: Char -> String -umlaut 'A' = "Ä" -umlaut 'E' = "Ë" -umlaut 'I' = "Ï" -umlaut 'O' = "Ö" -umlaut 'U' = "Ü" -umlaut 'a' = "ä" -umlaut 'e' = "ë" -umlaut 'i' = "ï" -umlaut 'o' = "ö" -umlaut 'u' = "ü" -umlaut c = [c] - -hungarumlaut :: Char -> String -hungarumlaut 'A' = "A̋" -hungarumlaut 'E' = "E̋" -hungarumlaut 'I' = "I̋" -hungarumlaut 'O' = "Ő" -hungarumlaut 'U' = "Ű" -hungarumlaut 'Y' = "ӳ" -hungarumlaut 'a' = "a̋" -hungarumlaut 'e' = "e̋" -hungarumlaut 'i' = "i̋" -hungarumlaut 'o' = "ő" -hungarumlaut 'u' = "ű" -hungarumlaut 'y' = "ӳ" -hungarumlaut c = [c] - -dot :: Char -> String -dot 'C' = "Ċ" -dot 'c' = "ċ" -dot 'E' = "Ė" -dot 'e' = "ė" -dot 'G' = "Ġ" -dot 'g' = "ġ" -dot 'I' = "İ" -dot 'Z' = "Ż" -dot 'z' = "ż" -dot c = [c] - -macron :: Char -> String -macron 'A' = "Ā" -macron 'E' = "Ē" -macron 'I' = "Ī" -macron 'O' = "Ō" -macron 'U' = "Ū" -macron 'a' = "ā" -macron 'e' = "ē" -macron 'i' = "ī" -macron 'o' = "ō" -macron 'u' = "ū" -macron c = [c] - -ringabove :: Char -> String -ringabove 'A' = "Å" -ringabove 'a' = "å" -ringabove 'U' = "Ů" -ringabove 'u' = "ů" -ringabove c = [c] - -dotbelow :: Char -> String -dotbelow 'B' = "Ḅ" -dotbelow 'b' = "ḅ" -dotbelow 'D' = "Ḍ" -dotbelow 'd' = "ḍ" -dotbelow 'H' = "Ḥ" -dotbelow 'h' = "ḥ" -dotbelow 'K' = "Ḳ" -dotbelow 'k' = "ḳ" -dotbelow 'L' = "Ḷ" -dotbelow 'l' = "ḷ" -dotbelow 'M' = "Ṃ" -dotbelow 'm' = "ṃ" -dotbelow 'N' = "Ṇ" -dotbelow 'n' = "ṇ" -dotbelow 'R' = "Ṛ" -dotbelow 'r' = "ṛ" -dotbelow 'S' = "Ṣ" -dotbelow 's' = "ṣ" -dotbelow 'T' = "Ṭ" -dotbelow 't' = "ṭ" -dotbelow 'V' = "Ṿ" -dotbelow 'v' = "ṿ" -dotbelow 'W' = "Ẉ" -dotbelow 'w' = "ẉ" -dotbelow 'Z' = "Ẓ" -dotbelow 'z' = "ẓ" -dotbelow 'A' = "Ạ" -dotbelow 'a' = "ạ" -dotbelow 'E' = "Ẹ" -dotbelow 'e' = "ẹ" -dotbelow 'I' = "Ị" -dotbelow 'i' = "ị" -dotbelow 'O' = "Ọ" -dotbelow 'o' = "ọ" -dotbelow 'U' = "Ụ" -dotbelow 'u' = "ụ" -dotbelow 'Y' = "Ỵ" -dotbelow 'y' = "ỵ" -dotbelow c = [c] - -doublegrave :: Char -> String -doublegrave 'A' = "Ȁ" -doublegrave 'a' = "ȁ" -doublegrave 'E' = "Ȅ" -doublegrave 'e' = "ȅ" -doublegrave 'I' = "Ȉ" -doublegrave 'i' = "ȉ" -doublegrave 'O' = "Ȍ" -doublegrave 'o' = "ȍ" -doublegrave 'R' = "Ȑ" -doublegrave 'r' = "ȑ" -doublegrave 'U' = "Ȕ" -doublegrave 'u' = "ȕ" -doublegrave c = [c] - -hookabove :: Char -> String -hookabove 'A' = "Ả" -hookabove 'a' = "ả" -hookabove 'E' = "Ẻ" -hookabove 'e' = "ẻ" -hookabove 'I' = "Ỉ" -hookabove 'i' = "ỉ" -hookabove 'O' = "Ỏ" -hookabove 'o' = "ỏ" -hookabove 'U' = "Ủ" -hookabove 'u' = "ủ" -hookabove 'Y' = "Ỷ" -hookabove 'y' = "ỷ" -hookabove c = [c] - -cedilla :: Char -> String -cedilla 'c' = "ç" -cedilla 'C' = "Ç" -cedilla 's' = "ş" -cedilla 'S' = "Ş" -cedilla 't' = "ţ" -cedilla 'T' = "Ţ" -cedilla 'e' = "ȩ" -cedilla 'E' = "Ȩ" -cedilla 'h' = "ḩ" -cedilla 'H' = "Ḩ" -cedilla 'o' = "o̧" -cedilla 'O' = "O̧" -cedilla c = [c] - -hacek :: Char -> String -hacek 'A' = "Ǎ" -hacek 'a' = "ǎ" -hacek 'C' = "Č" -hacek 'c' = "č" -hacek 'D' = "Ď" -hacek 'd' = "ď" -hacek 'E' = "Ě" -hacek 'e' = "ě" -hacek 'G' = "Ǧ" -hacek 'g' = "ǧ" -hacek 'H' = "Ȟ" -hacek 'h' = "ȟ" -hacek 'I' = "Ǐ" -hacek 'i' = "ǐ" -hacek 'j' = "ǰ" -hacek 'K' = "Ǩ" -hacek 'k' = "ǩ" -hacek 'L' = "Ľ" -hacek 'l' = "ľ" -hacek 'N' = "Ň" -hacek 'n' = "ň" -hacek 'O' = "Ǒ" -hacek 'o' = "ǒ" -hacek 'R' = "Ř" -hacek 'r' = "ř" -hacek 'S' = "Š" -hacek 's' = "š" -hacek 'T' = "Ť" -hacek 't' = "ť" -hacek 'U' = "Ǔ" -hacek 'u' = "ǔ" -hacek 'Z' = "Ž" -hacek 'z' = "ž" -hacek c = [c] - -ogonek :: Char -> String -ogonek 'a' = "ą" -ogonek 'e' = "ę" -ogonek 'o' = "ǫ" -ogonek 'i' = "į" -ogonek 'u' = "ų" -ogonek 'A' = "Ą" -ogonek 'E' = "Ę" -ogonek 'I' = "Į" -ogonek 'O' = "Ǫ" -ogonek 'U' = "Ų" -ogonek c = [c] - -breve :: Char -> String -breve 'A' = "Ă" -breve 'a' = "ă" -breve 'E' = "Ĕ" -breve 'e' = "ĕ" -breve 'G' = "Ğ" -breve 'g' = "ğ" -breve 'I' = "Ĭ" -breve 'i' = "ĭ" -breve 'O' = "Ŏ" -breve 'o' = "ŏ" -breve 'U' = "Ŭ" -breve 'u' = "ŭ" -breve c = [c] - mathDisplay :: String -> Inlines mathDisplay = displayMath . trim @@ -1228,32 +939,32 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList , ("copyright", lit "©") , ("textasciicircum", lit "^") , ("textasciitilde", lit "~") - , ("H", accent '\779' hungarumlaut) - , ("`", accent '`' grave) - , ("'", accent '\'' acute) - , ("^", accent '^' circ) - , ("~", accent '~' tilde) - , ("\"", accent '\776' umlaut) - , (".", accent '\775' dot) - , ("=", accent '\772' macron) - , ("|", accent '\781' (:[])) -- vertical line above - , ("b", accent '\817' (:[])) -- macron below - , ("c", accent '\807' cedilla) - , ("G", accent '\783' doublegrave) - , ("h", accent '\777' hookabove) - , ("d", accent '\803' dotbelow) - , ("f", accent '\785' (:[])) -- inverted breve - , ("r", accent '\778' ringabove) - , ("t", accent '\865' (:[])) -- double inverted breve - , ("U", accent '\782' (:[])) -- double vertical line above - , ("v", accent 'ˇ' hacek) - , ("u", accent '\774' breve) - , ("k", accent '\808' ogonek) - , ("textogonekcentered", accent '\808' ogonek) + , ("H", accent '\779' Nothing) -- hungarumlaut + , ("`", accent '\768' (Just '`')) -- grave + , ("'", accent '\769' (Just '\'')) -- acute + , ("^", accent '\770' (Just '^')) -- circ + , ("~", accent '\771' (Just '~')) -- tilde + , ("\"", accent '\776' Nothing) -- umlaut + , (".", accent '\775' Nothing) -- dot + , ("=", accent '\772' Nothing) -- macron + , ("|", accent '\781' Nothing) -- vertical line above + , ("b", accent '\817' Nothing) -- macron below + , ("c", accent '\807' Nothing) -- cedilla + , ("G", accent '\783' Nothing) -- doublegrave + , ("h", accent '\777' Nothing) -- hookabove + , ("d", accent '\803' Nothing) -- dotbelow + , ("f", accent '\785' Nothing) -- inverted breve + , ("r", accent '\778' Nothing) -- ringabove + , ("t", accent '\865' Nothing) -- double inverted breve + , ("U", accent '\782' Nothing) -- double vertical line above + , ("v", accent '\780' Nothing) -- hacek + , ("u", accent '\774' Nothing) -- breve + , ("k", accent '\808' Nothing) -- ogonek + , ("textogonekcentered", accent '\808' Nothing) -- ogonek , ("i", lit "ı") -- dotless i , ("j", lit "ȷ") -- dotless j - , ("newtie", accent '\785' (:[])) -- inverted breve - , ("textcircled", accent '\8413' (:[])) -- combining circle + , ("newtie", accent '\785' Nothing) -- inverted breve + , ("textcircled", accent '\8413' Nothing) -- combining circle , ("\\", linebreak <$ (do inTableCell <- sInTableCell <$> getState guard $ not inTableCell optional opt -- cgit v1.2.3 From 0a8d212a097267cafc4cd5a64691b8e85aadb5c3 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 30 Sep 2018 21:09:06 -0700 Subject: Text.Pandoc.Options: add writerPreferAscii to WriterOptions. [API change] --- src/Text/Pandoc/Options.hs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs index e5ca1764c..204060d70 100644 --- a/src/Text/Pandoc/Options.hs +++ b/src/Text/Pandoc/Options.hs @@ -194,6 +194,7 @@ data WriterOptions = WriterOptions , writerReferenceDoc :: Maybe FilePath -- ^ Path to reference document if specified , writerReferenceLocation :: ReferenceLocation -- ^ Location of footnotes and references for writing markdown , writerSyntaxMap :: SyntaxMap + , writerPreferAscii :: Bool -- ^ Prefer ASCII representations of characters when possible } deriving (Show, Data, Typeable, Generic) instance Default WriterOptions where @@ -228,6 +229,7 @@ instance Default WriterOptions where , writerReferenceDoc = Nothing , writerReferenceLocation = EndOfDocument , writerSyntaxMap = defaultSyntaxMap + , writerPreferAscii = False } instance HasSyntaxExtensions WriterOptions where -- cgit v1.2.3 From 36f1846cc3130dbe4168789cc03f916ebf5828c8 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 30 Sep 2018 22:32:00 -0700 Subject: Implement `--ascii` (`writerPreferAscii`) in writers, not App. Now the `write*` functions for Docbook, HTML, ICML, JATS, Man, Ms, OPML are sensitive to `writerPreferAscii`. Previously the to-ascii translation was done in Text.Pandoc.App, and thus not available to those using the writer functions directly. In addition, the LaTeX writer is now sensitive to `writerPreferAscii` and to `--ascii`. 100% ASCII output can't be guaranteed, but the writer will use commands like `\"{a}` and `\l` whenever possible, to avoid emiting a non-ASCII character. A new unexported module, Text.Pandoc.Groff, has been added to store functions used in the different groff-based writers. --- MANUAL.txt | 6 +- pandoc.cabal | 1 + src/Text/Pandoc/App.hs | 25 ++----- src/Text/Pandoc/Groff.hs | 43 +++++++++++ src/Text/Pandoc/Writers/Docbook.hs | 7 +- src/Text/Pandoc/Writers/HTML.hs | 18 +++-- src/Text/Pandoc/Writers/ICML.hs | 3 +- src/Text/Pandoc/Writers/JATS.hs | 3 +- src/Text/Pandoc/Writers/LaTeX.hs | 144 +++++++++++++++++++++++++++---------- src/Text/Pandoc/Writers/Man.hs | 4 +- src/Text/Pandoc/Writers/Ms.hs | 4 +- src/Text/Pandoc/Writers/OPML.hs | 3 +- test/command/ascii.md | 45 ++++++++++++ 13 files changed, 230 insertions(+), 76 deletions(-) create mode 100644 src/Text/Pandoc/Groff.hs create mode 100644 test/command/ascii.md (limited to 'src/Text/Pandoc') diff --git a/MANUAL.txt b/MANUAL.txt index 351929e92..802ce556e 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -860,8 +860,10 @@ Options affecting specific writers {.options} : Use only ASCII characters in output. Currently supported for XML and HTML formats (which use numerical entities instead of - UTF-8 when this option is selected) and for groff ms and man - (which use hexadecimal escapes). + UTF-8 when this option is selected), groff ms and man + (which use hexadecimal escapes), and to a limited degree + for LaTeX (which uses standard commands for accented + characters when possible). `--reference-links` diff --git a/pandoc.cabal b/pandoc.cabal index 1c227b5a1..cf3590681 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -540,6 +540,7 @@ library Text.Pandoc.Lua.Packages, Text.Pandoc.Lua.StackInstances, Text.Pandoc.Lua.Util, + Text.Pandoc.Groff Text.Pandoc.CSS, Text.Pandoc.CSV, Text.Pandoc.UUID, diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs index cb1db4f89..79d83c0d3 100644 --- a/src/Text/Pandoc/App.hs +++ b/src/Text/Pandoc/App.hs @@ -52,7 +52,7 @@ import Data.Aeson (defaultOptions) import Data.Aeson.TH (deriveJSON) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as B -import Data.Char (toLower, toUpper, isAscii, ord) +import Data.Char (toLower, toUpper) import Data.List (find, intercalate, isPrefixOf, isSuffixOf, sort) import qualified Data.Map as M import Data.Maybe (fromMaybe, isJust, isNothing) @@ -95,7 +95,6 @@ import Text.Pandoc.Shared (eastAsianLineBreakFilter, stripEmptyParagraphs, headerShift, isURI, ordNub, safeRead, tabFilter, uriPathToPath) import qualified Text.Pandoc.UTF8 as UTF8 import Text.Pandoc.Writers.Math (defaultKaTeXURL, defaultMathJaxURL) -import Text.Pandoc.XML (toEntities) import Text.Printf #ifndef _WINDOWS import System.Posix.IO (stdOutput) @@ -443,6 +442,7 @@ convertWithOpts opts = do , writerTOCDepth = optTOCDepth opts , writerReferenceDoc = optReferenceDoc opts , writerSyntaxMap = syntaxMap + , writerPreferAscii = optAscii opts } let readerOpts = def{ @@ -519,19 +519,10 @@ convertWithOpts opts = do let htmlFormat = format `elem` ["html","html4","html5","s5","slidy", "slideous","dzslides","revealjs"] - escape - | optAscii opts - , htmlFormat || format == "docbook4" || - format == "docbook5" || format == "docbook" || - format == "jats" || format == "opml" || - format == "icml" = toEntities - | optAscii opts - , format == "ms" || format == "man" = groffEscape - | otherwise = id addNl = if standalone then id else (<> T.singleton '\n') - output <- (addNl . escape) <$> f writerOptions doc + output <- addNl <$> f writerOptions doc writerFn eol outputFile =<< if optSelfContained opts && htmlFormat -- TODO not maximally efficient; change type @@ -539,12 +530,6 @@ convertWithOpts opts = do then T.pack <$> makeSelfContained (T.unpack output) else return output -groffEscape :: Text -> Text -groffEscape = T.concatMap toUchar - where toUchar c - | isAscii c = T.singleton c - | otherwise = T.pack $ printf "\\[u%04X]" (ord c) - type Transform = Pandoc -> Pandoc isTextFormat :: String -> Bool @@ -606,7 +591,7 @@ data Opt = Opt , optPdfEngineArgs :: [String] -- ^ Flags to pass to the engine , optSlideLevel :: Maybe Int -- ^ Header level that creates slides , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2 - , optAscii :: Bool -- ^ Use ascii characters only in html + , optAscii :: Bool -- ^ Prefer ascii output , optDefaultImageExtension :: String -- ^ Default image extension , optExtractMedia :: Maybe FilePath -- ^ Path to extract embedded media , optTrackChanges :: TrackChanges -- ^ Accept or reject MS Word track-changes. @@ -1173,7 +1158,7 @@ options = , Option "" ["ascii"] (NoArg (\opt -> return opt { optAscii = True })) - "" -- "Use ascii characters only in HTML output" + "" -- "Prefer ASCII output" , Option "" ["reference-links"] (NoArg diff --git a/src/Text/Pandoc/Groff.hs b/src/Text/Pandoc/Groff.hs new file mode 100644 index 000000000..46acc8fa8 --- /dev/null +++ b/src/Text/Pandoc/Groff.hs @@ -0,0 +1,43 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{- +Copyright (C) 2018 John MacFarlane + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-} + +{- | + Module : Text.Pandoc.Groff + Copyright : Copyright (C) 2018 John MacFarlane + License : GNU GPL, version 2 or above + + Maintainer : John MacFarlane + Stability : alpha + Portability : portable + +Shared functions for escaping and formatting groff. +-} +module Text.Pandoc.Groff ( groffEscape ) +where + +import Prelude +import Data.Char (isAscii, ord) +import qualified Data.Text as T +import Text.Printf (printf) + +groffEscape :: T.Text -> T.Text +groffEscape = T.concatMap toUchar + where toUchar c + | isAscii c = T.singleton c + | otherwise = T.pack $ printf "\\[u%04X]" (ord c) diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs index f6e814095..3306e4f31 100644 --- a/src/Text/Pandoc/Writers/Docbook.hs +++ b/src/Text/Pandoc/Writers/Docbook.hs @@ -126,9 +126,10 @@ writeDocbook opts (Pandoc meta blocks) = do defField "mathml" (case writerHTMLMathMethod opts of MathML -> True _ -> False) metadata - case writerTemplate opts of - Nothing -> return main - Just tpl -> renderTemplate' tpl context + (if writerPreferAscii opts then toEntities else id) <$> + case writerTemplate opts of + Nothing -> return main + Just tpl -> renderTemplate' tpl context -- | Convert an Element to Docbook. elementToDocbook :: PandocMonad m => WriterOptions -> Int -> Element -> DB m Doc diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index c7f25197f..19ec4692e 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -75,7 +75,7 @@ import Text.Pandoc.Templates import Text.Pandoc.Walk import Text.Pandoc.Writers.Math import Text.Pandoc.Writers.Shared -import Text.Pandoc.XML (escapeStringForXML, fromEntities) +import Text.Pandoc.XML (escapeStringForXML, fromEntities, toEntities) #if MIN_VERSION_blaze_markup(0,6,3) #else import Text.Blaze.Internal (preEscapedString, preEscapedText) @@ -206,7 +206,8 @@ writeHtmlString' :: PandocMonad m => WriterState -> WriterOptions -> Pandoc -> m Text writeHtmlString' st opts d = do (body, context) <- evalStateT (pandocToHtml opts d) st - case writerTemplate opts of + (if writerPreferAscii opts then toEntities else id) <$> + case writerTemplate opts of Nothing -> return $ renderHtml' body Just tpl -> do -- warn if empty lang @@ -221,16 +222,19 @@ writeHtmlString' st opts d = do lookup "sourcefile" (writerVariables opts) report $ NoTitleElement fallback return $ resetField "pagetitle" fallback context - renderTemplate' tpl $ - defField "body" (renderHtml' body) context' + renderTemplate' tpl + (defField "body" (renderHtml' body) context') writeHtml' :: PandocMonad m => WriterState -> WriterOptions -> Pandoc -> m Html writeHtml' st opts d = case writerTemplate opts of Just _ -> preEscapedText <$> writeHtmlString' st opts d - Nothing -> do - (body, _) <- evalStateT (pandocToHtml opts d) st - return body + Nothing + | writerPreferAscii opts + -> preEscapedText <$> writeHtmlString' st opts d + | otherwise -> do + (body, _) <- evalStateT (pandocToHtml opts d) st + return body -- result is (title, authors, date, toc, body, new variables) pandocToHtml :: PandocMonad m diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs index b8fc0dc94..ef1e2af0a 100644 --- a/src/Text/Pandoc/Writers/ICML.hs +++ b/src/Text/Pandoc/Writers/ICML.hs @@ -149,7 +149,8 @@ writeICML opts (Pandoc meta blocks) = do $ defField "charStyles" (render' $ charStylesToDoc st) $ defField "parStyles" (render' $ parStylesToDoc st) $ defField "hyperlinks" (render' $ hyperlinksToDoc $ links st) metadata - case writerTemplate opts of + (if writerPreferAscii opts then toEntities else id) <$> + case writerTemplate opts of Nothing -> return main Just tpl -> renderTemplate' tpl context diff --git a/src/Text/Pandoc/Writers/JATS.hs b/src/Text/Pandoc/Writers/JATS.hs index f55a49d4e..4e78a4cce 100644 --- a/src/Text/Pandoc/Writers/JATS.hs +++ b/src/Text/Pandoc/Writers/JATS.hs @@ -102,7 +102,8 @@ docToJATS opts (Pandoc meta blocks) = do $ defField "mathml" (case writerHTMLMathMethod opts of MathML -> True _ -> False) metadata - case writerTemplate opts of + (if writerPreferAscii opts then toEntities else id) <$> + case writerTemplate opts of Nothing -> return main Just tpl -> renderTemplate' tpl context diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs index 7be3fce28..c1b5d0fa4 100644 --- a/src/Text/Pandoc/Writers/LaTeX.hs +++ b/src/Text/Pandoc/Writers/LaTeX.hs @@ -42,8 +42,9 @@ import Data.Aeson (FromJSON, object, (.=)) import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isPunctuation, ord, toLower) import Data.List (foldl', intercalate, intersperse, isInfixOf, nubBy, - stripPrefix, (\\)) + stripPrefix, (\\), uncons) import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe, isNothing) +import qualified Data.Map as M import Data.Text (Text) import qualified Data.Text as T import Network.URI (unEscapeString) @@ -63,6 +64,7 @@ import Text.Pandoc.Walk import Text.Pandoc.Writers.Shared import qualified Text.Parsec as P import Text.Printf (printf) +import qualified Data.Text.Normalize as Normalize data WriterState = WriterState { stInNote :: Bool -- true if we're in a note @@ -318,46 +320,110 @@ data StringContext = TextString -- escape things as needed for LaTeX stringToLaTeX :: PandocMonad m => StringContext -> String -> LW m String -stringToLaTeX _ [] = return "" -stringToLaTeX ctx (x:xs) = do +stringToLaTeX context zs = do opts <- gets stOptions - rest <- stringToLaTeX ctx xs - let ligatures = isEnabled Ext_smart opts && ctx == TextString - let isUrl = ctx == URLString - return $ + go opts context $ + if writerPreferAscii opts + then T.unpack $ Normalize.normalize Normalize.NFD $ T.pack zs + else zs + where + go _ _ [] = return "" + go opts ctx (x:xs) = do + let ligatures = isEnabled Ext_smart opts && ctx == TextString + let isUrl = ctx == URLString + let mbAccentCmd = + if writerPreferAscii opts && ctx == TextString + then uncons xs >>= \(c,_) -> M.lookup c accents + else Nothing + let emits s = + case mbAccentCmd of + Just cmd -> ((cmd ++ "{" ++ s ++ "}") ++) + <$> go opts ctx (drop 1 xs) -- drop combining accent + Nothing -> (s++) <$> go opts ctx xs + let emitc c = + case mbAccentCmd of + Just cmd -> ((cmd ++ "{" ++ [c] ++ "}") ++) + <$> go opts ctx (drop 1 xs) -- drop combining accent + Nothing -> (c:) <$> go opts ctx xs case x of - '{' -> "\\{" ++ rest - '}' -> "\\}" ++ rest - '`' | ctx == CodeString -> "\\textasciigrave{}" ++ rest - '$' | not isUrl -> "\\$" ++ rest - '%' -> "\\%" ++ rest - '&' -> "\\&" ++ rest - '_' | not isUrl -> "\\_" ++ rest - '#' -> "\\#" ++ rest - '-' | not isUrl -> case xs of - -- prevent adjacent hyphens from forming ligatures - ('-':_) -> "-\\/" ++ rest - _ -> '-' : rest - '~' | not isUrl -> "\\textasciitilde{}" ++ rest - '^' -> "\\^{}" ++ rest - '\\'| isUrl -> '/' : rest -- NB. / works as path sep even on Windows - | otherwise -> "\\textbackslash{}" ++ rest - '|' | not isUrl -> "\\textbar{}" ++ rest - '<' -> "\\textless{}" ++ rest - '>' -> "\\textgreater{}" ++ rest - '[' -> "{[}" ++ rest -- to avoid interpretation as - ']' -> "{]}" ++ rest -- optional arguments - '\'' | ctx == CodeString -> "\\textquotesingle{}" ++ rest - '\160' -> "~" ++ rest - '\x202F' -> "\\," ++ rest - '\x2026' -> "\\ldots{}" ++ rest - '\x2018' | ligatures -> "`" ++ rest - '\x2019' | ligatures -> "'" ++ rest - '\x201C' | ligatures -> "``" ++ rest - '\x201D' | ligatures -> "''" ++ rest - '\x2014' | ligatures -> "---" ++ rest - '\x2013' | ligatures -> "--" ++ rest - _ -> x : rest + '{' -> emits "\\{" + '}' -> emits "\\}" + '`' | ctx == CodeString -> emits "\\textasciigrave{}" + '$' | not isUrl -> emits "\\$" + '%' -> emits "\\%" + '&' -> emits "\\&" + '_' | not isUrl -> emits "\\_" + '#' -> emits "\\#" + '-' | not isUrl -> case xs of + -- prevent adjacent hyphens from forming ligatures + ('-':_) -> emits "-\\/" + _ -> emitc '-' + '~' | not isUrl -> emits "\\textasciitilde{}" + '^' -> emits "\\^{}" + '\\'| isUrl -> emitc '/' -- NB. / works as path sep even on Windows + | otherwise -> emits "\\textbackslash{}" + '|' | not isUrl -> emits "\\textbar{}" + '<' -> emits "\\textless{}" + '>' -> emits "\\textgreater{}" + '[' -> emits "{[}" -- to avoid interpretation as + ']' -> emits "{]}" -- optional arguments + '\'' | ctx == CodeString -> emits "\\textquotesingle{}" + '\160' -> emits "~" + '\x202F' -> emits "\\," + '\x2026' -> emits "\\ldots{}" + '\x2018' | ligatures -> emits "`" + '\x2019' | ligatures -> emits "'" + '\x201C' | ligatures -> emits "``" + '\x201D' | ligatures -> emits "''" + '\x2014' | ligatures -> emits "---" + '\x2013' | ligatures -> emits "--" + _ | writerPreferAscii opts + -> case x of + 'ı' -> emits "\\i " + 'ȷ' -> emits "\\j " + 'å' -> emits "\\aa " + 'Å' -> emits "\\AA " + 'ß' -> emits "\\ss " + 'ø' -> emits "\\o " + 'Ø' -> emits "\\O " + 'Ł' -> emits "\\L " + 'ł' -> emits "\\l " + 'æ' -> emits "\\ae " + 'Æ' -> emits "\\AE " + 'œ' -> emits "\\oe " + 'Œ' -> emits "\\OE " + '£' -> emits "\\pounds " + '€' -> emits "\\euro " + '©' -> emits "\\copyright " + _ -> emitc x + | otherwise -> emitc x + +accents :: M.Map Char String +accents = M.fromList + [ ('\779' , "\\H") + , ('\768' , "\\`") + , ('\769' , "\\'") + , ('\770' , "\\^") + , ('\771' , "\\~") + , ('\776' , "\\\"") + , ('\775' , "\\.") + , ('\772' , "\\=") + , ('\781' , "\\|") + , ('\817' , "\\b") + , ('\807' , "\\c") + , ('\783' , "\\G") + , ('\777' , "\\h") + , ('\803' , "\\d") + , ('\785' , "\\f") + , ('\778' , "\\r") + , ('\865' , "\\t") + , ('\782' , "\\U") + , ('\780' , "\\v") + , ('\774' , "\\u") + , ('\808' , "\\k") + , ('\785' , "\\newtie") + , ('\8413', "\\textcircled") + ] toLabel :: PandocMonad m => String -> LW m String toLabel z = go `fmap` stringToLaTeX URLString z diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs index be490bf22..b6b72d07f 100644 --- a/src/Text/Pandoc/Writers/Man.hs +++ b/src/Text/Pandoc/Writers/Man.hs @@ -45,6 +45,7 @@ import Text.Pandoc.Logging import Text.Pandoc.Options import Text.Pandoc.Pretty import Text.Pandoc.Shared +import Text.Pandoc.Groff (groffEscape) import Text.Pandoc.Templates import Text.Pandoc.Writers.Math import Text.Pandoc.Writers.Shared @@ -107,7 +108,8 @@ pandocToMan opts (Pandoc meta blocks) = do $ defField "has-tables" hasTables $ defField "hyphenate" True $ defField "pandoc-version" pandocVersion metadata - case writerTemplate opts of + (if writerPreferAscii opts then groffEscape else id) <$> + case writerTemplate opts of Nothing -> return main Just tpl -> renderTemplate' tpl context diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs index 3dcf816b8..a29524bbb 100644 --- a/src/Text/Pandoc/Writers/Ms.hs +++ b/src/Text/Pandoc/Writers/Ms.hs @@ -60,6 +60,7 @@ import Text.Pandoc.Shared import Text.Pandoc.Templates import Text.Pandoc.Writers.Math import Text.Pandoc.Writers.Shared +import Text.Pandoc.Groff (groffEscape) import Text.Printf (printf) import Text.TeXMath (writeEqn) @@ -127,7 +128,8 @@ pandocToMs opts (Pandoc meta blocks) = do $ defField "title-meta" titleMeta $ defField "author-meta" (intercalate "; " authorsMeta) $ defField "highlighting-macros" highlightingMacros metadata - case writerTemplate opts of + (if writerPreferAscii opts then groffEscape else id) <$> + case writerTemplate opts of Nothing -> return main Just tpl -> renderTemplate' tpl context diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs index 6c48046a2..716c5cbad 100644 --- a/src/Text/Pandoc/Writers/OPML.hs +++ b/src/Text/Pandoc/Writers/OPML.hs @@ -62,7 +62,8 @@ writeOPML opts (Pandoc meta blocks) = do meta' main <- (render colwidth . vcat) <$> mapM (elementToOPML opts) elements let context = defField "body" main metadata - case writerTemplate opts of + (if writerPreferAscii opts then toEntities else id) <$> + case writerTemplate opts of Nothing -> return main Just tpl -> renderTemplate' tpl context diff --git a/test/command/ascii.md b/test/command/ascii.md new file mode 100644 index 000000000..523baa46c --- /dev/null +++ b/test/command/ascii.md @@ -0,0 +1,45 @@ +``` +pandoc -t html --ascii +äéıå +^D +

    äéıå

    +``` + +``` +pandoc -t latex --ascii +äéıå +^D +\"{a}\'{e}\i \r{a} +``` + +``` +pandoc -t man --ascii +äéıå +^D +.PP +\[u00E4]\[u00E9]\[u0131]\[u00E5] +``` + +``` +pandoc -t ms --ascii +äéıå +^D +.LP +\[u00E4]\[u00E9]\[u0131]\[u00E5] +``` + +``` +pandoc -t docbook --ascii +äéıå +^D + + äéıå + +``` + +``` +pandoc -t jats --ascii +äéıå +^D +

    äéıå

    +``` -- cgit v1.2.3 From 1ffe47b9b9d1bdd204046adfcfb1496195ffa383 Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Mon, 1 Oct 2018 11:09:34 +0200 Subject: Lua Util: add missing docstring to defineHowTo --- src/Text/Pandoc/Lua/Util.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Lua/Util.hs b/src/Text/Pandoc/Lua/Util.hs index 46e11da24..89db9520d 100644 --- a/src/Text/Pandoc/Lua/Util.hs +++ b/src/Text/Pandoc/Lua/Util.hs @@ -134,6 +134,6 @@ throwTopMessageAsError' modifier = do Lua.pop 2 -- remove error and error string pushed by tostring' Lua.throwException (modifier (UTF8.toString msg)) - +-- | Mark the context of a Lua computation for better error reporting. defineHowTo :: String -> Lua a -> Lua a defineHowTo ctx = Lua.withExceptionMessage (("Could not " <> ctx <> ": ") <>) -- cgit v1.2.3 From 9abdbb2783d246c736f05119390e81084f9ab07c Mon Sep 17 00:00:00 2001 From: Albert Krewinkel Date: Mon, 1 Oct 2018 16:10:46 +0200 Subject: Lua filters: report traceback when an error occurs A proper Lua traceback is added if either loading of a file or execution of a filter function fails. This should be of help to authors of Lua filters who need to debug their code. --- pandoc.cabal | 2 +- src/Text/Pandoc/Lua.hs | 3 ++- src/Text/Pandoc/Lua/Filter.hs | 9 ++++----- src/Text/Pandoc/Lua/Util.hs | 38 ++++++++++++++++++++++++++++++++++++-- src/Text/Pandoc/Writers/Custom.hs | 4 ++-- stack.lts10.yaml | 3 +-- stack.lts11.yaml | 2 +- stack.lts9.yaml | 2 +- stack.yaml | 2 +- 9 files changed, 49 insertions(+), 16 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index cf3590681..888a0570b 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -372,7 +372,7 @@ library blaze-html >= 0.9 && < 0.10, blaze-markup >= 0.8 && < 0.9, vector >= 0.10 && < 0.13, - hslua >= 1.0 && < 1.1, + hslua >= 1.0.1 && < 1.1, hslua-module-text >= 0.2 && < 0.3, binary >= 0.5 && < 0.10, SHA >= 1.6 && < 1.7, diff --git a/src/Text/Pandoc/Lua.hs b/src/Text/Pandoc/Lua.hs index c4e5791b6..e160f7123 100644 --- a/src/Text/Pandoc/Lua.hs +++ b/src/Text/Pandoc/Lua.hs @@ -39,6 +39,7 @@ import Text.Pandoc.Class (PandocIO) import Text.Pandoc.Definition (Pandoc) import Text.Pandoc.Lua.Filter (LuaFilter, walkMWithLuaFilter) import Text.Pandoc.Lua.Init (LuaException (..), runPandocLua, registerScriptPath) +import Text.Pandoc.Lua.Util (dofileWithTraceback) import Text.Pandoc.Options (ReaderOptions) import qualified Foreign.Lua as Lua @@ -58,7 +59,7 @@ runLuaFilter' ropts filterPath format pd = do registerReaderOptions registerScriptPath filterPath top <- Lua.gettop - stat <- Lua.dofile filterPath + stat <- dofileWithTraceback filterPath if stat /= Lua.OK then Lua.throwTopMessage else do diff --git a/src/Text/Pandoc/Lua/Filter.hs b/src/Text/Pandoc/Lua/Filter.hs index 9b5f5f40a..d17f9a969 100644 --- a/src/Text/Pandoc/Lua/Filter.hs +++ b/src/Text/Pandoc/Lua/Filter.hs @@ -52,6 +52,7 @@ import Text.Pandoc.Walk (walkM, Walkable) import qualified Data.Map.Strict as Map import qualified Foreign.Lua as Lua +import qualified Text.Pandoc.Lua.Util as LuaUtil -- | Filter function stored in the registry newtype LuaFilterFunction = LuaFilterFunction Lua.Reference @@ -118,11 +119,9 @@ tryFilter (LuaFilter fnMap) x = -- element is left unchanged. runFilterFunction :: Pushable a => LuaFilterFunction -> a -> Lua () runFilterFunction lf x = do - let errorPrefix = "Error while running filter function:\n" - Lua.withExceptionMessage (errorPrefix <>) $ do - pushFilterFunction lf - Lua.push x - Lua.call 1 1 + pushFilterFunction lf + Lua.push x + LuaUtil.callWithTraceback 1 1 walkMWithLuaFilter :: LuaFilter -> Pandoc -> Lua Pandoc walkMWithLuaFilter f = diff --git a/src/Text/Pandoc/Lua/Util.hs b/src/Text/Pandoc/Lua/Util.hs index 89db9520d..77b27b88e 100644 --- a/src/Text/Pandoc/Lua/Util.hs +++ b/src/Text/Pandoc/Lua/Util.hs @@ -40,12 +40,14 @@ module Text.Pandoc.Lua.Util , loadScriptFromDataDir , defineHowTo , throwTopMessageAsError' + , callWithTraceback + , dofileWithTraceback ) where import Prelude import Control.Monad (unless, when) -import Foreign.Lua ( Lua, NumArgs, Peekable, Pushable, StackIndex - , ToHaskellFunction ) +import Foreign.Lua ( Lua, NumArgs, NumResults, Peekable, Pushable, StackIndex + , Status, ToHaskellFunction ) import Text.Pandoc.Class (readDataFile, runIOorExplode, setUserDataDir) import qualified Foreign.Lua as Lua @@ -137,3 +139,35 @@ throwTopMessageAsError' modifier = do -- | Mark the context of a Lua computation for better error reporting. defineHowTo :: String -> Lua a -> Lua a defineHowTo ctx = Lua.withExceptionMessage (("Could not " <> ctx <> ": ") <>) + +-- | Like @'Lua.pcall'@, but uses a predefined error handler which adds a +-- traceback on error. +pcallWithTraceback :: NumArgs -> NumResults -> Lua Status +pcallWithTraceback nargs nresults = do + let traceback' :: Lua NumResults + traceback' = do + l <- Lua.state + msg <- Lua.tostring' (Lua.nthFromBottom 1) + Lua.traceback l (Just (UTF8.toString msg)) 2 + return 1 + tracebackIdx <- Lua.absindex (Lua.nthFromTop (Lua.fromNumArgs nargs + 1)) + Lua.pushHaskellFunction traceback' + Lua.insert tracebackIdx + result <- Lua.pcall nargs nresults (Just tracebackIdx) + Lua.remove tracebackIdx + return result + +-- | Like @'Lua.call'@, but adds a traceback to the error message (if any). +callWithTraceback :: NumArgs -> NumResults -> Lua () +callWithTraceback nargs nresults = do + result <- pcallWithTraceback nargs nresults + when (result /= Lua.OK) Lua.throwTopMessage + +-- | Run the given string as a Lua program, while also adding a traceback to the +-- error message if an error occurs. +dofileWithTraceback :: FilePath -> Lua Status +dofileWithTraceback fp = do + loadRes <- Lua.loadfile fp + case loadRes of + Lua.OK -> pcallWithTraceback 0 Lua.multret + _ -> return loadRes diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs index 1d1261baf..37fec9f0f 100644 --- a/src/Text/Pandoc/Writers/Custom.hs +++ b/src/Text/Pandoc/Writers/Custom.hs @@ -47,7 +47,7 @@ import Text.Pandoc.Error import Text.Pandoc.Lua.Init (LuaException (LuaException), runPandocLua, registerScriptPath) import Text.Pandoc.Lua.StackInstances () -import Text.Pandoc.Lua.Util (addField) +import Text.Pandoc.Lua.Util (addField, dofileWithTraceback) import Text.Pandoc.Options import Text.Pandoc.Templates import qualified Text.Pandoc.UTF8 as UTF8 @@ -111,7 +111,7 @@ writeCustom :: FilePath -> WriterOptions -> Pandoc -> PandocIO Text writeCustom luaFile opts doc@(Pandoc meta _) = do res <- runPandocLua $ do registerScriptPath luaFile - stat <- Lua.dofile luaFile + stat <- dofileWithTraceback luaFile -- check for error in lua script (later we'll change the return type -- to handle this more gracefully): when (stat /= Lua.OK) $ diff --git a/stack.lts10.yaml b/stack.lts10.yaml index 8ae75405b..76fc3b921 100644 --- a/stack.lts10.yaml +++ b/stack.lts10.yaml @@ -19,13 +19,12 @@ extra-deps: - test-framework-0.8.2.0 - pandoc-types-1.17.5.1 - cmark-gfm-0.1.3 -- hslua-module-text-0.1.2.1 - texmath-0.11.1 - haddock-library-1.6.0 - HsYAML-0.1.1.1 - text-1.2.3.0 - hs-bibutils-6.6.0.0 -- hslua-1.0.0 +- hslua-1.0.1 - hslua-module-text-0.2.0 ghc-options: "$locals": -fhide-source-paths -XNoImplicitPrelude diff --git a/stack.lts11.yaml b/stack.lts11.yaml index 57a183552..afacb655f 100644 --- a/stack.lts11.yaml +++ b/stack.lts11.yaml @@ -20,7 +20,7 @@ extra-deps: - HsYAML-0.1.1.1 - hs-bibutils-6.6.0.0 - yaml-0.9.0 -- hslua-1.0.0 +- hslua-1.0.1 - hslua-module-text-0.2.0 ghc-options: "$locals": -fhide-source-paths -XNoImplicitPrelude diff --git a/stack.lts9.yaml b/stack.lts9.yaml index c09b318a0..b12cd57dc 100644 --- a/stack.lts9.yaml +++ b/stack.lts9.yaml @@ -12,7 +12,7 @@ packages: - '.' extra-deps: - pandoc-citeproc-0.14.4 -- hslua-1.0.0 +- hslua-1.0.1 - hslua-module-text-0.2.0 - ansi-terminal-0.8.0.2 - cmark-gfm-0.1.3 diff --git a/stack.yaml b/stack.yaml index 36c5ee105..986cae642 100644 --- a/stack.yaml +++ b/stack.yaml @@ -24,7 +24,7 @@ extra-deps: - HsYAML-0.1.1.1 - texmath-0.11.1 - yaml-0.9.0 -- hslua-1.0.0 +- hslua-1.0.1 - hslua-module-text-0.2.0 ghc-options: "$locals": -fhide-source-paths -XNoImplicitPrelude -- cgit v1.2.3 From 799cd5db7a52573fff305a88196c4e7fd8dd0567 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 1 Oct 2018 21:27:20 -0700 Subject: Moved babelLangToBCP, polyglossiaLangToBCP to new module... Text.Pandoc.Readers.LaTeX.Lang (unexported). --- pandoc.cabal | 1 + src/Text/Pandoc/Readers/LaTeX.hs | 136 +------------------------- src/Text/Pandoc/Readers/LaTeX/Lang.hs | 173 ++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 134 deletions(-) create mode 100644 src/Text/Pandoc/Readers/LaTeX/Lang.hs (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index 888a0570b..2a34d5680 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -510,6 +510,7 @@ library Text.Pandoc.Readers.Docx.StyleMap, Text.Pandoc.Readers.Docx.Fields, Text.Pandoc.Readers.LaTeX.Parsing, + Text.Pandoc.Readers.LaTeX.Lang, Text.Pandoc.Readers.Odt.Base, Text.Pandoc.Readers.Odt.Namespaces, Text.Pandoc.Readers.Odt.StyleReader, diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 1af82246e..816fa35de 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -72,6 +72,8 @@ import Text.Pandoc.Parsing hiding (blankline, many, mathDisplay, mathInline, import Text.Pandoc.Readers.LaTeX.Types (ExpansionPoint (..), Macro (..), ArgSpec (..), Tok (..), TokType (..)) import Text.Pandoc.Readers.LaTeX.Parsing +import Text.Pandoc.Readers.LaTeX.Lang (polyglossiaLangToBCP47, + babelLangToBCP47) import Text.Pandoc.Shared import qualified Text.Pandoc.Translations as Translations import Text.Pandoc.Walk @@ -2265,137 +2267,3 @@ setDefaultLanguage = do setTranslations l updateState $ setMeta "lang" $ str (renderLang l) return mempty - -polyglossiaLangToBCP47 :: M.Map String (String -> Lang) -polyglossiaLangToBCP47 = M.fromList - [ ("arabic", \o -> case filter (/=' ') o of - "locale=algeria" -> Lang "ar" "" "DZ" [] - "locale=mashriq" -> Lang "ar" "" "SY" [] - "locale=libya" -> Lang "ar" "" "LY" [] - "locale=morocco" -> Lang "ar" "" "MA" [] - "locale=mauritania" -> Lang "ar" "" "MR" [] - "locale=tunisia" -> Lang "ar" "" "TN" [] - _ -> Lang "ar" "" "" []) - , ("german", \o -> case filter (/=' ') o of - "spelling=old" -> Lang "de" "" "DE" ["1901"] - "variant=austrian,spelling=old" - -> Lang "de" "" "AT" ["1901"] - "variant=austrian" -> Lang "de" "" "AT" [] - "variant=swiss,spelling=old" - -> Lang "de" "" "CH" ["1901"] - "variant=swiss" -> Lang "de" "" "CH" [] - _ -> Lang "de" "" "" []) - , ("lsorbian", \_ -> Lang "dsb" "" "" []) - , ("greek", \o -> case filter (/=' ') o of - "variant=poly" -> Lang "el" "" "polyton" [] - "variant=ancient" -> Lang "grc" "" "" [] - _ -> Lang "el" "" "" []) - , ("english", \o -> case filter (/=' ') o of - "variant=australian" -> Lang "en" "" "AU" [] - "variant=canadian" -> Lang "en" "" "CA" [] - "variant=british" -> Lang "en" "" "GB" [] - "variant=newzealand" -> Lang "en" "" "NZ" [] - "variant=american" -> Lang "en" "" "US" [] - _ -> Lang "en" "" "" []) - , ("usorbian", \_ -> Lang "hsb" "" "" []) - , ("latin", \o -> case filter (/=' ') o of - "variant=classic" -> Lang "la" "" "" ["x-classic"] - _ -> Lang "la" "" "" []) - , ("slovenian", \_ -> Lang "sl" "" "" []) - , ("serbianc", \_ -> Lang "sr" "cyrl" "" []) - , ("pinyin", \_ -> Lang "zh" "Latn" "" ["pinyin"]) - , ("afrikaans", \_ -> Lang "af" "" "" []) - , ("amharic", \_ -> Lang "am" "" "" []) - , ("assamese", \_ -> Lang "as" "" "" []) - , ("asturian", \_ -> Lang "ast" "" "" []) - , ("bulgarian", \_ -> Lang "bg" "" "" []) - , ("bengali", \_ -> Lang "bn" "" "" []) - , ("tibetan", \_ -> Lang "bo" "" "" []) - , ("breton", \_ -> Lang "br" "" "" []) - , ("catalan", \_ -> Lang "ca" "" "" []) - , ("welsh", \_ -> Lang "cy" "" "" []) - , ("czech", \_ -> Lang "cs" "" "" []) - , ("coptic", \_ -> Lang "cop" "" "" []) - , ("danish", \_ -> Lang "da" "" "" []) - , ("divehi", \_ -> Lang "dv" "" "" []) - , ("esperanto", \_ -> Lang "eo" "" "" []) - , ("spanish", \_ -> Lang "es" "" "" []) - , ("estonian", \_ -> Lang "et" "" "" []) - , ("basque", \_ -> Lang "eu" "" "" []) - , ("farsi", \_ -> Lang "fa" "" "" []) - , ("finnish", \_ -> Lang "fi" "" "" []) - , ("french", \_ -> Lang "fr" "" "" []) - , ("friulan", \_ -> Lang "fur" "" "" []) - , ("irish", \_ -> Lang "ga" "" "" []) - , ("scottish", \_ -> Lang "gd" "" "" []) - , ("ethiopic", \_ -> Lang "gez" "" "" []) - , ("galician", \_ -> Lang "gl" "" "" []) - , ("hebrew", \_ -> Lang "he" "" "" []) - , ("hindi", \_ -> Lang "hi" "" "" []) - , ("croatian", \_ -> Lang "hr" "" "" []) - , ("magyar", \_ -> Lang "hu" "" "" []) - , ("armenian", \_ -> Lang "hy" "" "" []) - , ("interlingua", \_ -> Lang "ia" "" "" []) - , ("indonesian", \_ -> Lang "id" "" "" []) - , ("icelandic", \_ -> Lang "is" "" "" []) - , ("italian", \_ -> Lang "it" "" "" []) - , ("japanese", \_ -> Lang "jp" "" "" []) - , ("khmer", \_ -> Lang "km" "" "" []) - , ("kurmanji", \_ -> Lang "kmr" "" "" []) - , ("kannada", \_ -> Lang "kn" "" "" []) - , ("korean", \_ -> Lang "ko" "" "" []) - , ("lao", \_ -> Lang "lo" "" "" []) - , ("lithuanian", \_ -> Lang "lt" "" "" []) - , ("latvian", \_ -> Lang "lv" "" "" []) - , ("malayalam", \_ -> Lang "ml" "" "" []) - , ("mongolian", \_ -> Lang "mn" "" "" []) - , ("marathi", \_ -> Lang "mr" "" "" []) - , ("dutch", \_ -> Lang "nl" "" "" []) - , ("nynorsk", \_ -> Lang "nn" "" "" []) - , ("norsk", \_ -> Lang "no" "" "" []) - , ("nko", \_ -> Lang "nqo" "" "" []) - , ("occitan", \_ -> Lang "oc" "" "" []) - , ("panjabi", \_ -> Lang "pa" "" "" []) - , ("polish", \_ -> Lang "pl" "" "" []) - , ("piedmontese", \_ -> Lang "pms" "" "" []) - , ("portuguese", \_ -> Lang "pt" "" "" []) - , ("romansh", \_ -> Lang "rm" "" "" []) - , ("romanian", \_ -> Lang "ro" "" "" []) - , ("russian", \_ -> Lang "ru" "" "" []) - , ("sanskrit", \_ -> Lang "sa" "" "" []) - , ("samin", \_ -> Lang "se" "" "" []) - , ("slovak", \_ -> Lang "sk" "" "" []) - , ("albanian", \_ -> Lang "sq" "" "" []) - , ("serbian", \_ -> Lang "sr" "" "" []) - , ("swedish", \_ -> Lang "sv" "" "" []) - , ("syriac", \_ -> Lang "syr" "" "" []) - , ("tamil", \_ -> Lang "ta" "" "" []) - , ("telugu", \_ -> Lang "te" "" "" []) - , ("thai", \_ -> Lang "th" "" "" []) - , ("turkmen", \_ -> Lang "tk" "" "" []) - , ("turkish", \_ -> Lang "tr" "" "" []) - , ("ukrainian", \_ -> Lang "uk" "" "" []) - , ("urdu", \_ -> Lang "ur" "" "" []) - , ("vietnamese", \_ -> Lang "vi" "" "" []) - ] - -babelLangToBCP47 :: String -> Maybe Lang -babelLangToBCP47 s = - case s of - "austrian" -> Just $ Lang "de" "" "AT" ["1901"] - "naustrian" -> Just $ Lang "de" "" "AT" [] - "swissgerman" -> Just $ Lang "de" "" "CH" ["1901"] - "nswissgerman" -> Just $ Lang "de" "" "CH" [] - "german" -> Just $ Lang "de" "" "DE" ["1901"] - "ngerman" -> Just $ Lang "de" "" "DE" [] - "lowersorbian" -> Just $ Lang "dsb" "" "" [] - "uppersorbian" -> Just $ Lang "hsb" "" "" [] - "polutonikogreek" -> Just $ Lang "el" "" "" ["polyton"] - "slovene" -> Just $ Lang "sl" "" "" [] - "australian" -> Just $ Lang "en" "" "AU" [] - "canadian" -> Just $ Lang "en" "" "CA" [] - "british" -> Just $ Lang "en" "" "GB" [] - "newzealand" -> Just $ Lang "en" "" "NZ" [] - "american" -> Just $ Lang "en" "" "US" [] - "classiclatin" -> Just $ Lang "la" "" "" ["x-classic"] - _ -> fmap ($ "") $ M.lookup s polyglossiaLangToBCP47 diff --git a/src/Text/Pandoc/Readers/LaTeX/Lang.hs b/src/Text/Pandoc/Readers/LaTeX/Lang.hs new file mode 100644 index 000000000..9b57c98fd --- /dev/null +++ b/src/Text/Pandoc/Readers/LaTeX/Lang.hs @@ -0,0 +1,173 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{- +Copyright (C) 2018 John MacFarlane + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-} + +{- | + Module : Text.Pandoc.Readers.LaTeX.Lang + Copyright : Copyright (C) 2018 John MacFarlane + License : GNU GPL, version 2 or above + + Maintainer : John MacFarlane + Stability : alpha + Portability : portable + +Functions for parsing polyglossia and babel language specifiers to +BCP47 'Lang'. +-} +module Text.Pandoc.Readers.LaTeX.Lang + ( polyglossiaLangToBCP47 + , babelLangToBCP47 + ) +where +import Prelude +import qualified Data.Map as M +import Text.Pandoc.BCP47 (Lang(..)) + +polyglossiaLangToBCP47 :: M.Map String (String -> Lang) +polyglossiaLangToBCP47 = M.fromList + [ ("arabic", \o -> case filter (/=' ') o of + "locale=algeria" -> Lang "ar" "" "DZ" [] + "locale=mashriq" -> Lang "ar" "" "SY" [] + "locale=libya" -> Lang "ar" "" "LY" [] + "locale=morocco" -> Lang "ar" "" "MA" [] + "locale=mauritania" -> Lang "ar" "" "MR" [] + "locale=tunisia" -> Lang "ar" "" "TN" [] + _ -> Lang "ar" "" "" []) + , ("german", \o -> case filter (/=' ') o of + "spelling=old" -> Lang "de" "" "DE" ["1901"] + "variant=austrian,spelling=old" + -> Lang "de" "" "AT" ["1901"] + "variant=austrian" -> Lang "de" "" "AT" [] + "variant=swiss,spelling=old" + -> Lang "de" "" "CH" ["1901"] + "variant=swiss" -> Lang "de" "" "CH" [] + _ -> Lang "de" "" "" []) + , ("lsorbian", \_ -> Lang "dsb" "" "" []) + , ("greek", \o -> case filter (/=' ') o of + "variant=poly" -> Lang "el" "" "polyton" [] + "variant=ancient" -> Lang "grc" "" "" [] + _ -> Lang "el" "" "" []) + , ("english", \o -> case filter (/=' ') o of + "variant=australian" -> Lang "en" "" "AU" [] + "variant=canadian" -> Lang "en" "" "CA" [] + "variant=british" -> Lang "en" "" "GB" [] + "variant=newzealand" -> Lang "en" "" "NZ" [] + "variant=american" -> Lang "en" "" "US" [] + _ -> Lang "en" "" "" []) + , ("usorbian", \_ -> Lang "hsb" "" "" []) + , ("latin", \o -> case filter (/=' ') o of + "variant=classic" -> Lang "la" "" "" ["x-classic"] + _ -> Lang "la" "" "" []) + , ("slovenian", \_ -> Lang "sl" "" "" []) + , ("serbianc", \_ -> Lang "sr" "cyrl" "" []) + , ("pinyin", \_ -> Lang "zh" "Latn" "" ["pinyin"]) + , ("afrikaans", \_ -> Lang "af" "" "" []) + , ("amharic", \_ -> Lang "am" "" "" []) + , ("assamese", \_ -> Lang "as" "" "" []) + , ("asturian", \_ -> Lang "ast" "" "" []) + , ("bulgarian", \_ -> Lang "bg" "" "" []) + , ("bengali", \_ -> Lang "bn" "" "" []) + , ("tibetan", \_ -> Lang "bo" "" "" []) + , ("breton", \_ -> Lang "br" "" "" []) + , ("catalan", \_ -> Lang "ca" "" "" []) + , ("welsh", \_ -> Lang "cy" "" "" []) + , ("czech", \_ -> Lang "cs" "" "" []) + , ("coptic", \_ -> Lang "cop" "" "" []) + , ("danish", \_ -> Lang "da" "" "" []) + , ("divehi", \_ -> Lang "dv" "" "" []) + , ("esperanto", \_ -> Lang "eo" "" "" []) + , ("spanish", \_ -> Lang "es" "" "" []) + , ("estonian", \_ -> Lang "et" "" "" []) + , ("basque", \_ -> Lang "eu" "" "" []) + , ("farsi", \_ -> Lang "fa" "" "" []) + , ("finnish", \_ -> Lang "fi" "" "" []) + , ("french", \_ -> Lang "fr" "" "" []) + , ("friulan", \_ -> Lang "fur" "" "" []) + , ("irish", \_ -> Lang "ga" "" "" []) + , ("scottish", \_ -> Lang "gd" "" "" []) + , ("ethiopic", \_ -> Lang "gez" "" "" []) + , ("galician", \_ -> Lang "gl" "" "" []) + , ("hebrew", \_ -> Lang "he" "" "" []) + , ("hindi", \_ -> Lang "hi" "" "" []) + , ("croatian", \_ -> Lang "hr" "" "" []) + , ("magyar", \_ -> Lang "hu" "" "" []) + , ("armenian", \_ -> Lang "hy" "" "" []) + , ("interlingua", \_ -> Lang "ia" "" "" []) + , ("indonesian", \_ -> Lang "id" "" "" []) + , ("icelandic", \_ -> Lang "is" "" "" []) + , ("italian", \_ -> Lang "it" "" "" []) + , ("japanese", \_ -> Lang "jp" "" "" []) + , ("khmer", \_ -> Lang "km" "" "" []) + , ("kurmanji", \_ -> Lang "kmr" "" "" []) + , ("kannada", \_ -> Lang "kn" "" "" []) + , ("korean", \_ -> Lang "ko" "" "" []) + , ("lao", \_ -> Lang "lo" "" "" []) + , ("lithuanian", \_ -> Lang "lt" "" "" []) + , ("latvian", \_ -> Lang "lv" "" "" []) + , ("malayalam", \_ -> Lang "ml" "" "" []) + , ("mongolian", \_ -> Lang "mn" "" "" []) + , ("marathi", \_ -> Lang "mr" "" "" []) + , ("dutch", \_ -> Lang "nl" "" "" []) + , ("nynorsk", \_ -> Lang "nn" "" "" []) + , ("norsk", \_ -> Lang "no" "" "" []) + , ("nko", \_ -> Lang "nqo" "" "" []) + , ("occitan", \_ -> Lang "oc" "" "" []) + , ("panjabi", \_ -> Lang "pa" "" "" []) + , ("polish", \_ -> Lang "pl" "" "" []) + , ("piedmontese", \_ -> Lang "pms" "" "" []) + , ("portuguese", \_ -> Lang "pt" "" "" []) + , ("romansh", \_ -> Lang "rm" "" "" []) + , ("romanian", \_ -> Lang "ro" "" "" []) + , ("russian", \_ -> Lang "ru" "" "" []) + , ("sanskrit", \_ -> Lang "sa" "" "" []) + , ("samin", \_ -> Lang "se" "" "" []) + , ("slovak", \_ -> Lang "sk" "" "" []) + , ("albanian", \_ -> Lang "sq" "" "" []) + , ("serbian", \_ -> Lang "sr" "" "" []) + , ("swedish", \_ -> Lang "sv" "" "" []) + , ("syriac", \_ -> Lang "syr" "" "" []) + , ("tamil", \_ -> Lang "ta" "" "" []) + , ("telugu", \_ -> Lang "te" "" "" []) + , ("thai", \_ -> Lang "th" "" "" []) + , ("turkmen", \_ -> Lang "tk" "" "" []) + , ("turkish", \_ -> Lang "tr" "" "" []) + , ("ukrainian", \_ -> Lang "uk" "" "" []) + , ("urdu", \_ -> Lang "ur" "" "" []) + , ("vietnamese", \_ -> Lang "vi" "" "" []) + ] + +babelLangToBCP47 :: String -> Maybe Lang +babelLangToBCP47 s = + case s of + "austrian" -> Just $ Lang "de" "" "AT" ["1901"] + "naustrian" -> Just $ Lang "de" "" "AT" [] + "swissgerman" -> Just $ Lang "de" "" "CH" ["1901"] + "nswissgerman" -> Just $ Lang "de" "" "CH" [] + "german" -> Just $ Lang "de" "" "DE" ["1901"] + "ngerman" -> Just $ Lang "de" "" "DE" [] + "lowersorbian" -> Just $ Lang "dsb" "" "" [] + "uppersorbian" -> Just $ Lang "hsb" "" "" [] + "polutonikogreek" -> Just $ Lang "el" "" "" ["polyton"] + "slovene" -> Just $ Lang "sl" "" "" [] + "australian" -> Just $ Lang "en" "" "AU" [] + "canadian" -> Just $ Lang "en" "" "CA" [] + "british" -> Just $ Lang "en" "" "GB" [] + "newzealand" -> Just $ Lang "en" "" "NZ" [] + "american" -> Just $ Lang "en" "" "US" [] + "classiclatin" -> Just $ Lang "la" "" "" ["x-classic"] + _ -> fmap ($ "") $ M.lookup s polyglossiaLangToBCP47 -- cgit v1.2.3 From 963ba931a6a4450242fc5dd19f37813f09939c4f Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 1 Oct 2018 22:09:45 -0700 Subject: Moved isArgTok to Readers.LaTeX.Parsing. --- src/Text/Pandoc/Readers/LaTeX.hs | 4 ---- src/Text/Pandoc/Readers/LaTeX/Parsing.hs | 7 ++++++- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs index 816fa35de..7c5619165 100644 --- a/src/Text/Pandoc/Readers/LaTeX.hs +++ b/src/Text/Pandoc/Readers/LaTeX.hs @@ -1533,10 +1533,6 @@ argspecPattern = (toktype' == Symbol || toktype' == Word) && (txt /= "{" && txt /= "\\" && txt /= "}"))) -isArgTok :: Tok -> Bool -isArgTok (Tok _ (Arg _) _) = True -isArgTok _ = False - newcommand :: PandocMonad m => LP m (Text, Macro) newcommand = do pos <- getPosition diff --git a/src/Text/Pandoc/Readers/LaTeX/Parsing.hs b/src/Text/Pandoc/Readers/LaTeX/Parsing.hs index 81d83dab2..9256217fe 100644 --- a/src/Text/Pandoc/Readers/LaTeX/Parsing.hs +++ b/src/Text/Pandoc/Readers/LaTeX/Parsing.hs @@ -52,8 +52,9 @@ module Text.Pandoc.Readers.LaTeX.Parsing , setpos , anyControlSeq , anySymbol - , isWordTok , isNewlineTok + , isWordTok + , isArgTok , spaces , spaces1 , tokTypeIn @@ -476,6 +477,10 @@ isWordTok :: Tok -> Bool isWordTok (Tok _ Word _) = True isWordTok _ = False +isArgTok :: Tok -> Bool +isArgTok (Tok _ (Arg _) _) = True +isArgTok _ = False + spaces :: PandocMonad m => LP m () spaces = skipMany (satisfyTok (tokTypeIn [Comment, Spaces, Newline])) -- cgit v1.2.3 From e25c7ce035e7af220d3715ab156eabd01f861e4e Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 1 Oct 2018 22:47:01 -0700 Subject: Shared: new export `splitSentences` [API change]. This was duplicated in the Man and Ms writers, and really belongs in Shared. --- src/Text/Pandoc/Shared.hs | 26 ++++++++++++++++++++++++++ src/Text/Pandoc/Writers/Man.hs | 26 -------------------------- src/Text/Pandoc/Writers/Ms.hs | 26 -------------------------- 3 files changed, 26 insertions(+), 52 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs index 412de99a0..9f48080b8 100644 --- a/src/Text/Pandoc/Shared.hs +++ b/src/Text/Pandoc/Shared.hs @@ -79,6 +79,7 @@ module Text.Pandoc.Shared ( makeMeta, eastAsianLineBreakFilter, underlineSpan, + splitSentences, -- * TagSoup HTML handling renderTags', -- * File handling @@ -582,6 +583,31 @@ eastAsianLineBreakFilter = bottomUp go underlineSpan :: Inlines -> Inlines underlineSpan = B.spanWith ("", ["underline"], []) +-- | Returns the first sentence in a list of inlines, and the rest. +breakSentence :: [Inline] -> ([Inline], [Inline]) +breakSentence [] = ([],[]) +breakSentence xs = + let isSentenceEndInline (Str ys@(_:_)) | last ys == '.' = True + isSentenceEndInline (Str ys@(_:_)) | last ys == '?' = True + isSentenceEndInline LineBreak = True + isSentenceEndInline _ = False + (as, bs) = break isSentenceEndInline xs + in case bs of + [] -> (as, []) + [c] -> (as ++ [c], []) + (c:Space:cs) -> (as ++ [c], cs) + (c:SoftBreak:cs) -> (as ++ [c], cs) + (Str ".":Str (')':ys):cs) -> (as ++ [Str ".", Str (')':ys)], cs) + (x@(Str ('.':')':_)):cs) -> (as ++ [x], cs) + (LineBreak:x@(Str ('.':_)):cs) -> (as ++[LineBreak], x:cs) + (c:cs) -> (as ++ [c] ++ ds, es) + where (ds, es) = breakSentence cs + +-- | Split a list of inlines into sentences. +splitSentences :: [Inline] -> [[Inline]] +splitSentences xs = + let (sent, rest) = breakSentence xs + in if null rest then [sent] else sent : splitSentences rest -- -- TagSoup HTML handling diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs index b6b72d07f..c37d13841 100644 --- a/src/Text/Pandoc/Writers/Man.hs +++ b/src/Text/Pandoc/Writers/Man.hs @@ -154,32 +154,6 @@ escapeCode = intercalate "\n" . map escapeLine . lines where -- line. groff/troff treats the line-ending period differently. -- See http://code.google.com/p/pandoc/issues/detail?id=148. --- | Returns the first sentence in a list of inlines, and the rest. -breakSentence :: [Inline] -> ([Inline], [Inline]) -breakSentence [] = ([],[]) -breakSentence xs = - let isSentenceEndInline (Str ys@(_:_)) | last ys == '.' = True - isSentenceEndInline (Str ys@(_:_)) | last ys == '?' = True - isSentenceEndInline LineBreak = True - isSentenceEndInline _ = False - (as, bs) = break isSentenceEndInline xs - in case bs of - [] -> (as, []) - [c] -> (as ++ [c], []) - (c:Space:cs) -> (as ++ [c], cs) - (c:SoftBreak:cs) -> (as ++ [c], cs) - (Str ".":Str (')':ys):cs) -> (as ++ [Str ".", Str (')':ys)], cs) - (x@(Str ('.':')':_)):cs) -> (as ++ [x], cs) - (LineBreak:x@(Str ('.':_)):cs) -> (as ++[LineBreak], x:cs) - (c:cs) -> (as ++ [c] ++ ds, es) - where (ds, es) = breakSentence cs - --- | Split a list of inlines into sentences. -splitSentences :: [Inline] -> [[Inline]] -splitSentences xs = - let (sent, rest) = breakSentence xs - in if null rest then [sent] else sent : splitSentences rest - -- | Convert Pandoc block element to man. blockToMan :: PandocMonad m => WriterOptions -- ^ Options diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs index a29524bbb..5eda77233 100644 --- a/src/Text/Pandoc/Writers/Ms.hs +++ b/src/Text/Pandoc/Writers/Ms.hs @@ -190,32 +190,6 @@ escapeCode = intercalate "\n" . map escapeLine . lines -- line. groff/troff treats the line-ending period differently. -- See http://code.google.com/p/pandoc/issues/detail?id=148. --- | Returns the first sentence in a list of inlines, and the rest. -breakSentence :: [Inline] -> ([Inline], [Inline]) -breakSentence [] = ([],[]) -breakSentence xs = - let isSentenceEndInline (Str ys@(_:_)) | last ys == '.' = True - isSentenceEndInline (Str ys@(_:_)) | last ys == '?' = True - isSentenceEndInline LineBreak = True - isSentenceEndInline _ = False - (as, bs) = break isSentenceEndInline xs - in case bs of - [] -> (as, []) - [c] -> (as ++ [c], []) - (c:Space:cs) -> (as ++ [c], cs) - (c:SoftBreak:cs) -> (as ++ [c], cs) - (Str ".":Str (')':ys):cs) -> (as ++ [Str ".", Str (')':ys)], cs) - (x@(Str ('.':')':_)):cs) -> (as ++ [x], cs) - (LineBreak:x@(Str ('.':_)):cs) -> (as ++[LineBreak], x:cs) - (c:cs) -> (as ++ [c] ++ ds, es) - where (ds, es) = breakSentence cs - --- | Split a list of inlines into sentences. -splitSentences :: [Inline] -> [[Inline]] -splitSentences xs = - let (sent, rest) = breakSentence xs - in if null rest then [sent] else sent : splitSentences rest - blockToMs :: PandocMonad m => WriterOptions -- ^ Options -> Block -- ^ Block element -- cgit v1.2.3 From 05146ac97c22d0480311b72397ec2ce1425b48ac Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 2 Oct 2018 00:09:48 -0700 Subject: T.P.Lua.StackInstances - moved pragmas to top of file. --- src/Text/Pandoc/Lua/StackInstances.hs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Lua/StackInstances.hs b/src/Text/Pandoc/Lua/StackInstances.hs index 220dfccfa..931b8c225 100644 --- a/src/Text/Pandoc/Lua/StackInstances.hs +++ b/src/Text/Pandoc/Lua/StackInstances.hs @@ -1,3 +1,8 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE LambdaCase #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} {- Copyright © 2012-2018 John MacFarlane 2017-2018 Albert Krewinkel @@ -16,11 +21,6 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} {- | Module : Text.Pandoc.Lua.StackInstances Copyright : © 2012-2018 John MacFarlane -- cgit v1.2.3 From f82d574d14c9ad71e76b8dfcbadac89ab4d10501 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 2 Oct 2018 10:11:32 -0700 Subject: OpenDocument writer: improve bullet/numbering alignment. This patch eliminates the large gap we used to have between bullet and text, and also ensures that numbers in numbered lists will be right-aligned. Closes #4385. --- src/Text/Pandoc/Writers/OpenDocument.hs | 16 +- test/writer.opendocument | 756 ++++++++++++++++++++++++-------- 2 files changed, 579 insertions(+), 193 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index 6f6f58ae6..cb29e390a 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -563,10 +563,18 @@ orderedListLevelStyle (s,n, d) (l,ls) = listLevelStyle :: Int -> Doc listLevelStyle i = - let indent = show (0.4 * fromIntegral (i - 1) :: Double) in - selfClosingTag "style:list-level-properties" - [ ("text:space-before" , indent ++ "in") - , ("text:min-label-width", "0.4in")] + let indent = show (0.5 * fromIntegral i :: Double) in + inTags True "style:list-level-properties" + [ ("text:list-level-position-and-space-mode", + "label-alignment") + , ("fo:text-align", "right") + ] $ + selfClosingTag "style:list-level-label-alignment" + [ ("text:label-followed-by", "listtab") + , ("text:list-tab-stop-position", indent ++ "in") + , ("fo:text-indent", "-0.1in") + , ("fo:margin-left", indent ++ "in") + ] tableStyle :: Int -> [(Char,Double)] -> Doc tableStyle num wcs = diff --git a/test/writer.opendocument b/test/writer.opendocument index 535130c0a..28c38ee1d 100644 --- a/test/writer.opendocument +++ b/test/writer.opendocument @@ -6,629 +6,1007 @@ - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + -- cgit v1.2.3 From d975917509061e4dfbeb4d2444f5ef7ccbe1887b Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Tue, 2 Oct 2018 18:16:43 -0700 Subject: Removed Text.Pandoc.Groff. Moved groffEscape function to Text.Pandoc.Writers.Shared. [API change, since T.P.W.S is exported.] --- pandoc.cabal | 1 - src/Text/Pandoc/Groff.hs | 43 --------------------------------------- src/Text/Pandoc/Writers/Man.hs | 1 - src/Text/Pandoc/Writers/Ms.hs | 1 - src/Text/Pandoc/Writers/Shared.hs | 11 ++++++++++ 5 files changed, 11 insertions(+), 46 deletions(-) delete mode 100644 src/Text/Pandoc/Groff.hs (limited to 'src/Text/Pandoc') diff --git a/pandoc.cabal b/pandoc.cabal index 4f7794dc4..58e8d6348 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -541,7 +541,6 @@ library Text.Pandoc.Lua.Packages, Text.Pandoc.Lua.StackInstances, Text.Pandoc.Lua.Util, - Text.Pandoc.Groff Text.Pandoc.CSS, Text.Pandoc.CSV, Text.Pandoc.UUID, diff --git a/src/Text/Pandoc/Groff.hs b/src/Text/Pandoc/Groff.hs deleted file mode 100644 index 46acc8fa8..000000000 --- a/src/Text/Pandoc/Groff.hs +++ /dev/null @@ -1,43 +0,0 @@ -{-# LANGUAGE NoImplicitPrelude #-} -{- -Copyright (C) 2018 John MacFarlane - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --} - -{- | - Module : Text.Pandoc.Groff - Copyright : Copyright (C) 2018 John MacFarlane - License : GNU GPL, version 2 or above - - Maintainer : John MacFarlane - Stability : alpha - Portability : portable - -Shared functions for escaping and formatting groff. --} -module Text.Pandoc.Groff ( groffEscape ) -where - -import Prelude -import Data.Char (isAscii, ord) -import qualified Data.Text as T -import Text.Printf (printf) - -groffEscape :: T.Text -> T.Text -groffEscape = T.concatMap toUchar - where toUchar c - | isAscii c = T.singleton c - | otherwise = T.pack $ printf "\\[u%04X]" (ord c) diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs index c37d13841..81fa38bd7 100644 --- a/src/Text/Pandoc/Writers/Man.hs +++ b/src/Text/Pandoc/Writers/Man.hs @@ -45,7 +45,6 @@ import Text.Pandoc.Logging import Text.Pandoc.Options import Text.Pandoc.Pretty import Text.Pandoc.Shared -import Text.Pandoc.Groff (groffEscape) import Text.Pandoc.Templates import Text.Pandoc.Writers.Math import Text.Pandoc.Writers.Shared diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs index 5eda77233..9a35a9693 100644 --- a/src/Text/Pandoc/Writers/Ms.hs +++ b/src/Text/Pandoc/Writers/Ms.hs @@ -60,7 +60,6 @@ import Text.Pandoc.Shared import Text.Pandoc.Templates import Text.Pandoc.Writers.Math import Text.Pandoc.Writers.Shared -import Text.Pandoc.Groff (groffEscape) import Text.Printf (printf) import Text.TeXMath (writeEqn) diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs index 438a35ca4..ccf39c3c8 100644 --- a/src/Text/Pandoc/Writers/Shared.hs +++ b/src/Text/Pandoc/Writers/Shared.hs @@ -44,6 +44,7 @@ module Text.Pandoc.Writers.Shared ( , gridTable , metaValueToInlines , stripLeadingTrailingSpace + , groffEscape ) where import Prelude @@ -63,6 +64,8 @@ import Text.Pandoc.Pretty import Text.Pandoc.Walk (query) import Text.Pandoc.UTF8 (toStringLazy) import Text.Pandoc.XML (escapeStringForXML) +import Text.Printf (printf) +import Data.Char (isAscii, ord) -- | Create JSON value for template from a 'Meta' and an association list -- of variables, specified at the command line or in the writer. @@ -340,3 +343,11 @@ metaValueToInlines (MetaInlines ils) = ils metaValueToInlines (MetaBlocks bs) = query return bs metaValueToInlines (MetaBool b) = [Str $ show b] metaValueToInlines _ = [] + +-- | Escape non-ASCII characters using groff \u[..] sequences. +groffEscape :: T.Text -> T.Text +groffEscape = T.concatMap toUchar + where toUchar c + | isAscii c = T.singleton c + | otherwise = T.pack $ printf "\\[u%04X]" (ord c) + -- cgit v1.2.3 From 05d52eb9bbaf6faf2ce52947e916a82d7f29275e Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Wed, 3 Oct 2018 19:42:08 +0300 Subject: TWiki reader: hlint --- src/Text/Pandoc/Readers/TWiki.hs | 111 ++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 61 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/TWiki.hs b/src/Text/Pandoc/Readers/TWiki.hs index 1f230ae7e..c3cfedcfb 100644 --- a/src/Text/Pandoc/Readers/TWiki.hs +++ b/src/Text/Pandoc/Readers/TWiki.hs @@ -74,9 +74,6 @@ type TWParser = ParserT [Char] ParserState tryMsg :: String -> TWParser m a -> TWParser m a tryMsg msg p = try p msg -skip :: TWParser m a -> TWParser m () -skip parser = parser >> return () - nested :: PandocMonad m => TWParser m a -> TWParser m a nested p = do nestlevel <- stateMaxNestingLevel <$> getState @@ -92,7 +89,7 @@ htmlElement tag = tryMsg tag $ do content <- manyTill anyChar (endtag <|> endofinput) return (htmlAttrToPandoc attr, trim content) where - endtag = skip $ htmlTag (~== TagClose tag) + endtag = void $ htmlTag (~== TagClose tag) endofinput = lookAhead $ try $ skipMany blankline >> skipSpaces >> eof trim = dropWhile (=='\n') . reverse . dropWhile (=='\n') . reverse @@ -114,18 +111,15 @@ parseHtmlContentWithAttrs tag parser = do endOfContent = try $ skipMany blankline >> skipSpaces >> eof parseHtmlContent :: PandocMonad m => String -> TWParser m a -> TWParser m [a] -parseHtmlContent tag p = parseHtmlContentWithAttrs tag p >>= return . snd +parseHtmlContent tag p = snd <$> parseHtmlContentWithAttrs tag p -- -- main parser -- parseTWiki :: PandocMonad m => TWParser m Pandoc -parseTWiki = do - bs <- mconcat <$> many block - spaces - eof - return $ B.doc bs +parseTWiki = + B.doc . mconcat <$> many block <* spaces <* eof -- @@ -158,7 +152,7 @@ separator = tryMsg "separator" $ string "---" >> newline >> return B.horizontalR header :: PandocMonad m => TWParser m B.Blocks header = tryMsg "header" $ do string "---" - level <- many1 (char '+') >>= return . length + level <- length <$> many1 (char '+') guard $ level <= 6 classes <- option [] $ string "!!" >> return ["unnumbered"] skipSpaces @@ -167,11 +161,10 @@ header = tryMsg "header" $ do return $ B.headerWith attr level content verbatim :: PandocMonad m => TWParser m B.Blocks -verbatim = (htmlElement "verbatim" <|> htmlElement "pre") - >>= return . (uncurry B.codeBlockWith) +verbatim = uncurry B.codeBlockWith <$> (htmlElement "verbatim" <|> htmlElement "pre") literal :: PandocMonad m => TWParser m B.Blocks -literal = htmlElement "literal" >>= return . rawBlock +literal = rawBlock <$> htmlElement "literal" where format (_, _, kvs) = fromMaybe "html" $ lookup "format" kvs rawBlock (attrs, content) = B.rawBlock (format attrs) content @@ -183,7 +176,7 @@ list prefix = choice [ bulletList prefix definitionList :: PandocMonad m => String -> TWParser m B.Blocks definitionList prefix = tryMsg "definitionList" $ do - indent <- lookAhead $ string prefix *> (many1 $ string " ") <* string "$ " + indent <- lookAhead $ string prefix *> many1 (string " ") <* string "$ " elements <- many $ parseDefinitionListItem (prefix ++ concat indent) return $ B.definitionList elements where @@ -193,7 +186,7 @@ definitionList prefix = tryMsg "definitionList" $ do string (indent ++ "$ ") >> skipSpaces term <- many1Till inline $ string ": " line <- listItemLine indent $ string "$ " - return $ (mconcat term, [line]) + return (mconcat term, [line]) bulletList :: PandocMonad m => String -> TWParser m B.Blocks bulletList prefix = tryMsg "bulletList" $ @@ -227,25 +220,24 @@ parseListItem prefix marker = string prefix >> marker >> listItemLine prefix mar listItemLine :: (PandocMonad m, Show a) => String -> TWParser m a -> TWParser m B.Blocks -listItemLine prefix marker = lineContent >>= parseContent >>= return . mconcat +listItemLine prefix marker = mconcat <$> (lineContent >>= parseContent) where lineContent = do content <- anyLine continuation <- optionMaybe listContinuation - return $ filterSpaces content ++ "\n" ++ (maybe "" (" " ++) continuation) + return $ filterSpaces content ++ "\n" ++ maybe "" (" " ++) continuation filterSpaces = reverse . dropWhile (== ' ') . reverse listContinuation = notFollowedBy (string prefix >> marker) >> string " " >> lineContent parseContent = parseFromString' $ many1 $ nestedList <|> parseInline - parseInline = many1Till inline (lastNewline <|> newlineBeforeNestedList) >>= - return . B.plain . mconcat + parseInline = (B.plain . mconcat) <$> many1Till inline (lastNewline <|> newlineBeforeNestedList) nestedList = list prefix lastNewline = try $ char '\n' <* eof newlineBeforeNestedList = try $ char '\n' <* lookAhead nestedList table :: PandocMonad m => TWParser m B.Blocks table = try $ do - tableHead <- optionMaybe $ many1Till tableParseHeader newline >>= return . unzip + tableHead <- optionMaybe (unzip <$> many1Till tableParseHeader newline) rows <- many1 tableParseRow return $ buildTable mempty rows $ fromMaybe (align rows, columns rows) tableHead where @@ -258,11 +250,11 @@ table = try $ do tableParseHeader :: PandocMonad m => TWParser m ((Alignment, Double), B.Blocks) tableParseHeader = try $ do char '|' - leftSpaces <- many spaceChar >>= return . length + leftSpaces <- length <$> many spaceChar char '*' content <- tableColumnContent (char '*' >> skipSpaces >> char '|') char '*' - rightSpaces <- many spaceChar >>= return . length + rightSpaces <- length <$> many spaceChar optional tableEndOfRow return (tableAlign leftSpaces rightSpaces, content) where @@ -283,13 +275,13 @@ tableEndOfRow :: PandocMonad m => TWParser m Char tableEndOfRow = lookAhead (try $ char '|' >> char '\n') >> char '|' tableColumnContent :: PandocMonad m => TWParser m a -> TWParser m B.Blocks -tableColumnContent end = manyTill content (lookAhead $ try end) >>= return . B.plain . mconcat +tableColumnContent end = (B.plain . mconcat) <$> manyTill content (lookAhead $ try end) where content = continuation <|> inline continuation = try $ char '\\' >> newline >> return mempty blockQuote :: PandocMonad m => TWParser m B.Blocks -blockQuote = parseHtmlContent "blockquote" block >>= return . B.blockQuote . mconcat +blockQuote = (B.blockQuote . mconcat) <$> parseHtmlContent "blockquote" block noautolink :: PandocMonad m => TWParser m B.Blocks noautolink = do @@ -300,15 +292,15 @@ noautolink = do setState $ st{ stateAllowLinks = True } return $ mconcat blocks where - parseContent = parseFromString' $ many $ block + parseContent = parseFromString' $ many block para :: PandocMonad m => TWParser m B.Blocks -para = many1Till inline endOfParaElement >>= return . result . mconcat +para = (result . mconcat) <$> many1Till inline endOfParaElement where endOfParaElement = lookAhead $ endOfInput <|> endOfPara <|> newBlockElement endOfInput = try $ skipMany blankline >> skipSpaces >> eof endOfPara = try $ blankline >> skipMany1 blankline - newBlockElement = try $ blankline >> skip blockElements + newBlockElement = try $ blankline >> void blockElements result content = if F.all (==Space) content then mempty else B.para $ B.trimInlines content @@ -340,7 +332,7 @@ inline = choice [ whitespace ] "inline" whitespace :: PandocMonad m => TWParser m B.Inlines -whitespace = (lb <|> regsp) >>= return +whitespace = lb <|> regsp where lb = try $ skipMany spaceChar >> linebreak >> return B.space regsp = try $ skipMany1 spaceChar >> return B.space @@ -362,13 +354,13 @@ enclosed :: (Monoid b, PandocMonad m, Show a) => TWParser m a -> (TWParser m a -> TWParser m b) -> TWParser m b enclosed sep p = between sep (try $ sep <* endMarker) p where - endMarker = lookAhead $ skip endSpace <|> skip (oneOf ".,!?:)|") <|> eof + endMarker = lookAhead $ void endSpace <|> void (oneOf ".,!?:)|") <|> eof endSpace = (spaceChar <|> newline) >> return B.space macro :: PandocMonad m => TWParser m B.Inlines macro = macroWithParameters <|> withoutParameters where - withoutParameters = enclosed (char '%') (\_ -> macroName) >>= return . emptySpan + withoutParameters = emptySpan <$> enclosed (char '%') (const macroName) emptySpan name = buildSpan name [] mempty macroWithParameters :: PandocMonad m => TWParser m B.Inlines @@ -393,13 +385,13 @@ macroName = do return (first:rest) attributes :: PandocMonad m => TWParser m (String, [(String, String)]) -attributes = char '{' *> spnl *> many (attribute <* spnl) <* char '}' >>= - return . foldr (either mkContent mkKvs) ([], []) +attributes = foldr (either mkContent mkKvs) ([], []) + <$> (char '{' *> spnl *> many (attribute <* spnl) <* char '}') where spnl = skipMany (spaceChar <|> newline) mkContent c ([], kvs) = (c, kvs) mkContent c (rest, kvs) = (c ++ " " ++ rest, kvs) - mkKvs kv (cont, rest) = (cont, (kv : rest)) + mkKvs kv (cont, rest) = (cont, kv : rest) attribute :: PandocMonad m => TWParser m (Either String (String, String)) attribute = withKey <|> withoutKey @@ -407,52 +399,50 @@ attribute = withKey <|> withoutKey withKey = try $ do key <- macroName char '=' - parseValue False >>= return . (curry Right key) - withoutKey = try $ parseValue True >>= return . Left - parseValue allowSpaces = (withQuotes <|> withoutQuotes allowSpaces) >>= return . fromEntities + curry Right key <$> parseValue False + withoutKey = try $ Left <$> parseValue True + parseValue allowSpaces = fromEntities <$> (withQuotes <|> withoutQuotes allowSpaces) withQuotes = between (char '"') (char '"') (\_ -> count 1 $ noneOf ['"']) withoutQuotes allowSpaces - | allowSpaces == True = many1 $ noneOf "}" - | otherwise = many1 $ noneOf " }" + | allowSpaces = many1 $ noneOf "}" + | otherwise = many1 $ noneOf " }" nestedInlines :: (Show a, PandocMonad m) => TWParser m a -> TWParser m B.Inlines nestedInlines end = innerSpace <|> nestedInline where - innerSpace = try $ whitespace <* (notFollowedBy end) + innerSpace = try $ whitespace <* notFollowedBy end nestedInline = notFollowedBy whitespace >> nested inline strong :: PandocMonad m => TWParser m B.Inlines -strong = try $ enclosed (char '*') nestedInlines >>= return . B.strong +strong = try $ B.strong <$> enclosed (char '*') nestedInlines strongHtml :: PandocMonad m => TWParser m B.Inlines -strongHtml = (parseHtmlContent "strong" inline <|> parseHtmlContent "b" inline) - >>= return . B.strong . mconcat +strongHtml = B.strong . mconcat <$> (parseHtmlContent "strong" inline <|> parseHtmlContent "b" inline) strongAndEmph :: PandocMonad m => TWParser m B.Inlines -strongAndEmph = try $ enclosed (string "__") nestedInlines >>= return . B.emph . B.strong +strongAndEmph = try $ B.emph . B.strong <$> enclosed (string "__") nestedInlines emph :: PandocMonad m => TWParser m B.Inlines -emph = try $ enclosed (char '_') nestedInlines >>= return . B.emph +emph = try $ B.emph <$> enclosed (char '_') nestedInlines emphHtml :: PandocMonad m => TWParser m B.Inlines -emphHtml = (parseHtmlContent "em" inline <|> parseHtmlContent "i" inline) - >>= return . B.emph . mconcat +emphHtml = B.emph . mconcat <$> (parseHtmlContent "em" inline <|> parseHtmlContent "i" inline) nestedString :: (Show a, PandocMonad m) => TWParser m a -> TWParser m String -nestedString end = innerSpace <|> (count 1 nonspaceChar) +nestedString end = innerSpace <|> count 1 nonspaceChar where innerSpace = try $ many1 spaceChar <* notFollowedBy end boldCode :: PandocMonad m => TWParser m B.Inlines -boldCode = try $ enclosed (string "==") nestedString >>= return . B.strong . B.code . fromEntities +boldCode = try $ (B.strong . B.code . fromEntities) <$> enclosed (string "==") nestedString htmlComment :: PandocMonad m => TWParser m B.Inlines htmlComment = htmlTag isCommentTag >> return mempty code :: PandocMonad m => TWParser m B.Inlines -code = try $ enclosed (char '=') nestedString >>= return . B.code . fromEntities +code = try $ (B.code . fromEntities) <$> enclosed (char '=') nestedString codeHtml :: PandocMonad m => TWParser m B.Inlines codeHtml = do @@ -464,7 +454,7 @@ autoLink = try $ do state <- getState guard $ stateAllowLinks state (text, url) <- parseLink - guard $ checkLink (head $ reverse url) + guard $ checkLink (last url) return $ makeLink (text, url) where parseLink = notFollowedBy nop >> (uri <|> emailAddress) @@ -474,17 +464,17 @@ autoLink = try $ do | otherwise = isAlphaNum c str :: PandocMonad m => TWParser m B.Inlines -str = (many1 alphaNum <|> count 1 characterReference) >>= return . B.str +str = B.str <$> (many1 alphaNum <|> count 1 characterReference) nop :: PandocMonad m => TWParser m B.Inlines -nop = try $ (skip exclamation <|> skip nopTag) >> followContent +nop = try $ (void exclamation <|> void nopTag) >> followContent where exclamation = char '!' nopTag = stringAnyCase "" - followContent = many1 nonspaceChar >>= return . B.str . fromEntities + followContent = B.str . fromEntities <$> many1 nonspaceChar symbol :: PandocMonad m => TWParser m B.Inlines -symbol = count 1 nonspaceChar >>= return . B.str +symbol = B.str <$> count 1 nonspaceChar smart :: PandocMonad m => TWParser m B.Inlines smart = do @@ -498,17 +488,16 @@ smart = do singleQuoted :: PandocMonad m => TWParser m B.Inlines singleQuoted = try $ do singleQuoteStart - withQuoteContext InSingleQuote $ - many1Till inline singleQuoteEnd >>= - (return . B.singleQuoted . B.trimInlines . mconcat) + withQuoteContext InSingleQuote + (B.singleQuoted . B.trimInlines . mconcat <$> many1Till inline singleQuoteEnd) doubleQuoted :: PandocMonad m => TWParser m B.Inlines doubleQuoted = try $ do doubleQuoteStart contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline) - (withQuoteContext InDoubleQuote $ doubleQuoteEnd >> + withQuoteContext InDoubleQuote (doubleQuoteEnd >> return (B.doubleQuoted $ B.trimInlines contents)) - <|> (return $ (B.str "\8220") B.<> contents) + <|> return (B.str "\8220" B.<> contents) link :: PandocMonad m => TWParser m B.Inlines link = try $ do @@ -527,5 +516,5 @@ linkText = do char ']' return (url, "", content) where - linkContent = (char '[') >> many1Till anyChar (char ']') >>= parseLinkContent + linkContent = char '[' >> many1Till anyChar (char ']') >>= parseLinkContent parseLinkContent = parseFromString' $ many1 inline -- cgit v1.2.3 From ecd4d5b8d8cfda6a2cd8d8fb631e0d7c79bee363 Mon Sep 17 00:00:00 2001 From: Nils Carlson Date: Wed, 3 Oct 2018 21:21:46 +0000 Subject: OpenDocument writer: Implement figure numbering in captions (#4944) Figure captions are now numbered 1, 2, 3, ... The format in the caption is "Figure 1: " and so on. This is necessary in order for libreoffice to generate an Illustration Index (Table of Figures) for included figures. --- src/Text/Pandoc/Writers/OpenDocument.hs | 14 +++++++++++++- test/writer.opendocument | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index cb29e390a..cd907bbea 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -411,10 +411,22 @@ blockToOpenDocument o bs figure attr caption source title | null caption = withParagraphStyle o "Figure" [Para [Image attr caption (source,title)]] | otherwise = do + id' <- gets stImageId imageDoc <- withParagraphStyle o "FigureWithCaption" [Para [Image attr caption (source,title)]] - captionDoc <- withParagraphStyle o "FigureCaption" [Para caption] + captionDoc <- numberedFigureCaption id' <$> inlinesToOpenDocument o caption return $ imageDoc $$ captionDoc +numberedFigureCaption :: Int -> Doc -> Doc +numberedFigureCaption num caption = + let t = text "Figure " + r = num - 1 + s = inTags False "text:sequence" [ ("text:ref-name", "refIllustration" ++ show r), + ("text:name", "Illustration"), + ("text:formula", "ooow:Illustration+1"), + ("style:num-format", "1") ] $ text $ show num + c = text ": " + in inParagraphTagsWithStyle "FigureCaption" $ hcat [ t, s, c, caption ] + colHeadsToOpenDocument :: PandocMonad m => WriterOptions -> [String] -> [[Block]] -> OD m Doc diff --git a/test/writer.opendocument b/test/writer.opendocument index 28c38ee1d..09a246b52 100644 --- a/test/writer.opendocument +++ b/test/writer.opendocument @@ -1880,7 +1880,7 @@ link in pointy braces. From “Voyage dans la Lune” by Georges Melies (1902): -lalune +Figure 1: lalune Here is a movie icon. -- cgit v1.2.3 From d7263a7e5fb1ba53465099c6f1be7a85e05564f8 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 3 Oct 2018 17:36:32 -0700 Subject: Text.Pandoc.Writers.Shared: added `metaValueToString`. [API change] --- src/Text/Pandoc/Writers/Shared.hs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs index ccf39c3c8..6113b0a66 100644 --- a/src/Text/Pandoc/Writers/Shared.hs +++ b/src/Text/Pandoc/Writers/Shared.hs @@ -43,6 +43,7 @@ module Text.Pandoc.Writers.Shared ( , unsmartify , gridTable , metaValueToInlines + , metaValueToString , stripLeadingTrailingSpace , groffEscape ) @@ -61,6 +62,7 @@ import qualified Text.Pandoc.Builder as Builder import Text.Pandoc.Definition import Text.Pandoc.Options import Text.Pandoc.Pretty +import Text.Pandoc.Shared (stringify) import Text.Pandoc.Walk (query) import Text.Pandoc.UTF8 (toStringLazy) import Text.Pandoc.XML (escapeStringForXML) @@ -344,6 +346,13 @@ metaValueToInlines (MetaBlocks bs) = query return bs metaValueToInlines (MetaBool b) = [Str $ show b] metaValueToInlines _ = [] +metaValueToString :: MetaValue -> String +metaValueToString (MetaString s) = s +metaValueToString (MetaInlines ils) = stringify ils +metaValueToString (MetaBlocks bs) = stringify bs +metaValueToString (MetaBool b) = show b +metaValueToString _ = "" + -- | Escape non-ASCII characters using groff \u[..] sequences. groffEscape :: T.Text -> T.Text groffEscape = T.concatMap toUchar -- cgit v1.2.3 From 58ae017075cc9dbaacce85866b6fc04a02fa1ab4 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Wed, 3 Oct 2018 17:36:52 -0700 Subject: OpenDocument writer: make 'Figure' term sensitive to `lang` in metadata. We use the new translations API. --- src/Text/Pandoc/Writers/OpenDocument.hs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index cd907bbea..e3d7f2e5c 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -39,17 +39,20 @@ import Control.Monad.State.Strict hiding (when) import Data.Char (chr) import Data.List (sortBy) import qualified Data.Map as Map +import Data.Maybe (fromMaybe) import Data.Ord (comparing) import qualified Data.Set as Set import Data.Text (Text) import Text.Pandoc.BCP47 (Lang (..), parseBCP47) -import Text.Pandoc.Class (PandocMonad, report) +import Text.Pandoc.Class (PandocMonad, report, translateTerm, + setTranslations, toLang) import Text.Pandoc.Definition import Text.Pandoc.Logging import Text.Pandoc.Options import Text.Pandoc.Pretty import Text.Pandoc.Shared (linesToPara) import Text.Pandoc.Templates (renderTemplate') +import Text.Pandoc.Translations (Term(Figure)) import Text.Pandoc.Writers.Math import Text.Pandoc.Writers.Shared import Text.Pandoc.XML @@ -223,6 +226,9 @@ handleSpaces s -- | Convert Pandoc document to string in OpenDocument format. writeOpenDocument :: PandocMonad m => WriterOptions -> Pandoc -> m Text writeOpenDocument opts (Pandoc meta blocks) = do + lang <- fromMaybe (Lang "en" "US" "" []) <$> + toLang (metaValueToString <$> lookupMeta "lang" meta) + setTranslations lang let colwidth = if writerWrapText opts == WrapAuto then Just $ writerColumns opts else Nothing @@ -413,19 +419,20 @@ blockToOpenDocument o bs | otherwise = do id' <- gets stImageId imageDoc <- withParagraphStyle o "FigureWithCaption" [Para [Image attr caption (source,title)]] - captionDoc <- numberedFigureCaption id' <$> inlinesToOpenDocument o caption + captionDoc <- inlinesToOpenDocument o caption >>= numberedFigureCaption id' return $ imageDoc $$ captionDoc -numberedFigureCaption :: Int -> Doc -> Doc -numberedFigureCaption num caption = - let t = text "Figure " - r = num - 1 - s = inTags False "text:sequence" [ ("text:ref-name", "refIllustration" ++ show r), +numberedFigureCaption :: PandocMonad m => Int -> Doc -> OD m Doc +numberedFigureCaption num caption = do + figterm <- translateTerm Figure + let t = text figterm + let r = num - 1 + let s = inTags False "text:sequence" [ ("text:ref-name", "refIllustration" ++ show r), ("text:name", "Illustration"), ("text:formula", "ooow:Illustration+1"), ("style:num-format", "1") ] $ text $ show num - c = text ": " - in inParagraphTagsWithStyle "FigureCaption" $ hcat [ t, s, c, caption ] + let c = text ": " + return $ inParagraphTagsWithStyle "FigureCaption" $ hcat [ t, text " ", s, c, caption ] colHeadsToOpenDocument :: PandocMonad m => WriterOptions -> [String] -> [[Block]] -- cgit v1.2.3 From 1a6e6a3a032b70eddc945eafd67599cc071b0f6a Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Thu, 4 Oct 2018 12:05:20 +0300 Subject: Vimwiki reader: code cleanup --- src/Text/Pandoc/Readers/Vimwiki.hs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Vimwiki.hs b/src/Text/Pandoc/Readers/Vimwiki.hs index 824a912c3..15f0d991f 100644 --- a/src/Text/Pandoc/Readers/Vimwiki.hs +++ b/src/Text/Pandoc/Readers/Vimwiki.hs @@ -429,9 +429,7 @@ tableRow = try $ do s <- lookAhead $ manyTill anyChar (try (char '|' >> many spaceChar >> newline)) guard $ not $ "||" `isInfixOf` ("|" ++ s ++ "|") - tr <- many tableCell - many spaceChar >> char '\n' - return tr + many tableCell <* many spaceChar <* char '\n' tableCell :: PandocMonad m => VwParser m Blocks tableCell = try $ @@ -451,13 +449,13 @@ ph s = try $ do noHtmlPh :: PandocMonad m => VwParser m () noHtmlPh = try $ - () <$ (many spaceChar >> string "%nohtml" >> many spaceChar - >> lookAhead newline) + () <$ many spaceChar <* string "%nohtml" <* many spaceChar + <* lookAhead newline templatePh :: PandocMonad m => VwParser m () templatePh = try $ - () <$ (many spaceChar >> string "%template" >>many (noneOf "\n") - >> lookAhead newline) + () <$ many spaceChar <* string "%template" <* many (noneOf "\n") + <* lookAhead newline -- inline parser @@ -617,10 +615,8 @@ procImgurl :: String -> String procImgurl s = if take 6 s == "local:" then "file" ++ drop 5 s else s inlineMath :: PandocMonad m => VwParser m Inlines -inlineMath = try $ do - char '$' - contents <- many1Till (noneOf "\n") (char '$') - return $ B.math contents +inlineMath = try $ + B.math <$ char '$' <*> many1Till (noneOf "\n") (char '$') tag :: PandocMonad m => VwParser m Inlines tag = try $ do -- cgit v1.2.3 From 600034d7ff83b7ece292016a1e9c232fd7ac66f7 Mon Sep 17 00:00:00 2001 From: Mauro Bieg Date: Thu, 4 Oct 2018 18:45:59 +0200 Subject: Add lookupMeta* functions to Text.Pandoc.Writers.Shared (#4907) Remove exported functions `metaValueToInlines`, `metaValueToString`. Add new exported functions `lookupMetaBool`, `lookupMetaBlocks`, `lookupMetaInlines`, `lookupMetaString`. Use these whenever possible for uniformity in writers. API change (major, because of removed function `metaValueToInlines`. `metaValueToString` wasn't in any released version.) --- src/Text/Pandoc/Readers/Org/DocumentTree.hs | 9 +--- src/Text/Pandoc/Writers/Docx.hs | 29 +++------- src/Text/Pandoc/Writers/OpenDocument.hs | 6 ++- src/Text/Pandoc/Writers/Powerpoint/Presentation.hs | 22 +++----- src/Text/Pandoc/Writers/RST.hs | 5 +- src/Text/Pandoc/Writers/Shared.hs | 62 ++++++++++++++++------ 6 files changed, 68 insertions(+), 65 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Org/DocumentTree.hs b/src/Text/Pandoc/Readers/Org/DocumentTree.hs index c7a5f22c4..a9df3b437 100644 --- a/src/Text/Pandoc/Readers/Org/DocumentTree.hs +++ b/src/Text/Pandoc/Readers/Org/DocumentTree.hs @@ -43,7 +43,6 @@ import Text.Pandoc.Readers.Org.BlockStarts import Text.Pandoc.Readers.Org.ParserState import Text.Pandoc.Readers.Org.Parsing -import qualified Data.Map as Map import qualified Text.Pandoc.Builder as B -- @@ -58,7 +57,7 @@ documentTree :: PandocMonad m documentTree blocks inline = do initialBlocks <- blocks headlines <- sequence <$> manyTill (headline blocks inline 1) eof - title <- fmap (getTitle . unMeta) . orgStateMeta <$> getState + title <- fmap docTitle . orgStateMeta <$> getState return $ do headlines' <- headlines initialBlocks' <- initialBlocks @@ -73,12 +72,6 @@ documentTree blocks inline = do , headlineContents = initialBlocks' , headlineChildren = headlines' } - where - getTitle :: Map.Map String MetaValue -> [Inline] - getTitle metamap = - case Map.lookup "title" metamap of - Just (MetaInlines inlns) -> inlns - _ -> [] newtype Tag = Tag { fromTag :: String } deriving (Show, Eq) diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs index 5bd7e809b..524d20fd1 100644 --- a/src/Text/Pandoc/Writers/Docx.hs +++ b/src/Text/Pandoc/Writers/Docx.hs @@ -66,8 +66,7 @@ import Text.Pandoc.Readers.Docx.StyleMap import Text.Pandoc.Shared hiding (Element) import Text.Pandoc.Walk import Text.Pandoc.Writers.Math -import Text.Pandoc.Writers.Shared (isDisplayMath, fixDisplayMath, - metaValueToInlines) +import Text.Pandoc.Writers.Shared import Text.Printf (printf) import Text.TeXMath import Text.XML.Light as XML @@ -267,8 +266,9 @@ writeDocx opts doc@(Pandoc meta _) = do -- parse styledoc for heading styles let styleMaps = getStyleMaps styledoc - let tocTitle = fromMaybe (stTocTitle defaultWriterState) $ - metaValueToInlines <$> lookupMeta "toc-title" meta + let tocTitle = case lookupMetaInlines "toc-title" meta of + [] -> stTocTitle defaultWriterState + ls -> ls let initialSt = defaultWriterState { stStyleMaps = styleMaps @@ -760,24 +760,9 @@ writeOpenXML opts (Pandoc meta blocks) = do let tit = docTitle meta let auths = docAuthors meta let dat = docDate meta - let abstract' = case lookupMeta "abstract" meta of - Just (MetaBlocks bs) -> bs - Just (MetaInlines ils) -> [Plain ils] - Just (MetaString s) -> [Plain [Str s]] - _ -> [] - let subtitle' = case lookupMeta "subtitle" meta of - Just (MetaBlocks [Plain xs]) -> xs - Just (MetaBlocks [Para xs]) -> xs - Just (MetaInlines xs) -> xs - Just (MetaString s) -> [Str s] - _ -> [] - let includeTOC = writerTableOfContents opts || - case lookupMeta "toc" meta of - Just (MetaBlocks _) -> True - Just (MetaInlines _) -> True - Just (MetaString (_:_)) -> True - Just (MetaBool True) -> True - _ -> False + let abstract' = lookupMetaBlocks "abstract" meta + let subtitle' = lookupMetaInlines "subtitle" meta + let includeTOC = writerTableOfContents opts || lookupMetaBool "toc" meta title <- withParaPropM (pStyleM "Title") $ blocksToOpenXML opts [Para tit | not (null tit)] subtitle <- withParaPropM (pStyleM "Subtitle") $ blocksToOpenXML opts [Para subtitle' | not (null subtitle')] authors <- withParaProp (pCustomStyle "Author") $ blocksToOpenXML opts $ diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index e3d7f2e5c..676a1acb0 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -226,8 +226,10 @@ handleSpaces s -- | Convert Pandoc document to string in OpenDocument format. writeOpenDocument :: PandocMonad m => WriterOptions -> Pandoc -> m Text writeOpenDocument opts (Pandoc meta blocks) = do - lang <- fromMaybe (Lang "en" "US" "" []) <$> - toLang (metaValueToString <$> lookupMeta "lang" meta) + let defLang = Lang "en" "US" "" [] + lang <- case lookupMetaString "lang" meta of + "" -> pure defLang + s -> fromMaybe defLang <$> toLang (Just s) setTranslations lang let colwidth = if writerWrapText opts == WrapAuto then Just $ writerColumns opts diff --git a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs index e14476b16..c97d8d770 100644 --- a/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs +++ b/src/Text/Pandoc/Writers/Powerpoint/Presentation.hs @@ -72,7 +72,7 @@ import Text.Pandoc.Logging import Text.Pandoc.Walk import Data.Time (UTCTime) import qualified Text.Pandoc.Shared as Shared -- so we don't overlap "Element" -import Text.Pandoc.Writers.Shared (metaValueToInlines) +import Text.Pandoc.Writers.Shared (lookupMetaInlines) import qualified Data.Map as M import qualified Data.Set as S import Data.Maybe (maybeToList, fromMaybe) @@ -731,9 +731,9 @@ makeEndNotesSlideBlocks = do anchorSet <- M.keysSet <$> gets stAnchorMap if M.null noteIds then return [] - else let title = case lookupMeta "notes-title" meta of - Just val -> metaValueToInlines val - Nothing -> [Str "Notes"] + else let title = case lookupMetaInlines "notes-title" meta of + [] -> [Str "Notes"] + ls -> ls ident = Shared.uniqueIdent title anchorSet hdr = Header slideLevel (ident, [], []) title blks = concatMap (\(n, bs) -> makeNoteEntry n bs) $ @@ -744,13 +744,7 @@ getMetaSlide :: Pres (Maybe Slide) getMetaSlide = do meta <- asks envMetadata title <- inlinesToParElems $ docTitle meta - subtitle <- inlinesToParElems $ - case lookupMeta "subtitle" meta of - Just (MetaString s) -> [Str s] - Just (MetaInlines ils) -> ils - Just (MetaBlocks [Plain ils]) -> ils - Just (MetaBlocks [Para ils]) -> ils - _ -> [] + subtitle <- inlinesToParElems $ lookupMetaInlines "subtitle" meta authors <- mapM inlinesToParElems $ docAuthors meta date <- inlinesToParElems $ docDate meta if null title && null subtitle && null authors && null date @@ -785,9 +779,9 @@ makeTOCSlide blks = local (\env -> env{envCurSlideId = tocSlideId}) $ do contents <- BulletList <$> mapM elementToListItem (Shared.hierarchicalize blks) meta <- asks envMetadata slideLevel <- asks envSlideLevel - let tocTitle = case lookupMeta "toc-title" meta of - Just val -> metaValueToInlines val - Nothing -> [Str "Table of Contents"] + let tocTitle = case lookupMetaInlines "toc-title" meta of + [] -> [Str "Table of Contents"] + ls -> ls hdr = Header slideLevel nullAttr tocTitle blocksToSlide [hdr, contents] diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index b416eca59..34d5cce04 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -82,10 +82,7 @@ pandocToRST (Pandoc meta blocks) = do else Nothing let render' :: Doc -> Text render' = render colwidth - let subtit = case lookupMeta "subtitle" meta of - Just (MetaBlocks [Plain xs]) -> xs - Just (MetaInlines xs) -> xs - _ -> [] + let subtit = lookupMetaInlines "subtitle" meta title <- titleToRST (docTitle meta) subtit metadata <- metaToJSON opts (fmap render' . blockListToRST) diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs index 6113b0a66..323748aad 100644 --- a/src/Text/Pandoc/Writers/Shared.hs +++ b/src/Text/Pandoc/Writers/Shared.hs @@ -42,8 +42,10 @@ module Text.Pandoc.Writers.Shared ( , fixDisplayMath , unsmartify , gridTable - , metaValueToInlines - , metaValueToString + , lookupMetaBool + , lookupMetaBlocks + , lookupMetaInlines + , lookupMetaString , stripLeadingTrailingSpace , groffEscape ) @@ -63,7 +65,6 @@ import Text.Pandoc.Definition import Text.Pandoc.Options import Text.Pandoc.Pretty import Text.Pandoc.Shared (stringify) -import Text.Pandoc.Walk (query) import Text.Pandoc.UTF8 (toStringLazy) import Text.Pandoc.XML (escapeStringForXML) import Text.Printf (printf) @@ -339,19 +340,50 @@ gridTable opts blocksToDoc headless aligns widths headers rows = do body $$ border '-' (repeat AlignDefault) widthsInChars -metaValueToInlines :: MetaValue -> [Inline] -metaValueToInlines (MetaString s) = [Str s] -metaValueToInlines (MetaInlines ils) = ils -metaValueToInlines (MetaBlocks bs) = query return bs -metaValueToInlines (MetaBool b) = [Str $ show b] -metaValueToInlines _ = [] -metaValueToString :: MetaValue -> String -metaValueToString (MetaString s) = s -metaValueToString (MetaInlines ils) = stringify ils -metaValueToString (MetaBlocks bs) = stringify bs -metaValueToString (MetaBool b) = show b -metaValueToString _ = "" + +-- | Retrieve the metadata value for a given @key@ +-- and convert to Bool. +lookupMetaBool :: String -> Meta -> Bool +lookupMetaBool key meta = + case lookupMeta key meta of + Just (MetaBlocks _) -> True + Just (MetaInlines _) -> True + Just (MetaString (_:_)) -> True + Just (MetaBool True) -> True + _ -> False + +-- | Retrieve the metadata value for a given @key@ +-- and extract blocks. +lookupMetaBlocks :: String -> Meta -> [Block] +lookupMetaBlocks key meta = + case lookupMeta key meta of + Just (MetaBlocks bs) -> bs + Just (MetaInlines ils) -> [Plain ils] + Just (MetaString s) -> [Plain [Str s]] + _ -> [] + +-- | Retrieve the metadata value for a given @key@ +-- and extract inlines. +lookupMetaInlines :: String -> Meta -> [Inline] +lookupMetaInlines key meta = + case lookupMeta key meta of + Just (MetaString s) -> [Str s] + Just (MetaInlines ils) -> ils + Just (MetaBlocks [Plain ils]) -> ils + Just (MetaBlocks [Para ils]) -> ils + _ -> [] + +-- | Retrieve the metadata value for a given @key@ +-- and convert to String. +lookupMetaString :: String -> Meta -> String +lookupMetaString key meta = + case lookupMeta key meta of + Just (MetaString s) -> s + Just (MetaInlines ils) -> stringify ils + Just (MetaBlocks bs) -> stringify bs + Just (MetaBool b) -> show b + _ -> "" -- | Escape non-ASCII characters using groff \u[..] sequences. groffEscape :: T.Text -> T.Text -- cgit v1.2.3 From f766348fd8ca2d619d9d4081d744a331eacdce02 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 4 Oct 2018 10:04:49 -0700 Subject: KaTeX: don't use autorenderer. We no longer surround formulas with `\(..\)` or `\[..\]` and rely on the autorenderer. Instead, we tell katex to convert the contents of span elements with class "math". Since math has already been identified, this avoids wasted time parsing for LaTeX delimiters. Note, however, that this may yield unexpected results if you have span elements with class "math" that don't contain LaTeX math. Also, use latest version of KaTeX by default (0.9.0). Closes #4946. --- src/Text/Pandoc/Writers/HTML.hs | 10 +++++----- src/Text/Pandoc/Writers/Math.hs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs index 19ec4692e..46f754226 100644 --- a/src/Text/Pandoc/Writers/HTML.hs +++ b/src/Text/Pandoc/Writers/HTML.hs @@ -277,10 +277,10 @@ pandocToHtml opts (Pandoc meta blocks) = do KaTeX url -> do H.script ! A.src (toValue $ url ++ "katex.min.js") $ mempty - H.script ! - A.src (toValue $ url ++ "contrib/auto-render.min.js") $ mempty + nl opts H.script - "document.addEventListener(\"DOMContentLoaded\", function() {\n renderMathInElement(document.body);\n});" + "document.addEventListener(\"DOMContentLoaded\", function () {\n var mathElements = document.getElementsByClassName(\"math\");\n for (var i = 0; i < mathElements.length; i++) {\n var texText = mathElements[i].firstChild;\n if (mathElements[i].tagName == \"SPAN\") { katex.render(texText.data, mathElements[i], { displayMode: mathElements[i].classList.contains(\"display\"), throwOnError: false } );\n }}});" + nl opts H.link ! A.rel "stylesheet" ! A.href (toValue $ url ++ "katex.min.css") @@ -1065,8 +1065,8 @@ inlineToHtml opts inline = do DisplayMath -> "\\[" ++ str ++ "\\]" KaTeX _ -> return $ H.span ! A.class_ mathClass $ toHtml $ case t of - InlineMath -> "\\(" ++ str ++ "\\)" - DisplayMath -> "\\[" ++ str ++ "\\]" + InlineMath -> str + DisplayMath -> str PlainMath -> do x <- lift (texMathToInlines t str) >>= inlineListToHtml opts let m = H.span ! A.class_ mathClass $ x diff --git a/src/Text/Pandoc/Writers/Math.hs b/src/Text/Pandoc/Writers/Math.hs index 99d17d594..61decf2df 100644 --- a/src/Text/Pandoc/Writers/Math.hs +++ b/src/Text/Pandoc/Writers/Math.hs @@ -55,4 +55,4 @@ defaultMathJaxURL :: String defaultMathJaxURL = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/" defaultKaTeXURL :: String -defaultKaTeXURL = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.8.3/" +defaultKaTeXURL = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0/" -- cgit v1.2.3 From 5b7d04984bb5c053c80b1a3e8d9779785613d583 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 4 Oct 2018 10:49:05 -0700 Subject: Docx reader: trigger bold/italic with bCs, iCs. These are variants for "complex scripts" like Arabic and are now treated just like b, i (bold, italic). Colses #4947. --- src/Text/Pandoc/Readers/Docx/Parse.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs index cbf865de8..b4e52de14 100644 --- a/src/Text/Pandoc/Readers/Docx/Parse.hs +++ b/src/Text/Pandoc/Readers/Docx/Parse.hs @@ -1056,8 +1056,10 @@ elemToRunStyle ns element parentStyle | Just rPr <- findChildByName ns "w" "rPr" element = RunStyle { - isBold = checkOnOff ns rPr (elemName ns "w" "b") - , isItalic = checkOnOff ns rPr (elemName ns "w" "i") + isBold = checkOnOff ns rPr (elemName ns "w" "b") `mplus` + checkOnOff ns rPr (elemName ns "w" "bCs") + , isItalic = checkOnOff ns rPr (elemName ns "w" "i") `mplus` + checkOnOff ns rPr (elemName ns "w" "iCs") , isSmallCaps = checkOnOff ns rPr (elemName ns "w" "smallCaps") , isStrike = checkOnOff ns rPr (elemName ns "w" "strike") , rVertAlign = -- cgit v1.2.3 From 5f7799ac8f359fbb7896037a79f2abb61be2fd2c Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 5 Oct 2018 11:58:41 +0300 Subject: Muse reader: allow table caption to contain "+" --- src/Text/Pandoc/Readers/Muse.hs | 2 +- test/Tests/Readers/Muse.hs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 6475669ce..d5236c5a2 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -749,7 +749,7 @@ tableParseCaption :: PandocMonad m => MuseParser m (F MuseTableElement) tableParseCaption = try $ fmap MuseCaption . trimInlinesF . mconcat <$ many spaceChar <* string "|+" - <*> many1Till inline (string "+|") + <*> many1Till inline (try $ string "+|") -- ** Inline parsers diff --git a/test/Tests/Readers/Muse.hs b/test/Tests/Readers/Muse.hs index 8393e45d9..958a74915 100644 --- a/test/Tests/Readers/Muse.hs +++ b/test/Tests/Readers/Muse.hs @@ -857,6 +857,14 @@ tests = [plain "Foo", plain "bar", plain "baz"] [[plain "First", plain "row", plain "here"], [plain "Second", plain "row", plain "there"]] + , "Table caption with +" =: + T.unlines + [ "Foo | bar" + , "|+ Table + caption +|" + ] =?> + table (text "Table + caption") (replicate 2 (AlignDefault, 0.0)) + [] + [[plain "Foo", plain "bar"]] , "Caption without table" =: "|+ Foo bar baz +|" =?> table (text "Foo bar baz") [] [] [] -- cgit v1.2.3 From ef4bc58cc1b2ce8226cfe3449eb188734dcb5c51 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 5 Oct 2018 12:37:41 +0300 Subject: Muse reader: simplify verse parsers --- src/Text/Pandoc/Readers/Muse.hs | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index d5236c5a2..c3b8ea25f 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -453,10 +453,9 @@ playTag = do fmap (B.divWith ("", ["play"], [])) . snd <$> parseHtmlContent "play" verseLine :: PandocMonad m => MuseParser m (F Inlines) -verseLine = do - indent <- (B.str <$> many1 ('\160' <$ char ' ')) <|> pure mempty - rest <- manyTill inline' newline - return $ trimInlinesF $ mconcat (pure indent : rest) +verseLine = (<>) + <$> fmap pure (option mempty (B.str <$> many1 ('\160' <$ char ' '))) + <*> fmap (trimInlinesF . mconcat) (manyTill inline' eol) -- | Parse @\@ tag. verseTag :: PandocMonad m => MuseParser m (F Blocks) @@ -541,26 +540,16 @@ emacsNoteBlock = try $ do -- Verse markup -- -lineVerseLine :: PandocMonad m => MuseParser m (F Inlines) -lineVerseLine = try $ do - string "> " - indent <- many ('\160' <$ char ' ') - let indentEl = if null indent then mempty else B.str indent - rest <- manyTill inline' eol - return $ trimInlinesF $ mconcat (pure indentEl : rest) - -blanklineVerseLine :: PandocMonad m => MuseParser m (F Inlines) -blanklineVerseLine = try $ mempty - <$ char '>' - <* blankline - -- | Parse a line block indicated by @\'>\'@ characters. lineBlock :: PandocMonad m => MuseParser m (F Blocks) lineBlock = try $ do many spaceChar col <- sourceColumn <$> getPosition - lns <- (blanklineVerseLine <|> lineVerseLine) `sepBy1'` try (indentWith (col - 1)) + lns <- (blankVerseLine <|> nonblankVerseLine) `sepBy1'` try (indentWith (col - 1)) return $ B.lineBlock <$> sequence lns + where + blankVerseLine = try $ mempty <$ char '>' <* blankline + nonblankVerseLine = try (string "> ") *> verseLine -- *** List parsers -- cgit v1.2.3 From 0ce7183c81715ce212196f64ba916fd5d9a5c0dd Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 5 Oct 2018 15:57:03 +0300 Subject: Muse reader: get rid of TagSoup import --- src/Text/Pandoc/Readers/Muse.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index c3b8ea25f..8e1f3a2af 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -51,7 +51,6 @@ import qualified Data.Map as M import qualified Data.Set as Set import Data.Maybe (fromMaybe, isNothing, maybeToList) import Data.Text (Text, unpack) -import Text.HTML.TagSoup import Text.Pandoc.Builder (Blocks, Inlines) import qualified Text.Pandoc.Builder as B import Text.Pandoc.Class (PandocMonad (..)) @@ -196,7 +195,7 @@ closeTag :: PandocMonad m => String -> MuseParser m () closeTag tag = try $ string " string tag *> void (char '>') -- | Convert HTML attributes to Pandoc 'Attr' -htmlAttrToPandoc :: [Attribute String] -> Attr +htmlAttrToPandoc :: [(String, String)] -> Attr htmlAttrToPandoc attrs = (ident, classes, keyvals) where ident = fromMaybe "" $ lookup "id" attrs -- cgit v1.2.3 From abd770c691ce09ff74e175f5bd25de2058d3c766 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 5 Oct 2018 16:27:29 +0300 Subject: Muse reader internals: simplify parseMuse --- src/Text/Pandoc/Readers/Muse.hs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 8e1f3a2af..aaa9d2eb1 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -123,13 +123,9 @@ instance HasLogMessages MuseState where parseMuse :: PandocMonad m => MuseParser m Pandoc parseMuse = do many directive - firstSection <- parseBlocks - rest <- many parseSection - let blocks = mconcat (firstSection : rest) + blocks <- (:) <$> parseBlocks <*> many parseSection st <- getState - let doc = runF (do Pandoc _ bs <- B.doc <$> blocks - meta <- museMeta st - return $ Pandoc meta bs) st + let doc = runF (Pandoc <$> museMeta st <*> fmap B.toList (mconcat blocks)) st reportLogMessages return doc -- cgit v1.2.3 From 7cfce586f6ef6e97934c48f8871741aa0e8379dc Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 5 Oct 2018 18:27:05 +0300 Subject: Muse reader: reduce duplication by introducing `getIndent` --- src/Text/Pandoc/Readers/Muse.hs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index aaa9d2eb1..39d835af7 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -548,6 +548,10 @@ lineBlock = try $ do -- *** List parsers +getIndent :: PandocMonad m + => MuseParser m Int +getIndent = subtract 1 . sourceColumn <$ many spaceChar <*> getPosition + bulletListItemsUntil :: PandocMonad m => Int -- ^ Indentation -> MuseParser m a -- ^ Terminator parser @@ -564,9 +568,7 @@ bulletListUntil :: PandocMonad m => MuseParser m a -> MuseParser m (F Blocks, a) bulletListUntil end = try $ do - many spaceChar - pos <- getPosition - let indent = sourceColumn pos - 1 + indent <- getIndent guard $ indent /= 0 (items, e) <- bulletListItemsUntil indent end return (B.bulletList <$> sequence items, e) @@ -604,9 +606,7 @@ orderedListUntil :: PandocMonad m => MuseParser m a -> MuseParser m (F Blocks, a) orderedListUntil end = try $ do - many spaceChar - pos <- getPosition - let indent = sourceColumn pos - 1 + indent <- getIndent guard $ indent /= 0 (style, start) <- decimal <|> lowerRoman <|> upperRoman <|> lowerAlpha <|> upperAlpha char '.' @@ -642,9 +642,7 @@ definitionListUntil :: PandocMonad m => MuseParser m a -- ^ Terminator parser -> MuseParser m (F Blocks, a) definitionListUntil end = try $ do - many spaceChar - pos <- getPosition - let indent = sourceColumn pos - 1 + indent <- getIndent guardDisabled Ext_amuse <|> guard (indent /= 0) -- Initial space is required by Amusewiki, but not Emacs Muse first (fmap B.definitionList . sequence) <$> definitionListItemsUntil indent end -- cgit v1.2.3 From 659cce8442ee8ba89000b8f499f46a9bbead9cda Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 5 Oct 2018 18:31:48 +0300 Subject: Muse reader: make bulletListUntil similar to definitionListUntil --- src/Text/Pandoc/Readers/Muse.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 39d835af7..7dc2f0c2a 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -570,8 +570,7 @@ bulletListUntil :: PandocMonad m bulletListUntil end = try $ do indent <- getIndent guard $ indent /= 0 - (items, e) <- bulletListItemsUntil indent end - return (B.bulletList <$> sequence items, e) + first (fmap B.bulletList . sequence) <$> bulletListItemsUntil indent end museOrderedListMarker :: PandocMonad m => ListNumberStyle -- cgit v1.2.3 From 131dcff71d65c343d1721ec0e577b5a773d9e737 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 5 Oct 2018 18:47:45 +0300 Subject: Muse reader: use getIndent in parseHtmlContent --- src/Text/Pandoc/Readers/Muse.hs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 7dc2f0c2a..a87ce97a2 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -169,6 +169,10 @@ firstColumn = getPosition >>= \pos -> guard (sourceColumn pos == 1) eol :: Stream s m Char => ParserT s st m () eol = void newline <|> eof +getIndent :: PandocMonad m + => MuseParser m Int +getIndent = subtract 1 . sourceColumn <$ many spaceChar <*> getPosition + someUntil :: (Stream s m t) => ParserT s u m a -> ParserT s u m b @@ -202,11 +206,10 @@ parseHtmlContent :: PandocMonad m => String -- ^ Tag name -> MuseParser m (Attr, F Blocks) parseHtmlContent tag = try $ do - many spaceChar - pos <- getPosition + indent <- getIndent attr <- openTag tag manyTill spaceChar eol - content <- parseBlocksTill $ try $ count (sourceColumn pos - 1) spaceChar *> closeTag tag + content <- parseBlocksTill $ try $ count indent spaceChar *> closeTag tag manyTill spaceChar eol -- closing tag must be followed by optional whitespace and newline return (htmlAttrToPandoc attr, content) @@ -548,10 +551,6 @@ lineBlock = try $ do -- *** List parsers -getIndent :: PandocMonad m - => MuseParser m Int -getIndent = subtract 1 . sourceColumn <$ many spaceChar <*> getPosition - bulletListItemsUntil :: PandocMonad m => Int -- ^ Indentation -> MuseParser m a -- ^ Terminator parser -- cgit v1.2.3 From 37cc977b12233203f0af27a15918e7d5b73189c5 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 5 Oct 2018 19:14:13 +0300 Subject: Muse reader: use getIndent more for code cleanup --- src/Text/Pandoc/Readers/Muse.hs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index a87ce97a2..404636c54 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -458,12 +458,10 @@ verseLine = (<>) -- | Parse @\@ tag. verseTag :: PandocMonad m => MuseParser m (F Blocks) verseTag = try $ do - many spaceChar - pos <- getPosition + indent <- getIndent openTag "verse" manyTill spaceChar eol - let indent = count (sourceColumn pos - 1) spaceChar - content <- sequence <$> manyTill (indent *> verseLine) (try $ indent *> closeTag "verse") + content <- sequence <$> manyTill (count indent spaceChar *> verseLine) (try $ count indent spaceChar *> closeTag "verse") manyTill spaceChar eol return $ B.lineBlock <$> content @@ -541,9 +539,8 @@ emacsNoteBlock = try $ do -- | Parse a line block indicated by @\'>\'@ characters. lineBlock :: PandocMonad m => MuseParser m (F Blocks) lineBlock = try $ do - many spaceChar - col <- sourceColumn <$> getPosition - lns <- (blankVerseLine <|> nonblankVerseLine) `sepBy1'` try (indentWith (col - 1)) + indent <- getIndent + lns <- (blankVerseLine <|> nonblankVerseLine) `sepBy1'` try (indentWith indent) return $ B.lineBlock <$> sequence lns where blankVerseLine = try $ mempty <$ char '>' <* blankline -- cgit v1.2.3 From 90a4d693efe155139ae6b8f077ba7c7c0993c387 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 5 Oct 2018 19:41:25 +0300 Subject: Muse reader: move museInLink state into ReaderT --- src/Text/Pandoc/Readers/Muse.hs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 404636c54..4d9013cce 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -41,6 +41,7 @@ module Text.Pandoc.Readers.Muse (readMuse) where import Prelude import Control.Monad +import Control.Monad.Reader import Control.Monad.Except (throwError) import Data.Bifunctor import Data.Char (isAlphaNum) @@ -68,7 +69,7 @@ readMuse :: PandocMonad m -> m Pandoc readMuse opts s = do let input = crFilter s - res <- mapLeft (PandocParsecError $ unpack input) `liftM` runParserT parseMuse def{ museOptions = opts } "source" input + res <- mapLeft (PandocParsecError $ unpack input) `liftM` (runReaderT (runParserT parseMuse def{ museOptions = opts } "source" input) def) case res of Left e -> throwError e Right d -> return d @@ -82,7 +83,6 @@ data MuseState = MuseState { museMeta :: F Meta -- ^ Document metadata , museLastStrPos :: Maybe SourcePos -- ^ Position after last str parsed , museLogMessages :: [LogMessage] , museNotes :: M.Map String (SourcePos, F Blocks) - , museInLink :: Bool -- ^ True when parsing a link description to avoid nested links , museInPara :: Bool -- ^ True when looking for a paragraph terminator } @@ -94,11 +94,17 @@ instance Default MuseState where , museLastStrPos = Nothing , museLogMessages = [] , museNotes = M.empty - , museInLink = False , museInPara = False } -type MuseParser = ParserT Text MuseState +data MuseEnv = + MuseEnv { museInLink :: Bool } + +instance Default MuseEnv where + def = MuseEnv { museInLink = False -- ^ True when parsing a link description to avoid nested links + } + +type MuseParser m = ParserT Text MuseState (ReaderT MuseEnv m) instance HasReaderOptions MuseState where extractReaderOptions = museOptions @@ -778,7 +784,7 @@ anchor = try $ do -- | Parse a footnote reference. footnote :: PandocMonad m => MuseParser m (F Inlines) footnote = try $ do - inLink <- museInLink <$> getState + inLink <- asks museInLink guard $ not inLink ref <- noteMarker return $ do @@ -915,12 +921,9 @@ symbol = return . B.str <$> count 1 nonspaceChar -- | Parse a link or image. linkOrImage :: PandocMonad m => MuseParser m (F Inlines) linkOrImage = try $ do - st <- getState - guard $ not $ museInLink st - setState $ st{ museInLink = True } - res <- explicitLink <|> image <|> link - updateState (\state -> state { museInLink = False }) - return res + inLink <- asks museInLink + guard $ not inLink + local (\s -> s { museInLink = True }) (explicitLink <|> image <|> link) linkContent :: PandocMonad m => MuseParser m (F Inlines) linkContent = trimInlinesF . mconcat -- cgit v1.2.3 From 6304720d8d7906d698018203e1c743683f0234f3 Mon Sep 17 00:00:00 2001 From: Nils Carlson Date: Fri, 5 Oct 2018 16:58:23 +0000 Subject: OpenDocument writer: Implement table caption numbering (#4949) Implement table caption numbering with a format "Table 1: ". Translations are enabled and numbering is consecutive for captioned tables, uncaptioned tables are not enumerated. Captioned figures are now also numbered consecutively and uncaptioned figures are not enumerated. --- src/Text/Pandoc/Writers/OpenDocument.hs | 89 ++++++++++++++++++++------------- test/tables.opendocument | 10 ++-- 2 files changed, 59 insertions(+), 40 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs index 676a1acb0..d9f0a8e44 100644 --- a/src/Text/Pandoc/Writers/OpenDocument.hs +++ b/src/Text/Pandoc/Writers/OpenDocument.hs @@ -52,7 +52,7 @@ import Text.Pandoc.Options import Text.Pandoc.Pretty import Text.Pandoc.Shared (linesToPara) import Text.Pandoc.Templates (renderTemplate') -import Text.Pandoc.Translations (Term(Figure)) +import qualified Text.Pandoc.Translations as Term (Term(Figure, Table)) import Text.Pandoc.Writers.Math import Text.Pandoc.Writers.Shared import Text.Pandoc.XML @@ -70,32 +70,36 @@ plainToPara x = x type OD m = StateT WriterState m data WriterState = - WriterState { stNotes :: [Doc] - , stTableStyles :: [Doc] - , stParaStyles :: [Doc] - , stListStyles :: [(Int, [Doc])] - , stTextStyles :: Map.Map (Set.Set TextStyle) (String, Doc) - , stTextStyleAttr :: Set.Set TextStyle - , stIndentPara :: Int - , stInDefinition :: Bool - , stTight :: Bool - , stFirstPara :: Bool - , stImageId :: Int + WriterState { stNotes :: [Doc] + , stTableStyles :: [Doc] + , stParaStyles :: [Doc] + , stListStyles :: [(Int, [Doc])] + , stTextStyles :: Map.Map (Set.Set TextStyle) (String, Doc) + , stTextStyleAttr :: Set.Set TextStyle + , stIndentPara :: Int + , stInDefinition :: Bool + , stTight :: Bool + , stFirstPara :: Bool + , stImageId :: Int + , stTableCaptionId :: Int + , stImageCaptionId :: Int } defaultWriterState :: WriterState defaultWriterState = - WriterState { stNotes = [] - , stTableStyles = [] - , stParaStyles = [] - , stListStyles = [] - , stTextStyles = Map.empty - , stTextStyleAttr = Set.empty - , stIndentPara = 0 - , stInDefinition = False - , stTight = False - , stFirstPara = False - , stImageId = 1 + WriterState { stNotes = [] + , stTableStyles = [] + , stParaStyles = [] + , stListStyles = [] + , stTextStyles = Map.empty + , stTextStyleAttr = Set.empty + , stIndentPara = 0 + , stInDefinition = False + , stTight = False + , stFirstPara = False + , stImageId = 1 + , stTableCaptionId = 1 + , stImageCaptionId = 1 } when :: Bool -> Doc -> Doc @@ -408,7 +412,7 @@ blockToOpenDocument o bs mapM_ addParaStyle . newPara $ paraHStyles ++ paraStyles captionDoc <- if null c then return empty - else withParagraphStyle o "Table" [Para c] + else inlinesToOpenDocument o c >>= numberedTableCaption th <- if all null h then return empty else colHeadsToOpenDocument o (map fst paraHStyles) h @@ -419,22 +423,35 @@ blockToOpenDocument o bs figure attr caption source title | null caption = withParagraphStyle o "Figure" [Para [Image attr caption (source,title)]] | otherwise = do - id' <- gets stImageId imageDoc <- withParagraphStyle o "FigureWithCaption" [Para [Image attr caption (source,title)]] - captionDoc <- inlinesToOpenDocument o caption >>= numberedFigureCaption id' + captionDoc <- inlinesToOpenDocument o caption >>= numberedFigureCaption return $ imageDoc $$ captionDoc -numberedFigureCaption :: PandocMonad m => Int -> Doc -> OD m Doc -numberedFigureCaption num caption = do - figterm <- translateTerm Figure - let t = text figterm - let r = num - 1 - let s = inTags False "text:sequence" [ ("text:ref-name", "refIllustration" ++ show r), - ("text:name", "Illustration"), - ("text:formula", "ooow:Illustration+1"), + +numberedTableCaption :: PandocMonad m => Doc -> OD m Doc +numberedTableCaption caption = do + id' <- gets stTableCaptionId + modify (\st -> st{ stTableCaptionId = id' + 1 }) + capterm <- translateTerm Term.Table + return $ numberedCaption "Table" capterm "Table" id' caption + +numberedFigureCaption :: PandocMonad m => Doc -> OD m Doc +numberedFigureCaption caption = do + id' <- gets stImageCaptionId + modify (\st -> st{ stImageCaptionId = id' + 1 }) + capterm <- translateTerm Term.Figure + return $ numberedCaption "FigureCaption" capterm "Illustration" id' caption + +numberedCaption :: String -> String -> String -> Int -> Doc -> Doc +numberedCaption style term name num caption = + let t = text term + r = num - 1 + s = inTags False "text:sequence" [ ("text:ref-name", "ref" ++ name ++ show r), + ("text:name", name), + ("text:formula", "ooow:" ++ name ++ "+1"), ("style:num-format", "1") ] $ text $ show num - let c = text ": " - return $ inParagraphTagsWithStyle "FigureCaption" $ hcat [ t, text " ", s, c, caption ] + c = text ": " + in inParagraphTagsWithStyle style $ hcat [ t, text " ", s, c, caption ] colHeadsToOpenDocument :: PandocMonad m => WriterOptions -> [String] -> [[Block]] diff --git a/test/tables.opendocument b/test/tables.opendocument index c04afd492..5c68476b8 100644 --- a/test/tables.opendocument +++ b/test/tables.opendocument @@ -63,7 +63,8 @@ -Demonstration of simple table syntax. +Table 1: Demonstration +of simple table syntax. Simple table without caption: @@ -196,7 +197,8 @@ spaces: -Demonstration of simple table syntax. +Table 2: Demonstration +of simple table syntax. Multiline table with caption: @@ -251,8 +253,8 @@ caption: -Here’s the caption. It may span multiple -lines. +Table 3: Here’s +the caption. It may span multiple lines. Multiline table without caption: -- cgit v1.2.3 From 9b715d0cf2bd414b9574d6b5688ca760a042f933 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 5 Oct 2018 19:54:01 +0300 Subject: Muse reader: remove redundant bracket --- src/Text/Pandoc/Readers/Muse.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 4d9013cce..9c699651e 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -69,7 +69,7 @@ readMuse :: PandocMonad m -> m Pandoc readMuse opts s = do let input = crFilter s - res <- mapLeft (PandocParsecError $ unpack input) `liftM` (runReaderT (runParserT parseMuse def{ museOptions = opts } "source" input) def) + res <- mapLeft (PandocParsecError $ unpack input) `liftM` runReaderT (runParserT parseMuse def{ museOptions = opts } "source" input) def case res of Left e -> throwError e Right d -> return d -- cgit v1.2.3 From e4ca51c2a738e924a1a2abdd1ef26abe4ee6c173 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 5 Oct 2018 12:32:48 -0700 Subject: Fixed haddock error in Muse reader. --- src/Text/Pandoc/Readers/Muse.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 9c699651e..418ba71f2 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -101,7 +101,8 @@ data MuseEnv = MuseEnv { museInLink :: Bool } instance Default MuseEnv where - def = MuseEnv { museInLink = False -- ^ True when parsing a link description to avoid nested links + def = MuseEnv { museInLink = False + -- True when parsing a link description to avoid nested links } type MuseParser m = ParserT Text MuseState (ReaderT MuseEnv m) -- cgit v1.2.3 From a26b3a2d6af8614e13299bbf477e28c5932ef680 Mon Sep 17 00:00:00 2001 From: Brian Leung Date: Fri, 5 Oct 2018 14:28:17 -0700 Subject: Org reader: Add partial support for `#+EXCLUDE_TAGS` option. (#4950) Closes #4284. Headers with the corresponding tags should not appear in the output. If one or more of the specified tags contains a non-tag character like `+`, Org-mode will not treat that as a valid tag, but will nonetheless continue scanning for valid tags. That behavior is not replicated in this patch; entering `cat+dog` as one of the entries in `#+EXCLUDE_TAGS` and running the file through Pandoc will cause the parser to fail and result in the only excluded tag being the default, `noexport`. --- src/Text/Pandoc/Readers/Org/DocumentTree.hs | 14 +++++++------- src/Text/Pandoc/Readers/Org/Meta.hs | 11 +++++++++++ src/Text/Pandoc/Readers/Org/ParserState.hs | 6 ++++++ src/Text/Pandoc/Readers/Org/Parsing.hs | 8 ++++++++ test/command/4284.md | 29 +++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 test/command/4284.md (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Org/DocumentTree.hs b/src/Text/Pandoc/Readers/Org/DocumentTree.hs index a9df3b437..7d55892fe 100644 --- a/src/Text/Pandoc/Readers/Org/DocumentTree.hs +++ b/src/Text/Pandoc/Readers/Org/DocumentTree.hs @@ -43,6 +43,7 @@ import Text.Pandoc.Readers.Org.BlockStarts import Text.Pandoc.Readers.Org.ParserState import Text.Pandoc.Readers.Org.Parsing +import qualified Data.Set as Set import qualified Text.Pandoc.Builder as B -- @@ -73,9 +74,6 @@ documentTree blocks inline = do , headlineChildren = headlines' } -newtype Tag = Tag { fromTag :: String } - deriving (Show, Eq) - -- | Create a tag containing the given string. toTag :: String -> Tag toTag = Tag @@ -153,7 +151,7 @@ headline blocks inline lvl = try $ do headerTags :: Monad m => OrgParser m [Tag] headerTags = try $ - let tag = many1 (alphaNum <|> oneOf "@%#_") <* char ':' + let tag = orgTagWord <* char ':' in map toTag <$> (skipSpaces *> char ':' *> many1 tag <* skipSpaces) -- | Convert an Org mode headline (i.e. a document tree) into pandoc's Blocks @@ -163,15 +161,17 @@ headlineToBlocks hdln = do let tags = headlineTags hdln let text = headlineText hdln let level = headlineLevel hdln + shouldNotExport <- hasDoNotExportTag tags case () of - _ | any isNoExportTag tags -> return mempty + _ | shouldNotExport -> return mempty _ | any isArchiveTag tags -> archivedHeadlineToBlocks hdln _ | isCommentTitle text -> return mempty _ | maxLevel <= level -> headlineToHeaderWithList hdln _ | otherwise -> headlineToHeaderWithContents hdln -isNoExportTag :: Tag -> Bool -isNoExportTag = (== toTag "noexport") +hasDoNotExportTag :: Monad m => [Tag] -> OrgParser m Bool +hasDoNotExportTag tags = containsExcludedTag . orgStateExcludedTags <$> getState + where containsExcludedTag s = any (`Set.member` s) tags isArchiveTag :: Tag -> Bool isArchiveTag = (== toTag "ARCHIVE") diff --git a/src/Text/Pandoc/Readers/Org/Meta.hs b/src/Text/Pandoc/Readers/Org/Meta.hs index 965e33d94..921cd27e0 100644 --- a/src/Text/Pandoc/Readers/Org/Meta.hs +++ b/src/Text/Pandoc/Readers/Org/Meta.hs @@ -52,6 +52,7 @@ import Data.Char (toLower) import Data.List (intersperse) import Data.Maybe (fromMaybe) import qualified Data.Map as M +import qualified Data.Set as Set import Network.HTTP (urlEncode) -- | Returns the current meta, respecting export options. @@ -158,6 +159,7 @@ optionLine = try $ do "seq_todo" -> todoSequence >>= updateState . registerTodoSequence "typ_todo" -> todoSequence >>= updateState . registerTodoSequence "macro" -> macroDefinition >>= updateState . registerMacro + "exclude_tags" -> excludedTagSet >>= updateState . setExcludedTags "pandoc-emphasis-pre" -> emphChars >>= updateState . setEmphasisPreChar "pandoc-emphasis-post" -> emphChars >>= updateState . setEmphasisPostChar _ -> mzero @@ -190,6 +192,15 @@ parseFormat = try $ replacePlain <|> replaceUrl <|> justAppend rest = manyTill anyChar (eof <|> () <$ oneOf "\n\r") tillSpecifier c = manyTill (noneOf "\n\r") (try $ string ('%':c:"")) +excludedTagSet :: Monad m => OrgParser m (Set.Set Tag) +excludedTagSet = do + skipSpaces + Set.fromList . map Tag <$> + many (orgTagWord <* skipSpaces) <* newline + +setExcludedTags :: Set.Set Tag -> OrgParserState -> OrgParserState +setExcludedTags tagSet st = st { orgStateExcludedTags = tagSet } + setEmphasisPreChar :: Maybe [Char] -> OrgParserState -> OrgParserState setEmphasisPreChar csMb st = let preChars = fromMaybe (orgStateEmphasisPostChars defaultOrgParserState) csMb diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs index d33602575..381d4c5ee 100644 --- a/src/Text/Pandoc/Readers/Org/ParserState.hs +++ b/src/Text/Pandoc/Readers/Org/ParserState.hs @@ -33,6 +33,7 @@ module Text.Pandoc.Readers.Org.ParserState , defaultOrgParserState , OrgParserLocal (..) , OrgNoteRecord + , Tag(..) , HasReaderOptions (..) , HasQuoteContext (..) , HasMacros (..) @@ -88,6 +89,9 @@ type OrgNoteTable = [OrgNoteRecord] type OrgLinkFormatters = M.Map String (String -> String) -- | Macro expander function type MacroExpander = [String] -> String +-- | Tag +newtype Tag = Tag { fromTag :: String } + deriving (Show, Eq, Ord) -- | The states in which a todo item can be data TodoState = Todo | Done @@ -113,6 +117,7 @@ data OrgParserState = OrgParserState -- specified here. , orgStateEmphasisPostChars :: [Char] -- ^ Chars allowed at after emphasis , orgStateEmphasisNewlines :: Maybe Int + , orgStateExcludedTags :: Set.Set Tag , orgStateExportSettings :: ExportSettings , orgStateHeaderMap :: M.Map Inlines String , orgStateIdentifiers :: Set.Set String @@ -183,6 +188,7 @@ defaultOrgParserState = OrgParserState , orgStateEmphasisCharStack = [] , orgStateEmphasisNewlines = Nothing , orgStateExportSettings = def + , orgStateExcludedTags = Set.singleton $ Tag "noexport" , orgStateHeaderMap = M.empty , orgStateIdentifiers = Set.empty , orgStateIncludeFiles = [] diff --git a/src/Text/Pandoc/Readers/Org/Parsing.hs b/src/Text/Pandoc/Readers/Org/Parsing.hs index b37b36624..52a346e36 100644 --- a/src/Text/Pandoc/Readers/Org/Parsing.hs +++ b/src/Text/Pandoc/Readers/Org/Parsing.hs @@ -46,6 +46,8 @@ module Text.Pandoc.Readers.Org.Parsing , orgArgKey , orgArgWord , orgArgWordChar + , orgTagWord + , orgTagWordChar -- * Re-exports from Text.Pandoc.Parser , ParserContext (..) , many1Till @@ -220,3 +222,9 @@ orgArgWord = many1 orgArgWordChar -- | Chars treated as part of a word in plists. orgArgWordChar :: Monad m => OrgParser m Char orgArgWordChar = alphaNum <|> oneOf "-_" + +orgTagWord :: Monad m => OrgParser m String +orgTagWord = many1 orgTagWordChar + +orgTagWordChar :: Monad m => OrgParser m Char +orgTagWordChar = alphaNum <|> oneOf "@%#_" diff --git a/test/command/4284.md b/test/command/4284.md new file mode 100644 index 000000000..e2a41d14f --- /dev/null +++ b/test/command/4284.md @@ -0,0 +1,29 @@ +``` +% pandoc -f org -t native +#+EXCLUDE_TAGS:apple cat bye dog % + +* This should not appear :apple: +* NOEXPORT should appear if not specified in EXCLUDE_TAGS :noexport: +* This should not appear :cat:hi:laptop: +** Children of headers with excluded tags should not appear :xylophone: +* This should not appear :%: +^D +[Header 1 ("noexport-should-appear-if-not-specified-in-excludetags",[],[]) [Str "NOEXPORT",Space,Str "should",Space,Str "appear",Space,Str "if",Space,Str "not",Space,Str "specified",Space,Str "in",Space,Str "EXCLUDE",Subscript [Str "TAGS"],Space,Span ("",["tag"],[("tag-name","noexport")]) [SmallCaps [Str "noexport"]]]] +``` + +``` +% pandoc -f org -t native +#+EXCLUDE_TAGS:elephant +* This should not appear :elephant: +* This should appear :fawn: +^D +[Header 1 ("this-should-appear",[],[]) [Str "This",Space,Str "should",Space,Str "appear",Space,Span ("",["tag"],[("tag-name","fawn")]) [SmallCaps [Str "fawn"]]]] +``` + +``` +% pandoc -f org -t native +#+EXCLUDE_TAGS: +* NOEXPORT should appear if not specified in EXCLUDE_TAGS :noexport: +^D +[Header 1 ("noexport-should-appear-if-not-specified-in-excludetags",[],[]) [Str "NOEXPORT",Space,Str "should",Space,Str "appear",Space,Str "if",Space,Str "not",Space,Str "specified",Space,Str "in",Space,Str "EXCLUDE",Subscript [Str "TAGS"],Space,Span ("",["tag"],[("tag-name","noexport")]) [SmallCaps [Str "noexport"]]]] +``` -- cgit v1.2.3 From 6207bdeb681142e9fa3731e6e0ee7fa8e6c120f5 Mon Sep 17 00:00:00 2001 From: quasicomputational Date: Sat, 6 Oct 2018 05:33:14 +0100 Subject: CommonMark writer: add plain text fallbacks. (#4531) Previously, the writer would unconditionally emit HTMLish output for subscripts, superscripts, strikeouts (if the strikeout extension is disabled) and small caps, even with raw_html disabled. Now there are plain-text (and, where possible, fancy Unicode) fallbacks for all of these corresponding (mostly) to the Markdown fallbacks, and the HTMLish output is only used when raw_html is enabled. This commit adds exported functions `toSuperscript` and `toSubscript` to `Text.Pandoc.Writers.Shared`. [API change] Closes #4528. --- MANUAL.txt | 10 ++- src/Text/Pandoc/Writers/CommonMark.hs | 52 +++++++++--- src/Text/Pandoc/Writers/Markdown.hs | 29 +------ src/Text/Pandoc/Writers/Shared.hs | 31 ++++++- test/command/4528.md | 156 ++++++++++++++++++++++++++++++++++ 5 files changed, 237 insertions(+), 41 deletions(-) create mode 100644 test/command/4528.md (limited to 'src/Text/Pandoc') diff --git a/MANUAL.txt b/MANUAL.txt index 802ce556e..bf47184ce 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -3381,8 +3381,14 @@ Markdown allows it, but it has been made an extension so that it can be disabled if desired.) The raw HTML is passed through unchanged in HTML, S5, Slidy, Slideous, -DZSlides, EPUB, Markdown, Emacs Org mode, and Textile output, and suppressed -in other formats. +DZSlides, EPUB, Markdown, CommonMark, Emacs Org mode, and Textile +output, and suppressed in other formats. + +In the CommonMark format, if `raw_html` is enabled, superscripts, +subscripts, strikeouts and small capitals will be represented as HTML. +Otherwise, plain-text fallbacks will be used. Note that even if +`raw_html` is disabled, tables will be rendered with HTML syntax if +they cannot use pipe syntax. #### Extension: `markdown_in_html_blocks` #### diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs index 27179496c..84ea37f38 100644 --- a/src/Text/Pandoc/Writers/CommonMark.hs +++ b/src/Text/Pandoc/Writers/CommonMark.hs @@ -45,7 +45,7 @@ import Network.HTTP (urlEncode) import Text.Pandoc.Class (PandocMonad) import Text.Pandoc.Definition import Text.Pandoc.Options -import Text.Pandoc.Shared (isTightList, linesToPara, substitute) +import Text.Pandoc.Shared (isTightList, linesToPara, substitute, capitalize) import Text.Pandoc.Templates (renderTemplate') import Text.Pandoc.Walk (query, walk, walkM) import Text.Pandoc.Writers.HTML (writeHtml5String, tagWithAttributes) @@ -253,18 +253,34 @@ inlineToNodes opts (Strong xs) = (node STRONG (inlinesToNodes opts xs) :) inlineToNodes opts (Strikeout xs) = if isEnabled Ext_strikeout opts then (node (CUSTOM_INLINE "~~" "~~") (inlinesToNodes opts xs) :) - else ((node (HTML_INLINE (T.pack "")) [] : inlinesToNodes opts xs ++ - [node (HTML_INLINE (T.pack "")) []]) ++ ) + else if isEnabled Ext_raw_html opts + then ((node (HTML_INLINE (T.pack "")) [] : inlinesToNodes opts xs ++ + [node (HTML_INLINE (T.pack "")) []]) ++ ) + else (inlinesToNodes opts xs ++) inlineToNodes opts (Superscript xs) = - ((node (HTML_INLINE (T.pack "")) [] : inlinesToNodes opts xs ++ - [node (HTML_INLINE (T.pack "")) []]) ++ ) + if isEnabled Ext_raw_html opts + then ((node (HTML_INLINE (T.pack "")) [] : inlinesToNodes opts xs ++ + [node (HTML_INLINE (T.pack "")) []]) ++ ) + else case traverse toSuperscriptInline xs of + Nothing -> + ((node (TEXT (T.pack "^(")) [] : inlinesToNodes opts xs ++ + [node (TEXT (T.pack ")")) []]) ++ ) + Just xs' -> (inlinesToNodes opts xs' ++) inlineToNodes opts (Subscript xs) = - ((node (HTML_INLINE (T.pack "")) [] : inlinesToNodes opts xs ++ - [node (HTML_INLINE (T.pack "")) []]) ++ ) + if isEnabled Ext_raw_html opts + then ((node (HTML_INLINE (T.pack "")) [] : inlinesToNodes opts xs ++ + [node (HTML_INLINE (T.pack "")) []]) ++ ) + else case traverse toSubscriptInline xs of + Nothing -> + ((node (TEXT (T.pack "_(")) [] : inlinesToNodes opts xs ++ + [node (TEXT (T.pack ")")) []]) ++ ) + Just xs' -> (inlinesToNodes opts xs' ++) inlineToNodes opts (SmallCaps xs) = - ((node (HTML_INLINE (T.pack "")) [] - : inlinesToNodes opts xs ++ - [node (HTML_INLINE (T.pack "")) []]) ++ ) + if isEnabled Ext_raw_html opts + then ((node (HTML_INLINE (T.pack "")) [] + : inlinesToNodes opts xs ++ + [node (HTML_INLINE (T.pack "")) []]) ++ ) + else (inlinesToNodes opts (capitalize xs) ++) inlineToNodes opts (Link _ ils (url,tit)) = (node (LINK (T.pack url) (T.pack tit)) (inlinesToNodes opts ils) :) -- title beginning with fig: indicates implicit figure @@ -319,3 +335,19 @@ inlineToNodes opts (Span attr ils) = inlineToNodes opts (Cite _ ils) = (inlinesToNodes opts ils ++) inlineToNodes _ (Note _) = id -- should not occur -- we remove Note elements in preprocessing + +toSubscriptInline :: Inline -> Maybe Inline +toSubscriptInline Space = Just Space +toSubscriptInline (Span attr ils) = Span attr <$> traverse toSubscriptInline ils +toSubscriptInline (Str s) = Str <$> traverse toSubscript s +toSubscriptInline LineBreak = Just LineBreak +toSubscriptInline SoftBreak = Just SoftBreak +toSubscriptInline _ = Nothing + +toSuperscriptInline :: Inline -> Maybe Inline +toSuperscriptInline Space = Just Space +toSuperscriptInline (Span attr ils) = Span attr <$> traverse toSuperscriptInline ils +toSuperscriptInline (Str s) = Str <$> traverse toSuperscript s +toSuperscriptInline LineBreak = Just LineBreak +toSuperscriptInline SoftBreak = Just SoftBreak +toSuperscriptInline _ = Nothing diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs index 741d11580..9a4acb59d 100644 --- a/src/Text/Pandoc/Writers/Markdown.hs +++ b/src/Text/Pandoc/Writers/Markdown.hs @@ -38,7 +38,7 @@ module Text.Pandoc.Writers.Markdown (writeMarkdown, writePlain) where import Prelude import Control.Monad.Reader import Control.Monad.State.Strict -import Data.Char (chr, isPunctuation, isSpace, ord, isAlphaNum) +import Data.Char (isPunctuation, isSpace, isAlphaNum) import Data.Default import qualified Data.HashMap.Strict as H import Data.List (find, group, intersperse, sortBy, stripPrefix, transpose) @@ -1249,33 +1249,6 @@ makeMathPlainer = walk go go (Emph xs) = Span nullAttr xs go x = x -toSuperscript :: Char -> Maybe Char -toSuperscript '1' = Just '\x00B9' -toSuperscript '2' = Just '\x00B2' -toSuperscript '3' = Just '\x00B3' -toSuperscript '+' = Just '\x207A' -toSuperscript '-' = Just '\x207B' -toSuperscript '=' = Just '\x207C' -toSuperscript '(' = Just '\x207D' -toSuperscript ')' = Just '\x207E' -toSuperscript c - | c >= '0' && c <= '9' = - Just $ chr (0x2070 + (ord c - 48)) - | isSpace c = Just c - | otherwise = Nothing - -toSubscript :: Char -> Maybe Char -toSubscript '+' = Just '\x208A' -toSubscript '-' = Just '\x208B' -toSubscript '=' = Just '\x208C' -toSubscript '(' = Just '\x208D' -toSubscript ')' = Just '\x208E' -toSubscript c - | c >= '0' && c <= '9' = - Just $ chr (0x2080 + (ord c - 48)) - | isSpace c = Just c - | otherwise = Nothing - lineBreakToSpace :: Inline -> Inline lineBreakToSpace LineBreak = Space lineBreakToSpace SoftBreak = Space diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs index 323748aad..a7bf30aaa 100644 --- a/src/Text/Pandoc/Writers/Shared.hs +++ b/src/Text/Pandoc/Writers/Shared.hs @@ -48,12 +48,15 @@ module Text.Pandoc.Writers.Shared ( , lookupMetaString , stripLeadingTrailingSpace , groffEscape + , toSubscript + , toSuperscript ) where import Prelude import Control.Monad (zipWithM) import Data.Aeson (FromJSON (..), Result (..), ToJSON (..), Value (Object), encode, fromJSON) +import Data.Char (chr, ord, isAscii, isSpace) import qualified Data.HashMap.Strict as H import Data.List (groupBy, intersperse, transpose) import qualified Data.Map as M @@ -68,7 +71,6 @@ import Text.Pandoc.Shared (stringify) import Text.Pandoc.UTF8 (toStringLazy) import Text.Pandoc.XML (escapeStringForXML) import Text.Printf (printf) -import Data.Char (isAscii, ord) -- | Create JSON value for template from a 'Meta' and an association list -- of variables, specified at the command line or in the writer. @@ -392,3 +394,30 @@ groffEscape = T.concatMap toUchar | isAscii c = T.singleton c | otherwise = T.pack $ printf "\\[u%04X]" (ord c) + +toSuperscript :: Char -> Maybe Char +toSuperscript '1' = Just '\x00B9' +toSuperscript '2' = Just '\x00B2' +toSuperscript '3' = Just '\x00B3' +toSuperscript '+' = Just '\x207A' +toSuperscript '-' = Just '\x207B' +toSuperscript '=' = Just '\x207C' +toSuperscript '(' = Just '\x207D' +toSuperscript ')' = Just '\x207E' +toSuperscript c + | c >= '0' && c <= '9' = + Just $ chr (0x2070 + (ord c - 48)) + | isSpace c = Just c + | otherwise = Nothing + +toSubscript :: Char -> Maybe Char +toSubscript '+' = Just '\x208A' +toSubscript '-' = Just '\x208B' +toSubscript '=' = Just '\x208C' +toSubscript '(' = Just '\x208D' +toSubscript ')' = Just '\x208E' +toSubscript c + | c >= '0' && c <= '9' = + Just $ chr (0x2080 + (ord c - 48)) + | isSpace c = Just c + | otherwise = Nothing diff --git a/test/command/4528.md b/test/command/4528.md new file mode 100644 index 000000000..a60f6decf --- /dev/null +++ b/test/command/4528.md @@ -0,0 +1,156 @@ +# Rendering small caps, superscripts and subscripts with and without `raw_html` + +## Small caps + +``` +% pandoc --wrap=none -f latex -t commonmark-raw_html +This has \textsc{small caps} in it. +^D +This has SMALL CAPS in it. +``` + +``` +% pandoc --wrap=none -f latex -t commonmark+raw_html +This has \textsc{small caps} in it. +^D +This has small caps in it. +``` +``` + +``` +% pandoc --wrap=none -f latex -t markdown_strict+raw_html +This has \textsc{small caps} in it. +^D +This has small caps in it. +``` + +## Strikeout + +``` +% pandoc --wrap=none -f html -t commonmark-raw_html-strikeout +This has strikeout in it. +^D +This has strikeout in it. + +``` +% pandoc --wrap=none -f html -t commonmark+raw_html-strikeout +This has strikeout in it. +^D +This has strikeout in it. +``` + +``` +% pandoc --wrap=none -f html -t commonmark-raw_html+strikeout +This has strikeout in it. +^D +This has ~~strikeout~~ in it. +``` + +``` +% pandoc --wrap=none -f html -t commonmark+raw_html+strikeout +This has strikeout in it. +^D +This has ~~strikeout~~ in it. +``` + +``` +% pandoc --wrap=none -f html -t markdown_strict-raw_html-strikeout +This has strikeout in it. +^D +This has strikeout in it. +``` + +``` +% pandoc --wrap=none -f html -t markdown_strict+raw_html-strikeout +This has strikeout in it. +^D +This has strikeout in it. +``` + +``` +% pandoc --wrap=none -f html -t markdown_strict-raw_html+strikeout +This has strikeout in it. +^D +This has ~~strikeout~~ in it. +``` + +``` +% pandoc --wrap=none -f html -t markdown_strict+raw_html+strikeout +This has strikeout in it. +^D +This has ~~strikeout~~ in it. +``` + +## Superscript + +``` +% pandoc --wrap=none -f html -t commonmark-raw_html +This has superscript in it and 2 3 again. With emphasis: 2 3. With letters: foo. With a span: 2. +^D +This has ^(superscript) in it and ² ³ again. With emphasis: ^(*2* 3). With letters: ^(foo). With a span: ². +``` + +``` +% pandoc --wrap=none -f html -t commonmark+raw_html +This has superscript in it and 2 again. +^D +This has superscript in it and 2 again. +``` + +``` +% pandoc --wrap=none -f html -t markdown_strict-raw_html-superscript +This has superscript in it and 2 again. +^D +This has ^(superscript) in it and ² again. +``` + +``` +% pandoc --wrap=none -f html -t markdown_strict+raw_html-superscript +This has superscript in it and 2 again. +^D +This has superscript in it and 2 again. +``` + +``` +% pandoc --wrap=none -f html -t markdown_strict+raw_html+superscript +This has superscript in it and 2 again. +^D +This has ^superscript^ in it and ^2^ again. +``` + +## Subscript + +``` +% pandoc --wrap=none -f html -t commonmark-raw_html +This has subscript in it and 2 3 again. With emphasis: 2 3. With letters: foo. With a span: 2. +^D +This has \_(subscript) in it and ₂ ₃ again. With emphasis: \_(*2* 3). With letters: \_(foo). With a span: ₂. +``` + +``` +% pandoc --wrap=none -f html -t commonmark+raw_html +This has subscript in it and 2 again. +^D +This has subscript in it and 2 again. +``` + +``` +% pandoc --wrap=none -f html -t markdown_strict-raw_html-subscript +This has subscript in it and 2 again. +^D +This has _(subscript) in it and ₂ again. +``` + +``` +% pandoc --wrap=none -f html -t markdown_strict+raw_html-subscript +This has subscript in it and 2 again. +^D +This has subscript in it and 2 again. +``` + +``` +% pandoc --wrap=none -f html -t markdown_strict+raw_html+subscript +This has subscript in it and 2 again. +^D +This has ~subscript~ in it and ~2~ again. +``` -- cgit v1.2.3 From e257b54124f69682c237a5c9a5f99c5c72406c88 Mon Sep 17 00:00:00 2001 From: Brian Leung Date: Fri, 5 Oct 2018 22:21:20 -0700 Subject: Org reader: fix behavior for successive calls of `#+EXCLUDE_TAGS`. (#4951) Calling `#+EXCLUDE_TAGS` multiple times should preserve the status of the previously declared tags. --- src/Text/Pandoc/Readers/Org/Meta.hs | 19 +++++++++++-------- src/Text/Pandoc/Readers/Org/ParserState.hs | 2 ++ test/command/4284.md | 11 +++++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Org/Meta.hs b/src/Text/Pandoc/Readers/Org/Meta.hs index 921cd27e0..cad1d7123 100644 --- a/src/Text/Pandoc/Readers/Org/Meta.hs +++ b/src/Text/Pandoc/Readers/Org/Meta.hs @@ -159,7 +159,7 @@ optionLine = try $ do "seq_todo" -> todoSequence >>= updateState . registerTodoSequence "typ_todo" -> todoSequence >>= updateState . registerTodoSequence "macro" -> macroDefinition >>= updateState . registerMacro - "exclude_tags" -> excludedTagSet >>= updateState . setExcludedTags + "exclude_tags" -> excludedTagList >>= updateState . setExcludedTags "pandoc-emphasis-pre" -> emphChars >>= updateState . setEmphasisPreChar "pandoc-emphasis-post" -> emphChars >>= updateState . setEmphasisPostChar _ -> mzero @@ -192,14 +192,17 @@ parseFormat = try $ replacePlain <|> replaceUrl <|> justAppend rest = manyTill anyChar (eof <|> () <$ oneOf "\n\r") tillSpecifier c = manyTill (noneOf "\n\r") (try $ string ('%':c:"")) -excludedTagSet :: Monad m => OrgParser m (Set.Set Tag) -excludedTagSet = do +excludedTagList :: Monad m => OrgParser m [Tag] +excludedTagList = do skipSpaces - Set.fromList . map Tag <$> - many (orgTagWord <* skipSpaces) <* newline - -setExcludedTags :: Set.Set Tag -> OrgParserState -> OrgParserState -setExcludedTags tagSet st = st { orgStateExcludedTags = tagSet } + map Tag <$> many (orgTagWord <* skipSpaces) <* newline + +setExcludedTags :: [Tag] -> OrgParserState -> OrgParserState +setExcludedTags tagList st = + let finalSet = if orgStateExcludedTagsChanged st + then foldr Set.insert (orgStateExcludedTags st) tagList + else Set.fromList tagList + in st { orgStateExcludedTags = finalSet, orgStateExcludedTagsChanged = True} setEmphasisPreChar :: Maybe [Char] -> OrgParserState -> OrgParserState setEmphasisPreChar csMb st = diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs index 381d4c5ee..59478256f 100644 --- a/src/Text/Pandoc/Readers/Org/ParserState.hs +++ b/src/Text/Pandoc/Readers/Org/ParserState.hs @@ -118,6 +118,7 @@ data OrgParserState = OrgParserState , orgStateEmphasisPostChars :: [Char] -- ^ Chars allowed at after emphasis , orgStateEmphasisNewlines :: Maybe Int , orgStateExcludedTags :: Set.Set Tag + , orgStateExcludedTagsChanged :: Bool , orgStateExportSettings :: ExportSettings , orgStateHeaderMap :: M.Map Inlines String , orgStateIdentifiers :: Set.Set String @@ -189,6 +190,7 @@ defaultOrgParserState = OrgParserState , orgStateEmphasisNewlines = Nothing , orgStateExportSettings = def , orgStateExcludedTags = Set.singleton $ Tag "noexport" + , orgStateExcludedTagsChanged = False , orgStateHeaderMap = M.empty , orgStateIdentifiers = Set.empty , orgStateIncludeFiles = [] diff --git a/test/command/4284.md b/test/command/4284.md index e2a41d14f..eddd1b03a 100644 --- a/test/command/4284.md +++ b/test/command/4284.md @@ -20,6 +20,17 @@ [Header 1 ("this-should-appear",[],[]) [Str "This",Space,Str "should",Space,Str "appear",Space,Span ("",["tag"],[("tag-name","fawn")]) [SmallCaps [Str "fawn"]]]] ``` +``` +% pandoc -f org -t native +#+EXCLUDE_TAGS: giraffe +#+EXCLUDE_TAGS: hippo +* This should not appear :giraffe: +* This should not appear :hippo: +* This should appear :noexport: +^D +[Header 1 ("this-should-appear",[],[]) [Str "This",Space,Str "should",Space,Str "appear",Space,Span ("",["tag"],[("tag-name","noexport")]) [SmallCaps [Str "noexport"]]]] +``` + ``` % pandoc -f org -t native #+EXCLUDE_TAGS: -- cgit v1.2.3 From 73afce113b4dc06bc5c1c3b36ca94f6eb24cd109 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Sat, 6 Oct 2018 15:21:24 +0300 Subject: Moved Haddock comment in Muse reader --- src/Text/Pandoc/Readers/Muse.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Muse.hs b/src/Text/Pandoc/Readers/Muse.hs index 418ba71f2..134598c07 100644 --- a/src/Text/Pandoc/Readers/Muse.hs +++ b/src/Text/Pandoc/Readers/Muse.hs @@ -98,12 +98,11 @@ instance Default MuseState where } data MuseEnv = - MuseEnv { museInLink :: Bool } + MuseEnv { museInLink :: Bool -- ^ True when parsing a link description to avoid nested links + } instance Default MuseEnv where - def = MuseEnv { museInLink = False - -- True when parsing a link description to avoid nested links - } + def = MuseEnv { museInLink = False } type MuseParser m = ParserT Text MuseState (ReaderT MuseEnv m) -- cgit v1.2.3 From bd8a66394bc25b52dca9ffd963a560a4ca492f9c Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 6 Oct 2018 22:33:24 -0700 Subject: RST writer: use simple tables when possible. Closes #4750. Text.Pandoc.Writers.Shared now exports hasSimpleCells [API change]. --- src/Text/Pandoc/Writers/RST.hs | 38 ++++++++++++++++++++++--- src/Text/Pandoc/Writers/Shared.hs | 18 ++++++++++++ test/tables-rstsubset.native | 8 +++--- test/tables.rst | 60 +++++++++++++++++---------------------- 4 files changed, 82 insertions(+), 42 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs index 34d5cce04..d64529c21 100644 --- a/src/Text/Pandoc/Writers/RST.hs +++ b/src/Text/Pandoc/Writers/RST.hs @@ -35,7 +35,7 @@ module Text.Pandoc.Writers.RST ( writeRST, flatten ) where import Prelude import Control.Monad.State.Strict import Data.Char (isSpace, toLower) -import Data.List (isPrefixOf, stripPrefix) +import Data.List (isPrefixOf, stripPrefix, transpose) import Data.Maybe (fromMaybe) import Data.Text (Text, stripEnd) import qualified Text.Pandoc.Builder as B @@ -304,9 +304,12 @@ blockToRST (Table caption aligns widths headers rows) = do modify $ \st -> st{ stOptions = oldOpts } return result opts <- gets stOptions - tbl <- gridTable opts blocksToDoc (all null headers) - (map (const AlignDefault) aligns) widths - headers rows + let isSimple = all (== 0) widths + tbl <- if isSimple + then simpleTable opts blocksToDoc headers rows + else gridTable opts blocksToDoc (all null headers) + (map (const AlignDefault) aligns) widths + headers rows return $ if null caption then tbl $$ blankline else (".. table:: " <> caption') $$ blankline $$ nest 3 tbl $$ @@ -693,3 +696,30 @@ imageDimsToRST attr = do Just dim -> cols dim Nothing -> empty return $ cr <> name $$ showDim Width $$ showDim Height + +simpleTable :: PandocMonad m + => WriterOptions + -> (WriterOptions -> [Block] -> m Doc) + -> [[Block]] + -> [[[Block]]] + -> m Doc +simpleTable opts blocksToDoc headers rows = do + -- can't have empty cells in first column: + let fixEmpties (d:ds) = if isEmpty d + then text "\\ " : ds + else d : ds + fixEmpties [] = [] + headerDocs <- if all null headers + then return [] + else fixEmpties <$> mapM (blocksToDoc opts) headers + rowDocs <- mapM (fmap fixEmpties . mapM (blocksToDoc opts)) rows + let numChars [] = 0 + numChars xs = maximum . map offset $ xs + let colWidths = map numChars $ transpose (headerDocs : rowDocs) + let toRow = hsep . zipWith lblock colWidths + let hline = hsep (map (\n -> text (replicate n '=')) colWidths) + let hdr = if all null headers + then mempty + else hline $$ toRow headerDocs + let bdy = vcat $ map toRow rowDocs + return $ hdr $$ hline $$ bdy $$ hline diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs index a7bf30aaa..ed2c46d7b 100644 --- a/src/Text/Pandoc/Writers/Shared.hs +++ b/src/Text/Pandoc/Writers/Shared.hs @@ -41,6 +41,7 @@ module Text.Pandoc.Writers.Shared ( , isDisplayMath , fixDisplayMath , unsmartify + , hasSimpleCells , gridTable , lookupMetaBool , lookupMetaBlocks @@ -54,6 +55,7 @@ module Text.Pandoc.Writers.Shared ( where import Prelude import Control.Monad (zipWithM) +import Data.Monoid (Any (..)) import Data.Aeson (FromJSON (..), Result (..), ToJSON (..), Value (Object), encode, fromJSON) import Data.Char (chr, ord, isAscii, isSpace) @@ -70,6 +72,7 @@ import Text.Pandoc.Pretty import Text.Pandoc.Shared (stringify) import Text.Pandoc.UTF8 (toStringLazy) import Text.Pandoc.XML (escapeStringForXML) +import Text.Pandoc.Walk (query) import Text.Printf (printf) -- | Create JSON value for template from a 'Meta' and an association list @@ -243,6 +246,21 @@ unsmartify opts ('\8216':xs) = '\'' : unsmartify opts xs unsmartify opts (x:xs) = x : unsmartify opts xs unsmartify _ [] = [] +-- | True if block is a table that can be represented with +-- one line per row. +hasSimpleCells :: Block -> Bool +hasSimpleCells (Table _caption _aligns _widths headers rows) = + all isSimpleCell (concat (headers:rows)) + where + isLineBreak LineBreak = Any True + isLineBreak _ = Any False + hasLineBreak = getAny . query isLineBreak + isSimpleCell [Plain ils] = not (hasLineBreak ils) + isSimpleCell [Para ils ] = not (hasLineBreak ils) + isSimpleCell [] = True + isSimpleCell _ = False +hasSimpleCells _ = False + gridTable :: Monad m => WriterOptions -> (WriterOptions -> [Block] -> m Doc) diff --git a/test/tables-rstsubset.native b/test/tables-rstsubset.native index 5ea520d7c..a4f801b1c 100644 --- a/test/tables-rstsubset.native +++ b/test/tables-rstsubset.native @@ -1,5 +1,5 @@ [Para [Str "Simple",Space,Str "table",Space,Str "with",Space,Str "caption:"] -,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1,8.75e-2,0.1125,0.125] +,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0,0.0] [[Plain [Str "Right"]] ,[Plain [Str "Left"]] ,[Plain [Str "Center"]] @@ -17,7 +17,7 @@ ,[Plain [Str "1"]] ,[Plain [Str "1"]]]] ,Para [Str "Simple",Space,Str "table",Space,Str "without",Space,Str "caption:"] -,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1,8.75e-2,0.1125,0.125] +,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0,0.0] [[Plain [Str "Right"]] ,[Plain [Str "Left"]] ,[Plain [Str "Center"]] @@ -35,7 +35,7 @@ ,[Plain [Str "1"]] ,[Plain [Str "1"]]]] ,Para [Str "Simple",Space,Str "table",Space,Str "indented",Space,Str "two",Space,Str "spaces:"] -,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1,8.75e-2,0.1125,0.125] +,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0,0.0] [[Plain [Str "Right"]] ,[Plain [Str "Left"]] ,[Plain [Str "Center"]] @@ -81,7 +81,7 @@ ,[Plain [Str "5.0"]] ,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",Space,Str "Note",SoftBreak,Str "the",Space,Str "blank",Space,Str "line",Space,Str "between",SoftBreak,Str "rows."]]]] ,Para [Str "Table",Space,Str "without",Space,Str "column",Space,Str "headers:"] -,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [7.5e-2,7.5e-2,7.5e-2,7.5e-2] +,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0,0.0] [[] ,[] ,[] diff --git a/test/tables.rst b/test/tables.rst index 4559883cd..660df61d4 100644 --- a/test/tables.rst +++ b/test/tables.rst @@ -2,41 +2,35 @@ Simple table with caption: .. table:: Demonstration of simple table syntax. - +-------+------+--------+---------+ - | Right | Left | Center | Default | - +=======+======+========+=========+ - | 12 | 12 | 12 | 12 | - +-------+------+--------+---------+ - | 123 | 123 | 123 | 123 | - +-------+------+--------+---------+ - | 1 | 1 | 1 | 1 | - +-------+------+--------+---------+ + ===== ==== ====== ======= + Right Left Center Default + ===== ==== ====== ======= + 12 12 12 12 + 123 123 123 123 + 1 1 1 1 + ===== ==== ====== ======= Simple table without caption: -+-------+------+--------+---------+ -| Right | Left | Center | Default | -+=======+======+========+=========+ -| 12 | 12 | 12 | 12 | -+-------+------+--------+---------+ -| 123 | 123 | 123 | 123 | -+-------+------+--------+---------+ -| 1 | 1 | 1 | 1 | -+-------+------+--------+---------+ +===== ==== ====== ======= +Right Left Center Default +===== ==== ====== ======= +12 12 12 12 +123 123 123 123 +1 1 1 1 +===== ==== ====== ======= Simple table indented two spaces: .. table:: Demonstration of simple table syntax. - +-------+------+--------+---------+ - | Right | Left | Center | Default | - +=======+======+========+=========+ - | 12 | 12 | 12 | 12 | - +-------+------+--------+---------+ - | 123 | 123 | 123 | 123 | - +-------+------+--------+---------+ - | 1 | 1 | 1 | 1 | - +-------+------+--------+---------+ + ===== ==== ====== ======= + Right Left Center Default + ===== ==== ====== ======= + 12 12 12 12 + 123 123 123 123 + 1 1 1 1 + ===== ==== ====== ======= Multiline table with caption: @@ -70,13 +64,11 @@ Multiline table without caption: Table without column headers: -+-----+-----+-----+-----+ -| 12 | 12 | 12 | 12 | -+-----+-----+-----+-----+ -| 123 | 123 | 123 | 123 | -+-----+-----+-----+-----+ -| 1 | 1 | 1 | 1 | -+-----+-----+-----+-----+ +=== === === === +12 12 12 12 +123 123 123 123 +1 1 1 1 +=== === === === Multiline table without column headers: -- cgit v1.2.3