@@ -28,8 +28,7 @@ Parsers for org-mode headlines and document subtrees
2828-}
2929module Text.Pandoc.Readers.Org.DocumentTree
3030 ( documentTree
31− , headlineToBlocks
32− , filterHeadlineTree
31+ , unprunedHeadlineToBlocks
3332 ) where
3433
3534import Prelude
@@ -37,6 +36,7 @@ import Control.Arrow ((***))
3736import Control.Monad (guard, void)
3837import Data.Char (toLower, toUpper)
3938import Data.List (intersperse)
39+import Data.Maybe (mapMaybe)
4040import Text.Pandoc.Builder (Blocks, Inlines)
4141import Text.Pandoc.Class (PandocMonad)
4242import Text.Pandoc.Definition
@@ -155,6 +155,22 @@ headline blocks inline lvl = try $ do
155155 let tag = orgTagWord <* char ':'
156156 in map toTag <$> (skipSpaces *> char ':' *> many1 tag <* skipSpaces)
157157
158+unprunedHeadlineToBlocks :: Monad m => Headline -> OrgParserState -> OrgParser m [Block]
159+unprunedHeadlineToBlocks hdln st =
160+ let usingSelectedTags = docContainsSelectTags hdln st
161+ rootNode = if not usingSelectedTags
162+ then hdln
163+ else includeRootAndSelected hdln st
164+ rootNode' = removeExplicitlyExcludedNodes rootNode st
165+ in if not usingSelectedTags ||
166+ any (`Set.member` orgStateSelectTags st) (headlineTags rootNode')
167+ then do headlineBlocks <- headlineToBlocks rootNode'
168+ -- ignore first headline, it's the document's title
169+ return . drop 1 . B.toList $ headlineBlocks
170+ else do headlineBlocks <- mconcat <$> mapM headlineToBlocks
171+ (headlineChildren rootNode')
172+ return . B.toList $ headlineBlocks
173+
158174-- | Convert an Org mode headline (i.e. a document tree) into pandoc's Blocks
159175headlineToBlocks :: Monad m => Headline -> OrgParser m Blocks
160176headlineToBlocks hdln = do
@@ -168,12 +184,40 @@ headlineToBlocks hdln = do
168184 _ | maxLevel <= level -> headlineToHeaderWithList hdln
169185 _ | otherwise -> headlineToHeaderWithContents hdln
170186
171−filterHeadlineTree :: Headline -> OrgParserState -> Headline
172−filterHeadlineTree hdln st =
187+removeExplicitlyExcludedNodes :: Headline -> OrgParserState -> Headline
188+removeExplicitlyExcludedNodes hdln st =
173189 hdln { headlineChildren =
174− [filterHeadlineTree childHdln st |
190+ [removeExplicitlyExcludedNodes childHdln st |
175191 childHdln <- headlineChildren hdln,
176− not $ any (`Set.member` orgStateExcludedTags st) (headlineTags childHdln)] }
192+ not $ headlineContainsExcludeTags childHdln st] }
193+
194+includeRootAndSelected :: Headline -> OrgParserState -> Headline
195+includeRootAndSelected hdln st =
196+ hdln { headlineChildren = mapMaybe (`includeAncestorsAndSelected` st)
197+ (headlineChildren hdln)}
198+
199+docContainsSelectTags :: Headline -> OrgParserState -> Bool
200+docContainsSelectTags hdln st =
201+ headlineContainsSelectTags hdln st ||
202+ any (`docContainsSelectTags` st) (headlineChildren hdln)
203+
204+includeAncestorsAndSelected :: Headline -> OrgParserState -> Maybe Headline
205+includeAncestorsAndSelected hdln st =
206+ if headlineContainsSelectTags hdln st
207+ then Just hdln
208+ else let children = mapMaybe (`includeAncestorsAndSelected` st)
209+ (headlineChildren hdln)
210+ in case children of
211+ [] -> Nothing
212+ _ -> Just $ hdln { headlineChildren = children }
213+
214+headlineContainsSelectTags :: Headline -> OrgParserState -> Bool
215+headlineContainsSelectTags hdln st =
216+ any (`Set.member` orgStateSelectTags st) (headlineTags hdln)
217+
218+headlineContainsExcludeTags :: Headline -> OrgParserState -> Bool
219+headlineContainsExcludeTags hdln st =
220+ any (`Set.member` orgStateExcludeTags st) (headlineTags hdln)
177221
178222isArchiveTag :: Tag -> Bool
179223isArchiveTag = (== toTag "ARCHIVE")