-
Notifications
You must be signed in to change notification settings - Fork 0
/
HTMLPrinter.hs
75 lines (60 loc) · 2.66 KB
/
HTMLPrinter.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
{-# LANGUAGE Haskell2010 #-}
-- Transforms an ATerm tree representing HTML into a pretty printed HTML document.
-- Uses Text.PrettyPrint.
module HTMLPrinter (main) where
import Feedback
import ATermParser
import MainModule
import Control.Monad
import Data.List
import Data.Maybe
import System.IO
import Data.Char
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as B
import Data.Text.Lazy (Text)
import qualified Data.Text.Lazy as T
import Data.Text.Lazy.Encoding
import CCO.Tree (ATerm (..))
-- pretty
import Text.PrettyPrint
-- Pretty print a HTML page represented through an ATerm.
-- Errors are logged in case the tree is invalid.
-- Four spaces of identation are added each level.
ppHTML :: ATerm -> Feedback Doc
ppHTML (Ann (App tag [List children]) atts) =
do attDocs <- forM atts ppAttribute
childDocs <- forM (concatStrings children) ppHTML
return $ openTag tag attDocs $+$ nest 4 (vcat childDocs) $+$ closeTag tag
ppHTML c@(App _ _) = ppHTML $ Ann c []
ppHTML (String txt) = return $ text $ htmlEscape txt
ppHTML term = errorF ("Can not convert to HTML: '" ++ show term ++ "'.") >> return empty
-- Concatenate all adiencent ATerms within the list that are String literals. This prevents newlines from being
-- introduced when strings follow each other up.
concatStrings :: [ATerm] -> [ATerm]
concatStrings [] = []
concatStrings (String a : String b : xs) = concatStrings $ String (a ++ b) : xs
concatStrings (x:xs) = x : concatStrings xs
openTag :: String -> [Doc] -> Doc
openTag tag [] = char '<' <> text (map toLower tag) <> char '>'
openTag tag atts = char '<' <> text (map toLower tag) <+> hsep atts <> char '>'
closeTag :: String -> Doc
closeTag tag = text "</" <> text (map toLower tag) <> char '>'
-- Pretty prints a tag attribute.
ppAttribute :: ATerm -> Feedback Doc
ppAttribute (App key [String val]) = return $ text key <> text "=\"" <> text (htmlEscape val) <> char '"'
ppAttribute t = errorF ("Invalid attribute: '" ++ show t ++ "'.") >> return empty
-- Replaces all special characters (control characters, non-ASCII characters, characters that
-- conflict with HTML syntax) with their HTML escape sequences.
htmlEscape :: String -> String
htmlEscape = concatMap escapeChar
where escapeChar c | c < chr 32 || c > chr 126 || c `elem` "&<>\"'/" = "&#" ++ show (ord c)
| otherwise = [c]
-- The printing as a ProgramOperation.
-- Assume default page style.
printHTML :: ProgramOperation
printHTML inp = do aterm <- parseATerm inp
doc <- ppHTML aterm
return $ encodeUtf8 $ T.pack $ (++ "\n") $ render doc
main :: IO ()
main = makeMain printHTML