This repository has been archived by the owner on Jul 31, 2020. It is now read-only.
/
Highlight.hs
155 lines (143 loc) · 6.17 KB
/
Highlight.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
{-# LANGUAGE CPP, OverloadedStrings #-}
module Main where
import Text.Highlighting.Kate
import System.IO (hPutStrLn, stderr)
import System.Environment
import System.Console.GetOpt
import System.Exit
import System.FilePath (takeFileName)
import Data.Maybe (listToMaybe)
import Data.Char (toLower)
import Text.Blaze.Renderer.String
import Text.Blaze
import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A
data Flag = Sty String
| Format String
| Help
| Fragment
| List
| NumberLines
| Syntax String
| TitleAttributes
| Version
deriving (Eq, Show)
options :: [OptDescr Flag]
options =
[ Option ['S'] ["style"] (ReqArg Sty "STYLE") "specify style"
, Option ['F'] ["format"] (ReqArg Format "FORMAT") "output format (html|latex)"
, Option ['f'] ["fragment"] (NoArg Fragment) "fragment, without document header"
, Option ['h'] ["help"] (NoArg Help) "show usage message"
, Option ['l'] ["list"] (NoArg List) "list available language syntaxes"
, Option ['n'] ["number-lines"] (NoArg NumberLines) "number lines"
, Option ['s'] ["syntax"] (ReqArg Syntax "SYNTAX") "specify language syntax to use"
, Option ['t'] ["title-attributes"] (NoArg TitleAttributes) "include structure in title attributes"
, Option ['v'] ["version"] (NoArg Version) "print version"
]
syntaxOf :: [Flag] -> Maybe String
syntaxOf [] = Nothing
syntaxOf (Syntax s : _) = Just s
syntaxOf (_:xs) = syntaxOf xs
styleOf :: [Flag] -> Maybe Style
styleOf [] = Nothing
styleOf (Sty s : _) = case map toLower s of
"pygments" -> Just pygments
"espresso" -> Just espresso
"kate" -> Just kate
"tango" -> Just tango
"haddock" -> Just haddock
"monochrome" -> Just monochrome
_ -> error $ "Unknown style: " ++ s
styleOf (_ : xs) = styleOf xs
formatOf :: [Flag] -> String
formatOf [] = "html" -- default
formatOf (Format s : _) = case map toLower s of
"html" -> "html"
"latex" -> "latex"
_ -> error $ "Unknown format: " ++ s
formatOf (_ : xs) = formatOf xs
filterNewlines :: String -> String
filterNewlines ('\r':'\n':xs) = '\n' : filterNewlines xs
filterNewlines ('\r':xs) = '\n' : filterNewlines xs
filterNewlines (x:xs) = x : filterNewlines xs
filterNewlines [] = []
main = do
(opts, fnames, errs) <- getArgs >>= return . getOpt Permute options
prg <- getProgName
let usageHeader = prg ++ " [options] [files...]"
if not (null errs)
then ioError (userError $ concat errs ++ usageInfo usageHeader options)
else return ()
if List `elem` opts
then putStrLn (unwords languages) >> exitWith ExitSuccess
else return ()
if Help `elem` opts
then hPutStrLn stderr (usageInfo usageHeader options) >>
exitWith (ExitFailure 1)
else return ()
if Version `elem` opts
then putStrLn (prg ++ " " ++ highlightingKateVersion ++ " - (c) 2008 John MacFarlane") >>
exitWith ExitSuccess
else return ()
code <- if null fnames
then getContents >>= return . filterNewlines
else mapM readFile fnames >>= return . filterNewlines . concat
let lang' = case syntaxOf opts of
Just e -> Just e
Nothing -> case fnames of
[] -> Nothing
(x:_) -> listToMaybe $ languagesByFilename $ takeFileName x
lang <- if lang' == Nothing
then hPutStrLn stderr "No syntax specified." >>
hPutStrLn stderr (usageInfo usageHeader options) >>
exitWith (ExitFailure 5)
else do let (Just l) = lang'
return (map toLower l)
if not (lang `elem` (map (map toLower) languages))
then hPutStrLn stderr ("Unknown syntax: " ++ lang) >> exitWith (ExitFailure 4)
else return ()
let highlightOpts = defaultFormatOpts{ titleAttributes = TitleAttributes `elem` opts
, numberLines = NumberLines `elem` opts
, lineAnchors = NumberLines `elem` opts
}
let fragment = Fragment `elem` opts
let fname = case fnames of
[] -> ""
(x:_) -> x
case formatOf opts of
"html" -> hlHtml fragment fname highlightOpts (maybe pygments id $ styleOf opts)
lang code
"latex" -> hlLaTeX fragment fname highlightOpts (maybe pygments id $ styleOf opts) lang code
x -> error $ "Uknown format " ++ x
hlHtml :: Bool -- ^ Fragment
-> FilePath -- ^ Filename
-> FormatOptions
-> Style
-> String -- ^ language
-> String -- ^ code
-> IO ()
hlHtml frag fname opts sty lang code =
if frag
then putStrLn $ renderHtml fragment
else putStrLn $ renderHtml $ H.head (pageTitle >> metadata >> css) >> H.body (toHtml fragment)
where fragment = formatHtmlBlock opts $ highlightAs lang code
css = H.style ! A.type_ "text/css" $ toHtml $ styleToCss sty
pageTitle = H.title $ toHtml fname
metadata = H.meta ! A.httpEquiv "Content-Type" ! A.content "text/html; charset=UTF-8" >>
H.meta ! A.name "generator" ! A.content "highlight-kate"
hlLaTeX :: Bool -- ^ Fragment
-> FilePath -- ^ Filename
-> FormatOptions
-> Style
-> String -- ^ language
-> String -- ^ code
-> IO ()
hlLaTeX frag fname opts sty lang code =
if frag
then putStrLn fragment
else putStrLn $ "\\documentclass{article}\n\\usepackage[margin=1in]{geometry}\n" ++
macros ++ pageTitle ++
"\n\\begin{document}\n\\maketitle\n" ++ fragment ++ "\n\\end{document}"
where fragment = formatLaTeXBlock opts $ highlightAs lang code
macros = styleToLaTeX sty
pageTitle = "\\title{" ++ fname ++ "}\n"