@@ -44,11 +44,14 @@ import Data.List (foldl', isPrefixOf, isSuffixOf)
44import Data.Maybe (listToMaybe, fromMaybe)
44import Data.Maybe (listToMaybe, fromMaybe)
45import Data.Monoid (mconcat, mempty, mappend)
45import Data.Monoid (mconcat, mempty, mappend)
47+-- Ignore HLint warnings to use String instead of [Char]
48+{-# ANN module ("HLint: ignore Use String" :: String) #-}
47-- | Parse org-mode string and return a Pandoc document.
50-- | Parse org-mode string and return a Pandoc document.
48readOrg :: ReaderOptions -- ^ Reader options
51readOrg :: ReaderOptions -- ^ Reader options
49 -> String -- ^ String to parse (assuming @'\n'@ line endings)
52 -> String -- ^ String to parse (assuming @'\n'@ line endings)
51−readOrg opts s = (readWith parseOrg) def{ orgStateOptions = opts } (s ++ "\n\n")
54+readOrg opts s = readWith parseOrg def{ orgStateOptions = opts } (s ++ "\n\n")
53type OrgParser = Parser [Char] OrgParserState
56type OrgParser = Parser [Char] OrgParserState
@@ -111,7 +114,7 @@ updateLastPreCharPos = getPosition >>= \p ->
112pushToInlineCharStack :: Char -> OrgParser ()
115pushToInlineCharStack :: Char -> OrgParser ()
113pushToInlineCharStack c = updateState $ \st ->
116pushToInlineCharStack c = updateState $ \st ->
114− st { orgStateEmphasisCharStack = c:(orgStateEmphasisCharStack st) }
117+ st { orgStateEmphasisCharStack = c:orgStateEmphasisCharStack st }
116popInlineCharStack :: OrgParser ()
119popInlineCharStack :: OrgParser ()
117popInlineCharStack = updateState $ \st ->
120popInlineCharStack = updateState $ \st ->
@@ -176,7 +179,7 @@ orgBlock = try $ do
176 "comment" -> return mempty
179 "comment" -> return mempty
177 "src" -> return $ B.codeBlockWith ("", classArgs, []) blockStr
180 "src" -> return $ B.codeBlockWith ("", classArgs, []) blockStr
178 _ -> B.divWith ("", [blockType], [])
181 _ -> B.divWith ("", [blockType], [])
179− <$> (parseFromString parseBlocks blockStr)
182+ <$> parseFromString parseBlocks blockStr
181blockHeader :: OrgParser (Int, String, [String])
184blockHeader :: OrgParser (Int, String, [String])
182blockHeader = (,,) <$> blockIndent
185blockHeader = (,,) <$> blockIndent
@@ -199,7 +202,7 @@ rawBlockContent indent blockType =
199indentWith :: Int -> OrgParser String
202indentWith :: Int -> OrgParser String
200indentWith num = do
203indentWith num = do
201 tabStop <- getOption readerTabStop
204 tabStop <- getOption readerTabStop
202− if (num < tabStop)
205+ if num < tabStop
203 then count num (char ' ')
206 then count num (char ' ')
204 else choice [ try (count num (char ' '))
207 else choice [ try (count num (char ' '))
205 , try (char '\t' >> count (num - tabStop) (char ' ')) ]
208 , try (char '\t' >> count (num - tabStop) (char ' ')) ]
@@ -242,7 +245,7 @@ drawerStart = try $
242 <|> stringAnyCase "LOGBOOK"
245 <|> stringAnyCase "LOGBOOK"
244drawerLine :: OrgParser String
247drawerLine :: OrgParser String
245−drawerLine = try $ anyLine
248+drawerLine = try anyLine
247drawerEnd :: OrgParser String
250drawerEnd :: OrgParser String
248drawerEnd = try $
251drawerEnd = try $
@@ -276,7 +279,7 @@ declarationLine = try $ do
276metaValue :: OrgParser MetaValue
279metaValue :: OrgParser MetaValue
277metaValue = MetaInlines . B.toList . trimInlines <$> restOfLine
280metaValue = MetaInlines . B.toList . trimInlines <$> restOfLine
279−metaKey :: OrgParser [Char]
282+metaKey :: OrgParser String
280metaKey = map toLower <$> many1 (noneOf ": \n\r")
283metaKey = map toLower <$> many1 (noneOf ": \n\r")
281 <* char ':'
284 <* char ':'
282 <* skipSpaces
285 <* skipSpaces
@@ -350,7 +353,7 @@ tableAlignRow = try $
351tableAlignCell :: OrgParser Alignment
354tableAlignCell :: OrgParser Alignment
352tableAlignCell =
355tableAlignCell =
353− choice [ try $ emptyCell *> return (AlignDefault)
356+ choice [ try $ emptyCell *> return AlignDefault
354 , try $ skipSpaces
357 , try $ skipSpaces
355 *> char '<'
358 *> char '<'
356 *> tableAlignFromChar
359 *> tableAlignFromChar
@@ -381,8 +384,8 @@ normalizeTable (OrgTable cols aligns heads lns) =
381 let aligns' = fillColumns aligns AlignDefault
384 let aligns' = fillColumns aligns AlignDefault
382 heads' = if heads == mempty
385 heads' = if heads == mempty
383 then mempty
386 then mempty
384− else fillColumns heads (B.plain mempty)
387+ else fillColumns heads (B.plain mempty)
385− lns' = map (flip fillColumns (B.plain mempty)) lns
388+ lns' = map (`fillColumns` B.plain mempty) lns
386 fillColumns base padding = take cols $ base ++ repeat padding
389 fillColumns base padding = take cols $ base ++ repeat padding
387 in OrgTable cols aligns' heads' lns'
390 in OrgTable cols aligns' heads' lns'
@@ -512,6 +515,7 @@ inline =
512 , underline
515 , underline
515 , verbatim
519 , verbatim
516 , subscript
520 , subscript
517 , superscript
521 , superscript
@@ -564,13 +568,14 @@ explicitOrImageLink = try $ do
564 title <- enclosedRaw (char '[') (char ']')
568 title <- enclosedRaw (char '[') (char ']')
565 title' <- parseFromString (mconcat <$> many inline) title
569 title' <- parseFromString (mconcat <$> many inline) title
571+ return . B.link src ""
567− return $ if (isImageFilename src) && (isImageFilename title)
572+ $ if isImageFilename src && isImageFilename title
568− then B.link src "" (B.image title "" "")
573+ then B.image title "" ""
569− else B.link src "" title'
574+ else title'
571selflinkOrImage :: OrgParser Inlines
576selflinkOrImage :: OrgParser Inlines
572selflinkOrImage = try $ do
577selflinkOrImage = try $ do
573− src <- (char '[') *> linkTarget <* char ']'
578+ src <- char '[' *> linkTarget <* char ']'
574 return $ if isImageFilename src
579 return $ if isImageFilename src
575 then B.image src "" ""
580 then B.image src "" ""
576 else B.link src "" (B.str src)
581 else B.link src "" (B.str src)
@@ -607,13 +612,21 @@ verbatim :: OrgParser Inlines
607verbatim = B.rawInline "" <$> verbatimBetween '~'
612verbatim = B.rawInline "" <$> verbatimBetween '~'
609math :: OrgParser Inlines
614math :: OrgParser Inlines
615+math = B.math <$> choice [ math1CharBetween '$'
610−math = B.math <$> mathStringBetween '$'
616+ , mathStringBetween '$'
617+ , rawMathBetween "\\(" "\\)"
620+displayMath :: OrgParser Inlines
621+displayMath = B.displayMath <$> choice [ rawMathBetween "\\[" "\\]"
622+ , rawMathBetween "$$" "$$"
612subscript :: OrgParser Inlines
625subscript :: OrgParser Inlines
613−subscript = B.subscript <$> (try $ char '_' *> maybeGroupedByBraces)
626+subscript = B.subscript <$> try (char '_' *> maybeGroupedByBraces)
615superscript :: OrgParser Inlines
628superscript :: OrgParser Inlines
616−superscript = B.superscript <$> (try $ char '^' *> maybeGroupedByBraces)
629+superscript = B.superscript <$> try (char '^' *> maybeGroupedByBraces)
618maybeGroupedByBraces :: OrgParser Inlines
631maybeGroupedByBraces :: OrgParser Inlines
619maybeGroupedByBraces = try $
632maybeGroupedByBraces = try $
@@ -655,6 +668,21 @@ mathStringBetween c = try $ do
655 final <- mathEnd c
668 final <- mathEnd c
656 return $ body ++ [final]
669 return $ body ++ [final]
671+-- | Parse a single character between @c@ using math rules
672+math1CharBetween :: Char
674+math1CharBetween c = try $ do
676+ res <- noneOf $ c:mathForbiddenBorderChars
678+ eof <|> lookAhead (oneOf mathPostChars) *> return ()
681+rawMathBetween :: String
684+rawMathBetween s e = try $ string s *> manyTill anyChar (try $ string e)
658-- | Parses the start (opening character) of emphasis
686-- | Parses the start (opening character) of emphasis
659emphasisStart :: Char -> OrgParser Char
687emphasisStart :: Char -> OrgParser Char
660emphasisStart c = try $ do
688emphasisStart c = try $ do
@@ -678,14 +706,14 @@ emphasisEnd c = try $ do
680mathStart :: Char -> OrgParser Char
708mathStart :: Char -> OrgParser Char
681−mathStart c = try $ do
709+mathStart c = try $
682 char c <* notFollowedBy' (oneOf (c:mathForbiddenBorderChars))
710 char c <* notFollowedBy' (oneOf (c:mathForbiddenBorderChars))
684mathEnd :: Char -> OrgParser Char
712mathEnd :: Char -> OrgParser Char
685mathEnd c = try $ do
713mathEnd c = try $ do
686 res <- noneOf (c:mathForbiddenBorderChars)
714 res <- noneOf (c:mathForbiddenBorderChars)
688− eof <|> (lookAhead $ oneOf mathPostChars *> pure ())
716+ eof <|> lookAhead (oneOf mathPostChars *> pure ())
689 return res
717 return res
@@ -717,8 +745,8 @@ many1TillNOrLessNewlines n p end = try $
717 nMoreLines (Just 0) cs = try $ (cs ++) <$> finalLine
745 nMoreLines (Just 0) cs = try $ (cs ++) <$> finalLine
718 nMoreLines k cs = try $ (final k cs <|> rest k cs)
746 nMoreLines k cs = try $ (final k cs <|> rest k cs)
719 >>= uncurry nMoreLines
747 >>= uncurry nMoreLines
720− final _ cs = (\x -> (Nothing, cs ++ x)) <$> (try finalLine)
748+ final _ cs = (\x -> (Nothing, cs ++ x)) <$> try finalLine
721− rest m cs = (\x -> (minus1 <$> m, cs ++ x ++ "\n")) <$> (try $ manyTill p P.newline)
749+ rest m cs = (\x -> (minus1 <$> m, cs ++ x ++ "\n")) <$> try (manyTill p P.newline)
722 finalLine = try $ manyTill p end
750 finalLine = try $ manyTill p end
723 minus1 k = k - 1
751 minus1 k = k - 1
724 oneOrMore cs = guard (not $ null cs) *> return cs
752 oneOrMore cs = guard (not $ null cs) *> return cs
@@ -747,7 +775,7 @@ emphasisAllowedNewlines = 1
748-- | Chars allowed after an inline ($...$) math statement
776-- | Chars allowed after an inline ($...$) math statement
749mathPostChars :: [Char]
777mathPostChars :: [Char]
750−mathPostChars = "\t\n \"',-.:;?"
778+mathPostChars = "\t\n \"'),-.:;?"
752-- | Chars not allowed at the (inner) border of math
780-- | Chars not allowed at the (inner) border of math
753mathForbiddenBorderChars :: [Char]
781mathForbiddenBorderChars :: [Char]
@@ -762,7 +790,7 @@ afterEmphasisPreChar :: OrgParser Bool
762afterEmphasisPreChar = do
790afterEmphasisPreChar = do
763 pos <- getPosition
791 pos <- getPosition
764 lastPrePos <- orgStateLastPreCharPos <$> getState
792 lastPrePos <- orgStateLastPreCharPos <$> getState
765− return $ lastPrePos == Nothing || lastPrePos == Just pos
793+ return . fromMaybe True $ (== pos) <$> lastPrePos
767-- | Whether we are right after the end of a string
795-- | Whether we are right after the end of a string
768notAfterString :: OrgParser Bool
796notAfterString :: OrgParser Bool