module Rakka.Wiki.Engine
- ( formatPage
- , formatSubPage
+ ( InterpTable
+ , formatEntirePage
+ , formatUnexistentPage
+ , makeDraft
)
where
import Control.Arrow
import Control.Arrow.ArrowIO
+import Control.Arrow.ArrowList
import Data.Encoding
import Data.Encoding.UTF8
import Data.Generics
+import Data.Map (Map)
import qualified Data.Map as M
+import Data.Maybe
import Network.HTTP.Lucu
-import Rakka.Environment
+import Network.URI
import Rakka.Page
+import Rakka.Storage
import Rakka.SystemConfig
+import Rakka.Utils
import Rakka.Wiki
import Rakka.Wiki.Parser
import Rakka.Wiki.Formatter
import Rakka.Wiki.Interpreter
+import Text.HyperEstraier hiding (getText)
import Text.ParserCombinators.Parsec
+import Text.XML.HXT.Arrow.Namespace
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
+type InterpTable = Map String Interpreter
+
+
+formatEntirePage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
+ Storage
+ -> SystemConfig
+ -> InterpTable
+ -> a Page XmlTree
+formatEntirePage sto sysConf interpTable
+ = proc page
+ -> do SiteName siteName <- getSysConfA sysConf -< ()
+ BaseURI baseURI <- getSysConfA sysConf -< ()
+ StyleSheet cssName <- getSysConfA sysConf -< ()
+
+ Just pageTitle <- getPageA sto -< ("PageTitle" , Nothing)
+ Just leftSideBar <- getPageA sto -< ("SideBar/Left" , Nothing)
+ Just rightSideBar <- getPageA sto -< ("SideBar/Right", Nothing)
+
+ tree <- ( eelem "/"
+ += ( eelem "page"
+ += sattr "site" siteName
+ += sattr "name" (pageName page)
+ += sattr "type" (show $ pageType page)
+ += ( case pageLanguage page of
+ Just x -> sattr "lang" x
+ _ -> none
+ )
+ += ( case pageFileName page of
+ Just x -> sattr "fileName" x
+ _ -> none
+ )
+ += ( case pageType page of
+ MIMEType "text" "css" _
+ -> sattr "isTheme" (yesOrNo $ pageIsTheme page)
+ _ -> none
+ )
+ += ( case pageType page of
+ MIMEType "text" "x-rakka" _
+ -> sattr "isFeed" (yesOrNo $ pageIsFeed page)
+ _ -> none
+ )
+ += sattr "isLocked" (yesOrNo $ pageIsLocked page)
+ += sattr "isBoring" (yesOrNo $ pageIsBoring page)
+ += sattr "isBinary" (yesOrNo $ pageIsBinary page)
+ += sattr "revision" (show $ pageRevision page)
+ += sattr "lastModified" (formatW3CDateTime $ pageLastMod page)
+
+ += ( eelem "styleSheets"
+ += ( eelem "styleSheet"
+ += sattr "src" (uriToString id (mkObjectURI baseURI cssName) "")
+ )
+ )
+
+ += ( eelem "scripts"
+ += ( eelem "script"
+ += sattr "src" (uriToString id (baseURI { uriPath = "/js" }) "")
+ )
+ )
+
+ += ( case pageSummary page of
+ Nothing -> none
+ Just s -> eelem "summary" += txt s
+ )
+
+ += ( if M.null (pageOtherLang page) then
+ none
+ else
+ selem "otherLang"
+ [ eelem "link"
+ += sattr "lang" lang
+ += sattr "page" page
+ | (lang, page) <- M.toList (pageOtherLang page) ]
+ )
+ += ( eelem "pageTitle"
+ += ( (constA (pageName page) &&& constA (Just page) &&& constA pageTitle)
+ >>>
+ formatSubPage sto sysConf interpTable
+ )
+ )
+ += ( eelem "sideBar"
+ += ( eelem "left"
+ += ( (constA (pageName page) &&& constA (Just page) &&& constA leftSideBar)
+ >>>
+ formatSubPage sto sysConf interpTable
+ )
+ )
+ += ( eelem "right"
+ += ( (constA (pageName page) &&& constA (Just page) &&& constA rightSideBar)
+ >>>
+ formatSubPage sto sysConf interpTable
+ )
+ )
+ )
+ += ( eelem "body"
+ += (constA page >>> formatMainPage sto sysConf interpTable)
+ )
+ >>>
+ uniqueNamespacesFromDeclAndQNames
+ )
+ ) -<< ()
+ returnA -< tree
+
+
+formatUnexistentPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
+ Storage
+ -> SystemConfig
+ -> InterpTable
+ -> a PageName XmlTree
+formatUnexistentPage sto sysConf interpTable
+ = proc name
+ -> do SiteName siteName <- getSysConfA sysConf -< ()
+ BaseURI baseURI <- getSysConfA sysConf -< ()
+ StyleSheet cssName <- getSysConfA sysConf -< ()
+
+ Just pageTitle <- getPageA sto -< ("PageTitle" , Nothing)
+ Just leftSideBar <- getPageA sto -< ("SideBar/Left" , Nothing)
+ Just rightSideBar <- getPageA sto -< ("SideBar/Right", Nothing)
+
+ tree <- ( eelem "/"
+ += ( eelem "pageNotFound"
+ += sattr "site" siteName
+ += sattr "styleSheet" (uriToString id (mkObjectURI baseURI cssName) "")
+ += sattr "name" name
+
+ += ( eelem "pageTitle"
+ += ( (constA name &&& constA Nothing &&& constA pageTitle)
+ >>>
+ formatSubPage sto sysConf interpTable
+ )
+ )
+ += ( eelem "sideBar"
+ += ( eelem "left"
+ += ( (constA name &&& constA Nothing &&& constA leftSideBar)
+ >>>
+ formatSubPage sto sysConf interpTable
+ )
+ )
+ += ( eelem "right"
+ += ( (constA name &&& constA Nothing &&& constA rightSideBar)
+ >>>
+ formatSubPage sto sysConf interpTable
+ )
+ )
+ )
+ >>>
+ uniqueNamespacesFromDeclAndQNames
+ )
+ ) -<< ()
+ returnA -< tree
+
+
+formatMainPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
+ Storage
+ -> SystemConfig
+ -> InterpTable
+ -> a Page XmlTree
+formatMainPage sto sysConf interpTable
= proc page
- -> do BaseURI baseURI <- getSysConfA (envSysConf env) (BaseURI undefined) -< ()
- interpTable <- getInterpTableA env -< ()
- wiki <- wikifyPage env -< (interpTable, page)
- xs <- interpretCommandsA env -< (interpTable, (pageName page, (Just wiki, wiki)))
+ -> do BaseURI baseURI <- getSysConfA sysConf -< ()
+ wiki <- arr2 wikifyPage -< (interpTable, page)
+ xs <- interpretCommandsA sto sysConf interpTable
+ -< (pageName page, Just (page, wiki), wiki)
formatWikiBlocks -< (baseURI, xs)
formatSubPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
- Environment
+ Storage
+ -> SystemConfig
+ -> InterpTable
-> a (PageName, (Maybe Page, Page)) XmlTree
-formatSubPage env
+formatSubPage sto sysConf interpTable
= proc (mainPageName, (mainPage, subPage))
- -> do BaseURI baseURI <- getSysConfA (envSysConf env) (BaseURI undefined) -< ()
- interpTable <- getInterpTableA env -< ()
+ -> do BaseURI baseURI <- getSysConfA sysConf -< ()
mainWiki <- case mainPage of
Just page
- -> do wiki <- wikifyPage env -< (interpTable, page)
- returnA -< Just wiki
+ -> do wiki <- arr2 wikifyPage -< (interpTable, page)
+ returnA -< Just (page, wiki)
Nothing
-> returnA -< Nothing
- subWiki <- wikifyPage env -< (interpTable, subPage)
- xs <- interpretCommandsA env -< (interpTable, (mainPageName, (mainWiki, subWiki)))
+ subWiki <- arr2 wikifyPage -< (interpTable, subPage)
+ xs <- interpretCommandsA sto sysConf interpTable
+ -< (mainPageName, mainWiki, subWiki)
formatWikiBlocks -< (baseURI, xs)
-wikifyPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
- Environment
- -> a (InterpTable, Page) WikiPage
-wikifyPage env
- = proc (interpTable, page)
- -> case pageType page of
- MIMEType "text" "x-rakka" _
- -> do let source = decodeLazy UTF8 (pageContent page)
- parser = wikiPage (tableToFunc interpTable)
+wikifyPage :: InterpTable -> Page -> WikiPage
+wikifyPage interpTable page
+ = case pageType page of
+ MIMEType "text" "x-rakka" _
+ -> let source = decodeLazy UTF8 (pageContent page)
+ parser = wikiPage tableToFunc
+ in
+ case parse parser "" source of
+ Left err -> wikifyParseError err
+ Right xs -> xs
- case parse parser "" source of
- Left err
- -> wikifyParseError -< err
+ MIMEType "image" _ _
+ -> [ Paragraph [ Image (pageName page) Nothing ] ]
- Right xs
- -> returnA -< xs
+ _ -> if pageIsBinary page then
+ -- object へのリンクのみ
+ [ Paragraph [ ObjectLink (pageName page) (Just $ pageFileName' page) ] ]
+ else
+ -- pre
+ let text = decodeLazy UTF8 (pageContent page)
+ in
+ [ Preformatted [ Text text ] ]
where
- tableToFunc :: InterpTable -> String -> Maybe CommandType
- tableToFunc table name
- = fmap commandType (M.lookup name table)
+ tableToFunc :: String -> Maybe CommandType
+ tableToFunc name
+ = fmap commandType (M.lookup name interpTable)
-interpretCommandsA :: ArrowIO a =>
- Environment
- -> a (InterpTable, (PageName, (Maybe WikiPage, WikiPage))) WikiPage
-interpretCommandsA = arrIO4 . interpretCommands
+interpretCommandsA :: (ArrowIO a, ArrowApply a) =>
+ Storage
+ -> SystemConfig
+ -> InterpTable
+ -> a (PageName, Maybe (Page, WikiPage), WikiPage) WikiPage
+interpretCommandsA sto sysConf interpTable
+ = proc (name, mainPageAndTree, targetTree)
+ -> arrIO0 (interpretCommands sto sysConf interpTable name mainPageAndTree targetTree)
+ -<< ()
-interpretCommands :: Environment -> InterpTable -> PageName -> Maybe WikiPage -> WikiPage -> IO WikiPage
-interpretCommands _ _ _ _ [] = return []
-interpretCommands env table name mainTree targetTree
+interpretCommands :: Storage
+ -> SystemConfig
+ -> InterpTable
+ -> PageName
+ -> Maybe (Page, WikiPage)
+ -> WikiPage
+ -> IO WikiPage
+interpretCommands sto sysConf interpTable name mainPageAndTree targetTree
= everywhereM' (mkM interpBlockCmd) targetTree
>>=
everywhereM' (mkM interpInlineCmd)
ctx :: InterpreterContext
ctx = InterpreterContext {
ctxPageName = name
- , ctxMainTree = mainTree
+ , ctxMainPage = fmap fst mainPageAndTree
+ , ctxMainTree = fmap snd mainPageAndTree
, ctxTargetTree = targetTree
- , ctxStorage = envStorage env
- , ctxSysConf = envSysConf env
+ , ctxStorage = sto
+ , ctxSysConf = sysConf
}
interpBlockCmd :: BlockElement -> IO BlockElement
interpBlockCmd' :: BlockCommand -> IO BlockElement
interpBlockCmd' cmd
- = case M.lookup (bCmdName cmd) table of
+ = case M.lookup (bCmdName cmd) interpTable of
Nothing
-> fail ("no such interpreter: " ++ bCmdName cmd)
interpInlineCmd' :: InlineCommand -> IO InlineElement
interpInlineCmd' cmd
- = case M.lookup (iCmdName cmd) table of
+ = case M.lookup (iCmdName cmd) interpTable of
Nothing
-> fail ("no such interpreter: " ++ iCmdName cmd)
-> iciInterpret interp ctx cmd
+makeDraft :: InterpTable -> Page -> IO Document
+makeDraft interpTable page
+ = do doc <- newDocument
+
+ setURI doc $ Just $ mkRakkaURI $ pageName page
+ setAttribute doc "@title" $ Just $ pageName page
+ setAttribute doc "@lang" $ pageLanguage page
+ setAttribute doc "@type" $ Just $ show $ pageType page
+ setAttribute doc "@mdate" $ Just $ formatW3CDateTime $ pageLastMod page
+ setAttribute doc "rakka:fileName" $ pageFileName page
+ setAttribute doc "rakka:isLocked" $ Just $ yesOrNo $ pageIsLocked page
+ setAttribute doc "rakka:isBoring" $ Just $ yesOrNo $ pageIsBoring page
+ setAttribute doc "rakka:isBinary" $ Just $ yesOrNo $ pageIsBinary page
+ setAttribute doc "rakka:revision" $ Just $ show $ pageRevision page
+ setAttribute doc "rakka:summary" $ pageSummary page
+
+ addHiddenText doc (pageName page)
+
+ case pageType page of
+ MIMEType "text" "css" _
+ -> setAttribute doc "rakka:isTheme" $ Just $ yesOrNo $ pageIsTheme page
+ MIMEType "text" "x-rakka" _
+ -> setAttribute doc "rakka:isFeed" $ Just $ yesOrNo $ pageIsFeed page
+ _ -> return ()
+
+ case pageSummary page of
+ Nothing -> return ()
+ Just s -> addHiddenText doc s
+
+ -- otherLang はリンク先ページ名を hidden text で入れる。
+ sequence_ [ addHiddenText doc x
+ | (_, x) <- M.toList (pageOtherLang page) ]
+
+ -- wikify して興味のある部分を addText する。
+ let wikiPage = wikifyPage interpTable page
+ everywhereM' (mkM (addBlockText doc)) wikiPage
+ everywhereM' (mkM (addInlineText doc)) wikiPage
+
+ return doc
+ where
+ addBlockText :: Document -> BlockElement -> IO BlockElement
+ addBlockText doc b
+ = do case b of
+ Heading _ text
+ -> addText doc text
+ _ -> return ()
+ return b
+
+ addInlineText :: Document -> InlineElement -> IO InlineElement
+ addInlineText doc i
+ = do case i of
+ Text text
+ -> addText doc text
+ ObjectLink page Nothing
+ -> addText doc page
+ ObjectLink page (Just text)
+ -> do addHiddenText doc page
+ addText doc text
+ PageLink page fragment Nothing
+ -> addText doc (fromMaybe "" page ++
+ fromMaybe "" fragment)
+ PageLink page fragment (Just text)
+ -> do addHiddenText doc (fromMaybe "" page ++
+ fromMaybe "" fragment)
+ addText doc text
+ ExternalLink uri Nothing
+ -> addText doc (uriToString id uri "")
+ ExternalLink uri (Just text)
+ -> do addHiddenText doc (uriToString id uri "")
+ addText doc text
+ _ -> return ()
+ return i
+
+
-- 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)] ]]
+wikifyParseError :: ParseError -> WikiPage
+wikifyParseError err
+ = [Div [("class", "error")]
+ [ Block (Preformatted [Text (show err)]) ]]