-- | Formats Haskell source code using LaTeX macros. module Language.Haskell.HsColour.LaTeX (hscolour) where import Language.Haskell.HsColour.Classify as Classify import Language.Haskell.HsColour.Colourise import Language.Haskell.HsColour.General -- | Formats Haskell source code as a complete LaTeX document. hscolour :: ColourPrefs -- ^ Colour preferences. -> Bool -- ^ Whether output should be partial (= no prologue). -> String -- ^ Haskell source code. -> String -- ^ A LaTeX document\/fragment containing the coloured -- Haskell source code. hscolour pref partial = ( if partial then id else top'n'tail) . concatMap (renderToken pref) . tokenise top'n'tail :: String -> String top'n'tail = (latexPrefix++) . (++latexSuffix) -- | Wrap each lexeme in the appropriate LaTeX macro. -- TODO: filter dangerous characters like "{}_$" renderToken :: ColourPrefs -> (TokenType,String) -> String renderToken pref (Space,text) = filterSpace text renderToken pref (cls,text) = let symb = case cls of String -> "``" ++ (dropFirst '\"' $ dropLast '\"' $ text) ++ "''" _ -> text style = colourise pref cls (pre, post) = unzip $ map latexHighlight style in concat pre ++ filterSpecial symb ++ concat post -- | Filter white space characters. filterSpace :: String -> String filterSpace ('\n':ss) = '\\':'\\':(filterSpace ss) filterSpace (' ':ss) = "\\hsspace "++(filterSpace ss) filterSpace ('\t':ss) = "\\hstab "++(filterSpace ss) filterSpace (c:ss) = c:(filterSpace ss) filterSpace [] = [] -- | Filters the characters "#$%&~_^\{}" which are special -- in LaTeX. filterSpecial :: String -- ^ The string to filter. -> String -- ^ The LaTeX-safe string. filterSpecial ('#':cs) = '\\':'#':(filterSpecial cs) filterSpecial ('$':cs) = '\\':'$':(filterSpecial cs) filterSpecial ('%':cs) = '\\':'%':(filterSpecial cs) filterSpecial ('&':cs) = '\\':'&':(filterSpecial cs) filterSpecial ('~':cs) = "\\tilde{ }"++(filterSpecial cs) filterSpecial ('_':cs) = '\\':'_':(filterSpecial cs) filterSpecial ('^':cs) = "\\ensuremath{\\hat{ }}"++(filterSpecial cs) filterSpecial ('\\':cs) = "$\\backslash$"++(filterSpecial cs) filterSpecial ('{':cs) = '\\':'{':(filterSpecial cs) filterSpecial ('}':cs) = '\\':'}':(filterSpecial cs) filterSpecial ('|':cs) = "\\ensuremath{|}"++(filterSpecial cs) filterSpecial ('<':'-':cs) = "\\ensuremath{\\leftarrow}"++(filterSpecial cs) filterSpecial ('<':cs) = "\\ensuremath{\\langle}"++(filterSpecial cs) filterSpecial ('-':'>':cs) = "\\ensuremath{\\rightarrow}"++(filterSpecial cs) filterSpecial ('>':cs) = "\\ensuremath{\\rangle}"++(filterSpecial cs) filterSpecial (c:cs) = c:(filterSpecial cs) filterSpecial [] = [] -- | Constructs the appropriate LaTeX macro for the given style. latexHighlight :: Highlight -> (String, String) latexHighlight Normal = ("{\\rm{}", "}") latexHighlight Bold = ("{\\bf{}", "}") latexHighlight Dim = ("", "") latexHighlight Underscore = ("\\underline{", "}") latexHighlight Blink = ("", "") latexHighlight ReverseVideo = ("", "") latexHighlight Concealed = ("\\conceal{", "}") latexHighlight (Foreground c) = ("\\textcolor{"++ latexColour c ++"}{", "}") latexHighlight (Background c) = ("\\colorbox{"++ latexColour c ++"}{", "}") -- | Translate a 'Colour' into a LaTeX colour name. latexColour :: Colour -> String latexColour Black = "black" latexColour Red = "red" latexColour Green = "green" latexColour Yellow = "yellow" latexColour Blue = "blue" latexColour Magenta = "magenta" latexColour Cyan = "cyan" latexColour White = "white" -- | Generic LaTeX document preamble. latexPrefix = unlines ["\\documentclass[a4paper, 12pt]{article}" ,"\\usepackage[usenames]{color}" ,"\\usepackage{hyperref}" ,"\\newsavebox{\\spaceb}" ,"\\newsavebox{\\tabb}" ,"\\savebox{\\spaceb}[1ex]{~}" ,"\\savebox{\\tabb}[4ex]{~}" ,"\\newcommand{\\hsspace}{\\usebox{\\spaceb}}" ,"\\newcommand{\\hstab}{\\usebox{\\tabb}}" ,"\\newcommand{\\conceal}[1]{}" ,"\\begin{document}" ,"\\noindent" ] -- | Generic LaTeX document postamble. latexSuffix = unlines ["" ,"\\end{document}" ]