module Rakka.Wiki
( WikiPage
- , WikiElement(..)
, BlockElement(..)
, InlineElement(..)
)
import Rakka.Page
-type WikiPage = [WikiElement]
-
-
-data WikiElement
- = Block !BlockElement
- | Inline !InlineElement
- deriving (Eq, Show)
+type WikiPage = [BlockElement]
data BlockElement
headingLevel :: !Int
, headingText :: !String
}
- | EmptyLine
+ | Paragraph ![InlineElement]
deriving (Eq, Show)
Left err
-> formatParseError -< err
- Right elems
+ Right blocks
-> do BaseURI baseURI <- getSysConfA (envSysConf env) (BaseURI undefined) -< ()
- formatWikiElements -< (baseURI, elems)
+ formatWikiBlocks -< (baseURI, blocks)
formatParseError :: ArrowXml a => a ParseError XmlTree
module Rakka.Wiki.Formatter
- ( formatWikiElements
+ ( formatWikiBlocks
)
where
import Text.XML.HXT.DOM.TypeDefs
--- 複數の Inline を一つに纏める
-packParagraph :: [WikiElement] -> [Either BlockElement [InlineElement]]
-packParagraph elems = map pack grp
- where
- grp :: [[WikiElement]]
- grp = groupBy criteria elems
-
- criteria :: WikiElement -> WikiElement -> Bool
- criteria (Inline _) (Inline _) = True
- criteria _ _ = False
-
- pack :: [WikiElement] -> Either BlockElement [InlineElement]
- pack (Block b : []) = Left b
- pack xs = Right [ case x of
- Inline i -> i | x <- xs ]
-
-
-formatWikiElements :: (ArrowXml a, ArrowChoice a) => a (URI, [WikiElement]) XmlTree
-formatWikiElements
- = proc (baseURI, elems)
- -> do chunk <- arrL id -< packParagraph elems
- case chunk of
- Left x -> formatBlock -< x
- Right xs -> formatParagraph -< (baseURI, xs)
+formatWikiBlocks :: (ArrowXml a, ArrowChoice a) => a (URI, [BlockElement]) XmlTree
+formatWikiBlocks
+ = proc (baseURI, blocks)
+ -> do block <- arrL id -< blocks
+ formatBlock -< (baseURI, block)
-formatBlock :: (ArrowXml a, ArrowChoice a) => a BlockElement XmlTree
+formatBlock :: (ArrowXml a, ArrowChoice a) => a (URI, BlockElement) XmlTree
formatBlock
- = proc b
- -> case b of
+ = proc (baseURI, block)
+ -> case block of
Heading level text
-> formatHeading -< (level, text)
- EmptyLine
- -> none -< ()
+
+ Paragraph inlines
+ -> formatParagraph -< (baseURI, inlines)
formatHeading :: ArrowXml a => a (Int, String) XmlTree
wikiPage :: Parser WikiPage
-wikiPage = do xs <- many (try wikiElement)
- skipMany comment
+wikiPage = do xs <- many (try blockElement)
+ skipMany ( comment
+ <|>
+ (newline >> return ())
+ )
eof
return xs
-wikiElement :: Parser WikiElement
-wikiElement = skipMany comment >>
- ( try (blockElement >>= return . Block)
- <|>
- try (inlineElement >>= return . Inline)
- )
-
-
blockElement :: Parser BlockElement
-blockElement = ( try heading
+blockElement = skipMany ( comment
+ <|>
+ (newline >> return ())
+ )
+ >>
+ ( heading
<|>
- try emptyLine
+ paragraph
)
heading :: Parser BlockElement
-heading = foldr (<|>) pzero (map (try . heading') [1..5])
+heading = foldr (<|>) pzero (map heading' [1..5])
<?>
"heading"
where
heading' :: Int -> Parser BlockElement
- heading' n = do count n (char '=')
- notFollowedBy (char '=')
+ heading' n = do try $ do count n (char '=')
+ notFollowedBy (char '=')
ws
x <- notFollowedBy (char '=') >> anyChar
- xs <- manyTill anyChar (try $ ws >> (count n (char '=')))
+ xs <- manyTill anyChar (try $ ws >> ( count n (char '=')
+ <?>
+ ("trailing " ++ take n (repeat '='))
+ )
+ )
ws
eol
return (Heading n (x:xs))
-emptyLine :: Parser BlockElement
-emptyLine = count 2 newline >> many newline >> return EmptyLine
- <?>
- "empty line"
+paragraph :: Parser BlockElement
+paragraph = paragraph' >>= return . Paragraph
+ where
+ paragraph' :: Parser [InlineElement]
+ paragraph' = do x <- inlineElement
+ xs <- try ( do newline
+ eof
+ return []
+ -- \n で文字列が終はってゐたら、ここ
+ -- で終了。
+ )
+ <|>
+ try ( do newline
+ ((oneOf ('\n':blockSymbols) >> pzero) <|> return ())
+ ys <- (paragraph' <|> return [])
+ return (Text "\n" : ys)
+ -- \n があり、その次に \n または
+ -- blockSymbols があれば、fail して
+ -- 最初の newline を讀んだ所まで卷き
+ -- 戻す。
+ )
+ <|>
+ try paragraph'
+ -- それ以外の場合は次の inlineElement から
+ -- を讀んで見る。但し一つも無くても良い。
+ <|>
+ return [] -- 全部失敗したらここで終了。
+ return (x:xs)
inlineElement :: Parser InlineElement
-inlineElement = ( try text
+inlineElement = skipMany comment
+ >>
+ ( try text
<|>
try pageLink
)
text :: Parser InlineElement
-text = text' >>= return . Text
- where
- text' :: Parser String
- text' = do x <- noneOf inlineSymbols
- case x of
- -- 單獨の \n は受け入れる。
- '\n' -> return [x]
- -- それ以外では \n を受け入れない。
- _ -> many (noneOf ('\n':inlineSymbols)) >>= return . (x:)
+text = many1 (noneOf ('\n':inlineSymbols)) >>= return . Text
pageLink :: Parser InlineElement
)
+blockSymbols :: [Char]
+blockSymbols = "="
+
+
inlineSymbols :: [Char]
inlineSymbols = "<["
-- end of line
eol :: Parser ()
-eol = ( (many1 newline >> return ())
+eol = ( (newline >> return ())
<|>
eof
)
~?=
(Right []))
+ , (parseWiki "\n"
+ ~?=
+ (Right []))
+
, (parseWiki "=heading="
~?=
- (Right [Block (Heading 1 "heading")]))
+ (Right [ Heading 1 "heading" ]))
, (parseWiki "== heading == \n"
~?=
- (Right [Block (Heading 2 "heading")]))
+ (Right [ Heading 2 "heading" ]))
, (parseWiki "===== hello world =====\n"
~?=
- (Right [Block (Heading 5 "hello world")]))
+ (Right [ Heading 5 "hello world" ]))
, (parseWiki "a =not a heading="
~?=
- (Right [Inline (Text "a =not a heading=")]))
+ (Right [ Paragraph [ Text "a =not a heading=" ]
+ ]))
, (parseWiki "=h=\n\n=h="
~?=
- (Right [ Block (Heading 1 "h")
- , Block (Heading 1 "h")
+ (Right [ Heading 1 "h"
+ , Heading 1 "h"
+ ]))
+ , (parseWiki "foo\nbar"
+ ~?=
+ (Right [ Paragraph [ Text "foo"
+ , Text "\n"
+ , Text "bar"
+ ]
]))
-
, (parseWiki "foo\nbar\n\nbaz\n"
~?=
- (Right [ Inline (Text "foo")
- , Inline (Text "\n")
- , Inline (Text "bar")
- , Block EmptyLine
- , Inline (Text "baz")
- , Inline (Text "\n")
+ (Right [ Paragraph [ Text "foo"
+ , Text "\n"
+ , Text "bar"
+ ]
+ , Paragraph [ Text "baz"
+ ]
]))
, (parseWiki "foo\n\n\nbar"
~?=
- (Right [ Inline (Text "foo")
- , Block EmptyLine
- , Inline (Text "bar")
+ (Right [ Paragraph [ Text "foo" ]
+ , Paragraph [ Text "bar" ]
]))
, (parseWiki "foo\n=h="
~?=
- (Right [ Inline (Text "foo")
- , Inline (Text "\n")
- , Block (Heading 1 "h")
+ (Right [ Paragraph [ Text "foo" ]
+ , Heading 1 "h"
]))
, (parseWiki "<!-- comment -->"
, (parseWiki "<!-- comment -->foo"
~?=
- (Right [Inline (Text "foo")]))
+ (Right [ Paragraph [ Text "foo" ]
+ ]))
- , (parseWiki "foo<!-- comment -->"
+ , (parseWiki "bar<!-- comment -->"
~?=
- (Right [Inline (Text "foo")]))
+ (Right [ Paragraph [ Text "bar" ]
+ ]))
, (parseWiki "foo<!-- comment -->bar"
~?=
- (Right [ Inline (Text "foo")
- , Inline (Text "bar")
+ (Right [ Paragraph [ Text "foo"
+ , Text "bar"
+ ]
]))
, (parseWiki "<!-- comment -->=h="
~?=
- (Right [Block (Heading 1 "h")]))
+ (Right [ Heading 1 "h" ]))
, (parseWiki "=h= <!---->"
~?=
- (Right [Block (Heading 1 "h")]))
+ (Right [ Heading 1 "h" ]))
, (parseWiki "<!-- <!-- nested --> comment -->"
~?=
, (parseWiki "[[Page]]"
~?=
- (Right [Inline (PageLink (Just "Page") Nothing Nothing)]))
+ (Right [ Paragraph [ PageLink (Just "Page") Nothing Nothing ]
+ ]))
, (parseWiki "[[Page|Link to \"Page\"]]"
~?=
- (Right [Inline (PageLink (Just "Page") Nothing (Just "Link to \"Page\""))]))
+ (Right [ Paragraph [ PageLink (Just "Page") Nothing (Just "Link to \"Page\"") ]
+ ]))
, (parseWiki "[[Page#foo]]"
~?=
- (Right [Inline (PageLink (Just "Page") (Just "foo") Nothing)]))
+ (Right [ Paragraph [ PageLink (Just "Page") (Just "foo") Nothing ]
+ ]))
, (parseWiki "[[#foo]]"
~?=
- (Right [Inline (PageLink Nothing (Just "foo") Nothing)]))
+ (Right [ Paragraph [ PageLink Nothing (Just "foo") Nothing ]
+ ]))
, (parseWiki "[[Page#foo|Link to \"Page#foo\"]]"
~?=
- (Right [Inline (PageLink (Just "Page") (Just "foo") (Just "Link to \"Page#foo\""))]))
+ (Right [ Paragraph [ PageLink (Just "Page") (Just "foo") (Just "Link to \"Page#foo\"") ]
+ ]))
, (parseWiki "foo [[Bar]] baz"
~?=
- (Right [ Inline (Text "foo ")
- , Inline (PageLink (Just "Bar") Nothing Nothing)
- , Inline (Text " baz")
+ (Right [ Paragraph [ Text "foo "
+ , PageLink (Just "Bar") Nothing Nothing
+ , Text " baz"
+ ]
]))
, (parseWiki "[[Foo]]\n[[Bar]]"
~?=
- (Right [ Inline (PageLink (Just "Foo") Nothing Nothing)
- , Inline (Text "\n")
- , Inline (PageLink (Just "Bar") Nothing Nothing)
+ (Right [ Paragraph [ PageLink (Just "Foo") Nothing Nothing
+ , Text "\n"
+ , PageLink (Just "Bar") Nothing Nothing
+ ]
]))
]