]> gitweb @ CieloNegro.org - Rakka.git/blob - Rakka/Wiki/Formatter.hs
a08fe304ff74385cfe66f19cdd8e73d6edece596
[Rakka.git] / Rakka / Wiki / Formatter.hs
1 module Rakka.Wiki.Formatter
2     ( formatWikiBlocks
3     )
4     where
5
6 import           Control.Arrow
7 import           Control.Arrow.ArrowList
8 import           Data.Char
9 import           Data.List
10 import           Data.Maybe
11 import           Network.URI
12 import           Rakka.Page
13 import           Rakka.Wiki
14 import           Text.XML.HXT.Arrow.XmlArrow
15 import           Text.XML.HXT.DOM.TypeDefs
16
17
18 formatWikiBlocks :: (ArrowXml a, ArrowChoice a) => a (URI, [BlockElement]) XmlTree
19 formatWikiBlocks
20     = proc (baseURI, blocks)
21     -> do block <- arrL id -< blocks
22           formatBlock -< (baseURI, block)
23
24
25 formatBlock :: (ArrowXml a, ArrowChoice a) => a (URI, BlockElement) XmlTree
26 formatBlock 
27     = proc (baseURI, block)
28     -> case block of
29          Heading level text
30              -> formatHeading -< (level, text)
31
32          HorizontalLine
33              -> eelem "hr" -< ()
34
35          List list
36              -> formatListElement -< (baseURI, list)
37
38          DefinitionList list
39              -> formatDefinitionList -< (baseURI, list)
40
41          Preformatted inlines
42              -> formatPreformatted -< (baseURI, inlines)
43                 
44          Paragraph inlines
45              -> formatParagraph -< (baseURI, inlines)
46
47          Div attrs contents
48              -> formatElem "div" -< (baseURI, attrs, contents)
49     where
50       formatElem :: (ArrowXml a, ArrowChoice a) =>
51                     String
52                  -> a (URI, [Attribute], [BlockElement]) XmlTree
53       formatElem name
54           = proc (baseURI, attrs, contents)
55           -> ( eelem name
56                += ( arrL (fst . snd)
57                        >>>
58                        attrFromPair
59                   )
60                += ( (arr fst &&& arrL (snd . snd))
61                     >>>
62                     formatBlock
63                   )
64              ) -< (baseURI, (attrs, contents))
65
66
67 formatHeading :: ArrowXml a => a (Int, String) XmlTree
68 formatHeading 
69     = proc (level, text)
70     -> mkelem ("h" ++ show level)
71        [ sattr "id" text ]
72        [ txt text        ] -<< ()
73
74
75 formatListElement :: (ArrowXml a, ArrowChoice a) => a (URI, ListElement) XmlTree
76 formatListElement 
77     = proc (baseURI, list)
78     -> let tag = case listType list of
79                    Bullet   -> "ul"
80                    Numbered -> "ol"
81        in
82          ( eelem tag
83            += ( (constA baseURI &&& constL (listItems list))
84                 >>>
85                 formatListItem
86               )
87          ) -<< ()
88       where
89         formatListItem :: (ArrowXml a, ArrowChoice a) => a (URI, ListItem) XmlTree
90         formatListItem 
91             = proc (baseURI, item)
92             -> eelem "li"
93                += ( (arr fst &&& arrL snd)
94                     >>>
95                     formatListItem'
96                   ) -< (baseURI, item)
97
98         formatListItem' :: (ArrowXml a, ArrowChoice a) => a (URI, Either ListElement InlineElement) XmlTree
99         formatListItem' 
100             = proc (baseURI, x)
101             -> case x of
102                  Left  nestedList -> formatListElement -< (baseURI, nestedList)
103                  Right inline     -> formatInline      -< (baseURI, inline    )
104
105
106 formatDefinitionList :: (ArrowXml a, ArrowChoice a) => a (URI, [Definition]) XmlTree
107 formatDefinitionList 
108     = proc (baseURI, list)
109     -> ( eelem "dl"
110          += ( (arr fst &&& arrL snd)
111               >>>
112               formatDefinition
113             )
114        ) -< (baseURI, list)
115     where
116       formatDefinition :: (ArrowXml a, ArrowChoice a) => a (URI, Definition) XmlTree
117       formatDefinition 
118           = proc (baseURI, def)
119           -> ( eelem "dt"
120                += ( (arr fst &&& arrL (defTerm . snd))
121                     >>>
122                     formatInline
123                   )
124                <+>
125                eelem "dd"
126                += ( (arr fst &&& arrL (defDesc . snd))
127                     >>>
128                     formatInline
129                   )
130              ) -< (baseURI, def)
131
132
133 formatPreformatted :: (ArrowXml a, ArrowChoice a) => a (URI, [InlineElement]) XmlTree
134 formatPreformatted
135     = eelem "pre"
136       += ( (arr fst &&& arrL snd)
137            >>>
138            formatInline
139          )
140
141
142 formatParagraph :: (ArrowXml a, ArrowChoice a) => a (URI, [InlineElement]) XmlTree
143 formatParagraph 
144     = eelem "p"
145       += ( (arr fst &&& arrL snd)
146            >>>
147            formatInline
148          )
149
150
151 formatInline :: (ArrowXml a, ArrowChoice a) => a (URI, InlineElement) XmlTree
152 formatInline 
153     = proc (baseURI, i)
154     -> case i of
155          Text text
156              -> mkText -< text
157
158          Italic contents
159              -> formatElem "i" -< (baseURI, [], contents)
160
161          Bold contents
162              -> formatElem "b" -< (baseURI, [], contents)
163
164          link@(PageLink _ _ _)
165              -> formatPageLink -< (baseURI, link)
166
167          link@(ExternalLink _ _)
168              -> formatExternalLink -< link
169
170          LineBreak attrs
171              -> formatElem "br" -< (baseURI, attrs, [])
172
173          Span attrs contents
174              -> formatElem "span" -< (baseURI, attrs, contents)
175
176          Image attrs
177              -> formatElem "img" -< (baseURI, attrs, [])
178
179          Anchor attrs contents
180              -> formatElem "a" -< (baseURI, attrs, contents)
181     where
182       formatElem :: (ArrowXml a, ArrowChoice a) =>
183                     String
184                  -> a (URI, [Attribute], [InlineElement]) XmlTree
185       formatElem name
186           = proc (baseURI, attrs, contents)
187           -> ( eelem name
188                += ( arrL (fst . snd)
189                        >>>
190                        attrFromPair
191                   )
192                += ( (arr fst &&& arrL (snd . snd))
193                     >>>
194                     formatInline
195                   )
196              ) -< (baseURI, (attrs, contents))
197
198
199 attrFromPair :: (ArrowXml a) => a (String, String) XmlTree
200 attrFromPair = proc (name, value)
201              -> attr name (txt value) -<< ()
202
203
204 formatPageLink :: (ArrowXml a) => a (URI, InlineElement) XmlTree
205 formatPageLink 
206     = proc (baseURI, PageLink page fragment text)
207     -> let uri    = case (page, fragment) of
208                       (Just  x, Just  y) -> mkPageFragmentURI baseURI (fix x) y
209                       (Just  x, Nothing) -> mkPageURI baseURI (fix x)
210                       (Nothing, Just  y) -> nullURI { uriFragment = ('#':y) }
211            fix    = (\ (x:xs) -> toUpper x : xs) . map (\ c -> if c == ' ' then '_' else c)
212            href   = uriToString id uri ""
213            dLabel = fromMaybe "" page ++ fromMaybe "" (fmap ('#':) fragment)
214            label  = fromMaybe dLabel text
215        in
216          ( eelem "a"
217            += attr "href" (arr fst >>> mkText)
218            += (arr snd >>> mkText)
219          ) -< (href, label)
220
221
222 formatExternalLink :: (ArrowXml a) => a InlineElement XmlTree
223 formatExternalLink 
224     = proc (ExternalLink uri text)
225     -> let href  = uriToString id uri ""
226            label = fromMaybe href text
227        in
228          ( eelem "a"
229            += attr "href" (arr fst >>> mkText)
230            += (arr snd >>> mkText)
231          ) -< (href, label)