@@ -1,6 +1,6 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3−{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances #-}
5Copyright (C) 2014 Albert Krewinkel <tarleb@moltkeplatz.de>
5Copyright (C) 2014 Albert Krewinkel <tarleb@moltkeplatz.de>
@@ -49,7 +49,7 @@ import Control.Applicative ( Applicative, pure
49 , (<$>), (<$), (<*>), (<*), (*>) )
49 , (<$>), (<$), (<*>), (<*), (*>) )
50import Control.Arrow (first)
50import Control.Arrow (first)
51import Control.Monad (foldM, guard, liftM, liftM2, mplus, mzero, when)
51import Control.Monad (foldM, guard, liftM, liftM2, mplus, mzero, when)
52−import Control.Monad.Reader (Reader, runReader, ask, asks)
52+import Control.Monad.Reader (Reader, runReader, ask, asks, local)
53import Data.Char (isAlphaNum, toLower)
53import Data.Char (isAlphaNum, toLower)
54import Data.Default
54import Data.Default
55import Data.List (intersperse, isPrefixOf, isSuffixOf)
55import Data.List (intersperse, isPrefixOf, isSuffixOf)
@@ -62,9 +62,11 @@ import Network.HTTP (urlEncode)
62readOrg :: ReaderOptions -- ^ Reader options
62readOrg :: ReaderOptions -- ^ Reader options
63 -> String -- ^ String to parse (assuming @'\n'@ line endings)
63 -> String -- ^ String to parse (assuming @'\n'@ line endings)
65−readOrg opts s = readWith parseOrg def{ orgStateOptions = opts } (s ++ "\n\n")
65+readOrg opts s = flip runReader def $ readWithM parseOrg def{ orgStateOptions = opts } (s ++ "\n\n")
67+data OrgParserLocal = OrgParserLocal { orgLocalQuoteContext :: QuoteContext }
67−type OrgParser = Parser [Char] OrgParserState
69+type OrgParser = ParserT [Char] OrgParserState (Reader OrgParserLocal)
69parseOrg :: OrgParser Pandoc
71parseOrg :: OrgParser Pandoc
70parseOrg = do
72parseOrg = do
@@ -125,6 +127,9 @@ data OrgParserState = OrgParserState
125 , orgStateNotes' :: OrgNoteTable
127 , orgStateNotes' :: OrgNoteTable
130+instance Default OrgParserLocal where
131+ def = OrgParserLocal NoQuote
128instance HasReaderOptions OrgParserState where
133instance HasReaderOptions OrgParserState where
129 extractReaderOptions = orgStateOptions
134 extractReaderOptions = orgStateOptions
@@ -138,6 +143,10 @@ instance HasLastStrPosition OrgParserState where
138 getLastStrPos = orgStateLastStrPos
143 getLastStrPos = orgStateLastStrPos
139 setLastStrPos pos st = st{ orgStateLastStrPos = Just pos }
144 setLastStrPos pos st = st{ orgStateLastStrPos = Just pos }
146+instance HasQuoteContext st (Reader OrgParserLocal) where
147+ getQuoteContext = asks orgLocalQuoteContext
148+ withQuoteContext q = local (\s -> s{orgLocalQuoteContext = q})
141instance Default OrgParserState where
150instance Default OrgParserState where
142 def = defaultOrgParserState
151 def = defaultOrgParserState
@@ -964,6 +973,7 @@ inline =
964 , subscript
973 , subscript
965 , superscript
974 , superscript
966 , inlineLaTeX
975 , inlineLaTeX
968 ] <* (guard =<< newlinesCountWithinLimits)
978 ] <* (guard =<< newlinesCountWithinLimits)
969 <?> "inline"
979 <?> "inline"
@@ -1270,12 +1280,16 @@ displayMath :: OrgParser (F Inlines)
1270displayMath = return . B.displayMath <$> choice [ rawMathBetween "\\[" "\\]"
1280displayMath = return . B.displayMath <$> choice [ rawMathBetween "\\[" "\\]"
1271 , rawMathBetween "$$" "$$"
1281 , rawMathBetween "$$" "$$"
1284+updatePositions :: Char
1285+ -> OrgParser (Char)
1286+updatePositions c = do
1287+ when (c `elem` emphasisPreChars) updateLastPreCharPos
1288+ when (c `elem` emphasisForbiddenBorderChars) updateLastForbiddenCharPos
1273symbol :: OrgParser (F Inlines)
1291symbol :: OrgParser (F Inlines)
1274symbol = return . B.str . (: "") <$> (oneOf specialChars >>= updatePositions)
1292symbol = return . B.str . (: "") <$> (oneOf specialChars >>= updatePositions)
1275− where updatePositions c = do
1276− when (c `elem` emphasisPreChars) updateLastPreCharPos
1277− when (c `elem` emphasisForbiddenBorderChars) updateLastForbiddenCharPos
1280emphasisBetween :: Char
1294emphasisBetween :: Char
1281 -> OrgParser (F Inlines)
1295 -> OrgParser (F Inlines)
@@ -1486,3 +1500,31 @@ inlineLaTeXCommand = try $ do
1486 count len anyChar
1500 count len anyChar
1487 return cs
1501 return cs
1488 _ -> mzero
1502 _ -> mzero
1504+smart :: OrgParser (F Inlines)
1506+ getOption readerSmart >>= guard
1507+ doubleQuoted <|> singleQuoted <|>
1508+ choice (map (return <$>) [orgApostrophe, dash, ellipses])
1509+ where orgApostrophe =
1510+ (char '\'' <|> char '\8217') <* updateLastPreCharPos
1511+ <* updateLastForbiddenCharPos
1512+ *> return (B.str "\x2019")
1514+singleQuoted :: OrgParser (F Inlines)
1515+singleQuoted = try $ do
1517+ withQuoteContext InSingleQuote $
1518+ fmap B.singleQuoted . trimInlinesF . mconcat <$>
1519+ many1Till inline singleQuoteEnd
1521+-- doubleQuoted will handle regular double-quoted sections, as well
1522+-- as dialogues with an open double-quote without a close double-quote
1523+-- in the same paragraph.
1524+doubleQuoted :: OrgParser (F Inlines)
1525+doubleQuoted = try $ do
1527+ contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
1528+ (withQuoteContext InDoubleQuote $ (doubleQuoteEnd <* updateLastForbiddenCharPos) >> return
1529+ (fmap B.doubleQuoted . trimInlinesF $ contents))
1530+ <|> (return $ return (B.str "\8220") <> contents)