----------------------------------------------------------------------------- -- | -- Module : Text.Highlighting.Pygments -- Copyright : (c) David Lazar, 2012 -- License : MIT -- -- Maintainer : lazar6@illinois.edu -- Stability : experimental -- Portability : unknown -- -- This library uses the @pygmentize@ script that comes with Pygments to -- highlight code in many languages. For documentation on the various lexers, -- formatters, and options, see the Pygments documentation -- . ----------------------------------------------------------------------------- module Text.Highlighting.Pygments ( highlight , pygmentize , module Text.Highlighting.Pygments.Lexers , module Text.Highlighting.Pygments.Formatters -- * Options , Option , Options -- * Examples -- $examples ) where import System.Exit import System.Process (readProcessWithExitCode) import Text.Highlighting.Pygments.Lexers import Text.Highlighting.Pygments.Formatters -- | Highlight code robustly. This function is more robust than the -- lower-level 'pygmentize' function since this library forbids the -- construction of invalid 'Lexer' and 'Formatter' values. Invalid -- 'Options' may still cause this function to raise an exception. highlight :: Lexer -> Formatter -> Options -> String -> IO String highlight lexer formatter options code = do let (lexerAlias : _) = lexerAliases lexer let (formatterAlias : _) = formatterAliases formatter pygmentize lexerAlias formatterAlias options code -- | Highlight code (less robustly) using the @pygmentize@ script that comes -- with Pygments. Invalid values for 'LexerAlias', 'FormatterAlias', or -- 'Options' will cause this function to raise an exception. pygmentize :: LexerAlias -> FormatterAlias -> Options -> String -> IO String pygmentize lexer formatter options code = do let args = ["-l", lexer, "-f", formatter] ++ optionsToArgs options (exitCode, stdout, stderr) <- readProcessWithExitCode "pygmentize" args code case exitCode of ExitSuccess -> return stdout -- TODO throw a custom exception? e -> error $ "hpygments: `pygmentize " ++ unwords args ++ "` failed: " ++ show e ++ if stderr /= "" then ": " ++ stderr else "" -- | The lexer/formatter option @(key, value)@ is passed to the @pygmentize@ -- script via the command-line flag @-P key=value@. -- -- Examples: -- -- > [("hl_lines", "16,23,42"), ("encoding", "utf-8"), ("anchorlines", "True")] -- type Option = (String, String) type Options = [Option] optionsToArgs :: Options -> [String] optionsToArgs options = concatMap optionToArg options optionToArg :: Option -> [String] optionToArg (name, value) = ["-P", name ++ "=" ++ value] {- $examples Highlight a proposition: >>> Just coqLexer <- getLexerByName "coq" >>> highlight coqLexer terminalFormatter [("encoding", "utf-8")] "∀ x y : Z, x * y = 0 -> x = 0 \\/ y = 0" >>= putStr ∀ x y : Z, x * y = 0 -> x = 0 \/ y = 0 Output a complete HTML document: >>> highlight haskellLexer htmlFormatter [("full", "True"), ("linenos", "table"), ("style", "emacs")] "fix f = let x = f x in x" >>= writeFile "fix.html" Self-highlighting quine: > quine = pygmentize "hs" "terminal" [] (s ++ show s) >>= putStr > where s = "quine = pygmentize \"hs\" \"terminal\" [] (s ++ show s) >>= putStr\n where s = " Highlight the code \"answer = 42\" using every language Pygments knows about: >>> lexers <- getAllLexers >>> forM_ lexers $ \l -> highlight l terminalFormatter [] "answer = 42" >>= printf "(%s) %s" (lexerName l) ... (Prolog) answer = 42 (CSS+Django/Jinja) answer = 42 (Smalltalk) answer = 42 ... -}