git.iko.soy/typeable/pandoc
on master help sign in
Org reader: extract parsing function to module
a340c72Albert Krewinkel
pandoc.cabal+1
@@ -394,6 +394,7 @@ Library
394 Text.Pandoc.Readers.Odt.Arrows.State,
394 Text.Pandoc.Readers.Odt.Arrows.State,
395 Text.Pandoc.Readers.Odt.Arrows.Utils,
395 Text.Pandoc.Readers.Odt.Arrows.Utils,
396 Text.Pandoc.Readers.Org.ParserState,
396 Text.Pandoc.Readers.Org.ParserState,
397+ Text.Pandoc.Readers.Org.Parsing,
397 Text.Pandoc.Writers.Shared,
398 Text.Pandoc.Writers.Shared,
398 Text.Pandoc.Asciify,
399 Text.Pandoc.Asciify,
399 Text.Pandoc.MIME,
400 Text.Pandoc.MIME,
src/Text/Pandoc/Readers/Org.hs+10−76
@@ -29,27 +29,23 @@ Conversion of org-mode formatted plain text to 'Pandoc' document.
29-}
29-}
30module Text.Pandoc.Readers.Org ( readOrg ) where
30module Text.Pandoc.Readers.Org ( readOrg ) where
31
31
32+import Text.Pandoc.Readers.Org.ParserState
33+import Text.Pandoc.Readers.Org.Parsing
34+
32import qualified Text.Pandoc.Builder as B
35import qualified Text.Pandoc.Builder as B
33import Text.Pandoc.Builder ( Inlines, Blocks )
36import Text.Pandoc.Builder ( Inlines, Blocks )
34import Text.Pandoc.Definition
37import Text.Pandoc.Definition
35import Text.Pandoc.Compat.Monoid ((<>))
38import Text.Pandoc.Compat.Monoid ((<>))
36import Text.Pandoc.Error
39import Text.Pandoc.Error
37import Text.Pandoc.Options
40import Text.Pandoc.Options
38−import qualified Text.Pandoc.Parsing as P
39−import Text.Pandoc.Parsing hiding ( F, unF, askF, asksF, runF
40− , anyLine, blanklines, newline
41− , orderedListMarker
42− , parseFromString
43− )
44import Text.Pandoc.Readers.LaTeX (inlineCommand, rawLaTeXInline)
41import Text.Pandoc.Readers.LaTeX (inlineCommand, rawLaTeXInline)
45−import Text.Pandoc.Readers.Org.ParserState
46import Text.Pandoc.Shared (compactify', compactify'DL)
42import Text.Pandoc.Shared (compactify', compactify'DL)
47import Text.TeXMath (readTeX, writePandoc, DisplayType(..))
43import Text.TeXMath (readTeX, writePandoc, DisplayType(..))
48import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap
44import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap
49
45
50import Control.Arrow (first)
46import Control.Arrow (first)
51import Control.Monad (foldM, guard, mplus, mzero, when)
47import Control.Monad (foldM, guard, mplus, mzero, when)
52−import Control.Monad.Reader ( Reader, runReader )
48+import Control.Monad.Reader ( runReader )
53import Data.Char (isAlphaNum, isSpace, toLower, toUpper)
49import Data.Char (isAlphaNum, isSpace, toLower, toUpper)
54import Data.List ( foldl', intersperse, isPrefixOf, isSuffixOf )
50import Data.List ( foldl', intersperse, isPrefixOf, isSuffixOf )
55import qualified Data.Map as M
51import qualified Data.Map as M
@@ -63,9 +59,6 @@ readOrg :: ReaderOptions -- ^ Reader options
63 -> Either PandocError Pandoc
59 -> Either PandocError Pandoc
64readOrg opts s = flip runReader def $ readWithM parseOrg def{ orgStateOptions = opts } (s ++ "\n\n")
60readOrg opts s = flip runReader def $ readWithM parseOrg def{ orgStateOptions = opts } (s ++ "\n\n")
65
61
66−-- | The parser used to read org files.
67−type OrgParser = ParserT [Char] OrgParserState (Reader OrgParserLocal)
68−
69--
62--
70-- Functions acting on the parser state
63-- Functions acting on the parser state
71--
64--
@@ -73,14 +66,6 @@ recordAnchorId :: String -> OrgParser ()
73recordAnchorId i = updateState $ \s ->
66recordAnchorId i = updateState $ \s ->
74 s{ orgStateAnchorIds = i : (orgStateAnchorIds s) }
67 s{ orgStateAnchorIds = i : (orgStateAnchorIds s) }
75
68
76−updateLastForbiddenCharPos :: OrgParser ()
77−updateLastForbiddenCharPos = getPosition >>= \p ->
78− updateState $ \s -> s{ orgStateLastForbiddenCharPos = Just p}
79−
80−updateLastPreCharPos :: OrgParser ()
81−updateLastPreCharPos = getPosition >>= \p ->
82− updateState $ \s -> s{ orgStateLastPreCharPos = Just p}
83−
84pushToInlineCharStack :: Char -> OrgParser ()
69pushToInlineCharStack :: Char -> OrgParser ()
85pushToInlineCharStack c = updateState $ \s ->
70pushToInlineCharStack c = updateState $ \s ->
86 s{ orgStateEmphasisCharStack = c:orgStateEmphasisCharStack s }
71 s{ orgStateEmphasisCharStack = c:orgStateEmphasisCharStack s }
@@ -258,57 +243,6 @@ isHeaderLevelLowerEq n blk =
258 _ -> False
243 _ -> False
259
244
260
245
261−--
262−-- Adaptions and specializations of parsing utilities
263−--
264−
265−-- The version Text.Pandoc.Parsing cannot be used, as we need additional parts
266−-- of the state saved and restored.
267−parseFromString :: OrgParser a -> String -> OrgParser a
268−parseFromString parser str' = do
269− oldLastPreCharPos <- orgStateLastPreCharPos <$> getState
270− updateState $ \s -> s{ orgStateLastPreCharPos = Nothing }
271− result <- P.parseFromString parser str'
272− updateState $ \s -> s{ orgStateLastPreCharPos = oldLastPreCharPos }
273− return result
274−
275−-- | Like @Text.Parsec.Char.newline@, but causes additional state changes.
276−newline :: OrgParser Char
277−newline =
278− P.newline
279− <* updateLastPreCharPos
280− <* updateLastForbiddenCharPos
281−
282−-- | Like @Text.Parsec.Char.blanklines@, but causes additional state changes.
283−blanklines :: OrgParser [Char]
284−blanklines =
285− P.blanklines
286− <* updateLastPreCharPos
287− <* updateLastForbiddenCharPos
288−
289−anyLine :: OrgParser String
290−anyLine =
291− P.anyLine
292− <* updateLastPreCharPos
293− <* updateLastForbiddenCharPos
294−
295−-- | Succeeds when we're in list context.
296−inList :: OrgParser ()
297−inList = do
298− ctx <- orgStateParserContext <$> getState
299− guard (ctx == ListItemState)
300−
301−-- | Parse in different context
302−withContext :: ParserContext -- ^ New parser context
303− -> OrgParser a -- ^ Parser to run in that context
304− -> OrgParser a
305−withContext context parser = do
306− oldContext <- orgStateParserContext <$> getState
307− updateState $ \s -> s{ orgStateParserContext = context }
308− result <- parser
309− updateState $ \s -> s{ orgStateParserContext = oldContext }
310− return result
311−
312--
246--
313-- parsing blocks
247-- parsing blocks
314--
248--
@@ -398,7 +332,7 @@ keyValues = try $
398 endOfValue :: OrgParser ()
332 endOfValue :: OrgParser ()
399 endOfValue =
333 endOfValue =
400 lookAhead $ (() <$ try (many1 spaceChar <* key))
334 lookAhead $ (() <$ try (many1 spaceChar <* key))
401− <|> () <$ P.newline
335+ <|> () <$ newline
402
336
403
337
404--
338--
@@ -675,7 +609,7 @@ propertiesDrawer = try $ do
675 key = try $ skipSpaces *> char ':' *> many1Till nonspaceChar (char ':')
609 key = try $ skipSpaces *> char ':' *> many1Till nonspaceChar (char ':')
676
610
677 value :: OrgParser String
611 value :: OrgParser String
678− value = try $ skipSpaces *> manyTill anyChar (try $ skipSpaces *> P.newline)
612+ value = try $ skipSpaces *> manyTill anyChar (try $ skipSpaces *> newline)
679
613
680keyValuesToAttr :: [(String, String)] -> Attr
614keyValuesToAttr :: [(String, String)] -> Attr
681keyValuesToAttr kvs =
615keyValuesToAttr kvs =
@@ -696,7 +630,7 @@ keyValuesToAttr kvs =
696figure :: OrgParser (F Blocks)
630figure :: OrgParser (F Blocks)
697figure = try $ do
631figure = try $ do
698 figAttrs <- blockAttributes
632 figAttrs <- blockAttributes
699− src <- skipSpaces *> selfTarget <* skipSpaces <* P.newline
633+ src <- skipSpaces *> selfTarget <* skipSpaces <* newline
700 guard . not . isNothing . blockAttrCaption $ figAttrs
634 guard . not . isNothing . blockAttrCaption $ figAttrs
701 guard (isImageFilename src)
635 guard (isImageFilename src)
702 let figName = fromMaybe mempty $ blockAttrName figAttrs
636 let figName = fromMaybe mempty $ blockAttrName figAttrs
@@ -785,7 +719,7 @@ parseFormat = try $ do
785header :: OrgParser (F Blocks)
719header :: OrgParser (F Blocks)
786header = try $ do
720header = try $ do
787 level <- headerStart
721 level <- headerStart
788− title <- manyTill inline (lookAhead $ optional headerTags <* P.newline)
722+ title <- manyTill inline (lookAhead $ optional headerTags <* newline)
789 tags <- option [] headerTags
723 tags <- option [] headerTags
790 newline
724 newline
791 propAttr <- option nullAttr (keyValuesToAttr <$> propertiesDrawer)
725 propAttr <- option nullAttr (keyValuesToAttr <$> propertiesDrawer)
@@ -1083,7 +1017,7 @@ definitionListItem parseMarkerGetLength = try $ do
1083 return $ (,) <$> term' <*> fmap (:[]) contents'
1017 return $ (,) <$> term' <*> fmap (:[]) contents'
1084 where
1018 where
1085 definitionMarker =
1019 definitionMarker =
1086− spaceChar *> string "::" <* (spaceChar <|> lookAhead P.newline)
1020+ spaceChar *> string "::" <* (spaceChar <|> lookAhead newline)
1087
1021
1088
1022
1089-- parse raw text for one list item, excluding start marker and continuations
1023-- parse raw text for one list item, excluding start marker and continuations
@@ -1559,7 +1493,7 @@ many1TillNOrLessNewlines n p end = try $
1559 nMoreLines k cs = try $ (final k cs <|> rest k cs)
1493 nMoreLines k cs = try $ (final k cs <|> rest k cs)
1560 >>= uncurry nMoreLines
1494 >>= uncurry nMoreLines
1561 final _ cs = (\x -> (Nothing, cs ++ x)) <$> try finalLine
1495 final _ cs = (\x -> (Nothing, cs ++ x)) <$> try finalLine
1562− rest m cs = (\x -> (minus1 <$> m, cs ++ x ++ "\n")) <$> try (manyTill p P.newline)
1496+ rest m cs = (\x -> (minus1 <$> m, cs ++ x ++ "\n")) <$> try (manyTill p newline)
1563 finalLine = try $ manyTill p end
1497 finalLine = try $ manyTill p end
1564 minus1 k = k - 1
1498 minus1 k = k - 1
1565 oneOrMore cs = guard (not $ null cs) *> return cs
1499 oneOrMore cs = guard (not $ null cs) *> return cs
src/Text/Pandoc/Readers/Org/ParserState.hs+5−2
@@ -29,9 +29,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29Define the Org-mode parser state.
29Define the Org-mode parser state.
30-}
30-}
31module Text.Pandoc.Readers.Org.ParserState
31module Text.Pandoc.Readers.Org.ParserState
32− ( OrgParserState(..)
32+ ( OrgParserState (..)
33− , OrgParserLocal(..)
33+ , OrgParserLocal (..)
34 , OrgNoteRecord
34 , OrgNoteRecord
35+ , HasReaderOptions (..)
36+ , HasQuoteContext (..)
35 , F(..)
37 , F(..)
36 , askF
38 , askF
37 , asksF
39 , asksF
@@ -184,6 +186,7 @@ modifyExportSettings :: ExportSettingSetter a -> a -> OrgParserState -> OrgParse
184modifyExportSettings setter val state =
186modifyExportSettings setter val state =
185 state { orgStateExportSettings = setter val . orgStateExportSettings $ state }
187 state { orgStateExportSettings = setter val . orgStateExportSettings $ state }
186
188
189+
187--
190--
188-- Parser state reader
191-- Parser state reader
189--
192--
src/Text/Pandoc/Readers/Org/Parsing.hsnew file+182
@@ -0,0 +1,182 @@
1+{-
2+Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
3+
4+This program is free software; you can redistribute it and/or modify
5+it under the terms of the GNU General Public License as published by
6+the Free Software Foundation; either version 2 of the License, or
7+(at your option) any later version.
8+
9+This program is distributed in the hope that it will be useful,
10+but WITHOUT ANY WARRANTY; without even the implied warranty of
11+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+GNU General Public License for more details.
13+
14+You should have received a copy of the GNU General Public License
15+along with this program; if not, write to the Free Software
16+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+-}
18+
19+{- |
20+ Module : Text.Pandoc.Readers.Org.Options
21+ Copyright : Copyright (C) 2014-2016 Albert Krewinkel
22+ License : GNU GPL, version 2 or above
23+
24+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
25+
26+Org-mode parsing utilities.
27+
28+Most functions are simply re-exports from @Text.Pandoc.Parsing@, some
29+functions are adapted to Org-mode specific functionality.
30+-}
31+module Text.Pandoc.Readers.Org.Parsing
32+ ( OrgParser
33+ , anyLine
34+ , blanklines
35+ , newline
36+ , parseFromString
37+ , inList
38+ , withContext
39+ , updateLastForbiddenCharPos
40+ , updateLastPreCharPos
41+ -- * Re-exports from Text.Pandoc.Parser
42+ , ParserContext (..)
43+ , many1Till
44+ , notFollowedBy'
45+ , spaceChar
46+ , nonspaceChar
47+ , skipSpaces
48+ , blankline
49+ , enclosed
50+ , stringAnyCase
51+ , charsInBalanced
52+ , uri
53+ , withRaw
54+ , readWithM
55+ , guardEnabled
56+ , updateLastStrPos
57+ , notAfterString
58+ , ParserState (..)
59+ , registerHeader
60+ , QuoteContext (..)
61+ , singleQuoteStart
62+ , singleQuoteEnd
63+ , doubleQuoteStart
64+ , doubleQuoteEnd
65+ , dash
66+ , ellipses
67+ , citeKey
68+ -- * Re-exports from Text.Pandoc.Parsec
69+ , runParser
70+ , getInput
71+ , char
72+ , letter
73+ , digit
74+ , alphaNum
75+ , skipMany1
76+ , spaces
77+ , anyChar
78+ , string
79+ , count
80+ , eof
81+ , noneOf
82+ , oneOf
83+ , lookAhead
84+ , notFollowedBy
85+ , many
86+ , many1
87+ , manyTill
88+ , (<|>)
89+ , (<?>)
90+ , choice
91+ , try
92+ , sepBy
93+ , sepBy1
94+ , option
95+ , optional
96+ , optionMaybe
97+ , getState
98+ , updateState
99+ , SourcePos
100+ , getPosition
101+ ) where
102+
103+import Text.Pandoc.Readers.Org.ParserState
104+
105+import qualified Text.Pandoc.Parsing as P
106+import Text.Pandoc.Parsing hiding ( anyLine, blanklines, newline
107+ , parseFromString )
108+
109+import Control.Monad ( guard )
110+import Control.Monad.Reader ( Reader )
111+
112+-- | The parser used to read org files.
113+type OrgParser = ParserT [Char] OrgParserState (Reader OrgParserLocal)
114+
115+--
116+-- Adaptions and specializations of parsing utilities
117+--
118+
119+-- | Parse any line of text
120+anyLine :: OrgParser String
121+anyLine =
122+ P.anyLine
123+ <* updateLastPreCharPos
124+ <* updateLastForbiddenCharPos
125+
126+-- The version Text.Pandoc.Parsing cannot be used, as we need additional parts
127+-- of the state saved and restored.
128+parseFromString :: OrgParser a -> String -> OrgParser a
129+parseFromString parser str' = do
130+ oldLastPreCharPos <- orgStateLastPreCharPos <$> getState
131+ updateState $ \s -> s{ orgStateLastPreCharPos = Nothing }
132+ result <- P.parseFromString parser str'
133+ updateState $ \s -> s{ orgStateLastPreCharPos = oldLastPreCharPos }
134+ return result
135+
136+-- | Like @Text.Parsec.Char.newline@, but causes additional state changes.
137+newline :: OrgParser Char
138+newline =
139+ P.newline
140+ <* updateLastPreCharPos
141+ <* updateLastForbiddenCharPos
142+
143+-- | Like @Text.Parsec.Char.blanklines@, but causes additional state changes.
144+blanklines :: OrgParser [Char]
145+blanklines =
146+ P.blanklines
147+ <* updateLastPreCharPos
148+ <* updateLastForbiddenCharPos
149+
150+-- | Succeeds when we're in list context.
151+inList :: OrgParser ()
152+inList = do
153+ ctx <- orgStateParserContext <$> getState
154+ guard (ctx == ListItemState)
155+
156+-- | Parse in different context
157+withContext :: ParserContext -- ^ New parser context
158+ -> OrgParser a -- ^ Parser to run in that context
159+ -> OrgParser a
160+withContext context parser = do
161+ oldContext <- orgStateParserContext <$> getState
162+ updateState $ \s -> s{ orgStateParserContext = context }
163+ result <- parser
164+ updateState $ \s -> s{ orgStateParserContext = oldContext }
165+ return result
166+
167+--
168+-- Parser state update functions
169+--
170+
171+-- | Set the current position as the last position at which a forbidden char
172+-- was found (i.e. a character which is not allowed at the inner border of
173+-- markup).
174+updateLastForbiddenCharPos :: OrgParser ()
175+updateLastForbiddenCharPos = getPosition >>= \p ->
176+ updateState $ \s -> s{ orgStateLastForbiddenCharPos = Just p}
177+
178+-- | Set the current parser position as the position at which a character was
179+-- seen which allows inline markup to follow.
180+updateLastPreCharPos :: OrgParser ()
181+updateLastPreCharPos = getPosition >>= \p ->
182+ updateState $ \s -> s{ orgStateLastPreCharPos = Just p}