git.iko.soy/typeable/pandoc
on master help sign in
Org reader: support macros

Closes: #3401

commitda8c153a6872a040440f8853a37f559bb3b26b02 authorAlbert Krewinkel <albert@zeitkraut.de> dateSat 6 May 2017, 10:59 (10 years ago) parent9f0a804
5 files changed+102−1
src/Text/Pandoc/Readers/Org/Inlines.hs+21 src/Text/Pandoc/Readers/Org/Meta.hs+26−1 src/Text/Pandoc/Readers/Org/ParserState.hs+18 test/Tests/Readers/Org.hs+18 test/command/3401.md+19
src/Text/Pandoc/Readers/Org/Inlines.hs+21
@@ -120,6 +120,7 @@ inline =
120120 , superscript
121121 , inlineLaTeX
122122 , exportSnippet
123+ , macro
123124 , smart
124125 , symbol
125126 ] <* (guard =<< newlinesCountWithinLimits)
@@ -839,6 +840,26 @@ exportSnippet = try $ do
839840 snippet <- manyTill anyChar (try $ string "@@")
840841 returnF $ B.rawInline format snippet
841842
843+macro :: PandocMonad m => OrgParser m (F Inlines)
844+macro = try $ do
845+ recursionDepth <- orgStateMacroDepth <$> getState
846+ guard $ recursionDepth < 15
847+ string "{{{"
848+ name <- many alphaNum
849+ args <- ([] <$ string "}}}")
850+ <|> char '(' *> argument `sepBy` char ',' <* eoa
851+ expander <- lookupMacro name <$> getState
852+ case expander of
853+ Nothing -> mzero
854+ Just fn -> do
855+ updateState $ \s -> s { orgStateMacroDepth = recursionDepth + 1 }
856+ res <- parseFromString (mconcat <$> many inline) $ fn args
857+ updateState $ \s -> s { orgStateMacroDepth = recursionDepth }
858+ return res
859+ where
860+ argument = many $ notFollowedBy eoa *> noneOf ","
861+ eoa = string ")}}}"
862+
842863smart :: PandocMonad m => OrgParser m (F Inlines)
843864smart = do
844865 guardEnabled Ext_smart
src/Text/Pandoc/Readers/Org/Meta.hs+26−1
@@ -46,7 +46,7 @@ import Text.Pandoc.Definition
4646
4747import Control.Monad (mzero, void)
4848import Data.Char (toLower)
49−import Data.List (intersperse)
49+import Data.List (intersperse, sort)
5050import qualified Data.Map as M
5151import Network.HTTP (urlEncode)
5252
@@ -151,6 +151,7 @@ optionLine = try $ do
151151 "todo" -> todoSequence >>= updateState . registerTodoSequence
152152 "seq_todo" -> todoSequence >>= updateState . registerTodoSequence
153153 "typ_todo" -> todoSequence >>= updateState . registerTodoSequence
154+ "macro" -> macroDefinition >>= updateState . registerMacro
154155 _ -> mzero
155156
156157addLinkFormat :: Monad m => String
@@ -218,3 +219,27 @@ todoSequence = try $ do
218219 let todoMarkers = map (TodoMarker Todo) todo
219220 doneMarkers = map (TodoMarker Done) done
220221 in todoMarkers ++ doneMarkers
222+
223+macroDefinition :: Monad m => OrgParser m (String, [String] -> String)
224+macroDefinition = try $ do
225+ macroName <- many1 nonspaceChar <* skipSpaces
226+ firstPart <- expansionPart
227+ (elemOrder, parts) <- unzip <$> many ((,) <$> placeholder <*> expansionPart)
228+ let expander = mconcat . alternate (firstPart:parts) . reorder elemOrder
229+ return (macroName, expander)
230+ where
231+ placeholder :: Monad m => OrgParser m Int
232+ placeholder = try . fmap read $ char '$' *> many1 digit
233+
234+ expansionPart :: Monad m => OrgParser m String
235+ expansionPart = try $ many (notFollowedBy placeholder *> noneOf "\n\r")
236+
237+ alternate :: [a] -> [a] -> [a]
238+ alternate [] ys = ys
239+ alternate xs [] = xs
240+ alternate (x:xs) (y:ys) = x : y : alternate xs ys
241+
242+ reorder :: [Int] -> [String] -> [String]
243+ reorder perm xs =
244+ let element n = take 1 $ drop (n - 1) xs
245+ in concatMap element perm
src/Text/Pandoc/Readers/Org/ParserState.hs+18
@@ -39,6 +39,9 @@ module Text.Pandoc.Readers.Org.ParserState
3939 , TodoState (..)
4040 , activeTodoMarkers
4141 , registerTodoSequence
42+ , MacroExpander
43+ , lookupMacro
44+ , registerMacro
4245 , F
4346 , askF
4447 , asksF
@@ -78,6 +81,8 @@ type OrgNoteTable = [OrgNoteRecord]
7881-- | Map of functions for link transformations. The map key is refers to the
7982-- link-type, the corresponding function transforms the given link string.
8083type OrgLinkFormatters = M.Map String (String -> String)
84+-- | Macro expander function
85+type MacroExpander = [String] -> String
8186
8287-- | The states in which a todo item can be
8388data TodoState = Todo | Done
@@ -105,6 +110,8 @@ data OrgParserState = OrgParserState
105110 , orgStateLastPreCharPos :: Maybe SourcePos
106111 , orgStateLastStrPos :: Maybe SourcePos
107112 , orgStateLinkFormatters :: OrgLinkFormatters
113+ , orgStateMacros :: M.Map String MacroExpander
114+ , orgStateMacroDepth :: Int
108115 , orgStateMeta :: F Meta
109116 , orgStateNotes' :: OrgNoteTable
110117 , orgStateOptions :: ReaderOptions
@@ -156,6 +163,8 @@ defaultOrgParserState = OrgParserState
156163 , orgStateLastPreCharPos = Nothing
157164 , orgStateLastStrPos = Nothing
158165 , orgStateLinkFormatters = M.empty
166+ , orgStateMacros = M.empty
167+ , orgStateMacroDepth = 0
159168 , orgStateMeta = return nullMeta
160169 , orgStateNotes' = []
161170 , orgStateOptions = def
@@ -185,6 +194,15 @@ activeTodoSequences st =
185194activeTodoMarkers :: OrgParserState -> TodoSequence
186195activeTodoMarkers = concat . activeTodoSequences
187196
197+lookupMacro :: String -> OrgParserState -> Maybe MacroExpander
198+lookupMacro macroName = M.lookup macroName . orgStateMacros
199+
200+registerMacro :: (String, MacroExpander) -> OrgParserState -> OrgParserState
201+registerMacro (name, expander) st =
202+ let curMacros = orgStateMacros st
203+ in st{ orgStateMacros = M.insert name expander curMacros }
204+
205+
188206
189207--
190208-- Export Settings
test/Tests/Readers/Org.hs+18
@@ -469,6 +469,24 @@ tests =
469469 , citationNoteNum = 0
470470 , citationHash = 0}
471471 in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}")
472+
473+ , "Macro" =:
474+ unlines [ "#+MACRO: HELLO /Hello, $1/"
475+ , "{{{HELLO(World)}}}"
476+ ] =?>
477+ para (emph "Hello, World")
478+
479+ , "Macro repeting its argument" =:
480+ unlines [ "#+MACRO: HELLO $1$1"
481+ , "{{{HELLO(moin)}}}"
482+ ] =?>
483+ para "moinmoin"
484+
485+ , "Macro called with too few arguments" =:
486+ unlines [ "#+MACRO: HELLO Foo $1 $2 Bar"
487+ , "{{{HELLO()}}}"
488+ ] =?>
489+ para "Foo Bar"
472490 ]
473491
474492 , testGroup "Meta Information" $
test/command/3401.mdnew file+19
@@ -0,0 +1,19 @@
1+See #3401 and <http://orgmode.org/manual/Macro-replacement.html>
2+
3+```
4+% pandoc -f org -t native
5+#+MACRO: HELLO /Hello, $1/
6+{{{HELLO(World)}}}
7+^D
8+[Para [Emph [Str "Hello,",Space,Str "World"]]]
9+```
10+
11+Inverted argument order
12+
13+```
14+% pandoc -f org -t native
15+#+MACRO: A $2,$1
16+{{{A(1,2)}}}
17+^D
18+[Para [Str "2,1"]]
19+```