@@ -70,6 +70,7 @@ documentTree blocks inline = do
7070 , headlineTodoMarker = Nothing
7171 , headlineText = B.fromList title'
7272 , headlineTags = mempty
73+ , headlinePlanning = emptyPlanning
7374 , headlineProperties = mempty
7475 , headlineContents = initialBlocks'
7576 , headlineChildren = headlines'
@@ -117,6 +118,7 @@ data Headline = Headline
117118 , headlineTodoMarker :: Maybe TodoMarker
118119 , headlineText :: Inlines
119120 , headlineTags :: [Tag]
121+ , headlinePlanning :: PlanningInfo -- ^ subtree planning information
120122 , headlineProperties :: Properties
121123 , headlineContents :: Blocks
122124 , headlineChildren :: [Headline]
@@ -136,6 +138,7 @@ headline blocks inline lvl = try $ do
136138 title <- trimInlinesF . mconcat <$> manyTill inline endOfTitle
137139 tags <- option [] headerTags
138140 newline
141+ planning <- option emptyPlanning planningInfo
139142 properties <- option mempty propertiesDrawer
140143 contents <- blocks
141144 children <- many (headline blocks inline (level + 1))
@@ -148,6 +151,7 @@ headline blocks inline lvl = try $ do
148151 , headlineTodoMarker = todoKw
149152 , headlineText = title'
150153 , headlineTags = tags
154+ , headlinePlanning = planning
151155 , headlineProperties = properties
152156 , headlineContents = contents'
153157 , headlineChildren = children'
@@ -277,9 +281,39 @@ tagsToInlines tags =
277281tagSpan :: Tag -> Inlines -> Inlines
278282tagSpan t = B.spanWith ("", ["tag"], [("tag-name", fromTag t)])
279283
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+ }
280301
302+emptyPlanning :: PlanningInfo
303+emptyPlanning = PlanningInfo Nothing Nothing Nothing
281304
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)
283317
284318-- | Read a :PROPERTIES: drawer and return the key/value pairs contained
285319-- within.