git.iko.soy/typeable/pandoc
on master help sign in
Org reader: strip planning info from output
ceec26fAlbert Krewinkel
src/Text/Pandoc/Readers/Org/DocumentTree.hs+35−1
@@ -70,6 +70,7 @@ documentTree blocks inline = do
70 , headlineTodoMarker = Nothing
70 , headlineTodoMarker = Nothing
71 , headlineText = B.fromList title'
71 , headlineText = B.fromList title'
72 , headlineTags = mempty
72 , headlineTags = mempty
73+ , headlinePlanning = emptyPlanning
73 , headlineProperties = mempty
74 , headlineProperties = mempty
74 , headlineContents = initialBlocks'
75 , headlineContents = initialBlocks'
75 , headlineChildren = headlines'
76 , headlineChildren = headlines'
@@ -117,6 +118,7 @@ data Headline = Headline
117 , headlineTodoMarker :: Maybe TodoMarker
118 , headlineTodoMarker :: Maybe TodoMarker
118 , headlineText :: Inlines
119 , headlineText :: Inlines
119 , headlineTags :: [Tag]
120 , headlineTags :: [Tag]
121+ , headlinePlanning :: PlanningInfo -- ^ subtree planning information
120 , headlineProperties :: Properties
122 , headlineProperties :: Properties
121 , headlineContents :: Blocks
123 , headlineContents :: Blocks
122 , headlineChildren :: [Headline]
124 , headlineChildren :: [Headline]
@@ -136,6 +138,7 @@ headline blocks inline lvl = try $ do
136 title <- trimInlinesF . mconcat <$> manyTill inline endOfTitle
138 title <- trimInlinesF . mconcat <$> manyTill inline endOfTitle
137 tags <- option [] headerTags
139 tags <- option [] headerTags
138 newline
140 newline
141+ planning <- option emptyPlanning planningInfo
139 properties <- option mempty propertiesDrawer
142 properties <- option mempty propertiesDrawer
140 contents <- blocks
143 contents <- blocks
141 children <- many (headline blocks inline (level + 1))
144 children <- many (headline blocks inline (level + 1))
@@ -148,6 +151,7 @@ headline blocks inline lvl = try $ do
148 , headlineTodoMarker = todoKw
151 , headlineTodoMarker = todoKw
149 , headlineText = title'
152 , headlineText = title'
150 , headlineTags = tags
153 , headlineTags = tags
154+ , headlinePlanning = planning
151 , headlineProperties = properties
155 , headlineProperties = properties
152 , headlineContents = contents'
156 , headlineContents = contents'
153 , headlineChildren = children'
157 , headlineChildren = children'
@@ -277,9 +281,39 @@ tagsToInlines tags =
277tagSpan :: Tag -> Inlines -> Inlines
281tagSpan :: Tag -> Inlines -> Inlines
278tagSpan t = B.spanWith ("", ["tag"], [("tag-name", fromTag t)])
282tagSpan t = B.spanWith ("", ["tag"], [("tag-name", fromTag t)])
279
283
284+-- | An Org timestamp, including repetition marks. TODO: improve
285+type Timestamp = String
286+
287+timestamp :: Monad m => OrgParser m Timestamp
288+timestamp = try $ do
289+ openChar <- oneOf "<["
290+ let isActive = openChar == '<'
291+ let closeChar = if isActive then '>' else ']'
292+ content <- many1Till anyChar (char closeChar)
293+ return (openChar : content ++ [closeChar])
294+
295+-- | Planning information for a subtree/headline.
296+data PlanningInfo = PlanningInfo
297+ { planningClosed :: Maybe Timestamp
298+ , planningDeadline :: Maybe Timestamp
299+ , planningScheduled :: Maybe Timestamp
300+ }
280
301
302+emptyPlanning :: PlanningInfo
303+emptyPlanning = PlanningInfo Nothing Nothing Nothing
281
304
282−
305+-- | Read a single planning-related and timestamped line.
306+planningInfo :: Monad m => OrgParser m PlanningInfo
307+planningInfo = try $ do
308+ updaters <- many1 planningDatum <* skipSpaces <* newline
309+ return $ foldr ($) emptyPlanning updaters
310+ where
311+ planningDatum = skipSpaces *> choice
312+ [ updateWith (\s p -> p { planningScheduled = Just s}) "SCHEDULED"
313+ , updateWith (\d p -> p { planningDeadline = Just d}) "DEADLINE"
314+ , updateWith (\c p -> p { planningClosed = Just c}) "CLOSED"
315+ ]
316+ updateWith fn cs = fn <$> (string cs *> char ':' *> skipSpaces *> timestamp)
283
317
284-- | Read a :PROPERTIES: drawer and return the key/value pairs contained
318-- | Read a :PROPERTIES: drawer and return the key/value pairs contained
285-- within.
319-- within.
test/Tests/Readers/Org/Block/Header.hs+25
@@ -181,4 +181,29 @@ tests =
181 , " :END:"
181 , " :END:"
182 ] =?>
182 ] =?>
183 headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered"
183 headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered"
184+
185+ , testGroup "planning information"
186+ [ "Planning info is not included in output" =:
187+ T.unlines [ "* important"
188+ , T.unwords
189+ [ "CLOSED: [2018-09-05 Wed 13:58]"
190+ , "DEADLINE: <2018-09-17 Mon>"
191+ , "SCHEDULED: <2018-09-10 Mon>"
192+ ]
193+ ] =?>
194+ headerWith ("important", [], []) 1 "important"
195+
196+ , "Properties after planning info are recognized" =:
197+ T.unlines [ "* important "
198+ , " " <> T.unwords
199+ [ "CLOSED: [2018-09-05 Wed 13:58]"
200+ , "DEADLINE: <2018-09-17 Mon>"
201+ , "SCHEDULED: <2018-09-10 Mon>"
202+ ]
203+ , " :PROPERTIES:"
204+ , " :custom_id: look"
205+ , " :END:"
206+ ] =?>
207+ headerWith ("look", [], []) 1 "important"
208+ ]
184 ]
209 ]