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"
50 Just leftSideBar <- getPageA sto -< "SideBar/Left"
51 Just rightSideBar <- getPageA sto -< "SideBar/Right"
55 += sattr "site" siteName
56 += sattr "styleSheet" (uriToString id (mkObjectURI baseURI cssName) "")
57 += sattr "name" (pageName page)
58 += sattr "type" (show $ pageType page)
59 += ( case pageLanguage page of
60 Just x -> sattr "lang" x
63 += ( case pageType page of
64 MIMEType "text" "css" _
65 -> sattr "isTheme" (yesOrNo $ pageIsTheme page)
68 += ( case pageType page of
69 MIMEType "text" "x-rakka" _
70 -> sattr "isFeed" (yesOrNo $ pageIsFeed page)
73 += sattr "isLocked" (yesOrNo $ pageIsLocked page)
74 += sattr "isBoring" (yesOrNo $ pageIsBoring page)
75 += sattr "isBinary" (yesOrNo $ pageIsBinary page)
76 += sattr "revision" (show $ pageRevision page)
77 += sattr "lastModified" (formatW3CDateTime $ pageLastMod page)
79 += ( case pageSummary page of
81 Just s -> eelem "summary" += txt s
84 += ( if M.null (pageOtherLang page) then
91 | (lang, page) <- M.toList (pageOtherLang page) ]
93 += ( eelem "pageTitle"
94 += ( (constA (pageName page) &&& constA (Just page) &&& constA pageTitle)
96 formatSubPage sto sysConf interpTable
101 += ( (constA (pageName page) &&& constA (Just page) &&& constA leftSideBar)
103 formatSubPage sto sysConf interpTable
107 += ( (constA (pageName page) &&& constA (Just page) &&& constA rightSideBar)
109 formatSubPage sto sysConf interpTable
114 += (constA page >>> formatMainPage sto sysConf interpTable)
117 uniqueNamespacesFromDeclAndQNames
123 formatUnexistentPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
127 -> a PageName XmlTree
128 formatUnexistentPage sto sysConf interpTable
130 -> do SiteName siteName <- getSysConfA sysConf -< ()
131 BaseURI baseURI <- getSysConfA sysConf -< ()
132 StyleSheet cssName <- getSysConfA sysConf -< ()
134 Just pageTitle <- getPageA sto -< "PageTitle"
135 Just leftSideBar <- getPageA sto -< "SideBar/Left"
136 Just rightSideBar <- getPageA sto -< "SideBar/Right"
139 += ( eelem "pageNotFound"
140 += sattr "site" siteName
141 += sattr "styleSheet" (uriToString id (mkObjectURI baseURI cssName) "")
144 += ( eelem "pageTitle"
145 += ( (constA name &&& constA Nothing &&& constA pageTitle)
147 formatSubPage sto sysConf interpTable
152 += ( (constA name &&& constA Nothing &&& constA leftSideBar)
154 formatSubPage sto sysConf interpTable
158 += ( (constA name &&& constA Nothing &&& constA rightSideBar)
160 formatSubPage sto sysConf interpTable
165 uniqueNamespacesFromDeclAndQNames
171 formatMainPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
176 formatMainPage sto sysConf interpTable
178 -> do BaseURI baseURI <- getSysConfA sysConf -< ()
179 wiki <- arr2 wikifyPage -< (interpTable, page)
180 xs <- interpretCommandsA sto sysConf interpTable
181 -< (pageName page, Just (page, wiki), wiki)
182 formatWikiBlocks -< (baseURI, xs)
185 formatSubPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
189 -> a (PageName, (Maybe Page, Page)) XmlTree
190 formatSubPage sto sysConf interpTable
191 = proc (mainPageName, (mainPage, subPage))
192 -> do BaseURI baseURI <- getSysConfA sysConf -< ()
193 mainWiki <- case mainPage of
195 -> do wiki <- arr2 wikifyPage -< (interpTable, page)
196 returnA -< Just (page, wiki)
198 -> returnA -< Nothing
199 subWiki <- arr2 wikifyPage -< (interpTable, subPage)
200 xs <- interpretCommandsA sto sysConf interpTable
201 -< (mainPageName, mainWiki, subWiki)
202 formatWikiBlocks -< (baseURI, xs)
205 wikifyPage :: InterpTable -> Page -> WikiPage
206 wikifyPage interpTable page
207 = case pageType page of
208 MIMEType "text" "x-rakka" _
209 -> let source = decodeLazy UTF8 (pageContent page)
210 parser = wikiPage tableToFunc
212 case parse parser "" source of
213 Left err -> wikifyParseError err
216 tableToFunc :: String -> Maybe CommandType
218 = fmap commandType (M.lookup name interpTable)
221 interpretCommandsA :: (ArrowIO a, ArrowApply a) =>
225 -> a (PageName, Maybe (Page, WikiPage), WikiPage) WikiPage
226 interpretCommandsA sto sysConf interpTable
227 = proc (name, mainPageAndTree, targetTree)
228 -> arrIO0 (interpretCommands sto sysConf interpTable name mainPageAndTree targetTree)
232 interpretCommands :: Storage
236 -> Maybe (Page, WikiPage)
239 interpretCommands sto sysConf interpTable name mainPageAndTree targetTree
240 = everywhereM' (mkM interpBlockCmd) targetTree
242 everywhereM' (mkM interpInlineCmd)
244 ctx :: InterpreterContext
245 ctx = InterpreterContext {
247 , ctxMainPage = fmap fst mainPageAndTree
248 , ctxMainTree = fmap snd mainPageAndTree
249 , ctxTargetTree = targetTree
251 , ctxSysConf = sysConf
254 interpBlockCmd :: BlockElement -> IO BlockElement
255 interpBlockCmd (BlockCmd cmd) = interpBlockCmd' cmd
256 interpBlockCmd others = return others
258 interpBlockCmd' :: BlockCommand -> IO BlockElement
260 = case M.lookup (bCmdName cmd) interpTable of
262 -> fail ("no such interpreter: " ++ bCmdName cmd)
265 -> bciInterpret interp ctx cmd
268 interpInlineCmd :: InlineElement -> IO InlineElement
269 interpInlineCmd (InlineCmd cmd) = interpInlineCmd' cmd
270 interpInlineCmd others = return others
272 interpInlineCmd' :: InlineCommand -> IO InlineElement
274 = case M.lookup (iCmdName cmd) interpTable of
276 -> fail ("no such interpreter: " ++ iCmdName cmd)
279 -> iciInterpret interp ctx cmd
282 makeDraft :: InterpTable -> Page -> IO Document
283 makeDraft interpTable page
284 = do doc <- newDocument
286 setURI doc $ Just $ mkRakkaURI $ pageName page
287 setAttribute doc "@title" $ Just $ pageName page
288 setAttribute doc "@lang" $ pageLanguage page
289 setAttribute doc "@type" $ Just $ show $ pageType page
290 setAttribute doc "@mdate" $ Just $ formatW3CDateTime $ pageLastMod page
291 setAttribute doc "rakka:isLocked" $ Just $ yesOrNo $ pageIsLocked page
292 setAttribute doc "rakka:isBoring" $ Just $ yesOrNo $ pageIsBoring page
293 setAttribute doc "rakka:isBinary" $ Just $ yesOrNo $ pageIsBinary page
294 setAttribute doc "rakka:revision" $ Just $ show $ pageRevision page
296 case pageType page of
297 MIMEType "text" "css" _
298 -> setAttribute doc "rakka:isTheme" $ Just $ yesOrNo $ pageIsTheme page
299 MIMEType "text" "x-rakka" _
300 -> setAttribute doc "rakka:isFeed" $ Just $ yesOrNo $ pageIsFeed page
303 case pageSummary page of
305 Just s -> addHiddenText doc s
307 -- otherLang はリンク先ページ名を hidden text で入れる。
308 sequence_ [ addHiddenText doc x
309 | (_, x) <- M.toList (pageOtherLang page) ]
311 -- wikify して興味のある部分を addText する。
312 let wikiPage = wikifyPage interpTable page
313 everywhereM' (mkM (addBlockText doc)) wikiPage
314 everywhereM' (mkM (addInlineText doc)) wikiPage
318 addBlockText :: Document -> BlockElement -> IO BlockElement
326 addInlineText :: Document -> InlineElement -> IO InlineElement
331 PageLink page fragment Nothing
332 -> addText doc (fromMaybe "" page ++
333 fromMaybe "" fragment)
334 PageLink page fragment (Just text)
335 -> do addHiddenText doc (fromMaybe "" page ++
336 fromMaybe "" fragment)
338 ExternalLink uri Nothing
339 -> addText doc (uriToString id uri "")
340 ExternalLink uri (Just text)
341 -> do addHiddenText doc (uriToString id uri "")
347 -- Perform monadic transformation in top-down order.
348 everywhereM' :: Monad m => GenericM m -> GenericM m
349 everywhereM' f x = f x >>= gmapM (everywhereM' f)
352 wikifyParseError :: ParseError -> WikiPage
354 = [Div [("class", "error")]
355 [ Preformatted [Text (show err)] ]]