module Rakka.Wiki.Engine ( formatPage , formatSubPage ) where import Control.Arrow import Control.Arrow.ArrowIO import Data.Encoding import Data.Encoding.UTF8 import Data.Generics import qualified Data.Map as M import Network.HTTP.Lucu import Rakka.Environment import Rakka.Page import Rakka.SystemConfig import Rakka.Wiki import Rakka.Wiki.Parser import Rakka.Wiki.Formatter import Rakka.Wiki.Interpreter import Text.ParserCombinators.Parsec import Text.XML.HXT.Arrow.XmlArrow import Text.XML.HXT.DOM.TypeDefs formatPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) => Environment -> a Page XmlTree formatPage env = proc page -> do BaseURI baseURI <- getSysConfA (envSysConf env) (BaseURI undefined) -< () wiki <- wikifyPage env -< page xs <- interpretCommandsA env -< (pageName page, (Just (page, wiki), wiki)) formatWikiBlocks -< (baseURI, xs) formatSubPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) => Environment -> a (PageName, (Maybe Page, Page)) XmlTree formatSubPage env = proc (mainPageName, (mainPage, subPage)) -> do BaseURI baseURI <- getSysConfA (envSysConf env) (BaseURI undefined) -< () mainWiki <- case mainPage of Just page -> do wiki <- wikifyPage env -< page returnA -< Just (page, wiki) Nothing -> returnA -< Nothing subWiki <- wikifyPage env -< subPage xs <- interpretCommandsA env -< (mainPageName, (mainWiki, subWiki)) formatWikiBlocks -< (baseURI, xs) wikifyPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) => Environment -> a Page WikiPage wikifyPage env = proc page -> case pageType page of MIMEType "text" "x-rakka" _ -> do let source = decodeLazy UTF8 (pageContent page) parser = wikiPage tableToFunc case parse parser "" source of Left err -> wikifyParseError -< err Right xs -> returnA -< xs where tableToFunc :: String -> Maybe CommandType tableToFunc name = fmap commandType (M.lookup name (envInterpTable env)) interpretCommandsA :: ArrowIO a => Environment -> a (PageName, (Maybe (Page, WikiPage), WikiPage)) WikiPage interpretCommandsA = arrIO3 . interpretCommands interpretCommands :: Environment -> PageName -> Maybe (Page, WikiPage) -> WikiPage -> IO WikiPage interpretCommands _ _ _ [] = return [] interpretCommands env name mainPageAndTree targetTree = everywhereM' (mkM interpBlockCmd) targetTree >>= everywhereM' (mkM interpInlineCmd) where ctx :: InterpreterContext ctx = InterpreterContext { ctxPageName = name , ctxMainPage = fmap fst mainPageAndTree , ctxMainTree = fmap snd mainPageAndTree , ctxTargetTree = targetTree , ctxStorage = envStorage env , ctxSysConf = envSysConf env } interpBlockCmd :: BlockElement -> IO BlockElement interpBlockCmd (BlockCmd cmd) = interpBlockCmd' cmd interpBlockCmd others = return others interpBlockCmd' :: BlockCommand -> IO BlockElement interpBlockCmd' cmd = case M.lookup (bCmdName cmd) (envInterpTable env) of Nothing -> fail ("no such interpreter: " ++ bCmdName cmd) Just interp -> bciInterpret interp ctx cmd interpInlineCmd :: InlineElement -> IO InlineElement interpInlineCmd (InlineCmd cmd) = interpInlineCmd' cmd interpInlineCmd others = return others interpInlineCmd' :: InlineCommand -> IO InlineElement interpInlineCmd' cmd = case M.lookup (iCmdName cmd) (envInterpTable env) of Nothing -> fail ("no such interpreter: " ++ iCmdName cmd) Just interp -> iciInterpret interp ctx cmd -- Perform monadic transformation in top-down order. everywhereM' :: Monad m => GenericM m -> GenericM m everywhereM' f x = f x >>= gmapM (everywhereM' f) wikifyParseError :: ArrowXml a => a ParseError WikiPage wikifyParseError = proc err -> returnA -< [Div [("class", "error")] [ Preformatted [Text (show err)] ]]