-- | Monadic directory tree. -- -- > -- List of files under "." or subfolders with ".markdown" extension, -- > -- except for those with a name starting with "_" somewhere in their path. (like "_cache/index.markdown") -- > markdownFiles :: ListT IO FilePath -- > markdownFiles -- > = filter ((== ".markdown") . takeExtension) -- only take files with a ".markdown" extension -- > . lastL -- get the leaves of the tree (files, not directories) -- > . scanl1 appendPath -- transform tree nodes to filenames including path -- > . prune (not . isPrefixOf "_") -- ignore directories or files whose name starts with "_" -- > $ directoryTree "." -- directory tree starting at "." -- -- Module name System.Directory.Tree is a better fit but it is taken by "directory-tree", a read-directory-tree-in-bulk module. module System.Directory.ListTree ( directoryTree, appendPath ) where import Control.Monad (guard) import Control.Monad.IO.Class (MonadIO (liftIO)) import Control.Monad.ListT (ListT) import Control.Monad.Trans.Class (MonadTrans (lift)) import Data.List.Class (cons, fromList) import Data.List.Tree (prune) import System.Directory (doesDirectoryExist, getDirectoryContents) import System.FilePath (joinPath) directoryTree :: MonadIO m => FilePath -> ListT (ListT m) FilePath directoryTree rootDir = prune (`notElem` [".", ".."]) $ do dirContentsList <- liftIO $ getDirectoryContents rootDir pathName <- lift $ fromList dirContentsList cons pathName $ do isDir <- liftIO . doesDirectoryExist $ joinPath [rootDir, pathName] guard isDir directoryTree $ joinPath [rootDir, pathName] -- | When used with @scanl@ or @scanl1@, transforms tree of filenames to tree of filenames with the paths appendPath :: FilePath -> FilePath -> FilePath appendPath x y = joinPath [x, y]