module Rakka.Wiki.Parser ( wikiPage ) where import Rakka.Wiki import Text.ParserCombinators.Parsec wikiPage :: Parser WikiPage wikiPage = do xs <- many (try wikiElement) skipMany comment eof return xs wikiElement :: Parser WikiElement wikiElement = skipMany comment >> ( try (blockElement >>= return . Block) <|> try (inlineElement >>= return . Inline) ) blockElement :: Parser BlockElement blockElement = ( try heading <|> try emptyLine ) heading :: Parser BlockElement heading = foldr (<|>) pzero (map (try . heading') [1..5]) "heading" where heading' :: Int -> Parser BlockElement heading' n = do count n (char '=') notFollowedBy (char '=') ws x <- notFollowedBy (char '=') >> anyChar xs <- manyTill anyChar (try $ ws >> (count n (char '='))) ws eol return (Heading n (x:xs)) emptyLine :: Parser BlockElement emptyLine = count 2 newline >> many newline >> return EmptyLine "empty line" inlineElement :: Parser InlineElement inlineElement = ( 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:) pageLink :: Parser InlineElement pageLink = do string "[[" page <- option Nothing (many1 (noneOf "#|]") >>= return . Just) fragment <- option Nothing (char '#' >> many1 (noneOf "|]") >>= return . Just) text <- option Nothing (char '|' >> many1 (noneOf "]") >>= return . Just) case (page, fragment) of (Nothing, Nothing) -> pzero (_, _) -> return () string "]]" return $ PageLink page fragment text "page link" comment :: Parser () comment = (try (string "") >> case level of 1 -> return () n -> skipTillEnd (n - 1)) <|> (anyChar >> skipTillEnd level) ) inlineSymbols :: [Char] inlineSymbols = "<[" -- white space ws :: Parser () ws = skipMany ( (oneOf " \t" >> return ()) <|> comment ) -- end of line eol :: Parser () eol = ( (many1 newline >> return ()) <|> eof )