1 module Rakka.Wiki.Parser
8 import Text.ParserCombinators.Parsec
11 wikiPage :: Parser WikiPage
12 wikiPage = do xs <- many (try blockElement)
15 (newline >> return ())
21 blockElement :: Parser BlockElement
22 blockElement = skipMany ( comment
24 (newline >> return ())
39 heading :: Parser BlockElement
40 heading = foldr (<|>) pzero (map heading' [1..5])
44 heading' :: Int -> Parser BlockElement
45 heading' n = do try $ do count n (char '=')
46 notFollowedBy (char '=')
48 x <- notFollowedBy (char '=') >> anyChar
49 xs <- manyTill anyChar (try $ ws >> ( count n (char '=')
51 ("trailing " ++ take n (repeat '='))
56 return (Heading n (x:xs))
59 horizontalLine :: Parser BlockElement
60 horizontalLine = try $ do count 4 (char '-')
67 listElement :: Parser BlockElement
68 listElement = listElement' [] >>= return . List
70 listElement' :: [Char] -> Parser ListElement
72 = try $ do t <- oneOf "*#"
74 xs <- items (stack ++ [t])
75 return (ListElement (toType t) xs)
78 items :: [Char] -> Parser [ListItem]
79 items stack = do xs <- many1 inlineElement
80 nested <- option Nothing
83 listElement' stack >>= return . Just
85 return $ (map Right xs ++ map Left (catMaybes [nested])) : rest
95 items stack = do nested <- listElement' stack
97 return (Left nested : rest)
99 do xs <- many1 inlineElement
101 return (Right xs : rest)
113 toType :: Char -> ListType
115 toType '#' = Numbered
118 leadingSpaced :: Parser BlockElement
119 leadingSpaced = char ' ' >> leadingSpaced' >>= return . LeadingSpaced
121 leadingSpaced' :: Parser [InlineElement]
122 leadingSpaced' = do x <- inlineElement
132 return . (Text "\n" :)
138 blockTag :: Parser BlockElement
139 blockTag = pzero -- not implemented
142 paragraph :: Parser BlockElement
143 paragraph = paragraph' >>= return . Paragraph
145 paragraph' :: Parser [InlineElement]
146 paragraph' = do x <- inlineElement
147 xs <- try ( do newline
150 -- \n で文字列が終はってゐたら、ここ
155 ((oneOf ('\n':blockSymbols) >> pzero) <|> return ())
156 ((blockTag >> pzero) <|> return ())
157 ys <- (paragraph' <|> return [])
158 return (Text "\n" : ys)
159 -- \n があり、その次に \n、ブロックタ
160 -- グまたは blockSymbols があれば、
161 -- fail して 最初の newline を讀んだ
166 -- それ以外の場合は次の inlineElement から
167 -- を讀んで見る。但し一つも無くても良い。
169 return [] -- 全部失敗したらここで終了。
173 inlineElement :: Parser InlineElement
174 inlineElement = skipMany comment
182 text :: Parser InlineElement
183 text = many1 (noneOf ('\n':inlineSymbols)) >>= return . Text
186 pageLink :: Parser InlineElement
187 pageLink = do string "[["
188 page <- option Nothing
189 (many1 (noneOf "#|]") >>= return . Just)
190 fragment <- option Nothing
191 (char '#' >> many1 (noneOf "|]") >>= return . Just)
192 text <- option Nothing
193 (char '|' >> many1 (noneOf "]") >>= return . Just)
195 case (page, fragment) of
196 (Nothing, Nothing) -> pzero
200 return $ PageLink page fragment text
206 comment = (try (string "<!--") >> skipTillEnd 1)
210 skipTillEnd :: Int -> Parser ()
211 skipTillEnd level = ( (try (string "<!--") >> skipTillEnd (level + 1))
213 (try (string "-->") >> case level of
215 n -> skipTillEnd (n - 1))
217 (anyChar >> skipTillEnd level)
221 blockSymbols :: [Char]
222 blockSymbols = " =-*#"
225 inlineSymbols :: [Char]
230 ws = skipMany ( (oneOf " \t" >> return ())
237 eol = ( (newline >> return ())