1 module Rakka.Wiki.Engine
10 import Control.Arrow.ArrowIO
11 import Control.Arrow.ArrowList
13 import Data.Encoding.UTF8
16 import qualified Data.Map as M
18 import Network.HTTP.Lucu
22 import Rakka.SystemConfig
25 import Rakka.Wiki.Parser
26 import Rakka.Wiki.Formatter
27 import Rakka.Wiki.Interpreter
28 import Text.HyperEstraier hiding (getText)
29 import Text.ParserCombinators.Parsec
30 import Text.XML.HXT.Arrow.Namespace
31 import Text.XML.HXT.Arrow.XmlArrow
32 import Text.XML.HXT.DOM.TypeDefs
35 type InterpTable = Map String Interpreter
38 formatEntirePage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
43 formatEntirePage sto sysConf interpTable
45 -> do SiteName siteName <- getSysConfA sysConf -< ()
46 BaseURI baseURI <- getSysConfA sysConf -< ()
47 StyleSheet cssName <- getSysConfA sysConf -< ()
49 Just pageTitle <- getPageA sto -< ("PageTitle" , Nothing)
50 Just leftSideBar <- getPageA sto -< ("SideBar/Left" , Nothing)
51 Just rightSideBar <- getPageA sto -< ("SideBar/Right", Nothing)
55 += sattr "site" siteName
56 += sattr "name" (pageName page)
57 += sattr "type" (show $ pageType page)
58 += ( case pageLanguage page of
59 Just x -> sattr "lang" x
62 += ( case pageFileName page of
63 Just x -> sattr "fileName" x
66 += ( case pageType page of
67 MIMEType "text" "css" _
68 -> sattr "isTheme" (yesOrNo $ pageIsTheme page)
71 += ( case pageType page of
72 MIMEType "text" "x-rakka" _
73 -> sattr "isFeed" (yesOrNo $ pageIsFeed page)
76 += sattr "isLocked" (yesOrNo $ pageIsLocked page)
77 += sattr "isBoring" (yesOrNo $ pageIsBoring page)
78 += sattr "isBinary" (yesOrNo $ pageIsBinary page)
79 += sattr "revision" (show $ pageRevision page)
80 += sattr "lastModified" (formatW3CDateTime $ pageLastMod page)
82 += ( eelem "styleSheets"
83 += ( eelem "styleSheet"
84 += sattr "src" (uriToString id (mkObjectURI baseURI cssName) "")
90 += sattr "src" (uriToString id (baseURI { uriPath = "/js" }) "")
94 += ( case pageSummary page of
96 Just s -> eelem "summary" += txt s
99 += ( if M.null (pageOtherLang page) then
106 | (lang, page) <- M.toList (pageOtherLang page) ]
108 += ( eelem "pageTitle"
109 += ( (constA (pageName page) &&& constA (Just page) &&& constA pageTitle)
111 formatSubPage sto sysConf interpTable
116 += ( (constA (pageName page) &&& constA (Just page) &&& constA leftSideBar)
118 formatSubPage sto sysConf interpTable
122 += ( (constA (pageName page) &&& constA (Just page) &&& constA rightSideBar)
124 formatSubPage sto sysConf interpTable
129 += (constA page >>> formatMainPage sto sysConf interpTable)
132 uniqueNamespacesFromDeclAndQNames
138 formatUnexistentPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
142 -> a PageName XmlTree
143 formatUnexistentPage sto sysConf interpTable
145 -> do SiteName siteName <- getSysConfA sysConf -< ()
146 BaseURI baseURI <- getSysConfA sysConf -< ()
147 StyleSheet cssName <- getSysConfA sysConf -< ()
149 Just pageTitle <- getPageA sto -< ("PageTitle" , Nothing)
150 Just leftSideBar <- getPageA sto -< ("SideBar/Left" , Nothing)
151 Just rightSideBar <- getPageA sto -< ("SideBar/Right", Nothing)
154 += ( eelem "pageNotFound"
155 += sattr "site" siteName
156 += sattr "styleSheet" (uriToString id (mkObjectURI baseURI cssName) "")
159 += ( eelem "pageTitle"
160 += ( (constA name &&& constA Nothing &&& constA pageTitle)
162 formatSubPage sto sysConf interpTable
167 += ( (constA name &&& constA Nothing &&& constA leftSideBar)
169 formatSubPage sto sysConf interpTable
173 += ( (constA name &&& constA Nothing &&& constA rightSideBar)
175 formatSubPage sto sysConf interpTable
180 uniqueNamespacesFromDeclAndQNames
186 formatMainPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
191 formatMainPage sto sysConf interpTable
193 -> do BaseURI baseURI <- getSysConfA sysConf -< ()
194 wiki <- arr2 wikifyPage -< (interpTable, page)
195 xs <- interpretCommandsA sto sysConf interpTable
196 -< (pageName page, Just (page, wiki), wiki)
197 formatWikiBlocks -< (baseURI, xs)
200 formatSubPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
204 -> a (PageName, (Maybe Page, Page)) XmlTree
205 formatSubPage sto sysConf interpTable
206 = proc (mainPageName, (mainPage, subPage))
207 -> do BaseURI baseURI <- getSysConfA sysConf -< ()
208 mainWiki <- case mainPage of
210 -> do wiki <- arr2 wikifyPage -< (interpTable, page)
211 returnA -< Just (page, wiki)
213 -> returnA -< Nothing
214 subWiki <- arr2 wikifyPage -< (interpTable, subPage)
215 xs <- interpretCommandsA sto sysConf interpTable
216 -< (mainPageName, mainWiki, subWiki)
217 formatWikiBlocks -< (baseURI, xs)
220 wikifyPage :: InterpTable -> Page -> WikiPage
221 wikifyPage interpTable page
222 = case pageType page of
223 MIMEType "text" "x-rakka" _
224 -> let source = decodeLazy UTF8 (pageContent page)
225 parser = wikiPage tableToFunc
227 case parse parser "" source of
228 Left err -> wikifyParseError err
232 -> [ Paragraph [ Image (pageName page) Nothing ] ]
234 _ -> if pageIsBinary page then
236 [ Paragraph [ ObjectLink (pageName page) (Just $ pageFileName' page) ] ]
239 let text = decodeLazy UTF8 (pageContent page)
241 [ Preformatted [ Text text ] ]
243 tableToFunc :: String -> Maybe CommandType
245 = fmap commandType (M.lookup name interpTable)
248 interpretCommandsA :: (ArrowIO a, ArrowApply a) =>
252 -> a (PageName, Maybe (Page, WikiPage), WikiPage) WikiPage
253 interpretCommandsA sto sysConf interpTable
254 = proc (name, mainPageAndTree, targetTree)
255 -> arrIO0 (interpretCommands sto sysConf interpTable name mainPageAndTree targetTree)
259 interpretCommands :: Storage
263 -> Maybe (Page, WikiPage)
266 interpretCommands sto sysConf interpTable name mainPageAndTree targetTree
267 = everywhereM' (mkM interpBlockCmd) targetTree
269 everywhereM' (mkM interpInlineCmd)
271 ctx :: InterpreterContext
272 ctx = InterpreterContext {
274 , ctxMainPage = fmap fst mainPageAndTree
275 , ctxMainTree = fmap snd mainPageAndTree
276 , ctxTargetTree = targetTree
278 , ctxSysConf = sysConf
281 interpBlockCmd :: BlockElement -> IO BlockElement
282 interpBlockCmd (BlockCmd cmd) = interpBlockCmd' cmd
283 interpBlockCmd others = return others
285 interpBlockCmd' :: BlockCommand -> IO BlockElement
287 = case M.lookup (bCmdName cmd) interpTable of
289 -> fail ("no such interpreter: " ++ bCmdName cmd)
292 -> bciInterpret interp ctx cmd
295 interpInlineCmd :: InlineElement -> IO InlineElement
296 interpInlineCmd (InlineCmd cmd) = interpInlineCmd' cmd
297 interpInlineCmd others = return others
299 interpInlineCmd' :: InlineCommand -> IO InlineElement
301 = case M.lookup (iCmdName cmd) interpTable of
303 -> fail ("no such interpreter: " ++ iCmdName cmd)
306 -> iciInterpret interp ctx cmd
309 makeDraft :: InterpTable -> Page -> IO Document
310 makeDraft interpTable page
311 = do doc <- newDocument
313 setURI doc $ Just $ mkRakkaURI $ pageName page
314 setAttribute doc "@title" $ Just $ pageName page
315 setAttribute doc "@lang" $ pageLanguage page
316 setAttribute doc "@type" $ Just $ show $ pageType page
317 setAttribute doc "@mdate" $ Just $ formatW3CDateTime $ pageLastMod page
318 setAttribute doc "rakka:fileName" $ pageFileName page
319 setAttribute doc "rakka:isLocked" $ Just $ yesOrNo $ pageIsLocked page
320 setAttribute doc "rakka:isBoring" $ Just $ yesOrNo $ pageIsBoring page
321 setAttribute doc "rakka:isBinary" $ Just $ yesOrNo $ pageIsBinary page
322 setAttribute doc "rakka:revision" $ Just $ show $ pageRevision page
323 setAttribute doc "rakka:summary" $ pageSummary page
325 addHiddenText doc (pageName page)
327 case pageType page of
328 MIMEType "text" "css" _
329 -> setAttribute doc "rakka:isTheme" $ Just $ yesOrNo $ pageIsTheme page
330 MIMEType "text" "x-rakka" _
331 -> setAttribute doc "rakka:isFeed" $ Just $ yesOrNo $ pageIsFeed page
334 case pageSummary page of
336 Just s -> addHiddenText doc s
338 -- otherLang はリンク先ページ名を hidden text で入れる。
339 sequence_ [ addHiddenText doc x
340 | (_, x) <- M.toList (pageOtherLang page) ]
342 -- wikify して興味のある部分を addText する。
343 let wikiPage = wikifyPage interpTable page
344 everywhereM' (mkM (addBlockText doc)) wikiPage
345 everywhereM' (mkM (addInlineText doc)) wikiPage
349 addBlockText :: Document -> BlockElement -> IO BlockElement
357 addInlineText :: Document -> InlineElement -> IO InlineElement
362 ObjectLink page Nothing
364 ObjectLink page (Just text)
365 -> do addHiddenText doc page
367 PageLink page fragment Nothing
368 -> addText doc (fromMaybe "" page ++
369 fromMaybe "" fragment)
370 PageLink page fragment (Just text)
371 -> do addHiddenText doc (fromMaybe "" page ++
372 fromMaybe "" fragment)
374 ExternalLink uri Nothing
375 -> addText doc (uriToString id uri "")
376 ExternalLink uri (Just text)
377 -> do addHiddenText doc (uriToString id uri "")
383 -- Perform monadic transformation in top-down order.
384 everywhereM' :: Monad m => GenericM m -> GenericM m
385 everywhereM' f x = f x >>= gmapM (everywhereM' f)
388 wikifyParseError :: ParseError -> WikiPage
390 = [Div [("class", "error")]
391 [ Block (Preformatted [Text (show err)]) ]]