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 ())
41 heading :: Parser BlockElement
42 heading = foldr (<|>) pzero (map heading' [1..5])
46 heading' :: Int -> Parser BlockElement
47 heading' n = do try $ do count n (char '=')
48 notFollowedBy (char '=')
50 x <- notFollowedBy (char '=') >> anyChar
51 xs <- manyTill anyChar (try $ ws >> ( count n (char '=')
53 ("trailing " ++ take n (repeat '='))
58 return (Heading n (x:xs))
61 horizontalLine :: Parser BlockElement
62 horizontalLine = try $ do count 4 (char '-')
69 listElement :: Parser BlockElement
70 listElement = listElement' [] >>= return . List
72 listElement' :: [Char] -> Parser ListElement
74 = try $ do t <- oneOf "*#"
76 xs <- items (stack ++ [t])
77 return (ListElement (toType t) xs)
80 items :: [Char] -> Parser [ListItem]
81 items stack = do xs <- many1 inlineElement
82 nested <- option Nothing
85 listElement' stack >>= return . Just
87 return $ (map Right xs ++ map Left (catMaybes [nested])) : rest
97 toType :: Char -> ListType
102 definitionList :: Parser BlockElement
103 definitionList = many1 definition >>= return . DefinitionList
105 definition :: Parser Definition
106 definition = do char ';'
108 tHead <- inlineElement
111 return (Definition (tHead:tRest) d)
115 term :: Parser [InlineElement]
116 term = (char ':' >> ws >> return [])
118 (newline >> char ':' >> ws >> return [])
120 do x <- inlineElement
126 description :: Parser [InlineElement]
127 description = do x <- inlineElement
135 return (Text "\n" : xs)
138 (newline >> return [])
142 "description of term"
145 leadingSpaced :: Parser BlockElement
146 leadingSpaced = char ' ' >> leadingSpaced' >>= return . LeadingSpaced
148 leadingSpaced' :: Parser [InlineElement]
149 leadingSpaced' = do x <- inlineElement
159 return . (Text "\n" :)
165 blockTag :: Parser BlockElement
166 blockTag = pzero -- not implemented
169 paragraph :: Parser BlockElement
170 paragraph = paragraph' >>= return . Paragraph
172 paragraph' :: Parser [InlineElement]
173 paragraph' = do x <- inlineElement
174 xs <- try ( do newline
177 -- \n で文字列が終はってゐたら、ここ
182 ((oneOf ('\n':blockSymbols) >> pzero) <|> return ())
183 ((blockTag >> pzero) <|> return ())
184 ys <- (paragraph' <|> return [])
185 return (Text "\n" : ys)
186 -- \n があり、その次に \n、ブロックタ
187 -- グまたは blockSymbols があれば、
188 -- fail して 最初の newline を讀んだ
193 -- それ以外の場合は次の inlineElement から
194 -- を讀んで見る。但し一つも無くても良い。
196 return [] -- 全部失敗したらここで終了。
200 inlineElement :: Parser InlineElement
201 inlineElement = skipMany comment
209 text :: Parser InlineElement
212 many (noneOf ('\n':':':inlineSymbols))
214 return . Text . (':' :)
215 -- 定義リストとの關係上、コロンは先頭にしか存在できない。
218 ( many1 (noneOf ('\n':':':inlineSymbols))
224 pageLink :: Parser InlineElement
225 pageLink = do string "[["
226 page <- option Nothing
227 (many1 (noneOf "#|]") >>= return . Just)
228 fragment <- option Nothing
229 (char '#' >> many1 (noneOf "|]") >>= return . Just)
230 text <- option Nothing
231 (char '|' >> many1 (noneOf "]") >>= return . Just)
233 case (page, fragment) of
234 (Nothing, Nothing) -> pzero
238 return $ PageLink page fragment text
244 comment = (try (string "<!--") >> skipTillEnd 1)
248 skipTillEnd :: Int -> Parser ()
249 skipTillEnd level = ( (try (string "<!--") >> skipTillEnd (level + 1))
251 (try (string "-->") >> case level of
253 n -> skipTillEnd (n - 1))
255 (anyChar >> skipTillEnd level)
259 blockSymbols :: [Char]
260 blockSymbols = " =-*#;"
263 inlineSymbols :: [Char]
268 ws = skipMany ( (oneOf " \t" >> return ())
275 eol = ( (newline >> return ())