diff options
Diffstat (limited to 'pandoc.hs')
-rw-r--r-- | pandoc.hs | 1490 |
1 files changed, 6 insertions, 1484 deletions
@@ -1,6 +1,5 @@ -{-# LANGUAGE CPP, TupleSections, ScopedTypeVariables, PatternGuards #-} {- -Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu> +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 @@ -19,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA {- | Module : Main - Copyright : Copyright (C) 2006-2016 John MacFarlane + Copyright : Copyright (C) 2006-2018 John MacFarlane License : GNU GPL, version 2 or above Maintainer : John MacFarlane <jgm@berkeley@edu> @@ -30,1487 +29,10 @@ Parses command-line options and calls the appropriate readers and writers. -} module Main where -import Text.Pandoc -import Text.Pandoc.Builder (setMeta) -import Text.Pandoc.PDF (makePDF) -import Text.Pandoc.Walk (walk) -import Text.Pandoc.Readers.LaTeX (handleIncludes) -import Text.Pandoc.Shared ( tabFilter, readDataFileUTF8, readDataFile, - safeRead, headerShift, normalize, err, warn, - openURL ) -import Text.Pandoc.MediaBag ( mediaDirectory, extractMediaBag, MediaBag ) -import Text.Pandoc.XML ( toEntities ) -import Text.Pandoc.SelfContained ( makeSelfContained ) -import Text.Pandoc.Process (pipeProcess) -import Skylighting ( defaultSyntaxMap, Syntax(..), Style, tango, pygments, - espresso, zenburn, kate, haddock, breezeDark, monochrome ) -import System.Environment ( getArgs, getProgName, getEnvironment ) -import System.Exit ( ExitCode (..), exitSuccess ) -import System.FilePath -import System.Console.GetOpt -import qualified Data.Set as Set -import Data.Char ( toLower, toUpper ) -import Data.List ( intercalate, isPrefixOf, isSuffixOf, sort ) -import System.Directory ( getAppUserDataDirectory, findExecutable, - doesFileExist, Permissions(..), getPermissions ) -import System.IO ( stdout, stderr ) -import System.IO.Error ( isDoesNotExistError ) import qualified Control.Exception as E -import Control.Exception.Extensible ( throwIO ) -import qualified Text.Pandoc.UTF8 as UTF8 -import Control.Monad (when, unless, (>=>)) -import Data.Maybe (fromMaybe, isNothing, isJust) -import Data.Foldable (foldrM) -import Network.URI (parseURI, isURI, URI(..)) -import qualified Data.ByteString.Lazy as B -import qualified Data.ByteString as BS -import Data.Aeson (eitherDecode', encode) -import qualified Data.Map as M -import Data.Yaml (decode) -import qualified Data.Yaml as Yaml -import qualified Data.Text as T -import Control.Applicative ((<|>)) -import Text.Pandoc.Readers.Txt2Tags (getT2TMeta) -import Paths_pandoc (getDataDir) -import Text.Printf (printf) -#ifndef _WINDOWS -import System.Posix.Terminal (queryTerminal) -import System.Posix.IO (stdOutput) -#endif - -type Transform = Pandoc -> Pandoc - -copyrightMessage :: String -copyrightMessage = intercalate "\n" [ - "", - "Copyright (C) 2006-2016 John MacFarlane", - "Web: http://pandoc.org", - "This is free software; see the source for copying conditions.", - "There is no warranty, not even for merchantability or fitness", - "for a particular purpose." ] - -compileInfo :: String -compileInfo = - "\nCompiled with pandoc-types " ++ VERSION_pandoc_types ++ ", texmath " ++ - VERSION_texmath ++ ", skylighting " ++ VERSION_skylighting - --- | Converts a list of strings into a single string with the items printed as --- comma separated words in lines with a maximum line length. -wrapWords :: Int -> Int -> [String] -> String -wrapWords indent c = wrap' (c - indent) (c - indent) - where - wrap' _ _ [] = "" - wrap' cols remaining (x:xs) - | remaining == cols = - x ++ wrap' cols (remaining - length x) xs - | (length x + 1) > remaining = - ",\n" ++ replicate indent ' ' ++ x ++ - wrap' cols (cols - length x) xs - | otherwise = - ", " ++ x ++ - wrap' cols (remaining - length x - 2) xs - -isTextFormat :: String -> Bool -isTextFormat s = s `notElem` ["odt","docx","epub","epub3"] - -externalFilter :: FilePath -> [String] -> Pandoc -> IO Pandoc -externalFilter f args' d = do - exists <- doesFileExist f - isExecutable <- if exists - then executable <$> getPermissions f - else return True - let (f', args'') = if exists - then case map toLower (takeExtension f) of - _ | isExecutable -> ("." </> f, args') - ".py" -> ("python", f:args') - ".hs" -> ("runhaskell", f:args') - ".pl" -> ("perl", f:args') - ".rb" -> ("ruby", f:args') - ".php" -> ("php", f:args') - ".js" -> ("node", f:args') - _ -> (f, args') - else (f, args') - unless (exists && isExecutable) $ do - mbExe <- findExecutable f' - when (isNothing mbExe) $ - err 83 $ "Error running filter " ++ f ++ ":\n" ++ - "Could not find executable '" ++ f' ++ "'." - env <- getEnvironment - let env' = Just $ ("PANDOC_VERSION", pandocVersion) : env - (exitcode, outbs, errbs) <- E.handle filterException $ - pipeProcess env' f' args'' $ encode d - unless (B.null errbs) $ B.hPutStr stderr errbs - case exitcode of - ExitSuccess -> return $ either error id $ eitherDecode' outbs - ExitFailure ec -> err 83 $ "Error running filter " ++ f ++ "\n" ++ - "Filter returned error status " ++ show ec - where filterException :: E.SomeException -> IO a - filterException e = err 83 $ "Error running filter " ++ f ++ "\n" ++ - show e - -highlightingStyles :: [(String, Style)] -highlightingStyles = - [("pygments", pygments), - ("tango", tango), - ("espresso", espresso), - ("zenburn", zenburn), - ("kate", kate), - ("monochrome", monochrome), - ("breezedark", breezeDark), - ("haddock", haddock)] - --- | Data structure for command line options. -data Opt = Opt - { optTabStop :: Int -- ^ Number of spaces per tab - , optPreserveTabs :: Bool -- ^ Preserve tabs instead of converting to spaces - , optStandalone :: Bool -- ^ Include header, footer - , optReader :: String -- ^ Reader format - , optWriter :: String -- ^ Writer format - , optParseRaw :: Bool -- ^ Parse unconvertable HTML and TeX - , optTableOfContents :: Bool -- ^ Include table of contents - , optTransforms :: [Transform] -- ^ Doc transforms to apply - , optTemplate :: Maybe FilePath -- ^ Custom template - , optVariables :: [(String,String)] -- ^ Template variables to set - , optMetadata :: M.Map String MetaValue -- ^ Metadata fields to set - , optOutputFile :: String -- ^ Name of output file - , optNumberSections :: Bool -- ^ Number sections in LaTeX - , optNumberOffset :: [Int] -- ^ Starting number for sections - , optSectionDivs :: Bool -- ^ Put sections in div tags in HTML - , optIncremental :: Bool -- ^ Use incremental lists in Slidy/Slideous/S5 - , optSelfContained :: Bool -- ^ Make HTML accessible offline - , optSmart :: Bool -- ^ Use smart typography - , optOldDashes :: Bool -- ^ Parse dashes like pandoc <=1.8.2.1 - , optHtml5 :: Bool -- ^ Produce HTML5 in HTML - , optHtmlQTags :: Bool -- ^ Use <q> tags in HTML - , optHighlight :: Bool -- ^ Highlight source code - , optHighlightStyle :: Style -- ^ Style to use for highlighted code - , optTopLevelDivision :: TopLevelDivision -- ^ Type of the top-level divisions - , optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math - , optReferenceODT :: Maybe FilePath -- ^ Path of reference.odt - , optReferenceDocx :: Maybe FilePath -- ^ Path of reference.docx - , optEpubStylesheet :: Maybe String -- ^ EPUB stylesheet - , optEpubMetadata :: String -- ^ EPUB metadata - , optEpubFonts :: [FilePath] -- ^ EPUB fonts to embed - , optEpubChapterLevel :: Int -- ^ Header level at which to split chapters - , optTOCDepth :: Int -- ^ Number of levels to include in TOC - , optDumpArgs :: Bool -- ^ Output command-line arguments - , optIgnoreArgs :: Bool -- ^ Ignore command-line arguments - , optVerbose :: Bool -- ^ Verbose diagnostic output - , optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst - , optReferenceLocation :: ReferenceLocation -- ^ location for footnotes and link references in markdown output - , optDpi :: Int -- ^ Dpi - , optWrapText :: WrapOption -- ^ Options for wrapping text - , optColumns :: Int -- ^ Line length in characters - , optFilters :: [FilePath] -- ^ Filters to apply - , optEmailObfuscation :: ObfuscationMethod - , optIdentifierPrefix :: String - , optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks - , optDataDir :: Maybe FilePath - , optCiteMethod :: CiteMethod -- ^ Method to output cites - , optListings :: Bool -- ^ Use listings package for code blocks - , optLaTeXEngine :: String -- ^ Program to use for latex -> pdf - , optLaTeXEngineArgs :: [String] -- ^ Flags to pass to the latex-engine - , optSlideLevel :: Maybe Int -- ^ Header level that creates slides - , optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2 - , optAscii :: Bool -- ^ Use ascii characters only in html - , optTeXLigatures :: Bool -- ^ Use TeX ligatures for quotes/dashes - , optDefaultImageExtension :: String -- ^ Default image extension - , optExtractMedia :: Maybe FilePath -- ^ Path to extract embedded media - , optTrace :: Bool -- ^ Print debug information - , optTrackChanges :: TrackChanges -- ^ Accept or reject MS Word track-changes. - , optFileScope :: Bool -- ^ Parse input files before combining - , optKaTeXStylesheet :: Maybe String -- ^ Path to stylesheet for KaTeX - , optKaTeXJS :: Maybe String -- ^ Path to js file for KaTeX - } - --- | Defaults for command-line options. -defaultOpts :: Opt -defaultOpts = Opt - { optTabStop = 4 - , optPreserveTabs = False - , optStandalone = False - , optReader = "" -- null for default reader - , optWriter = "" -- null for default writer - , optParseRaw = False - , optTableOfContents = False - , optTransforms = [] - , optTemplate = Nothing - , optVariables = [] - , optMetadata = M.empty - , optOutputFile = "-" -- "-" means stdout - , optNumberSections = False - , optNumberOffset = [0,0,0,0,0,0] - , optSectionDivs = False - , optIncremental = False - , optSelfContained = False - , optSmart = False - , optOldDashes = False - , optHtml5 = False - , optHtmlQTags = False - , optHighlight = True - , optHighlightStyle = pygments - , optTopLevelDivision = TopLevelDefault - , optHTMLMathMethod = PlainMath - , optReferenceODT = Nothing - , optReferenceDocx = Nothing - , optEpubStylesheet = Nothing - , optEpubMetadata = "" - , optEpubFonts = [] - , optEpubChapterLevel = 1 - , optTOCDepth = 3 - , optDumpArgs = False - , optIgnoreArgs = False - , optVerbose = False - , optReferenceLinks = False - , optReferenceLocation = EndOfDocument - , optDpi = 96 - , optWrapText = WrapAuto - , optColumns = 72 - , optFilters = [] - , optEmailObfuscation = NoObfuscation - , optIdentifierPrefix = "" - , optIndentedCodeClasses = [] - , optDataDir = Nothing - , optCiteMethod = Citeproc - , optListings = False - , optLaTeXEngine = "pdflatex" - , optLaTeXEngineArgs = [] - , optSlideLevel = Nothing - , optSetextHeaders = True - , optAscii = False - , optTeXLigatures = True - , optDefaultImageExtension = "" - , optExtractMedia = Nothing - , optTrace = False - , optTrackChanges = AcceptChanges - , optFileScope = False - , optKaTeXStylesheet = Nothing - , optKaTeXJS = Nothing - } - --- | A list of functions, each transforming the options data structure --- in response to a command-line option. -options :: [OptDescr (Opt -> IO Opt)] -options = - [ Option "fr" ["from","read"] - (ReqArg - (\arg opt -> return opt { optReader = arg }) - "FORMAT") - "" - - , Option "tw" ["to","write"] - (ReqArg - (\arg opt -> return opt { optWriter = arg }) - "FORMAT") - "" - - , Option "o" ["output"] - (ReqArg - (\arg opt -> return opt { optOutputFile = arg }) - "FILENAME") - "" -- "Name of output file" - - , Option "" ["data-dir"] - (ReqArg - (\arg opt -> return opt { optDataDir = Just arg }) - "DIRECTORY") -- "Directory containing pandoc data files." - "" - - , Option "R" ["parse-raw"] - (NoArg - (\opt -> return opt { optParseRaw = True })) - "" -- "Parse untranslatable HTML codes and LaTeX environments as raw" - - , Option "S" ["smart"] - (NoArg - (\opt -> return opt { optSmart = True })) - "" -- "Use smart quotes, dashes, and ellipses" - - , Option "" ["old-dashes"] - (NoArg - (\opt -> return opt { optSmart = True - , optOldDashes = True })) - "" -- "Use smart quotes, dashes, and ellipses" - - , Option "" ["base-header-level"] - (ReqArg - (\arg opt -> - case safeRead arg of - Just t | t > 0 -> do - let oldTransforms = optTransforms opt - let shift = t - 1 - return opt{ optTransforms = - headerShift shift : oldTransforms } - _ -> err 19 - "base-header-level must be a number > 0") - "NUMBER") - "" -- "Headers base level" - - , Option "" ["indented-code-classes"] - (ReqArg - (\arg opt -> return opt { optIndentedCodeClasses = words $ - map (\c -> if c == ',' then ' ' else c) arg }) - "STRING") - "" -- "Classes (whitespace- or comma-separated) to use for indented code-blocks" - - , Option "F" ["filter"] - (ReqArg - (\arg opt -> return opt { optFilters = arg : optFilters opt }) - "PROGRAM") - "" -- "External JSON filter" - - , Option "" ["normalize"] - (NoArg - (\opt -> return opt { optTransforms = - normalize : optTransforms opt } )) - "" -- "Normalize the Pandoc AST" - - , Option "p" ["preserve-tabs"] - (NoArg - (\opt -> return opt { optPreserveTabs = True })) - "" -- "Preserve tabs instead of converting to spaces" - - , Option "" ["tab-stop"] - (ReqArg - (\arg opt -> - case safeRead arg of - Just t | t > 0 -> return opt { optTabStop = t } - _ -> err 31 - "tab-stop must be a number greater than 0") - "NUMBER") - "" -- "Tab stop (default 4)" - - , Option "" ["track-changes"] - (ReqArg - (\arg opt -> do - action <- case arg of - "accept" -> return AcceptChanges - "reject" -> return RejectChanges - "all" -> return AllChanges - _ -> err 6 - ("Unknown option for track-changes: " ++ arg) - return opt { optTrackChanges = action }) - "accept|reject|all") - "" -- "Accepting or reject MS Word track-changes."" - - , Option "" ["file-scope"] - (NoArg - (\opt -> return opt { optFileScope = True })) - "" -- "Parse input files before combining" - - , Option "" ["extract-media"] - (ReqArg - (\arg opt -> - return opt { optExtractMedia = Just arg }) - "PATH") - "" -- "Directory to which to extract embedded media" - - , Option "s" ["standalone"] - (NoArg - (\opt -> return opt { optStandalone = True })) - "" -- "Include needed header and footer on output" - - , Option "" ["template"] - (ReqArg - (\arg opt -> - return opt{ optTemplate = Just arg, - optStandalone = True }) - "FILENAME") - "" -- "Use custom template" - - , Option "M" ["metadata"] - (ReqArg - (\arg opt -> do - let (key,val) = case break (`elem` ":=") arg of - (k,_:v) -> (k, readMetaValue v) - (k,_) -> (k, MetaBool True) - return opt{ optMetadata = addMetadata key val - $ optMetadata opt }) - "KEY[:VALUE]") - "" - - , Option "V" ["variable"] - (ReqArg - (\arg opt -> do - let (key,val) = case break (`elem` ":=") arg of - (k,_:v) -> (k,v) - (k,_) -> (k,"true") - return opt{ optVariables = (key,val) : optVariables opt }) - "KEY[:VALUE]") - "" - - , Option "D" ["print-default-template"] - (ReqArg - (\arg _ -> do - templ <- getDefaultTemplate Nothing arg - case templ of - Right t -> UTF8.hPutStr stdout t - Left e -> error $ show e - exitSuccess) - "FORMAT") - "" -- "Print default template for FORMAT" - - , Option "" ["print-default-data-file"] - (ReqArg - (\arg _ -> do - readDataFile Nothing arg >>= BS.hPutStr stdout - exitSuccess) - "FILE") - "" -- "Print default data file" - - , Option "" ["dpi"] - (ReqArg - (\arg opt -> - case safeRead arg of - Just t | t > 0 -> return opt { optDpi = t } - _ -> err 31 - "dpi must be a number greater than 0") - "NUMBER") - "" -- "Dpi (default 96)" - - , Option "" ["no-wrap"] - (NoArg - (\opt -> do warn $ "--no-wrap is deprecated. " ++ - "Use --wrap=none or --wrap=preserve instead." - return opt { optWrapText = WrapNone })) - "" - - , Option "" ["wrap"] - (ReqArg - (\arg opt -> - case safeRead ("Wrap" ++ uppercaseFirstLetter arg) of - Just o -> return opt { optWrapText = o } - Nothing -> err 77 "--wrap must be auto, none, or preserve") - "auto|none|preserve") - "" -- "Option for wrapping text in output" - - , Option "" ["columns"] - (ReqArg - (\arg opt -> - case safeRead arg of - Just t | t > 0 -> return opt { optColumns = t } - _ -> err 33 - "columns must be a number greater than 0") - "NUMBER") - "" -- "Length of line in characters" - - , Option "" ["toc", "table-of-contents"] - (NoArg - (\opt -> return opt { optTableOfContents = True })) - "" -- "Include table of contents" - - , Option "" ["toc-depth"] - (ReqArg - (\arg opt -> - case safeRead arg of - Just t | t >= 1 && t <= 6 -> - return opt { optTOCDepth = t } - _ -> err 57 - "TOC level must be a number between 1 and 6") - "NUMBER") - "" -- "Number of levels to include in TOC" - - , Option "" ["no-highlight"] - (NoArg - (\opt -> return opt { optHighlight = False })) - "" -- "Don't highlight source code" - - , Option "" ["highlight-style"] - (ReqArg - (\arg opt -> do - case lookup (map toLower arg) highlightingStyles of - Just s -> return opt{ optHighlightStyle = s } - Nothing -> err 39 $ "Unknown style: " ++ arg) - "STYLE") - "" -- "Style for highlighted code" - - , Option "H" ["include-in-header"] - (ReqArg - (\arg opt -> do - text <- UTF8.readFile arg - -- add new ones to end, so they're included in order specified - let newvars = optVariables opt ++ [("header-includes",text)] - return opt { optVariables = newvars, - optStandalone = True }) - "FILENAME") - "" -- "File to include at end of header (implies -s)" - - , Option "B" ["include-before-body"] - (ReqArg - (\arg opt -> do - text <- UTF8.readFile arg - -- add new ones to end, so they're included in order specified - let newvars = optVariables opt ++ [("include-before",text)] - return opt { optVariables = newvars, - optStandalone = True }) - "FILENAME") - "" -- "File to include before document body" - - , Option "A" ["include-after-body"] - (ReqArg - (\arg opt -> do - text <- UTF8.readFile arg - -- add new ones to end, so they're included in order specified - let newvars = optVariables opt ++ [("include-after",text)] - return opt { optVariables = newvars, - optStandalone = True }) - "FILENAME") - "" -- "File to include after document body" - - , Option "" ["self-contained"] - (NoArg - (\opt -> return opt { optSelfContained = True, - optStandalone = True })) - "" -- "Make slide shows include all the needed js and css" - - , Option "" ["html-q-tags"] - (NoArg - (\opt -> - return opt { optHtmlQTags = True })) - "" -- "Use <q> tags for quotes in HTML" - - , Option "" ["ascii"] - (NoArg - (\opt -> return opt { optAscii = True })) - "" -- "Use ascii characters only in HTML output" - - , Option "" ["reference-links"] - (NoArg - (\opt -> return opt { optReferenceLinks = True } )) - "" -- "Use reference links in parsing HTML" - - , Option "" ["reference-location"] - (ReqArg - (\arg opt -> do - action <- case arg of - "block" -> return EndOfBlock - "section" -> return EndOfSection - "document" -> return EndOfDocument - _ -> err 6 - ("Unknown option for reference-location: " ++ arg) - return opt { optReferenceLocation = action }) - "block|section|document") - "" -- "Accepting or reject MS Word track-changes."" - - , Option "" ["atx-headers"] - (NoArg - (\opt -> return opt { optSetextHeaders = False } )) - "" -- "Use atx-style headers for markdown" - - , Option "" ["chapters"] - (NoArg - (\opt -> do warn $ "--chapters is deprecated. " ++ - "Use --top-level-division=chapter instead." - return opt { optTopLevelDivision = TopLevelChapter })) - "" -- "Use chapter for top-level sections in LaTeX, DocBook" - - , Option "" ["top-level-division"] - (ReqArg - (\arg opt -> do - let tldName = "TopLevel" ++ uppercaseFirstLetter arg - case safeRead tldName of - Just tlDiv -> return opt { optTopLevelDivision = tlDiv } - _ -> err 76 ("Top-level division must be " ++ - "section, chapter, part, or default")) - "section|chapter|part") - "" -- "Use top-level division type in LaTeX, ConTeXt, DocBook" - - , Option "N" ["number-sections"] - (NoArg - (\opt -> return opt { optNumberSections = True })) - "" -- "Number sections in LaTeX" - - , Option "" ["number-offset"] - (ReqArg - (\arg opt -> - case safeRead ('[':arg ++ "]") of - Just ns -> return opt { optNumberOffset = ns, - optNumberSections = True } - _ -> err 57 "could not parse number-offset") - "NUMBERS") - "" -- "Starting number for sections, subsections, etc." - - , Option "" ["no-tex-ligatures"] - (NoArg - (\opt -> return opt { optTeXLigatures = False })) - "" -- "Don't use tex ligatures for quotes, dashes" - - , Option "" ["listings"] - (NoArg - (\opt -> return opt { optListings = True })) - "" -- "Use listings package for LaTeX code blocks" - - , Option "i" ["incremental"] - (NoArg - (\opt -> return opt { optIncremental = True })) - "" -- "Make list items display incrementally in Slidy/Slideous/S5" - - , Option "" ["slide-level"] - (ReqArg - (\arg opt -> - case safeRead arg of - Just t | t >= 1 && t <= 6 -> - return opt { optSlideLevel = Just t } - _ -> err 39 - "slide level must be a number between 1 and 6") - "NUMBER") - "" -- "Force header level for slides" - - , Option "" ["section-divs"] - (NoArg - (\opt -> return opt { optSectionDivs = True })) - "" -- "Put sections in div tags in HTML" - - , Option "" ["default-image-extension"] - (ReqArg - (\arg opt -> return opt { optDefaultImageExtension = arg }) - "extension") - "" -- "Default extension for extensionless images" - - , Option "" ["email-obfuscation"] - (ReqArg - (\arg opt -> do - method <- case arg of - "references" -> return ReferenceObfuscation - "javascript" -> return JavascriptObfuscation - "none" -> return NoObfuscation - _ -> err 6 - ("Unknown obfuscation method: " ++ arg) - return opt { optEmailObfuscation = method }) - "none|javascript|references") - "" -- "Method for obfuscating email in HTML" - - , Option "" ["id-prefix"] - (ReqArg - (\arg opt -> return opt { optIdentifierPrefix = arg }) - "STRING") - "" -- "Prefix to add to automatically generated HTML identifiers" - - , Option "T" ["title-prefix"] - (ReqArg - (\arg opt -> do - let newvars = ("title-prefix", arg) : optVariables opt - return opt { optVariables = newvars, - optStandalone = True }) - "STRING") - "" -- "String to prefix to HTML window title" - - , Option "c" ["css"] - (ReqArg - (\arg opt -> do - -- add new link to end, so it is included in proper order - let newvars = optVariables opt ++ [("css",arg)] - return opt { optVariables = newvars, - optStandalone = True }) - "URL") - "" -- "Link to CSS style sheet" - - , Option "" ["reference-odt"] - (ReqArg - (\arg opt -> - return opt { optReferenceODT = Just arg }) - "FILENAME") - "" -- "Path of custom reference.odt" - - , Option "" ["reference-docx"] - (ReqArg - (\arg opt -> - return opt { optReferenceDocx = Just arg }) - "FILENAME") - "" -- "Path of custom reference.docx" - - , Option "" ["epub-stylesheet"] - (ReqArg - (\arg opt -> do - text <- UTF8.readFile arg - return opt { optEpubStylesheet = Just text }) - "FILENAME") - "" -- "Path of epub.css" - - , Option "" ["epub-cover-image"] - (ReqArg - (\arg opt -> - return opt { optVariables = - ("epub-cover-image", arg) : optVariables opt }) - "FILENAME") - "" -- "Path of epub cover image" - - , Option "" ["epub-metadata"] - (ReqArg - (\arg opt -> do - text <- UTF8.readFile arg - return opt { optEpubMetadata = text }) - "FILENAME") - "" -- "Path of epub metadata file" - - , Option "" ["epub-embed-font"] - (ReqArg - (\arg opt -> - return opt{ optEpubFonts = arg : optEpubFonts opt }) - "FILE") - "" -- "Directory of fonts to embed" - - , Option "" ["epub-chapter-level"] - (ReqArg - (\arg opt -> - case safeRead arg of - Just t | t >= 1 && t <= 6 -> - return opt { optEpubChapterLevel = t } - _ -> err 59 - "chapter level must be a number between 1 and 6") - "NUMBER") - "" -- "Header level at which to split chapters in EPUB" - - , Option "" ["latex-engine"] - (ReqArg - (\arg opt -> do - let b = takeBaseName arg - if b `elem` ["pdflatex", "lualatex", "xelatex"] - then return opt { optLaTeXEngine = arg } - else err 45 "latex-engine must be pdflatex, lualatex, or xelatex.") - "PROGRAM") - "" -- "Name of latex program to use in generating PDF" - - , Option "" ["latex-engine-opt"] - (ReqArg - (\arg opt -> do - let oldArgs = optLaTeXEngineArgs opt - return opt { optLaTeXEngineArgs = arg : oldArgs }) - "STRING") - "" -- "Flags to pass to the LaTeX engine, all instances of this option are accumulated and used" - - , Option "" ["bibliography"] - (ReqArg - (\arg opt -> return opt{ optMetadata = addMetadata - "bibliography" (readMetaValue arg) - $ optMetadata opt - }) - "FILE") - "" - - , Option "" ["csl"] - (ReqArg - (\arg opt -> - return opt{ optMetadata = addMetadata "csl" - (readMetaValue arg) - $ optMetadata opt }) - "FILE") - "" - - , Option "" ["citation-abbreviations"] - (ReqArg - (\arg opt -> - return opt{ optMetadata = addMetadata - "citation-abbreviations" - (readMetaValue arg) - $ optMetadata opt }) - "FILE") - "" - - , Option "" ["natbib"] - (NoArg - (\opt -> return opt { optCiteMethod = Natbib })) - "" -- "Use natbib cite commands in LaTeX output" - - , Option "" ["biblatex"] - (NoArg - (\opt -> return opt { optCiteMethod = Biblatex })) - "" -- "Use biblatex cite commands in LaTeX output" - - , Option "m" ["latexmathml", "asciimathml"] - (OptArg - (\arg opt -> - return opt { optHTMLMathMethod = LaTeXMathML arg }) - "URL") - "" -- "Use LaTeXMathML script in html output" - - , Option "" ["mathml"] - (OptArg - (\arg opt -> - return opt { optHTMLMathMethod = MathML arg }) - "URL") - "" -- "Use mathml for HTML math" - - , Option "" ["mimetex"] - (OptArg - (\arg opt -> do - let url' = case arg of - Just u -> u ++ "?" - Nothing -> "/cgi-bin/mimetex.cgi?" - return opt { optHTMLMathMethod = WebTeX url' }) - "URL") - "" -- "Use mimetex for HTML math" - - , Option "" ["webtex"] - (OptArg - (\arg opt -> do - let url' = fromMaybe "https://latex.codecogs.com/png.latex?" arg - return opt { optHTMLMathMethod = WebTeX url' }) - "URL") - "" -- "Use web service for HTML math" - - , Option "" ["jsmath"] - (OptArg - (\arg opt -> return opt { optHTMLMathMethod = JsMath arg}) - "URL") - "" -- "Use jsMath for HTML math" - - , Option "" ["mathjax"] - (OptArg - (\arg opt -> do - let url' = fromMaybe "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_CHTML-full" arg - return opt { optHTMLMathMethod = MathJax url'}) - "URL") - "" -- "Use MathJax for HTML math" - , Option "" ["katex"] - (OptArg - (\arg opt -> - return opt - { optKaTeXJS = - arg <|> Just "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.js"}) - "URL") - "" -- Use KaTeX for HTML Math - - , Option "" ["katex-stylesheet"] - (ReqArg - (\arg opt -> - return opt { optKaTeXStylesheet = Just arg }) - "URL") - "" -- Set the KaTeX Stylesheet location - - , Option "" ["gladtex"] - (NoArg - (\opt -> return opt { optHTMLMathMethod = GladTeX })) - "" -- "Use gladtex for HTML math" - - , Option "" ["trace"] - (NoArg - (\opt -> return opt { optTrace = True })) - "" -- "Turn on diagnostic tracing in readers." - - , Option "" ["dump-args"] - (NoArg - (\opt -> return opt { optDumpArgs = True })) - "" -- "Print output filename and arguments to stdout." - - , Option "" ["ignore-args"] - (NoArg - (\opt -> return opt { optIgnoreArgs = True })) - "" -- "Ignore command-line arguments." - - , Option "" ["verbose"] - (NoArg - (\opt -> return opt { optVerbose = True })) - "" -- "Verbose diagnostic output." - - , Option "" ["bash-completion"] - (NoArg - (\_ -> do - ddir <- getDataDir - tpl <- readDataFileUTF8 Nothing "bash_completion.tpl" - let optnames (Option shorts longs _ _) = - map (\c -> ['-',c]) shorts ++ - map ("--" ++) longs - let allopts = unwords (concatMap optnames options) - UTF8.hPutStrLn stdout $ printf tpl allopts - (unwords (map fst readers)) - (unwords (map fst writers)) - (unwords $ map fst highlightingStyles) - ddir - exitSuccess )) - "" -- "Print bash completion script" - - , Option "" ["list-input-formats"] - (NoArg - (\_ -> do - let readers'names = sort (map fst readers) - mapM_ (UTF8.hPutStrLn stdout) readers'names - exitSuccess )) - "" - - , Option "" ["list-output-formats"] - (NoArg - (\_ -> do - let writers'names = sort (map fst writers) - mapM_ (UTF8.hPutStrLn stdout) writers'names - exitSuccess )) - "" - - , Option "" ["list-extensions"] - (NoArg - (\_ -> do - let showExt x = drop 4 (show x) ++ - if x `Set.member` pandocExtensions - then " +" - else " -" - mapM_ (UTF8.hPutStrLn stdout . showExt) - ([minBound..maxBound] :: [Extension]) - exitSuccess )) - "" - - , Option "" ["list-highlight-languages"] - (NoArg - (\_ -> do - let langs = [ T.unpack (T.toLower (sShortname s)) - | s <- M.elems defaultSyntaxMap - , sShortname s `notElem` - [T.pack "Alert", T.pack "Alert_indent"] - ] - mapM_ (UTF8.hPutStrLn stdout) langs - exitSuccess )) - "" - - , Option "" ["list-highlight-styles"] - (NoArg - (\_ -> do - mapM_ (UTF8.hPutStrLn stdout) $ - map fst highlightingStyles - exitSuccess )) - "" - - , Option "v" ["version"] - (NoArg - (\_ -> do - prg <- getProgName - defaultDatadir <- E.catch - (getAppUserDataDirectory "pandoc") - (\e -> let _ = (e :: E.SomeException) - in return "") - UTF8.hPutStrLn stdout (prg ++ " " ++ pandocVersion ++ - compileInfo ++ "\nDefault user data directory: " ++ - defaultDatadir ++ copyrightMessage) - exitSuccess )) - "" -- "Print version" - - , Option "h" ["help"] - (NoArg - (\_ -> do - prg <- getProgName - UTF8.hPutStr stdout (usageMessage prg options) - exitSuccess )) - "" -- "Show help" - - ] - - -addMetadata :: String -> MetaValue -> M.Map String MetaValue - -> M.Map String MetaValue -addMetadata k v m = case M.lookup k m of - Nothing -> M.insert k v m - Just (MetaList xs) -> M.insert k - (MetaList (xs ++ [v])) m - Just x -> M.insert k (MetaList [v, x]) m - -readMetaValue :: String -> MetaValue -readMetaValue s = case decode (UTF8.fromString s) of - Just (Yaml.String t) -> MetaString $ T.unpack t - Just (Yaml.Bool b) -> MetaBool b - _ -> MetaString s - --- Returns usage message -usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String -usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]") - --- Determine default reader based on source file extensions -defaultReaderName :: String -> [FilePath] -> String -defaultReaderName fallback [] = fallback -defaultReaderName fallback (x:xs) = - case takeExtension (map toLower x) of - ".xhtml" -> "html" - ".html" -> "html" - ".htm" -> "html" - ".md" -> "markdown" - ".markdown" -> "markdown" - ".tex" -> "latex" - ".latex" -> "latex" - ".ltx" -> "latex" - ".rst" -> "rst" - ".org" -> "org" - ".lhs" -> "markdown+lhs" - ".db" -> "docbook" - ".opml" -> "opml" - ".wiki" -> "mediawiki" - ".dokuwiki" -> "dokuwiki" - ".textile" -> "textile" - ".native" -> "native" - ".json" -> "json" - ".docx" -> "docx" - ".t2t" -> "t2t" - ".epub" -> "epub" - ".odt" -> "odt" - ".pdf" -> "pdf" -- so we get an "unknown reader" error - ".doc" -> "doc" -- so we get an "unknown reader" error - _ -> defaultReaderName fallback xs - --- Returns True if extension of first source is .lhs -lhsExtension :: [FilePath] -> Bool -lhsExtension (x:_) = takeExtension x == ".lhs" -lhsExtension _ = False - --- Determine default writer based on output file extension -defaultWriterName :: FilePath -> String -defaultWriterName "-" = "html" -- no output file -defaultWriterName x = - case takeExtension (map toLower x) of - "" -> "markdown" -- empty extension - ".tex" -> "latex" - ".latex" -> "latex" - ".ltx" -> "latex" - ".context" -> "context" - ".ctx" -> "context" - ".rtf" -> "rtf" - ".rst" -> "rst" - ".s5" -> "s5" - ".native" -> "native" - ".json" -> "json" - ".txt" -> "markdown" - ".text" -> "markdown" - ".md" -> "markdown" - ".markdown" -> "markdown" - ".textile" -> "textile" - ".lhs" -> "markdown+lhs" - ".texi" -> "texinfo" - ".texinfo" -> "texinfo" - ".db" -> "docbook" - ".odt" -> "odt" - ".docx" -> "docx" - ".epub" -> "epub" - ".org" -> "org" - ".asciidoc" -> "asciidoc" - ".adoc" -> "asciidoc" - ".pdf" -> "latex" - ".fb2" -> "fb2" - ".opml" -> "opml" - ".icml" -> "icml" - ".tei.xml" -> "tei" - ".tei" -> "tei" - ['.',y] | y `elem` ['1'..'9'] -> "man" - _ -> "html" - --- Transformations of a Pandoc document post-parsing: - -extractMedia :: MediaBag -> FilePath -> Pandoc -> IO Pandoc -extractMedia media dir d = - case [fp | (fp, _, _) <- mediaDirectory media] of - [] -> return d - fps -> do - extractMediaBag True dir media - return $ walk (adjustImagePath dir fps) d - -adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline -adjustImagePath dir paths (Image attr lab (src, tit)) - | src `elem` paths = Image attr lab (dir ++ "/" ++ src, tit) -adjustImagePath _ _ x = x - -adjustMetadata :: M.Map String MetaValue -> Pandoc -> IO Pandoc -adjustMetadata metadata d = return $ M.foldWithKey setMeta d metadata - -applyTransforms :: [Transform] -> Pandoc -> IO Pandoc -applyTransforms transforms d = return $ foldr ($) d transforms - - -- First we check to see if a filter is found. If not, and if it's - -- not an absolute path, we check to see whether it's in `userdir/filters`. - -- If not, we leave it unchanged. -expandFilterPath :: Maybe FilePath -> FilePath -> IO FilePath -expandFilterPath mbDatadir fp = do - fpExists <- doesFileExist fp - if fpExists - then return fp - else case mbDatadir of - Just datadir | isRelative fp -> do - let filterPath = (datadir </> "filters" </> fp) - filterPathExists <- doesFileExist filterPath - if filterPathExists - then return filterPath - else return fp - _ -> return fp - -applyFilters :: Maybe FilePath -> [FilePath] -> [String] -> Pandoc -> IO Pandoc -applyFilters mbDatadir filters args d = do - expandedFilters <- mapM (expandFilterPath mbDatadir) filters - foldrM ($) d $ map (flip externalFilter args) expandedFilters - -uppercaseFirstLetter :: String -> String -uppercaseFirstLetter (c:cs) = toUpper c : cs -uppercaseFirstLetter [] = [] +import Text.Pandoc.App (convertWithOpts, defaultOpts, options, parseOptions) +import Text.Pandoc.Error (handleError) main :: IO () -main = do - - rawArgs <- map UTF8.decodeArg <$> getArgs - prg <- getProgName - - let (actions, args, errors) = getOpt Permute options rawArgs - - unless (null errors) $ - err 2 $ concat $ errors ++ - ["Try " ++ prg ++ " --help for more information."] - - -- thread option data structure through all supplied option actions - opts <- foldl (>>=) (return defaultOpts) actions - convertWithOpts opts args - -convertWithOpts :: Opt -> [FilePath] -> IO () -convertWithOpts opts args = do - let Opt { optTabStop = tabStop - , optPreserveTabs = preserveTabs - , optStandalone = standalone - , optReader = readerName - , optWriter = writerName - , optParseRaw = parseRaw - , optVariables = variables - , optMetadata = metadata - , optTableOfContents = toc - , optTransforms = transforms - , optTemplate = templatePath - , optOutputFile = outputFile - , optNumberSections = numberSections - , optNumberOffset = numberFrom - , optSectionDivs = sectionDivs - , optIncremental = incremental - , optSelfContained = selfContained - , optSmart = smart - , optOldDashes = oldDashes - , optHtml5 = html5 - , optHtmlQTags = htmlQTags - , optHighlight = highlight - , optHighlightStyle = highlightStyle - , optTopLevelDivision = topLevelDivision - , optHTMLMathMethod = mathMethod' - , optReferenceODT = referenceODT - , optReferenceDocx = referenceDocx - , optEpubStylesheet = epubStylesheet - , optEpubMetadata = epubMetadata - , optEpubFonts = epubFonts - , optEpubChapterLevel = epubChapterLevel - , optTOCDepth = epubTOCDepth - , optDumpArgs = dumpArgs - , optIgnoreArgs = ignoreArgs - , optVerbose = verbose - , optReferenceLinks = referenceLinks - , optReferenceLocation = referenceLocation - , optDpi = dpi - , optWrapText = wrap - , optColumns = columns - , optFilters = filters - , optEmailObfuscation = obfuscationMethod - , optIdentifierPrefix = idPrefix - , optIndentedCodeClasses = codeBlockClasses - , optDataDir = mbDataDir - , optCiteMethod = citeMethod - , optListings = listings - , optLaTeXEngine = latexEngine - , optLaTeXEngineArgs = latexEngineArgs - , optSlideLevel = slideLevel - , optSetextHeaders = setextHeaders - , optAscii = ascii - , optTeXLigatures = texLigatures - , optDefaultImageExtension = defaultImageExtension - , optExtractMedia = mbExtractMedia - , optTrace = trace - , optTrackChanges = trackChanges - , optFileScope = fileScope - , optKaTeXStylesheet = katexStylesheet - , optKaTeXJS = katexJS - } = opts - - when dumpArgs $ - do UTF8.hPutStrLn stdout outputFile - mapM_ (UTF8.hPutStrLn stdout) args - exitSuccess - - let csscdn = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.6.0/katex.min.css" - let mathMethod = - case (katexJS, katexStylesheet) of - (Nothing, _) -> mathMethod' - (Just js, ss) -> KaTeX js (fromMaybe csscdn ss) - - - -- --bibliography implies -F pandoc-citeproc for backwards compatibility: - let needsCiteproc = isJust (M.lookup "bibliography" (optMetadata opts)) && - optCiteMethod opts `notElem` [Natbib, Biblatex] && - "pandoc-citeproc" `notElem` map takeBaseName filters - let filters' = if needsCiteproc then "pandoc-citeproc" : filters - else filters - - let sources = if ignoreArgs then [] else args - - datadir <- case mbDataDir of - Nothing -> E.catch - (Just <$> getAppUserDataDirectory "pandoc") - (\e -> let _ = (e :: E.SomeException) - in return Nothing) - Just _ -> return mbDataDir - - -- assign reader and writer based on options and filenames - let readerName' = case map toLower readerName of - [] -> defaultReaderName - (if any isURI sources - then "html" - else "markdown") sources - "html4" -> "html" - x -> x - - let writerName' = case map toLower writerName of - [] -> defaultWriterName outputFile - "epub2" -> "epub" - "html4" -> "html" - x -> x - let format = takeWhile (`notElem` ['+','-']) - $ takeFileName writerName' -- in case path to lua script - - let pdfOutput = map toLower (takeExtension outputFile) == ".pdf" - - let laTeXOutput = format `elem` ["latex", "beamer"] - let conTeXtOutput = format == "context" - let html5Output = format == "html5" - - let laTeXInput = "latex" `isPrefixOf` readerName' || - "beamer" `isPrefixOf` readerName' - - writer <- if ".lua" `isSuffixOf` format - -- note: use non-lowercased version writerName - then return $ IOStringWriter $ writeCustom writerName - else case getWriter writerName' of - Left e -> err 9 $ - if format == "pdf" - then e ++ - "\nTo create a pdf with pandoc, use " ++ - "the latex or beamer writer and specify\n" ++ - "an output file with .pdf extension " ++ - "(pandoc -t latex -o filename.pdf)." - else e - Right w -> return w - - reader <- if "t2t" == readerName' - then (mkStringReader . - readTxt2Tags) <$> - getT2TMeta sources outputFile - else case getReader readerName' of - Right r -> return r - Left e -> err 7 e' - where e' = case readerName' of - "pdf" -> e ++ - "\nPandoc can convert to PDF, but not from PDF." - "doc" -> e ++ - "\nPandoc can convert from DOCX, but not from DOC.\nTry using Word to save your DOC file as DOCX, and convert that with pandoc." - _ -> e - - let standalone' = standalone || not (isTextFormat format) || pdfOutput - - templ <- case templatePath of - _ | not standalone' -> return Nothing - Nothing -> do - deftemp <- getDefaultTemplate datadir format - case deftemp of - Left e -> throwIO e - Right t -> return (Just t) - Just tp -> do - -- strip off extensions - let tp' = case takeExtension tp of - "" -> tp <.> format - _ -> tp - Just <$> E.catch (UTF8.readFile tp') - (\e -> if isDoesNotExistError e - then E.catch - (readDataFileUTF8 datadir - ("templates" </> tp')) - (\e' -> let _ = (e' :: E.SomeException) - in throwIO e') - else throwIO e) - - variables' <- case mathMethod of - LaTeXMathML Nothing -> do - s <- readDataFileUTF8 datadir "LaTeXMathML.js" - return $ ("mathml-script", s) : variables - _ -> return variables - - variables'' <- if format == "dzslides" - then do - dztempl <- readDataFileUTF8 datadir - ("dzslides" </> "template.html") - let dzline = "<!-- {{{{ dzslides core" - let dzcore = unlines - $ dropWhile (not . (dzline `isPrefixOf`)) - $ lines dztempl - return $ ("dzslides-core", dzcore) : variables' - else return variables' - - let sourceURL = case sources of - [] -> Nothing - (x:_) -> case parseURI x of - Just u - | uriScheme u `elem` ["http:","https:"] -> - Just $ show u{ uriQuery = "", - uriFragment = "" } - _ -> Nothing - - let readerOpts = def{ readerSmart = if laTeXInput - then texLigatures - else smart || (texLigatures && - (laTeXOutput || conTeXtOutput)) - , readerStandalone = standalone' - , readerParseRaw = parseRaw - , readerColumns = columns - , readerTabStop = tabStop - , readerOldDashes = oldDashes - , readerIndentedCodeClasses = codeBlockClasses - , readerApplyMacros = not laTeXOutput - , readerDefaultImageExtension = defaultImageExtension - , readerTrace = trace - , readerTrackChanges = trackChanges - , readerFileScope = fileScope - } - -#ifdef _WINDOWS - let istty = True -#else - istty <- queryTerminal stdOutput -#endif - when (istty && not (isTextFormat format) && outputFile == "-") $ - err 5 $ "Cannot write " ++ format ++ " output to stdout.\n" ++ - "Specify an output file using the -o option." - - let readSources [] = mapM readSource ["-"] - readSources srcs = mapM readSource srcs - readSource "-" = UTF8.getContents - readSource src = case parseURI src of - Just u | uriScheme u `elem` ["http:","https:"] -> - readURI src - | uriScheme u == "file:" -> - UTF8.readFile (uriPath u) - _ -> UTF8.readFile src - readURI src = do - res <- openURL src - case res of - Left e -> throwIO e - Right (bs,_) -> return $ UTF8.toString bs - - let readFiles [] = error "Cannot read archive from stdin" - readFiles [x] = B.readFile x - readFiles (x:xs) = mapM_ (warn . ("Ignoring: " ++)) xs >> B.readFile x - - let convertTabs = tabFilter (if preserveTabs || readerName' == "t2t" - then 0 - else tabStop) - - let handleIncludes' :: String -> IO (Either PandocError String) - handleIncludes' = if readerName' `elem` ["latex", "latex+lhs"] - then handleIncludes - else return . Right - - let sourceToDoc :: [FilePath] -> IO (Pandoc, MediaBag) - sourceToDoc sources' = fmap handleError $ - case reader of - StringReader r-> do - srcs <- convertTabs . intercalate "\n" <$> readSources sources' - doc <- handleIncludes' srcs - either (return . Left) (\s -> fmap (,mempty) <$> r readerOpts s) doc - ByteStringReader r -> readFiles sources' >>= r readerOpts - - -- We parse first if (1) fileScope is set, (2), it's a binary - -- reader, or (3) we're reading JSON. This is easier to do of an AND - -- of negatives as opposed to an OR of positives, so we do default - -- parsing if it's a StringReader AND (fileScope is set AND it's not - -- a JSON reader). - (doc, media) <- case reader of - (StringReader _) | not fileScope && readerName' /= "json" -> - sourceToDoc sources - _ | null sources -> sourceToDoc sources - _ -> do pairs <- mapM (\s -> sourceToDoc [s]) sources - return (mconcat $ map fst pairs, mconcat $ map snd pairs) - - let writerOptions = def { writerTemplate = templ, - writerVariables = variables'', - writerTabStop = tabStop, - writerTableOfContents = toc, - writerHTMLMathMethod = mathMethod, - writerIncremental = incremental, - writerCiteMethod = citeMethod, - writerIgnoreNotes = False, - writerNumberSections = numberSections, - writerNumberOffset = numberFrom, - writerSectionDivs = sectionDivs, - writerReferenceLinks = referenceLinks, - writerReferenceLocation = referenceLocation, - writerDpi = dpi, - writerWrapText = wrap, - writerColumns = columns, - writerEmailObfuscation = obfuscationMethod, - writerIdentifierPrefix = idPrefix, - writerSourceURL = sourceURL, - writerUserDataDir = datadir, - writerHtml5 = html5, - writerHtmlQTags = htmlQTags, - writerTopLevelDivision = topLevelDivision, - writerListings = listings, - writerBeamer = False, - writerSlideLevel = slideLevel, - writerHighlight = highlight, - writerHighlightStyle = highlightStyle, - writerSetextHeaders = setextHeaders, - writerTeXLigatures = texLigatures, - writerEpubMetadata = epubMetadata, - writerEpubStylesheet = epubStylesheet, - writerEpubFonts = epubFonts, - writerEpubChapterLevel = epubChapterLevel, - writerTOCDepth = epubTOCDepth, - writerReferenceODT = referenceODT, - writerReferenceDocx = referenceDocx, - writerMediaBag = media, - writerVerbose = verbose, - writerLaTeXArgs = latexEngineArgs - } - - - doc' <- (maybe return (extractMedia media) mbExtractMedia >=> - adjustMetadata metadata >=> - applyTransforms transforms >=> - applyFilters datadir filters' [format]) doc - - let writeFnBinary :: FilePath -> B.ByteString -> IO () - writeFnBinary "-" = B.putStr - writeFnBinary f = B.writeFile (UTF8.encodePath f) - - let writerFn :: FilePath -> String -> IO () - writerFn "-" = UTF8.putStr - writerFn f = UTF8.writeFile f - - case writer of - IOStringWriter f -> f writerOptions doc' >>= writerFn outputFile - IOByteStringWriter f -> f writerOptions doc' >>= writeFnBinary outputFile - PureStringWriter f - | pdfOutput -> do - -- make sure writer is latex or beamer or context or html5 - unless (laTeXOutput || conTeXtOutput || html5Output) $ - err 47 $ "cannot produce pdf output with " ++ format ++ - " writer" - - let pdfprog = case () of - _ | conTeXtOutput -> "context" - _ | html5Output -> "wkhtmltopdf" - _ -> latexEngine - -- check for pdf creating program - mbPdfProg <- findExecutable pdfprog - when (isNothing mbPdfProg) $ - err 41 $ pdfprog ++ " not found. " ++ - pdfprog ++ " is needed for pdf output." - - res <- makePDF pdfprog f writerOptions doc' - case res of - Right pdf -> writeFnBinary outputFile pdf - Left err' -> do - B.hPutStr stderr err' - B.hPut stderr $ B.pack [10] - err 43 "Error producing PDF" - | otherwise -> selfcontain (f writerOptions doc' ++ - ['\n' | not standalone']) - >>= writerFn outputFile . handleEntities - where htmlFormat = format `elem` - ["html","html5","s5","slidy","slideous","dzslides","revealjs"] - selfcontain = if selfContained && htmlFormat - then makeSelfContained writerOptions - else return - handleEntities = if htmlFormat && ascii - then toEntities - else id +main = E.catch (parseOptions options defaultOpts >>= convertWithOpts) + (handleError . Left) |