+extLink :: Parser InlineElement
+extLink = do char '['
+ uriStr <- many1 (noneOf " \t]")
+ skipMany (oneOf " \t")
+ label <- option Nothing
+ (liftM Just (many1 (noneOf "]")))
+
+ case parseURI uriStr of
+ Just uri -> char ']' >> return (ExternalLink uri label)
+ Nothing -> pzero <?> "absolute URI"
+ <?>
+ "external link"
+
+
+inlineCmd :: CommandTypeOf -> Parser InlineElement
+inlineCmd cmdTypeOf
+ = (try $ do (tagName, tagAttrs) <- openTag
+ case cmdTypeOf tagName of
+ Just InlineCommandType
+ -> do xs <- contents
+ closeTag tagName
+ return $ InlineCmd InlineCommand {
+ iCmdName = tagName
+ , iCmdAttributes = tagAttrs
+ , iCmdContents = xs
+ }
+ _ -> pzero
+ )
+ <|>
+ (try $ do (tagName, tagAttrs) <- emptyTag
+ case cmdTypeOf tagName of
+ Just InlineCommandType
+ -> return $ InlineCmd InlineCommand {
+ iCmdName = tagName
+ , iCmdAttributes = tagAttrs
+ , iCmdContents = []
+ }
+ _ -> pzero
+ )
+ <?>
+ "inline command"
+ where
+ contents :: Parser [InlineElement]
+ contents = do x <- inlineElement cmdTypeOf
+ xs <- contents
+ return (x:xs)
+ <|>
+ (comment >> contents)
+ <|>
+ liftM (Text "\n" :) (newline >> contents)
+ <|>
+ return []
+
+
+openTag :: Parser (String, [Attribute])
+openTag = try $ do char '<'
+ many space
+ name <- many1 letter
+ many space
+ attrs <- many $ do attr <- tagAttr
+ many space
+ return attr
+ char '>'
+ return (name, attrs)
+
+
+emptyTag :: Parser (String, [Attribute])
+emptyTag = try $ do char '<'
+ many space
+ name <- many1 letter
+ many space
+ attrs <- many $ do attr <- tagAttr
+ many space
+ return attr
+ char '/'
+ many space
+ char '>'
+ return (name, attrs)
+
+
+closeTag :: String -> Parser ()
+closeTag name = try $ do char '<'
+ many space
+ char '/'
+ many space
+ string name
+ many space
+ char '>'
+ return ()
+
+
+tagAttr :: Parser (String, String)
+tagAttr = do name <- many1 letter
+ char '='
+ char '"'
+ value <- many (satisfy (/= '"'))
+ char '"'
+ return (name, value)
+
+