packages feed

pandoc 2.3 → 2.3.1

raw patch · 53 files changed

+1791/−1312 lines, 53 filesdep ~hsluadep ~hslua-module-textPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: hslua, hslua-module-text

API changes (from Hackage documentation)

- Text.Pandoc.Lua: data LuaException
- Text.Pandoc.Readers.LaTeX: instance Data.Default.Class.Default Text.Pandoc.Readers.LaTeX.LaTeXState
- Text.Pandoc.Readers.LaTeX: instance GHC.Show.Show Text.Pandoc.Readers.LaTeX.DottedNum
- Text.Pandoc.Readers.LaTeX: instance GHC.Show.Show Text.Pandoc.Readers.LaTeX.LaTeXState
- Text.Pandoc.Readers.LaTeX: instance Text.Pandoc.Builder.HasMeta Text.Pandoc.Readers.LaTeX.LaTeXState
- Text.Pandoc.Readers.LaTeX: instance Text.Pandoc.Class.PandocMonad m => Text.Pandoc.Parsing.HasQuoteContext Text.Pandoc.Readers.LaTeX.LaTeXState m
- Text.Pandoc.Readers.LaTeX: instance Text.Pandoc.Parsing.HasHeaderMap Text.Pandoc.Readers.LaTeX.LaTeXState
- Text.Pandoc.Readers.LaTeX: instance Text.Pandoc.Parsing.HasIdentifierList Text.Pandoc.Readers.LaTeX.LaTeXState
- Text.Pandoc.Readers.LaTeX: instance Text.Pandoc.Parsing.HasIncludeFiles Text.Pandoc.Readers.LaTeX.LaTeXState
- Text.Pandoc.Readers.LaTeX: instance Text.Pandoc.Parsing.HasLogMessages Text.Pandoc.Readers.LaTeX.LaTeXState
- Text.Pandoc.Readers.LaTeX: instance Text.Pandoc.Parsing.HasMacros Text.Pandoc.Readers.LaTeX.LaTeXState
- Text.Pandoc.Readers.LaTeX: instance Text.Pandoc.Parsing.HasReaderOptions Text.Pandoc.Readers.LaTeX.LaTeXState
- Text.Pandoc.Writers.Custom: instance (Foreign.Lua.Types.ToLuaStack.ToLuaStack a, Foreign.Lua.Types.ToLuaStack.ToLuaStack b) => Foreign.Lua.Types.ToLuaStack.ToLuaStack (Text.Pandoc.Writers.Custom.KeyValue a b)
- Text.Pandoc.Writers.Custom: instance Foreign.Lua.Types.ToLuaStack.ToLuaStack (Text.Pandoc.Writers.Custom.Stringify Text.Pandoc.Definition.Citation)
- Text.Pandoc.Writers.Custom: instance Foreign.Lua.Types.ToLuaStack.ToLuaStack (Text.Pandoc.Writers.Custom.Stringify Text.Pandoc.Definition.Format)
- Text.Pandoc.Writers.Custom: instance Foreign.Lua.Types.ToLuaStack.ToLuaStack (Text.Pandoc.Writers.Custom.Stringify Text.Pandoc.Definition.MetaValue)
- Text.Pandoc.Writers.Custom: instance Foreign.Lua.Types.ToLuaStack.ToLuaStack (Text.Pandoc.Writers.Custom.Stringify [Text.Pandoc.Definition.Block])
- Text.Pandoc.Writers.Custom: instance Foreign.Lua.Types.ToLuaStack.ToLuaStack (Text.Pandoc.Writers.Custom.Stringify [Text.Pandoc.Definition.Inline])
+ Text.Pandoc.Lua: newtype LuaException
+ Text.Pandoc.Writers.Custom: instance (Foreign.Lua.Types.Pushable.Pushable a, Foreign.Lua.Types.Pushable.Pushable b) => Foreign.Lua.Types.Pushable.Pushable (Text.Pandoc.Writers.Custom.KeyValue a b)
+ Text.Pandoc.Writers.Custom: instance Foreign.Lua.Types.Pushable.Pushable (Text.Pandoc.Writers.Custom.Stringify Text.Pandoc.Definition.Citation)
+ Text.Pandoc.Writers.Custom: instance Foreign.Lua.Types.Pushable.Pushable (Text.Pandoc.Writers.Custom.Stringify Text.Pandoc.Definition.Format)
+ Text.Pandoc.Writers.Custom: instance Foreign.Lua.Types.Pushable.Pushable (Text.Pandoc.Writers.Custom.Stringify Text.Pandoc.Definition.MetaValue)
+ Text.Pandoc.Writers.Custom: instance Foreign.Lua.Types.Pushable.Pushable (Text.Pandoc.Writers.Custom.Stringify [Text.Pandoc.Definition.Block])
+ Text.Pandoc.Writers.Custom: instance Foreign.Lua.Types.Pushable.Pushable (Text.Pandoc.Writers.Custom.Stringify [Text.Pandoc.Definition.Inline])

Files

AUTHORS.md view
@@ -28,6 +28,7 @@ - Bjorn Buckwalter - Bradley Kuhn - Brent Yorgey+- Brian Leung - Bryan O'Sullivan - Caleb McDaniel - Calvin Beck@@ -75,6 +76,7 @@ - Hubert Plociniczak - Igor Khorlo - Ilya V. Portnov+- Ivan Trubach - Ivo Clarysse - J. B. Rainsberger - J. Lewis Muir@@ -96,6 +98,7 @@ - John Muccigrosso - John Luke Bentley - Jonas Smedegaard+- Jonas Scholl - Jonathan Daugherty - Jose Luis Duran - José de Mattos Neto@@ -138,6 +141,7 @@ - Nick Bart - Nicolas Kaiser - Nikolay Yakimov+- Nils Carlson - Nokome Bentley - Oliver Matthews - Ophir Lifshitz
MANUAL.txt view
@@ -1,6 +1,6 @@ % Pandoc User's Guide % John MacFarlane-% September 16, 2018+% September 27, 2018  Synopsis ========@@ -211,7 +211,7 @@ Options ======= -General options+General options {.options} ---------------  `-f` *FORMAT*, `-r` *FORMAT*, `--from=`*FORMAT*, `--read=`*FORMAT*@@ -459,7 +459,7 @@ [PowerPoint]: https://en.wikipedia.org/wiki/Microsoft_PowerPoint [Vimwiki]: https://vimwiki.github.io -Reader options+Reader options {.options} --------------  `--base-header-level=`*NUMBER*@@ -645,7 +645,7 @@ [perl]: https://metacpan.org/pod/Pandoc::Filter [JavaScript/node.js]: https://github.com/mvhenderson/pandoc-filter-node -General writer options+General writer options {.options} ----------------------  `-s`, `--standalone`@@ -828,7 +828,7 @@     downloaded). If you're behind a proxy, you also need to set     the environment variable `http_proxy` to `http://...`. -Options affecting specific writers+Options affecting specific writers {.options} ----------------------------------  `--self-contained`@@ -1150,7 +1150,7 @@ [Encoding issue with the listings package]:   https://en.wikibooks.org/wiki/LaTeX/Source_Code_Listings#Encoding_issue -Citation rendering+Citation rendering {.options} ------------------  `--bibliography=`*FILE*@@ -1190,7 +1190,7 @@     with the `pandoc-citeproc` filter or with PDF output. It is intended for     use in producing a LaTeX file that can be processed with [`bibtex`] or [`biber`]. -Math rendering in HTML+Math rendering in HTML {.options} ----------------------  The default is to render TeX math as far as possible using Unicode characters.@@ -1251,7 +1251,7 @@ [KaTeX]: https://github.com/Khan/KaTeX [GladTeX]: http://humenda.github.io/GladTeX/ -Options for wrapper scripts+Options for wrapper scripts {.options} ---------------------------  `--dump-args`@@ -4627,9 +4627,9 @@ The `epub:type` attribute ------------------------- -You can mark up the header that corresponds to an EPUB chapter using the-[`epub:type` attribute][epub-type]. For example, to set the attribute-to the value `prologue`, use this markdown:+For `epub3` output, you can mark up the header that corresponds to an EPUB+chapter using the [`epub:type` attribute][epub-type]. For example, to set+the attribute to the value `prologue`, use this markdown:      # My chapter {epub:type=prologue} 
changelog view
@@ -1,3 +1,108 @@+pandoc (2.3.1)++  * RST reader:++    + Parse RST inlines containing newlines (#4912, Francesco Occhipinti).+      This eliminates a regression introduced after pandoc 2.1.1, which+      caused inline constructions containing newlines not to be recognized.+    + Fix bug with internal link targets (#4919).  They were gobbling up+      indented content underneath.++  * 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 AST.++  * Org reader:++    + Force inline code blocks to honor export options (Brian Leung).+    + Parse empty argument array in inline src blocks (Brian Leung).++  * Muse reader (Alexander Krotov):++    + Added additional tests.+    + Do not allow code markup to be followed by digit.+    + Remove heading level limit.+    + Simplify `<literal>` tag parsers+    + Parse Text instead of String. Benchmark shows 7% improvement.+    + Get rid of HTML parser dependency.+    + Various code improvements.++  * ConTeXt writer: change `\` to `/` in Windows image paths (#4918).+    We do this in the LaTeX writer, and it avoids problems.+    Note that `/` works as a LaTeX path separator on Windows.++  * LaTeX writer:++    + Add support for multiprenote and multipostnote arguments+      with `--biblatex` (Brian Leung, #4930).  The multiprenotes occur before+      the first prefix of a multicite, and the multipostnotes follow the+      last suffix.+    + 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.++  * RTF writer: Fix build failure with ghc-8.6.1 caused by missing+    MonadFail instance (Jonas Scholl).++  * ODT Writer: Improve table header row style handling (Nils Carlson).+    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.++  * HTML writer:++    + Don't add `uri` class to presumed autolinks.  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+      `<http://example.com>`.  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.+    + 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.+    + Omit unknown attributes in EPUB2 output.  For example,+      `epub:type` attributes should not be passed through,+      or the epub produced will not validate.++  * JATS writer: remove 'role' attribute on 'bold' and 'sc' elements (#4937).+    The JATS spec does not allow these.++  * Textile writer: don't represent `uri` class explicitly+    for autolinks (#4913).++  * Lua filters (Albert Krewinkel):++    + Cleanup filter execution code.+    + Better error on test failure.++  * HTML, Muse reader tests: reduce time taken by round-trip test.++  * Added cabal.project.++  * MANUAL: `epub:type` is only useful for epub3 (Maura Bieg).++  * Use hslua v1.0.0 (Albert Krewinkel).++  * Fix `translations/ru` to use modern Russian orthography+    (Ivan Trubach).++  * Build Windows binary using ghc 8.6.1 and cabal new-build. This+    fixes issues with segfaults in the 32-bit Windows binaries (#4283).+ pandoc (2.3)    * Add `--metadata-file` option (Mauro Bieg, #1960), which allows@@ -53,6 +158,9 @@    * LaTeX reader: +    + Split some general-purpose definitions into a separate, unexported+      module, Text.Pandoc.Readers.LaTeX.Parsing.  This is to avoid+      out-of-memory errors compiling the LaTeX reader.     + Handle parameter patterns for `\def` (#4768, #4771).       For example:  `\def\foo#1[#2]{#1 and #2}`.     + Allow `%` characters in URLs. This affects `\href` and `\url` (#4832).
data/translations/ru.yaml view
@@ -1,20 +1,20 @@-Abstract: Аннотація-Appendix: Приложеніе+Abstract: Аннотация+Appendix: Приложение Author: Именной указатель-Bibliography: Библіографія+Bibliography: Литература Cc: исх. Chapter: Глава-Contents: Оглавленіе+Contents: Оглавление Encl: вкл. Figure: Рис.-Index: Предмѣтный указатель-ListOfFigures: Списокъ иллюстрацій-ListOfTables: Списокъ таблицъ+Index: Предметный указатель+ListOfFigures: Список иллюстраций+ListOfTables: Список таблиц Page: с. Part: Часть-Preface: Предисловіе+Preface: Предисловие Proof: Доказательство-References: Примѣчанія+References: Список литературы See: см. SeeAlso: см. также Table: Таблица
man/pandoc.1 view
@@ -1,5 +1,5 @@ .\"t-.TH PANDOC 1 "September 16, 2018" "pandoc 2.3"+.TH PANDOC 1 "September 27, 2018" "pandoc 2.3.1" .SH NAME pandoc - general markup converter .SH SYNOPSIS@@ -5786,8 +5786,8 @@ .RE .SS The \f[C]epub:type\f[] attribute .PP-You can mark up the header that corresponds to an EPUB chapter using the-\f[C]epub:type\f[] attribute.+For \f[C]epub3\f[] output, you can mark up the header that corresponds+to an EPUB chapter using the \f[C]epub:type\f[] attribute. For example, to set the attribute to the value \f[C]prologue\f[], use this markdown: .IP
pandoc.cabal view
@@ -1,5 +1,5 @@ name:            pandoc-version:         2.3+version:         2.3.1 cabal-version:   2.0 build-type:      Custom license:         GPL-2@@ -372,8 +372,8 @@                  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,@@ -508,6 +508,7 @@                    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,@@ -615,7 +616,7 @@                   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,
src/Text/Pandoc/Lua.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2017–2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de> @@ -16,6 +15,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 NoImplicitPrelude #-} {- |    Module      : Text.Pandoc.Lua    Copyright   : Copyright © 2017–2018 Albert Krewinkel@@ -34,12 +34,11 @@  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 @@   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
src/Text/Pandoc/Lua/Filter.hs view
@@ -1,6 +1,33 @@-{-# LANGUAGE NoImplicitPrelude #-}+{-+Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>+            2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>++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 <tarleb+pandoc@moltkeplatz.de>+Stability   : alpha +Types and functions for running Lua filters.+-} module Text.Pandoc.Lua.Filter ( LuaFilterFunction                               , LuaFilter                               , tryFilter@@ -12,62 +39,57 @@                               , 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.Data (Data, DataType, dataTypeConstrs, dataTypeName, dataTypeOf,+                  showConstr, toConstr, tyconUQname) 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 Foreign.Lua (Lua, Peekable, Pushable)+import Text.Pandoc.Definition+import Text.Pandoc.Lua.StackInstances () import Text.Pandoc.Walk (walkM, Walkable)-import Data.Data (Data, DataType, dataTypeConstrs, dataTypeName, dataTypeOf,-                  showConstr, toConstr, tyconUQname)-import Text.Pandoc.Lua.StackInstances()-import Text.Pandoc.Lua.Util (typeCheck) -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 in the registry+newtype LuaFilterFunction = LuaFilterFunction Lua.Reference -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+instance Peekable LuaFilter where+  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+            Nothing -> acc+            Just fn -> Map.insert constr fn acc+    LuaFilter <$> foldrM go Map.empty constrs --- | Push the filter function to the top of the stack.+-- | 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)+pushFilterFunction (LuaFilterFunction fnRef) =+  Lua.getref Lua.registryindex fnRef -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 -elementOrList :: FromLuaStack a => a -> Lua [a]+elementOrList :: Peekable a => a -> Lua [a] elementOrList x = do   let topOfStack = Lua.stackTop   elementUnchanged <- Lua.isnil topOfStack@@ -77,12 +99,10 @@        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)@@ -96,14 +116,13 @@ -- 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-  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.withExceptionMessage (errorPrefix <>) $ do+    pushFilterFunction lf+    Lua.push x+    Lua.call 1 1  walkMWithLuaFilter :: LuaFilter -> Pandoc -> Lua Pandoc walkMWithLuaFilter f =@@ -156,7 +175,7 @@ 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@@ -167,6 +186,6 @@       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
src/Text/Pandoc/Lua/Init.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de> @@ -16,6 +15,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 NoImplicitPrelude #-} {- |    Module      : Text.Pandoc.Lua    Copyright   : Copyright © 2017-2018 Albert Krewinkel@@ -40,7 +40,7 @@ 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.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
src/Text/Pandoc/Lua/Module/MediaBag.hs view
@@ -87,7 +87,7 @@   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)
src/Text/Pandoc/Lua/Module/Pandoc.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de> @@ -17,6 +16,7 @@ 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 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 @@ -- 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 @@     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 @@        -> 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 @@   , 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 @@         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
src/Text/Pandoc/Lua/Module/Utils.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de> @@ -16,6 +15,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 NoImplicitPrelude #-} {- |    Module      : Text.Pandoc.Lua.Module.Utils    Copyright   : Copyright © 2017-2018 Albert Krewinkel@@ -33,11 +33,11 @@ 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 @@             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 @@   | 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
src/Text/Pandoc/Lua/Packages.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de> @@ -16,8 +15,9 @@ 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 @@  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 @@ -- | 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 @@  where   pushWrappedHsFun f = do     Lua.pushHaskellFunction f-    Lua.wrapHaskellFunction     return 1   searchPureLuaLoader = do     let filename = pkgName ++ ".lua"@@ -97,21 +91,19 @@         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
src/Text/Pandoc/Lua/StackInstances.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>             2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>@@ -19,6 +18,7 @@ -} {-# LANGUAGE FlexibleInstances    #-} {-# LANGUAGE LambdaCase           #-}+{-# LANGUAGE NoImplicitPrelude    #-} {-# LANGUAGE ScopedTypeVariables  #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {- |@@ -37,67 +37,59 @@ 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 @@     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 Pushable Alignment where+  push = Lua.push . show+instance Peekable Alignment where+  peek = Lua.peekRead -instance ToLuaStack ListNumberStyle where-  push = push . show-instance FromLuaStack ListNumberStyle where-  peek idx = safeRead' =<< peek idx+instance Pushable CitationMode where+  push = Lua.push . show+instance Peekable CitationMode where+  peek = Lua.peekRead -instance ToLuaStack MathType where-  push = push . show-instance FromLuaStack MathType where-  peek idx = safeRead' =<< peek idx+instance Pushable Format where+  push (Format f) = Lua.push f+instance Peekable Format where+  peek idx = Format <$> Lua.peek idx -instance ToLuaStack QuoteType where-  push = push . show-instance FromLuaStack QuoteType where-  peek idx = safeRead' =<< peek idx+instance Pushable ListNumberDelim where+  push = Lua.push . show+instance Peekable ListNumberDelim where+  peek = Lua.peekRead -instance ToLuaStack Double where-  push = push . (realToFrac :: Double -> LuaNumber)-instance FromLuaStack Double where-  peek = fmap (realToFrac :: LuaNumber -> Double) . peek+instance Pushable ListNumberStyle where+  push = Lua.push . show+instance Peekable ListNumberStyle where+  peek = Lua.peekRead -instance ToLuaStack Int where-  push = push . (fromIntegral :: Int -> LuaInteger)-instance FromLuaStack Int where-  peek = fmap (fromIntegral :: LuaInteger-> Int) . peek+instance Pushable MathType where+  push = Lua.push . show+instance Peekable MathType where+  peek = Lua.peekRead -safeRead' :: Read a => String -> Lua a-safeRead' s = case safeRead s of-  Nothing -> throwLuaError ("Could not read: " ++ s)-  Just x  -> return x+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 @@         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 @@ -- | 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 @@       "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 @@ -- | 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 @@     "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 @@ -- | 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 @@ -- -- Reader Options ---instance ToLuaStack Extensions where-  push exts = push (show exts)--instance ToLuaStack TrackChanges where-  push = push . showConstr . toConstr+instance Pushable Extensions where+  push exts = Lua.push (show exts) -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)
src/Text/Pandoc/Lua/Util.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE NoImplicitPrelude #-} {- Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>             2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>@@ -18,6 +17,8 @@ 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 @@   , 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 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 @@     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 @@ -- | 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 @@ 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 <> ": ") <>)
src/Text/Pandoc/Readers/LaTeX.hs view
@@ -47,8 +47,7 @@ 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.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 @@                             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,152 +136,7 @@ --        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 rawLaTeXBlock = do@@ -326,353 +180,6 @@   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 ']')--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@@ -684,13 +191,6 @@         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@@ -1391,9 +891,6 @@ breve 'u' = "ŭ" breve c   = [c] -toksToString :: [Tok] -> String-toksToString = T.unpack . untokenize- mathDisplay :: String -> Inlines mathDisplay = displayMath . trim @@ -1470,7 +967,21 @@ 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 +989,17 @@                              (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@@ -1532,22 +1054,12 @@           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) +paropt :: PandocMonad m => LP m Inlines+paropt = parenWrapped inline+ rawopt :: PandocMonad m => LP m Text rawopt = do   inner <- untokenize <$> bracketedToks@@ -1578,20 +1090,6 @@                     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 "]" @@ -1601,17 +1099,6 @@ 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@@ -2331,9 +1818,6 @@ 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@@ -2383,11 +1867,6 @@          Nothing -> return ()   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
+ src/Text/Pandoc/Readers/LaTeX/Parsing.hs view
@@ -0,0 +1,663 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>++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 <jgm@berkeley.edu>+   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)
src/Text/Pandoc/Readers/Markdown.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RelaxedPolyRec      #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}  {- Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>@@ -1879,23 +1880,24 @@ 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 `<http://hi---there>`,   -- 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
src/Text/Pandoc/Readers/Muse.hs view
@@ -43,7 +43,7 @@ import Control.Monad import Control.Monad.Except (throwError) import Data.Bifunctor-import Data.Char (isLetter, isDigit)+import Data.Char (isAlphaNum) import Data.Default import Data.List (intercalate) import Data.List.Split (splitOn)@@ -56,11 +56,11 @@ 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.Readers.HTML (htmlTag)-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@@ -68,7 +68,8 @@          -> 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@@ -98,7 +99,7 @@                   , museInPara = False                   } -type MuseParser = ParserT String MuseState+type MuseParser = ParserT Text MuseState  instance HasReaderOptions MuseState where   extractReaderOptions = museOptions@@ -125,7 +126,7 @@   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@@ -144,9 +145,8 @@  -- | 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@@ -165,6 +165,9 @@   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.@@ -179,25 +182,18 @@  -- ** HTML parsers --- | 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)+openTag :: PandocMonad m => String -> MuseParser m [(String, String)]+openTag tag = try $+  char '<' *> string tag *> manyTill attr (char '>')   where-    endtag = void $ htmlTag (~== TagClose tag)+    attr = try $ (,)+      <$  many1 spaceChar+      <*> many1 (noneOf "=\n")+      <*  string "=\""+      <*> manyTill (noneOf "\"") (char '"') -htmlBlock :: PandocMonad m-          => String -- ^ Tag name-          -> MuseParser m (Attr, String)-htmlBlock tag = try $ do-  many spaceChar-  res <- htmlElement tag-  manyTill spaceChar eol-  return res+closeTag :: PandocMonad m => String -> MuseParser m ()+closeTag tag = try $ string "</" *> string tag *> void (char '>')  -- | Convert HTML attributes to Pandoc 'Attr' htmlAttrToPandoc :: [Attribute String] -> Attr@@ -213,13 +209,11 @@ 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)  -- ** Directive parsers @@ -228,21 +222,19 @@ 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 inline' 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@@ -266,8 +258,8 @@   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)@@ -281,7 +273,7 @@              => MuseParser m (F Blocks) parseSection =   ((B.<>) <$> emacsHeading <*> parseBlocks) <|>-  ((uncurry (B.<>)) <$> amuseHeadingUntil parseBlocks)+  (uncurry (B.<>) <$> amuseHeadingUntil parseBlocks)  parseBlocksTill :: PandocMonad m                 => MuseParser m a@@ -357,30 +349,26 @@  -- | 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)-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-  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)+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)@@ -406,33 +394,28 @@ -- | 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 @\<example>@ 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 @\<literal>@ tag as a raw block. -- For 'RawInline' @\<literal>@ parser, see 'inlineLiteralTag'. literalTag :: PandocMonad m => MuseParser m (F Blocks)-literalTag = try $ do-  many spaceChar-  (TagOpen _ attr, _) <- htmlTag (~== TagOpen "literal" [])-  manyTill spaceChar eol-  content <- manyTill anyChar endtag-  manyTill spaceChar eol-  return $ return $ rawBlock (htmlAttrToPandoc attr, content)-  where-    endtag = void $ htmlTag (~== TagClose "literal")-    -- FIXME: Emacs Muse inserts <literal> 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 <literal> 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 @\<center>@ tag. -- Currently it is ignored as Pandoc cannot represent centered blocks.@@ -471,8 +454,8 @@  verseLine :: PandocMonad m => MuseParser m (F Inlines) verseLine = do-  indent <- (B.str <$> many1 (char ' ' >> pure '\160')) <|> pure mempty-  rest <- manyTill (choice inlineList) newline+  indent <- (B.str <$> many1 ('\160' <$ char ' ')) <|> pure mempty+  rest <- manyTill inline' newline   return $ trimInlinesF $ mconcat (pure indent : rest)  -- | Parse @\<verse>@ tag.@@ -480,18 +463,20 @@ 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 @\<comment>@ tag. commentTag :: PandocMonad m => MuseParser m (F Blocks)-commentTag = htmlBlock "comment" >> return mempty+commentTag = try $ mempty+  <$ many spaceChar+  <* openTag "comment"+  <* manyTill anyChar (closeTag "comment")+  <* manyTill spaceChar eol  -- | Parse paragraph contents. paraContentsUntil :: PandocMonad m@@ -499,7 +484,7 @@                   -> 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) @@ -513,9 +498,10 @@   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@@ -558,16 +544,15 @@ 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+  rest <- manyTill inline' 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)@@ -587,7 +572,7 @@   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.@@ -602,13 +587,6 @@   (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@@ -634,7 +612,7 @@       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.@@ -646,10 +624,10 @@   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@@ -658,7 +636,7 @@ 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@@ -670,8 +648,8 @@   where     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))+      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) @@ -727,7 +705,7 @@  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)@@ -749,11 +727,10 @@ 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)@@ -769,53 +746,51 @@  -- | 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 -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)-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-  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@@ -839,15 +814,11 @@         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 @\<br>@ tag. br :: PandocMonad m => MuseParser m (F Inlines)-br = try $ do-  string "<br>"-  return $ return B.linebreak+br = try $ pure B.linebreak <$ string "<br>"  emphasisBetween :: (PandocMonad m, Show a) => MuseParser m a -> MuseParser m (F Inlines) emphasisBetween c = try $ enclosedInlines c c@@ -858,22 +829,23 @@          -> 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                 -> 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 isAlphaNum)  -- | Parse an inline tag, such as @\<em>@ and @\<strong>@. inlineTag :: PandocMonad m           => String -- ^ Tag name           -> MuseParser m (F Inlines)-inlineTag tag = try $ do-  htmlTag (~== TagOpen tag [])-  mconcat <$> manyTill inline (void $ htmlTag (~== TagClose tag))+inlineTag tag = try $ mconcat+  <$  openTag tag+  <*> manyTill inline (closeTag tag)  -- | Parse strong inline markup, indicated by @**@. strong :: PandocMonad m => MuseParser m (F Inlines)@@ -886,9 +858,9 @@ -- | 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 @\<strong>@ tag. strongTag :: PandocMonad m => MuseParser m (F Inlines)@@ -912,21 +884,20 @@  -- | Parse @\<verbatim>@ 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 @\<class>@ tag. classTag :: PandocMonad m => MuseParser m (F Inlines) classTag = do-  (TagOpen _ attrs, _) <- htmlTag (~== TagOpen "class" [])-  res <- manyTill inline (void $ htmlTag (~== TagClose "class"))-  let classes = maybe [] words $ lookup "name" attrs+  classes <- maybe [] words . lookup "name" <$> openTag "class"+  res <- manyTill inline $ closeTag "class"   return $ B.spanWith ("", classes, []) <$> mconcat res  -- | 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)@@ -936,26 +907,27 @@   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 @\<code>@ 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 @\<math>@ tag. -- @\<math>@ 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 @\<literal>@ tag as a raw inline. inlineLiteralTag :: PandocMonad m => MuseParser m (F Inlines)-inlineLiteralTag =-  (return . rawInline) <$> htmlElement "literal"-  where-    -- FIXME: Emacs Muse inserts <literal> 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 <literal> 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@@ -974,7 +946,9 @@   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)@@ -989,7 +963,7 @@ 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%")]@@ -999,7 +973,7 @@                      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)@@ -1007,12 +981,11 @@           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
src/Text/Pandoc/Readers/Org/Blocks.hs view
@@ -40,7 +40,7 @@ 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)@@ -313,9 +313,6 @@     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"
src/Text/Pandoc/Readers/Org/Inlines.hs view
@@ -39,7 +39,7 @@ 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@@ -525,11 +525,13 @@ 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-  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
src/Text/Pandoc/Readers/Org/Shared.hs view
@@ -32,6 +32,7 @@   , isImageFilename   , originalLang   , translateLang+  , exportsCode   ) where  import Prelude@@ -96,3 +97,6 @@     "sh"         -> "bash"     "sqlite"     -> "sql"     _            -> cs++exportsCode :: [(String, String)] -> Bool+exportsCode = maybe True (`elem` ["code", "both"]) . lookup "exports"
src/Text/Pandoc/Readers/RST.hs view
@@ -1090,7 +1090,7 @@ 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"))@@ -1315,7 +1315,6 @@ 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 @@ inlineContent :: PandocMonad m => RSTParser m Inlines inlineContent = choice [ whitespace                        , str+                       , endline                        , smart                        , hyphens                        , escapedChar
src/Text/Pandoc/Writers/ConTeXt.hs view
@@ -453,7 +453,12 @@       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+      src' = fixPathSeparators $+             if isURI src                 then src                 else unEscapeString src   return $ braces $ "\\externalfigure" <> brackets (text src') <> dims <> clas
src/Text/Pandoc/Writers/Custom.hs view
@@ -1,6 +1,6 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE DeriveDataTypeable   #-}-{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleInstances  #-}+{-# LANGUAGE NoImplicitPrelude  #-} {- Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>  This program is free software; you can redistribute it and/or modify@@ -35,25 +35,26 @@ 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 @@  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 @@ -- 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 @@ -- | 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 @@                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 @@ 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 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 @@ -- | 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)
src/Text/Pandoc/Writers/HTML.hs view
@@ -50,13 +50,13 @@ 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) 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)@@ -461,7 +461,7 @@        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@@ -577,13 +577,23 @@         => [(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]@@ -1084,10 +1094,7 @@                                              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)@@ -1421,4 +1428,126 @@   , "width"   , "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"   ]
src/Text/Pandoc/Writers/JATS.hs view
@@ -344,7 +344,7 @@ 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 (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 '’'
src/Text/Pandoc/Writers/LaTeX.hs view
@@ -176,9 +176,9 @@     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''
src/Text/Pandoc/Writers/OpenDocument.hs view
@@ -403,8 +403,8 @@                       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 @@         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 @@                          , ("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
src/Text/Pandoc/Writers/RTF.hs view
@@ -341,8 +341,10 @@ 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 =
src/Text/Pandoc/Writers/Textile.hs view
@@ -463,15 +463,15 @@ 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
stack.yaml view
@@ -24,6 +24,8 @@ - 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
test/Tests/Lua.hs view
@@ -7,7 +7,7 @@ import Data.Version (Version (versionBranch)) import System.FilePath ((</>)) import Test.Tasty (TestTree, localOption)-import Test.Tasty.HUnit (Assertion, assertEqual, testCase)+import Test.Tasty.HUnit (Assertion, assertEqual, assertFailure, testCase) import Test.Tasty.QuickCheck (QuickCheckTests (..), ioProperty, testProperty) import Text.Pandoc.Arbitrary () import Text.Pandoc.Builder (bulletList, divWith, doc, doubleQuoted, emph,@@ -164,11 +164,11 @@    , 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."   ]@@ -179,13 +179,13 @@     setUserDataDir (Just "../data")     runLuaFilter def ("lua" </> filterPath) [] docIn   case docEither of-    Left _       -> fail "lua filter failed"+    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
test/Tests/Readers/HTML.hs view
@@ -31,12 +31,14 @@  roundTrip :: Blocks -> Bool roundTrip b = d'' == d'''-  where d = walk removeRawInlines $ walk makeRoundTrip $ Pandoc nullMeta $ toList b+  where d = walk removeRawInlines $+            walk makeRoundTrip $ Pandoc nullMeta $ toList b         d' = rewrite d         d'' = rewrite d'         d''' = rewrite d''         rewrite = html . T.pack . (++ "\n") . T.unpack .-                  purely (writeHtml5String def { writerWrapText = WrapPreserve })+                  purely (writeHtml5String def+                            { writerWrapText = WrapPreserve })  tests :: [TestTree] tests = [ testGroup "base tag"@@ -75,5 +77,5 @@           , test htmlNativeDivs "<main> followed by text" $ "<main>main content</main>non-main content" =?>             doc (divWith ("", [], [("role", "main")]) (plain (text "main content")) <> plain (text "non-main content"))           ]-        , testProperty "Round trip" roundTrip+        , testProperty "Round trip" (withMaxSuccess 25 roundTrip)         ]
test/Tests/Readers/Markdown.hs view
@@ -39,7 +39,7 @@        (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 @@   , ("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")
test/Tests/Readers/Muse.hs view
@@ -150,6 +150,10 @@           "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 "==="@@ -256,7 +260,7 @@       ]    , testGroup "Blocks"-      [ testProperty "Round trip" roundTrip+      [ testProperty "Round trip" (withMaxSuccess 25 roundTrip)       , "Block elements end paragraphs" =:         T.unlines [ "First paragraph"                   , "----"@@ -758,6 +762,13 @@                       , "    > Baz"                       ] =?>             para ("Foo" <> note (para "Bar" <> lineBlock ["Baz"]))+          , "Footnote ending in self-terminating element and followed by paragraph" =:+            T.unlines [ "Foo[1]"+                      , ""+                      , "[1] > bar"+                      , "baz"+                      ] =?>+            para (str "Foo" <> note (lineBlock ["bar"])) <> para (str "baz")           , test emacsMuse "Emacs multiparagraph footnotes"             (T.unlines               [ "First footnote reference[1] and second footnote reference[2]."@@ -1166,6 +1177,11 @@             ] =?>           bulletList [ lineBlock [ "foo" ] ] <> bulletList [ para "bar" ]         ]+      , "List ending in self-terminating element and followed by paragraph" =:+        T.unlines [ " - > Foo"+                  , "bar"+                  ] =?>+        bulletList [lineBlock ["Foo"]] <> para (str "bar")       -- Test that definition list requires a leading space.       -- Emacs Muse does not require a space, we follow Amusewiki here.       , "Not a definition list" =:
test/Tests/Readers/Org/Inline.hs view
@@ -280,6 +280,13 @@                        )                        "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 ( ""
test/Tests/Readers/RST.hs view
@@ -198,5 +198,8 @@           , "bare URI parsing disabled inside emphasis (#4561)" =:             "*http://location*" =?>             para (emph (text "http://location"))+          , "include newlines" =:+            "**before\nafter**" =?>+            para (strong (text "before\nafter"))           ]         ]
test/command/3716.md view
@@ -2,5 +2,5 @@ % pandoc <http://example.com>{.foo} ^D-<p><a href="http://example.com" class="uri foo">http://example.com</a></p>+<p><a href="http://example.com" class="foo">http://example.com</a></p> ```
+ test/command/4885.md view
@@ -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}$$+```
+ test/command/4913.md view
@@ -0,0 +1,34 @@+```+% pandoc -f markdown -t html+[https://pandoc.org](https://pandoc.org)+^D+<p><a href="https://pandoc.org">https://pandoc.org</a></p>+```++```+% pandoc -f markdown -t markdown+[https://pandoc.org](https://pandoc.org)+^D+<https://pandoc.org>+```++```+% pandoc -f markdown -t html+<https://pandoc.org>+^D+<p><a href="https://pandoc.org" class="uri">https://pandoc.org</a></p>+```++```+% pandoc -f markdown -t html+<https://pandoc.org>{.foo}+^D+<p><a href="https://pandoc.org" class="foo">https://pandoc.org</a></p>+```++```+% pandoc -f markdown -t html+<me@example.com>+^D+<p><a href="mailto:me@example.com" class="email">me@example.com</a></p>+```
+ test/command/4919.md view
@@ -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}"]]]]+```+
+ test/command/4928.md view
@@ -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 "."]]]]+```
test/markdown-reader-more.native view
@@ -45,9 +45,9 @@ ,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 @@   ,[]]] ,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)","")]
test/tables.opendocument view
@@ -6,59 +6,59 @@   <table:table-column table:style-name="Table1.D" />   <table:table-header-rows>     <table:table-row>-      <table:table-cell table:style-name="Table1.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="P1">Right</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table1.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="Table_20_Heading">Left</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table1.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="P2">Center</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table1.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="Table_20_Heading">Default</text:p>       </table:table-cell>     </table:table-row>   </table:table-header-rows>   <table:table-row>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P3">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P4">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">12</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P3">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P4">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">123</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P3">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P4">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table1.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">1</text:p>     </table:table-cell>   </table:table-row>@@ -73,59 +73,59 @@   <table:table-column table:style-name="Table2.D" />   <table:table-header-rows>     <table:table-row>-      <table:table-cell table:style-name="Table2.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="P5">Right</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table2.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="Table_20_Heading">Left</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table2.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="P6">Center</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table2.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="Table_20_Heading">Default</text:p>       </table:table-cell>     </table:table-row>   </table:table-header-rows>   <table:table-row>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P7">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P8">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">12</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P7">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P8">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">123</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P7">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P8">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table2.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">1</text:p>     </table:table-cell>   </table:table-row>@@ -139,59 +139,59 @@   <table:table-column table:style-name="Table3.D" />   <table:table-header-rows>     <table:table-row>-      <table:table-cell table:style-name="Table3.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="P9">Right</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table3.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="Table_20_Heading">Left</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table3.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="P10">Center</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table3.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="Table_20_Heading">Default</text:p>       </table:table-cell>     </table:table-row>   </table:table-header-rows>   <table:table-row>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P11">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P12">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">12</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P11">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P12">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">123</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P11">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P12">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table3.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">1</text:p>     </table:table-cell>   </table:table-row>@@ -206,46 +206,46 @@   <table:table-column table:style-name="Table4.D" />   <table:table-header-rows>     <table:table-row>-      <table:table-cell table:style-name="Table4.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="P13">Centered Header</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table4.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="Table_20_Heading">Left Aligned</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table4.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="P14">Right Aligned</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table4.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="Table_20_Heading">Default aligned</text:p>       </table:table-cell>     </table:table-row>   </table:table-header-rows>   <table:table-row>-    <table:table-cell table:style-name="Table4.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P15">First</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table4.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">row</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table4.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P16">12.0</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table4.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">Example of a row that spans       multiple lines.</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table4.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P15">Second</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table4.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">row</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table4.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P16">5.0</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table4.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">Here’s another one. Note the       blank line between rows.</text:p>     </table:table-cell>@@ -262,46 +262,46 @@   <table:table-column table:style-name="Table5.D" />   <table:table-header-rows>     <table:table-row>-      <table:table-cell table:style-name="Table5.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="P17">Centered Header</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table5.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="Table_20_Heading">Left Aligned</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table5.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="P18">Right Aligned</text:p>       </table:table-cell>-      <table:table-cell table:style-name="Table5.A1" office:value-type="string">+      <table:table-cell table:style-name="TableHeaderRowCell" office:value-type="string">         <text:p text:style-name="Table_20_Heading">Default aligned</text:p>       </table:table-cell>     </table:table-row>   </table:table-header-rows>   <table:table-row>-    <table:table-cell table:style-name="Table5.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P19">First</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table5.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">row</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table5.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P20">12.0</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table5.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">Example of a row that spans       multiple lines.</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table5.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P19">Second</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table5.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">row</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table5.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P20">5.0</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table5.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">Here’s another one. Note the       blank line between rows.</text:p>     </table:table-cell>@@ -315,44 +315,44 @@   <table:table-column table:style-name="Table6.C" />   <table:table-column table:style-name="Table6.D" />   <table:table-row>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P24">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P25">12</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P26">12</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P24">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P25">123</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P26">123</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P24">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P25">1</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table6.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P26">1</text:p>     </table:table-cell>   </table:table-row>@@ -365,31 +365,31 @@   <table:table-column table:style-name="Table7.C" />   <table:table-column table:style-name="Table7.D" />   <table:table-row>-    <table:table-cell table:style-name="Table7.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P29">First</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table7.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">row</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table7.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P30">12.0</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table7.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">Example of a row that spans       multiple lines.</text:p>     </table:table-cell>   </table:table-row>   <table:table-row>-    <table:table-cell table:style-name="Table7.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P29">Second</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table7.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">row</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table7.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="P30">5.0</text:p>     </table:table-cell>-    <table:table-cell table:style-name="Table7.A1" office:value-type="string">+    <table:table-cell table:style-name="TableRowCell" office:value-type="string">       <text:p text:style-name="Table_20_Contents">Here’s another one. Note the       blank line between rows.</text:p>     </table:table-cell>
test/testsuite.native view
@@ -384,14 +384,14 @@ ,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 ("",[],[]) "<http://example.com/>"] ,CodeBlock ("",[],[]) "or here: <http://example.com/>" ,HorizontalRule
test/writer.docbook4 view
@@ -1298,7 +1298,7 @@     <title>Autolinks</title>     <para>       With an ampersand:-      <ulink url="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</ulink>+      <ulink url="http://example.com/?foo=1&amp;bar=2" role="uri">http://example.com/?foo=1&amp;bar=2</ulink>     </para>     <itemizedlist spacing="compact">       <listitem>@@ -1308,7 +1308,7 @@       </listitem>       <listitem>         <para>-          <ulink url="http://example.com/">http://example.com/</ulink>+          <ulink url="http://example.com/" role="uri">http://example.com/</ulink>         </para>       </listitem>       <listitem>@@ -1323,7 +1323,7 @@     <blockquote>       <para>         Blockquoted:-        <ulink url="http://example.com/">http://example.com/</ulink>+        <ulink url="http://example.com/" role="uri">http://example.com/</ulink>       </para>     </blockquote>     <para>
test/writer.docbook5 view
@@ -1273,7 +1273,7 @@     <title>Autolinks</title>     <para>       With an ampersand:-      <link xlink:href="http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</link>+      <link xlink:href="http://example.com/?foo=1&amp;bar=2" role="uri">http://example.com/?foo=1&amp;bar=2</link>     </para>     <itemizedlist spacing="compact">       <listitem>@@ -1283,7 +1283,7 @@       </listitem>       <listitem>         <para>-          <link xlink:href="http://example.com/">http://example.com/</link>+          <link xlink:href="http://example.com/" role="uri">http://example.com/</link>         </para>       </listitem>       <listitem>@@ -1298,7 +1298,7 @@     <blockquote>       <para>         Blockquoted:-        <link xlink:href="http://example.com/">http://example.com/</link>+        <link xlink:href="http://example.com/" role="uri">http://example.com/</link>       </para>     </blockquote>     <para>
test/writer.html4 view
@@ -508,7 +508,7 @@ <li><a href="http://example.com/" class="uri">http://example.com/</a></li> <li>It should.</li> </ul>-<p>An e-mail address: <a href="mailto:nobody@nowhere.net">nobody@nowhere.net</a></p>+<p>An e-mail address: <a href="mailto:nobody@nowhere.net" class="email">nobody@nowhere.net</a></p> <blockquote> <p>Blockquoted: <a href="http://example.com/" class="uri">http://example.com/</a></p> </blockquote>
test/writer.html5 view
@@ -511,7 +511,7 @@ <li><a href="http://example.com/" class="uri">http://example.com/</a></li> <li>It should.</li> </ul>-<p>An e-mail address: <a href="mailto:nobody@nowhere.net">nobody@nowhere.net</a></p>+<p>An e-mail address: <a href="mailto:nobody@nowhere.net" class="email">nobody@nowhere.net</a></p> <blockquote> <p>Blockquoted: <a href="http://example.com/" class="uri">http://example.com/</a></p> </blockquote>
test/writer.jats view
@@ -583,7 +583,7 @@   </boxed-text>   <p>Interpreted markdown in a table:</p>   <p>This is <italic>emphasized</italic></p>-  <p>And this is <bold role="strong">strong</bold></p>+  <p>And this is <bold>strong</bold></p>   <p>Here’s a simple block:</p>   <boxed-text>     <p>foo</p>@@ -614,14 +614,13 @@ <sec id="inline-markup">   <title>Inline Markup</title>   <p>This is <italic>emphasized</italic>, and so <italic>is this</italic>.</p>-  <p>This is <bold role="strong">strong</bold>, and so <bold role="strong">is-  this</bold>.</p>+  <p>This is <bold>strong</bold>, and so <bold>is this</bold>.</p>   <p>An <italic><ext-link ext-link-type="uri" xlink:href="/url">emphasized   link</ext-link></italic>.</p>-  <p><bold role="strong"><italic>This is strong and em.</italic></bold></p>-  <p>So is <bold role="strong"><italic>this</italic></bold> word.</p>-  <p><bold role="strong"><italic>This is strong and em.</italic></bold></p>-  <p>So is <bold role="strong"><italic>this</italic></bold> word.</p>+  <p><bold><italic>This is strong and em.</italic></bold></p>+  <p>So is <bold><italic>this</italic></bold> word.</p>+  <p><bold><italic>This is strong and em.</italic></bold></p>+  <p>So is <bold><italic>this</italic></bold> word.</p>   <p>This is code: <monospace>&gt;</monospace>, <monospace>$</monospace>,   <monospace>\</monospace>, <monospace>\$</monospace>,   <monospace>&lt;html&gt;</monospace>.</p>
test/writer.native view
@@ -384,14 +384,14 @@ ,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 ("",[],[]) "<http://example.com/>"] ,CodeBlock ("",[],[]) "or here: <http://example.com/>" ,HorizontalRule
test/writer.textile view
@@ -660,7 +660,7 @@ * "$":http://example.com/ * It should. -An e&#45;mail address: "nobody&#64;nowhere.net":mailto:nobody@nowhere.net+An e&#45;mail address: "(email)nobody&#64;nowhere.net":mailto:nobody@nowhere.net  bq. Blockquoted: "$":http://example.com/