@@ -43,6 +43,7 @@ import System.Environment ( getArgs, getProgName )
4343import System.Exit ( exitWith, ExitCode (..) )
4444import System.FilePath
4545import System.Console.GetOpt
46+import System.Process (readProcess)
4647import Data.Char ( toLower )
4748import Data.List ( intercalate, isPrefixOf, sort )
4849import System.Directory ( getAppUserDataDirectory, doesFileExist, findExecutable )
@@ -53,6 +54,7 @@ import Control.Exception.Extensible ( throwIO )
5354import qualified Text.Pandoc.UTF8 as UTF8
5455import qualified Text.CSL as CSL
5556import Control.Monad (when, unless, liftM)
57+import Data.Foldable (foldrM)
5658import Network.HTTP (simpleHTTP, mkRequest, getResponseBody, RequestMethod(..))
5759import Network.URI (parseURI, isURI, URI(..))
5860import qualified Data.ByteString.Lazy as B
@@ -86,6 +88,12 @@ wrapWords indent c = wrap' (c - indent) (c - indent)
8688isTextFormat :: String -> Bool
8789isTextFormat s = takeWhile (`notElem` "+-") s `notElem` ["odt","docx","epub","epub3"]
8890
91+externalFilter :: FilePath -> Pandoc -> IO Pandoc
92+externalFilter f d = E.catch
93+ (readJSON def `fmap` readProcess f [] (writeJSON def d))
94+ (\e -> let _ = (e :: E.SomeException)
95+ in err 83 $ "Error running filter `" ++ f ++ "'")
96+
8997-- | Data structure for command line options.
9098data Opt = Opt
9199 { optTabStop :: Int -- ^ Number of spaces per tab
@@ -272,6 +280,13 @@ options =
272280 "STRING")
273281 "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks"
274282
283+ , Option "" ["filter"]
284+ (ReqArg
285+ (\arg opt -> return opt { optPlugins = externalFilter arg :
286+ optPlugins opt })
287+ "PROGRAM")
288+ "" -- "External JSON filter"
289+
275290 , Option "" ["normalize"]
276291 (NoArg
277292 (\opt -> return opt { optTransforms =
@@ -876,6 +891,7 @@ main = do
876891 , optReferenceLinks = referenceLinks
877892 , optWrapText = wrap
878893 , optColumns = columns
894+ , optPlugins = plugins
879895 , optEmailObfuscation = obfuscationMethod
880896 , optIdentifierPrefix = idPrefix
881897 , optIndentedCodeClasses = codeBlockClasses
@@ -1099,6 +1115,7 @@ main = do
10991115 reader readerOpts
11001116
11011117 let doc0 = foldr ($) doc transforms
1118+ doc1 <- foldrM ($) doc0 plugins
11021119
11031120 let writeBinary :: B.ByteString -> IO ()
11041121 writeBinary = B.writeFile (UTF8.encodePath outputFile)
@@ -1109,15 +1126,15 @@ main = do
11091126
11101127 case getWriter writerName' of
11111128 Left e -> err 9 e
1112− Right (IOStringWriter f) -> f writerOptions doc0 >>= writerFn outputFile
1113− Right (IOByteStringWriter f) -> f writerOptions doc0 >>= writeBinary
1129+ Right (IOStringWriter f) -> f writerOptions doc1 >>= writerFn outputFile
1130+ Right (IOByteStringWriter f) -> f writerOptions doc1 >>= writeBinary
11141131 Right (PureStringWriter f)
11151132 | pdfOutput -> do
1116− res <- makePDF latexEngine f writerOptions doc0
1133+ res <- makePDF latexEngine f writerOptions doc1
11171134 case res of
11181135 Right pdf -> writeBinary pdf
11191136 Left err' -> err 43 $ UTF8.toStringLazy err'
1120− | otherwise -> selfcontain (f writerOptions doc0 ++
1137+ | otherwise -> selfcontain (f writerOptions doc1 ++
11211138 ['\n' | not standalone'])
11221139 >>= writerFn outputFile . handleEntities
11231140 where htmlFormat = writerName' `elem`