@@ -38,13 +38,13 @@ import Text.Pandoc.Readers.LaTeX (handleIncludes)
3838import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, readDataFile,
3939 safeRead, headerShift, normalize, err, warn,
4040 openURL )
41−import Text.Pandoc.MediaBag ( mediaDirectory, extractMediaBag )
41+import Text.Pandoc.MediaBag ( mediaDirectory, extractMediaBag, MediaBag )
4242import Text.Pandoc.XML ( toEntities )
4343import Text.Pandoc.SelfContained ( makeSelfContained )
4444import Text.Pandoc.Process (pipeProcess)
4545import Text.Highlighting.Kate ( languages, Style, tango, pygments,
4646 espresso, zenburn, kate, haddock, monochrome )
47−import System.Environment ( getArgs, getProgName )
47+import System.Environment ( getArgs, getProgName, getEnvironment )
4848import System.Exit ( exitWith, ExitCode (..) )
4949import System.FilePath
5050import System.Console.GetOpt
@@ -71,6 +71,8 @@ import Control.Applicative ((<$>))
7171import Text.Pandoc.Readers.Txt2Tags (getT2TMeta)
7272import Data.Monoid
7373
74+type Transform = Pandoc -> Pandoc
75+
7476copyrightMessage :: String
7577copyrightMessage = "\nCopyright (C) 2006-2014 John MacFarlane\n" ++
7678 "Web: http://johnmacfarlane.net/pandoc\n" ++
@@ -101,7 +103,10 @@ isTextFormat s = takeWhile (`notElem` "+-") s `notElem` ["odt","docx","epub","ep
101103
102104externalFilter :: FilePath -> [String] -> Pandoc -> IO Pandoc
103105externalFilter f args' d = do
104− mbexe <- if '/' `elem` f -- don't check PATH if filter name it has a path
106+ mbPath <- lookup "PATH" <$> getEnvironment
107+ mbexe <- if '/' `elem` f || mbPath == Nothing
108+ -- don't check PATH if filter name has a path, or
109+ -- if the PATH is not set
105110 then return Nothing
106111 else findExecutable f
107112 (f', args'') <- case mbexe of
@@ -141,7 +146,7 @@ data Opt = Opt
141146 , optWriter :: String -- ^ Writer format
142147 , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX
143148 , optTableOfContents :: Bool -- ^ Include table of contents
144− , optTransforms :: [Pandoc -> Pandoc] -- ^ Doc transforms to apply
149+ , optTransforms :: [Transform] -- ^ Doc transforms to apply
145150 , optTemplate :: Maybe FilePath -- ^ Custom template
146151 , optVariables :: [(String,String)] -- ^ Template variables to set
147152 , optMetadata :: M.Map String MetaValue -- ^ Metadata fields to set
@@ -934,6 +939,31 @@ defaultWriterName x =
934939 ['.',y] | y `elem` ['1'..'9'] -> "man"
935940 _ -> "html"
936941
942+-- Transformations of a Pandoc document post-parsing:
943+
944+extractMedia :: MediaBag -> FilePath -> Pandoc -> IO Pandoc
945+extractMedia media dir d =
946+ case [fp | (fp, _, _) <- mediaDirectory media] of
947+ [] -> return d
948+ fps -> do
949+ extractMediaBag True dir media
950+ return $ walk (adjustImagePath dir fps) d
951+
952+adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
953+adjustImagePath dir paths (Image lab (src, tit))
954+ | src `elem` paths = Image lab (dir ++ "/" ++ src, tit)
955+adjustImagePath _ _ x = x
956+
957+adjustMetadata :: M.Map String MetaValue -> Pandoc -> IO Pandoc
958+adjustMetadata metadata d = return $ M.foldWithKey setMeta d metadata
959+
960+applyTransforms :: [Transform] -> Pandoc -> IO Pandoc
961+applyTransforms transforms d = return $ foldr ($) d transforms
962+
963+applyFilters :: [FilePath] -> [String] -> Pandoc -> IO Pandoc
964+applyFilters filters args d =
965+ foldrM ($) d $ map (flip externalFilter args) filters
966+
937967main :: IO ()
938968main = do
939969
@@ -1026,7 +1056,6 @@ main = do
10261056 all (\f -> takeBaseName f /= "pandoc-citeproc")
10271057 filters -> "pandoc-citeproc" : filters
10281058 _ -> filters
1029− let plugins = map externalFilter filters'
10301059
10311060 let sources = if ignoreArgs then [] else args
10321061
@@ -1143,6 +1172,40 @@ main = do
11431172 , readerTrackChanges = trackChanges
11441173 }
11451174
1175+ when (not (isTextFormat writerName') && outputFile == "-") $
1176+ err 5 $ "Cannot write " ++ writerName' ++ " output to stdout.\n" ++
1177+ "Specify an output file using the -o option."
1178+
1179+ let readSources [] = mapM readSource ["-"]
1180+ readSources srcs = mapM readSource srcs
1181+ readSource "-" = UTF8.getContents
1182+ readSource src = case parseURI src of
1183+ Just u | uriScheme u `elem` ["http:","https:"] ->
1184+ readURI src
1185+ _ -> UTF8.readFile src
1186+ readURI src = do
1187+ res <- openURL src
1188+ case res of
1189+ Left e -> throwIO e
1190+ Right (bs,_) -> return $ UTF8.toString bs
1191+
1192+ let readFiles [] = error "Cannot read archive from stdin"
1193+ readFiles (x:_) = B.readFile x
1194+
1195+ let convertTabs = tabFilter (if (preserveTabs || readerName' == "t2t") then 0 else tabStop)
1196+
1197+ let handleIncludes' = if readerName' == "latex" || readerName' == "latex+lhs"
1198+ then handleIncludes
1199+ else return
1200+
1201+ (doc, media) <-
1202+ case reader of
1203+ StringReader r-> (, mempty) <$>
1204+ ( readSources >=>
1205+ handleIncludes' . convertTabs . intercalate "\n" >=>
1206+ r readerOpts ) sources
1207+ ByteStringReader r -> readFiles sources >>= r readerOpts
1208+
11461209 let writerOptions = def { writerStandalone = standalone',
11471210 writerTemplate = templ,
11481211 writerVariables = variables'',
@@ -1178,70 +1241,15 @@ main = do
11781241 writerEpubChapterLevel = epubChapterLevel,
11791242 writerTOCDepth = epubTOCDepth,
11801243 writerReferenceODT = referenceODT,
1181− writerReferenceDocx = referenceDocx
1244+ writerReferenceDocx = referenceDocx,
1245+ writerMediaBag = media
11821246 }
11831247
1184− when (not (isTextFormat writerName') && outputFile == "-") $
1185− err 5 $ "Cannot write " ++ writerName' ++ " output to stdout.\n" ++
1186− "Specify an output file using the -o option."
1187−
1188− let readSources [] = mapM readSource ["-"]
1189− readSources srcs = mapM readSource srcs
1190− readSource "-" = UTF8.getContents
1191− readSource src = case parseURI src of
1192− Just u | uriScheme u `elem` ["http:","https:"] ->
1193− readURI src
1194− _ -> UTF8.readFile src
1195− readURI src = do
1196− res <- openURL src
1197− case res of
1198− Left e -> throwIO e
1199− Right (bs,_) -> return $ UTF8.toString bs
1200−
1201− let readFiles [] = error "Cannot read archive from stdin"
1202− readFiles (x:_) = B.readFile x
1203−
1204− let convertTabs = tabFilter (if (preserveTabs || readerName' == "t2t") then 0 else tabStop)
1205−
1206− let handleIncludes' = if readerName' == "latex" || readerName' == "latex+lhs"
1207− then handleIncludes
1208− else return
1209−
1210− let adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
1211− adjustImagePath dir paths (Image lab (src, tit))
1212− | src `elem` paths = Image lab (dir ++ "/" ++ src, tit)
1213− adjustImagePath _ _ x = x
1214−
1215− (doc, media) <-
1216− case reader of
1217− StringReader r-> (, mempty) <$>
1218− ( readSources >=>
1219− handleIncludes' . convertTabs . intercalate "\n" >=>
1220− r readerOpts ) sources
1221− ByteStringReader r -> readFiles sources >>= r readerOpts
1222−
1223− let writerOptions' = writerOptions{ writerMediaBag = media }
1224−
1225− let extractMedia d = do
1226− case mbExtractMedia of
1227− Just dir -> do
1228− case [fp | (fp, _, _) <- mediaDirectory media] of
1229− [] -> return d
1230− fps -> do
1231− extractMediaBag True dir media
1232− return $ walk (adjustImagePath dir fps) d
1233− _ -> return d
1234−
1235− let adjustMetadata d = return $ M.foldWithKey setMeta d metadata
1236−
1237− let applyTransforms d = return $ foldr ($) d transforms
1238−
1239− let applyPlugins d = foldrM ($) d $ map ($ [writerName']) plugins
12401248
1241− doc' <- (extractMedia >=>
1242− adjustMetadata >=>
1243− applyTransforms >=>
1244− applyPlugins) doc
1249+ doc' <- (maybe return (extractMedia media) mbExtractMedia >=>
1250+ adjustMetadata metadata >=>
1251+ applyTransforms transforms >=>
1252+ applyFilters filters' [writerName']) doc
12451253
12461254 let writeBinary :: B.ByteString -> IO ()
12471255 writeBinary = B.writeFile (UTF8.encodePath outputFile)
@@ -1251,8 +1259,8 @@ main = do
12511259 writerFn f = UTF8.writeFile f
12521260
12531261 case writer of
1254− IOStringWriter f -> f writerOptions' doc' >>= writerFn outputFile
1255− IOByteStringWriter f -> f writerOptions' doc' >>= writeBinary
1262+ IOStringWriter f -> f writerOptions doc' >>= writerFn outputFile
1263+ IOByteStringWriter f -> f writerOptions doc' >>= writeBinary
12561264 PureStringWriter f
12571265 | pdfOutput -> do
12581266 -- make sure writer is latex or beamer
@@ -1266,14 +1274,14 @@ main = do
12661274 err 41 $ latexEngine ++ " not found. " ++
12671275 latexEngine ++ " is needed for pdf output."
12681276
1269− res <- makePDF latexEngine f writerOptions' doc'
1277+ res <- makePDF latexEngine f writerOptions doc'
12701278 case res of
12711279 Right pdf -> writeBinary pdf
12721280 Left err' -> do
12731281 B.hPutStr stderr $ err'
12741282 B.hPut stderr $ B.pack [10]
12751283 err 43 "Error producing PDF from TeX source"
1276− | otherwise -> selfcontain (f writerOptions' doc' ++
1284+ | otherwise -> selfcontain (f writerOptions doc' ++
12771285 ['\n' | not standalone'])
12781286 >>= writerFn outputFile . handleEntities
12791287 where htmlFormat = writerName' `elem`
@@ -1281,8 +1289,8 @@ main = do
12811289 "s5","slidy","slideous","dzslides","revealjs"]
12821290 selfcontain = if selfContained && htmlFormat
12831291 then makeSelfContained
1284− (writerMediaBag writerOptions')
1285− (writerUserDataDir writerOptions')
1292+ (writerMediaBag writerOptions)
1293+ (writerUserDataDir writerOptions)
12861294 else return
12871295 handleEntities = if htmlFormat && ascii
12881296 then toEntities