X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=Rakka.git;a=blobdiff_plain;f=Rakka%2FWiki%2FEngine.hs;fp=Rakka%2FWiki%2FEngine.hs;h=02e987cd20f7ed92c6eb7521f3cd2d2e877c6f3f;hp=17c2933852ee5273485ac80fcbb570c36f6bd080;hb=42f51754dea02201aececaacbf194d714cd58aaf;hpb=98fd1cb53a837a9bda7145544c34872acb13a634 diff --git a/Rakka/Wiki/Engine.hs b/Rakka/Wiki/Engine.hs index 17c2933..02e987c 100644 --- a/Rakka/Wiki/Engine.hs +++ b/Rakka/Wiki/Engine.hs @@ -1,3 +1,10 @@ +{-# LANGUAGE + Arrows + , OverloadedStrings + , ScopedTypeVariables + , TypeOperators + , UnicodeSyntax + #-} module Rakka.Wiki.Engine ( InterpTable , makeMainXHTML @@ -7,16 +14,25 @@ module Rakka.Wiki.Engine , makeDraft ) where - +import Control.Applicative +import Control.Arrow +import Control.Arrow.ArrowIO +import Control.Arrow.ArrowList +import Control.Arrow.Unicode +import Control.Monad.Unicode import qualified Codec.Binary.UTF8.String as UTF8 import qualified Data.ByteString.Lazy as Lazy import qualified Data.ByteString.Lazy.Char8 as L8 hiding (ByteString) import Data.Map (Map) import qualified Data.Map as M import Data.Maybe +import Data.Monoid.Unicode +import Data.Text (Text) +import qualified Data.Text as T import Network.HTTP.Lucu import Network.URI import OpenSSL.EVP.Base64 +import Prelude.Unicode import Rakka.Page import Rakka.Storage import Rakka.SystemConfig @@ -27,44 +43,43 @@ import Rakka.Wiki.Formatter import Rakka.Wiki.Interpreter import Text.HyperEstraier hiding (getText) import Text.ParserCombinators.Parsec -import Text.XML.HXT.Arrow hiding (err) -import Text.XML.HXT.XPath - +import Text.XML.HXT.Arrow.XmlArrow hiding (err) +import Text.XML.HXT.DOM.TypeDefs +import Text.XML.HXT.XPath -type InterpTable = Map String Interpreter +type InterpTable = Map Text Interpreter - -wikifyPage :: (ArrowXml a, ArrowChoice a) => InterpTable -> a XmlTree WikiPage +wikifyPage ∷ (ArrowXml (⇝), ArrowChoice (⇝)) ⇒ InterpTable → XmlTree ⇝ WikiPage wikifyPage interpTable = proc tree - -> do pType <- getXPathTreesInDoc "/page/@type/text()" >>> getText >>> arr read -< tree - textData <- maybeA (getXPathTreesInDoc "/page/textData/text()" >>> getText) -< tree - base64Data <- maybeA (getXPathTreesInDoc "/page/binaryData/text()" >>> getText) -< tree - - let dataURI = fmap (binToURI pType) base64Data - - case pType of - MIMEType "text" "x-rakka" _ - -> case parse (wikiPage $ cmdTypeOf interpTable) "" (fromJust textData) of - Left err -> wikifyParseError -< err - Right xs -> returnA -< xs - - MIMEType "image" _ _ - -- - -> returnA -< [ Paragraph [Image (Left $ fromJust dataURI) Nothing] ] - - _ -> if isJust dataURI then - -- - -- application/zip - -- - returnA -< [ Paragraph [ Anchor - [("href", show dataURI)] - [Text (show pType)] - ] - ] - else - -- pre - returnA -< [ Preformatted [Text $ fromJust textData] ] + → do pType ← getXPathTreesInDoc "/page/@type/text()" ⋙ getText ⋙ arr read ⤙ tree + textData ← maybeA (getXPathTreesInDoc "/page/textData/text()" ⋙ getText) ⤙ tree + base64Data ← maybeA (getXPathTreesInDoc "/page/binaryData/text()" ⋙ getText) ⤙ tree + + let dataURI = binToURI pType <$> base64Data + + case pType of + MIMEType "text" "x-rakka" _ + → case parse (wikiPage $ cmdTypeOf interpTable) "" (fromJust textData) of + Left err → wikifyParseError ⤙ err + Right xs → returnA ⤙ xs + + MIMEType "image" _ _ + -- + → returnA ⤙ [ Paragraph [Image (Left $ fromJust dataURI) Nothing] ] + + _ → if isJust dataURI then + -- + -- application/zip + -- + returnA ⤙ [ Paragraph [ Anchor + [("href", T.pack $ show dataURI)] + [Text (T.pack $ show pType)] + ] + ] + else + -- pre + returnA ⤙ [ Preformatted [Text ∘ T.pack $ fromJust textData] ] where binToURI :: MIMEType -> String -> URI binToURI pType base64Data @@ -80,35 +95,34 @@ wikifyPage interpTable | otherwise = x : stripWhiteSpace xs -wikifyBin :: (ArrowXml a, ArrowChoice a) => InterpTable -> a (MIMEType, Lazy.ByteString) WikiPage +wikifyBin :: (ArrowXml (⇝), ArrowChoice (⇝)) ⇒ InterpTable → (MIMEType, Lazy.ByteString) ⇝ WikiPage wikifyBin interpTable = proc (pType, pBin) - -> do let text = UTF8.decode $ Lazy.unpack pBin - dataURI = binToURI pType pBin - - case pType of - MIMEType "text" "x-rakka" _ - -> case parse (wikiPage $ cmdTypeOf interpTable) "" text of - Left err -> wikifyParseError -< err - Right xs -> returnA -< xs - - MIMEType "image" _ _ - -- - -> returnA -< [ Paragraph [Image (Left dataURI) Nothing] ] - - - _ - -- - -- application/zip (19372 bytes) - -- - -> returnA -< [ Paragraph [ Anchor - [("href", show dataURI)] - [Text (show pType ++ - " (" ++ - show (Lazy.length pBin) ++ - " bytes)")] - ] - ] + → do let text = UTF8.decode $ Lazy.unpack pBin + dataURI = binToURI pType pBin + + case pType of + MIMEType "text" "x-rakka" _ + -> case parse (wikiPage $ cmdTypeOf interpTable) "" text of + Left err -> wikifyParseError -< err + Right xs -> returnA -< xs + + MIMEType "image" _ _ + -- + -> returnA -< [ Paragraph [Image (Left dataURI) Nothing] ] + + _ -- + -- application/zip (19372 bytes) + -- + -> returnA -< [ Paragraph [ Anchor + [("href", T.pack $ show dataURI)] + [Text (T.concat [ T.pack $ show pType + , "(" + , T.pack ∘ show $ Lazy.length pBin + , " bytes)" + ])] + ] + ] where binToURI :: MIMEType -> Lazy.ByteString -> URI binToURI m b @@ -117,25 +131,25 @@ wikifyBin interpTable , uriPath = show m ++ ";base64," ++ (L8.unpack $ encodeBase64LBS b) } - -cmdTypeOf :: InterpTable -> String -> Maybe CommandType +cmdTypeOf ∷ Alternative f ⇒ InterpTable → Text → f CommandType cmdTypeOf interpTable name - = fmap commandType (M.lookup name interpTable) - - -makeMainXHTML :: (ArrowXml a, ArrowChoice a, ArrowIO a) => - Storage - -> SystemConfig - -> InterpTable - -> a XmlTree XmlTree + = case M.lookup name interpTable of + Just t → pure $ commandType t + Nothing → empty + +makeMainXHTML ∷ (ArrowXml (⇝), ArrowChoice (⇝), ArrowIO (⇝)) + ⇒ Storage + → SystemConfig + → InterpTable + → XmlTree ⇝ XmlTree makeMainXHTML sto sysConf interpTable = proc tree - -> do BaseURI baseURI <- getSysConfA sysConf -< () - wiki <- wikifyPage interpTable -< tree - pName <- getXPathTreesInDoc "/page/@name/text()" >>> getText -< tree - interpreted <- interpretCommands sto sysConf interpTable - -< (Just pName, Just tree, Just wiki, wiki) - formatWikiBlocks -< (baseURI, interpreted) + → do BaseURI baseURI ← getSysConfA sysConf ⤙ () + wiki ← wikifyPage interpTable ⤙ tree + pName ← getXPathTreesInDoc "/page/@name/text()" ⋙ getText ⤙ tree + interpreted ← interpretCommands sto sysConf interpTable + ⤙ (Just (T.pack pName), Just tree, Just wiki, wiki) + formatWikiBlocks ⤙ (baseURI, interpreted) makeSubXHTML :: (ArrowXml a, ArrowChoice a, ArrowIO a) => @@ -220,115 +234,112 @@ interpretCommands sto sysConf interpTable desc' <- mapM (interpInline ctx) desc return (Definition term' desc') - interpBlockCommand :: InterpreterContext -> BlockCommand -> IO BlockElement + interpBlockCommand ∷ InterpreterContext → BlockCommand → IO BlockElement interpBlockCommand ctx cmd = case M.lookup (bCmdName cmd) interpTable of Nothing - -> fail ("no such interpreter: " ++ bCmdName cmd) + → fail ("no such interpreter: " ⊕ T.unpack (bCmdName cmd)) Just interp - -> bciInterpret interp ctx cmd - >>= - interpBlock ctx + → bciInterpret interp ctx cmd + ≫= + interpBlock ctx - interpInlineCommand :: InterpreterContext -> InlineCommand -> IO InlineElement + interpInlineCommand ∷ InterpreterContext → InlineCommand → IO InlineElement interpInlineCommand ctx cmd = case M.lookup (iCmdName cmd) interpTable of Nothing - -> fail ("no such interpreter: " ++ iCmdName cmd) + → fail ("no such interpreter: " ⊕ T.unpack (iCmdName cmd)) Just interp - -> iciInterpret interp ctx cmd - >>= - interpInline ctx - + → iciInterpret interp ctx cmd ≫= interpInline ctx -makeDraft :: (ArrowXml a, ArrowChoice a, ArrowIO a) => InterpTable -> a XmlTree Document +makeDraft ∷ ∀(⇝). (ArrowXml (⇝), ArrowChoice (⇝), ArrowIO (⇝)) ⇒ InterpTable → XmlTree ⇝ Document makeDraft interpTable - = proc tree -> - do redir <- maybeA (getXPathTreesInDoc "/page/@redirect") -< tree + = proc tree → + do redir ← maybeA (getXPathTreesInDoc "/page/@redirect") ⤙ tree case redir of - Nothing -> makeEntityDraft -< tree - Just _ -> makeRedirectDraft -< tree + Nothing → makeEntityDraft ⤙ tree + Just _ → makeRedirectDraft ⤙ tree where - makeEntityDraft :: (ArrowXml a, ArrowChoice a, ArrowIO a) => a XmlTree Document + makeEntityDraft ∷ XmlTree ⇝ Document makeEntityDraft - = proc tree -> - do doc <- arrIO0 newDocument -< () + = proc tree → + do doc ← arrIO0 newDocument ⤙ () - pName <- getXPathTreesInDoc "/page/@name/text()" >>> getText -< tree - pType <- getXPathTreesInDoc "/page/@type/text()" >>> getText -< tree - pLastMod <- getXPathTreesInDoc "/page/@lastModified/text()" >>> getText -< tree - pIsLocked <- getXPathTreesInDoc "/page/@isLocked/text()" >>> getText -< tree - pIsBinary <- getXPathTreesInDoc "/page/@isBinary/text()" >>> getText -< tree - pRevision <- getXPathTreesInDoc "/page/@revision/text()" >>> getText -< tree - pLang <- maybeA (getXPathTreesInDoc "/page/@lang/text()" >>> getText) -< tree - pIsTheme <- maybeA (getXPathTreesInDoc "/page/@isTheme/text()" >>> getText) -< tree - pIsFeed <- maybeA (getXPathTreesInDoc "/page/@isFeed/text()" >>> getText) -< tree - pSummary <- maybeA (getXPathTreesInDoc "/page/summary/text()" >>> getText) -< tree - - arrIO2 setURI -< (doc, Just $ mkRakkaURI pName) - arrIO2 (flip setAttribute "@title" ) -< (doc, Just pName) - arrIO2 (flip setAttribute "@type" ) -< (doc, Just pType) - arrIO2 (flip setAttribute "@mdate" ) -< (doc, Just pLastMod) - arrIO2 (flip setAttribute "@lang" ) -< (doc, pLang) - arrIO2 (flip setAttribute "rakka:isLocked") -< (doc, Just pIsLocked) - arrIO2 (flip setAttribute "rakka:isBinary") -< (doc, Just pIsBinary) - arrIO2 (flip setAttribute "rakka:revision") -< (doc, Just pRevision) - arrIO2 (flip setAttribute "rakka:summary" ) -< (doc, pSummary) - - arrIO2 addHiddenText -< (doc, pName) + pName ← getXPathTreesInDoc "/page/@name/text()" ⋙ getText ⤙ tree + pType ← getXPathTreesInDoc "/page/@type/text()" ⋙ getText ⤙ tree + pLastMod ← getXPathTreesInDoc "/page/@lastModified/text()" ⋙ getText ⤙ tree + pIsLocked ← getXPathTreesInDoc "/page/@isLocked/text()" ⋙ getText ⤙ tree + pIsBinary ← getXPathTreesInDoc "/page/@isBinary/text()" ⋙ getText ⤙ tree + pRevision ← getXPathTreesInDoc "/page/@revision/text()" ⋙ getText ⤙ tree + pLang ← maybeA (getXPathTreesInDoc "/page/@lang/text()" ⋙ getText) ⤙ tree + pIsTheme ← maybeA (getXPathTreesInDoc "/page/@isTheme/text()" ⋙ getText) ⤙ tree + pIsFeed ← maybeA (getXPathTreesInDoc "/page/@isFeed/text()" ⋙ getText) ⤙ tree + pSummary ← maybeA (getXPathTreesInDoc "/page/summary/text()" ⋙ getText) ⤙ tree + + arrIO2 setURI ⤙ (doc, Just ∘ mkRakkaURI $ T.pack pName ) + arrIO2 (flip setAttribute "@title" ) ⤙ (doc, Just $ T.pack pName ) + arrIO2 (flip setAttribute "@type" ) ⤙ (doc, Just $ T.pack pType ) + arrIO2 (flip setAttribute "@mdate" ) ⤙ (doc, Just $ T.pack pLastMod ) + arrIO2 (flip setAttribute "@lang" ) ⤙ (doc, T.pack <$> pLang) + arrIO2 (flip setAttribute "rakka:isLocked") ⤙ (doc, Just $ T.pack pIsLocked) + arrIO2 (flip setAttribute "rakka:isBinary") ⤙ (doc, Just $ T.pack pIsBinary) + arrIO2 (flip setAttribute "rakka:revision") ⤙ (doc, Just $ T.pack pRevision) + arrIO2 (flip setAttribute "rakka:summary" ) ⤙ (doc, T.pack <$> pSummary) + + arrIO2 addHiddenText ⤙ (doc, T.pack pName) case pSummary of - Just s -> arrIO2 addHiddenText -< (doc, s) - Nothing -> returnA -< () + Just s → arrIO2 addHiddenText ⤙ (doc, T.pack s) + Nothing → returnA ⤙ () -- otherLang はリンク先ページ名を hidden text で入れる。 - otherLangs <- listA (getXPathTreesInDoc "/page/otherLang/link/@page/text()" >>> getText) -< tree + otherLangs ← listA (getXPathTreesInDoc "/page/otherLang/link/@page/text()" ⋙ getText) ⤙ tree listA ( (arr fst &&& arrL snd) - >>> + ⋙ arrIO2 addHiddenText - >>> + ⋙ none - ) -< (doc, otherLangs) + ) ⤙ (doc, T.pack <$> otherLangs) case read pType of MIMEType "text" "css" _ - -> arrIO2 (flip setAttribute "rakka:isTheme") -< (doc, pIsTheme) + → arrIO2 (flip setAttribute "rakka:isTheme") ⤙ (doc, T.pack <$> pIsTheme) MIMEType "text" "x-rakka" _ - -- wikify して興味のある部分を addText する。 - -> do arrIO2 (flip setAttribute "rakka:isFeed") -< (doc, pIsFeed) - wiki <- wikifyPage interpTable -< tree - arrIO2 (mapM_ . addBlockText) -< (doc, wiki) + -- wikify して興味のある部分を addText する。 + → do arrIO2 (flip setAttribute "rakka:isFeed") ⤙ (doc, T.pack <$> pIsFeed) + wiki ← wikifyPage interpTable ⤙ tree + arrIO2 (mapM_ ∘ addBlockText) ⤙ (doc, wiki) MIMEType _ _ _ - -> returnA -< () + → returnA ⤙ () - returnA -< doc + returnA ⤙ doc - makeRedirectDraft :: (ArrowXml a, ArrowChoice a, ArrowIO a) => a XmlTree Document + makeRedirectDraft ∷ XmlTree ⇝ Document makeRedirectDraft - = proc tree -> - do doc <- arrIO0 newDocument -< () + = proc tree → + do doc ← arrIO0 newDocument ⤙ () - pName <- getXPathTreesInDoc "/page/@name/text()" >>> getText -< tree - pRedir <- getXPathTreesInDoc "/page/@redirect/text()" >>> getText -< tree - pIsLocked <- getXPathTreesInDoc "/page/@isLocked/text()" >>> getText -< tree - pRevision <- getXPathTreesInDoc "/page/@revision/text()" >>> getText -< tree - pLastMod <- getXPathTreesInDoc "/page/@lastModified/text()" >>> getText -< tree + pName ← getXPathTreesInDoc "/page/@name/text()" ⋙ getText ⤙ tree + pRedir ← getXPathTreesInDoc "/page/@redirect/text()" ⋙ getText ⤙ tree + pIsLocked ← getXPathTreesInDoc "/page/@isLocked/text()" ⋙ getText ⤙ tree + pRevision ← getXPathTreesInDoc "/page/@revision/text()" ⋙ getText ⤙ tree + pLastMod ← getXPathTreesInDoc "/page/@lastModified/text()" ⋙ getText ⤙ tree - arrIO2 setURI -< (doc, Just $ mkRakkaURI pName) - arrIO2 (flip setAttribute "@title" ) -< (doc, Just pName) + arrIO2 setURI -< (doc, Just ∘ mkRakkaURI $ T.pack pName ) + arrIO2 (flip setAttribute "@title" ) -< (doc, Just $ T.pack pName ) arrIO2 (flip setAttribute "@type" ) -< (doc, Just "application/x-rakka-redirection") - arrIO2 (flip setAttribute "@mdate" ) -< (doc, Just pLastMod) - arrIO2 (flip setAttribute "rakka:isLocked") -< (doc, Just pIsLocked) - arrIO2 (flip setAttribute "rakka:revision") -< (doc, Just pRevision) + arrIO2 (flip setAttribute "@mdate" ) -< (doc, Just $ T.pack pLastMod ) + arrIO2 (flip setAttribute "rakka:isLocked") -< (doc, Just $ T.pack pIsLocked ) + arrIO2 (flip setAttribute "rakka:revision") -< (doc, Just $ T.pack pRevision ) -- リダイレクト先ページ名はテキストとして入れる - arrIO2 addText -< (doc, pRedir) + arrIO2 addText ⤙ (doc, T.pack pRedir) - returnA -< doc + returnA ⤙ doc addElemText :: Document -> Element -> IO () addElemText doc (Block b) = addBlockText doc b @@ -345,23 +356,23 @@ makeDraft interpTable addBlockText _ EmptyBlock = return () addBlockText doc (BlockCmd bcmd) = addBlockCmdText doc bcmd - addInlineText :: Document -> InlineElement -> IO () + addInlineText ∷ Document → InlineElement → IO () addInlineText doc (Text text) = addText doc text addInlineText doc (Italic inlines) = mapM_ (addInlineText doc) inlines addInlineText doc (Bold inlines) = mapM_ (addInlineText doc) inlines addInlineText doc (ObjectLink page Nothing) = addText doc page addInlineText doc (ObjectLink page (Just text)) = addHiddenText doc page - >> addText doc text - addInlineText doc (PageLink page fragm Nothing) = addText doc (fromMaybe "" page ++ fromMaybe "" fragm) - addInlineText doc (PageLink page fragm (Just text)) = addHiddenText doc (fromMaybe "" page ++ fromMaybe "" fragm) - >> addText doc text - addInlineText doc (ExternalLink uri Nothing) = addText doc (uriToString id uri "") - addInlineText doc (ExternalLink uri (Just text)) = addHiddenText doc (uriToString id uri "") - >> addText doc text + *> addText doc text + addInlineText doc (PageLink page fragm Nothing) = addText doc (fromMaybe (∅) page ⊕ maybe (∅) (T.cons '#') fragm) + addInlineText doc (PageLink page fragm (Just text)) = addHiddenText doc (fromMaybe (∅) page ⊕ maybe (∅) (T.cons '#') fragm) + *> addText doc text + addInlineText doc (ExternalLink uri Nothing) = addText doc (T.pack $ uriToString id uri "") + addInlineText doc (ExternalLink uri (Just text)) = addHiddenText doc (T.pack $ uriToString id uri "") + *> addText doc text addInlineText _ (LineBreak _) = return () addInlineText doc (Span _ inlines) = mapM_ (addInlineText doc) inlines addInlineText doc (Image src alt) = do case src of - Left uri -> addHiddenText doc (uriToString id uri "") + Left uri -> addHiddenText doc (T.pack $ uriToString id uri "") Right page -> addHiddenText doc page case alt of Just text -> addHiddenText doc text @@ -386,18 +397,18 @@ makeDraft interpTable addInlineCmdText doc (InlineCommand _ _ inlines) = mapM_ (addInlineText doc) inlines -makePageLinkList :: (ArrowXml a, ArrowChoice a, ArrowIO a) => - Storage - -> SystemConfig - -> InterpTable - -> a XmlTree [PageName] +makePageLinkList ∷ (ArrowXml (⇝), ArrowChoice (⇝), ArrowIO (⇝)) + ⇒ Storage + → SystemConfig + → InterpTable + → XmlTree ⇝ [PageName] makePageLinkList sto sysConf interpTable = proc tree - -> do wiki <- wikifyPage interpTable -< tree - pName <- getXPathTreesInDoc "/page/@name/text()" >>> getText -< tree - interpreted <- interpretCommands sto sysConf interpTable - -< (Just pName, Just tree, Just wiki, wiki) - returnA -< concatMap extractFromBlock interpreted + → do wiki ← wikifyPage interpTable ⤙ tree + pName ← getXPathTreesInDoc "/page/@name/text()" ⋙ getText ⤙ tree + interpreted ← interpretCommands sto sysConf interpTable + ⤙ (Just (T.pack pName), Just tree, Just wiki, wiki) + returnA ⤙ concatMap extractFromBlock interpreted where extractFromElem :: Element -> [PageName] extractFromElem (Block b) = extractFromBlock b @@ -427,8 +438,7 @@ makePageLinkList sto sysConf interpTable ++ concatMap extractFromInline desc - -wikifyParseError :: Arrow a => a ParseError WikiPage +wikifyParseError ∷ Arrow (⇝) ⇒ ParseError ⇝ WikiPage wikifyParseError = proc err - -> returnA -< [Div [("class", "error")] - [ Block (Preformatted [Text (show err)]) ]] + → returnA -< [Div [("class", "error")] + [ Block (Preformatted [Text (T.pack $ show err)]) ]]