packages feed

filepather-0.5: src/System/FilePath/FilePather/Find.hs

{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE NoImplicitPrelude #-}

module System.FilePath.FilePather.Find(
  findWith
, findDirectories
, findAll
, findAllFiles
) where

import Control.Applicative ( Applicative(pure) )
import Control.Category ( Category((.)) )
import Control.Exception ( Exception )
import Control.Lens ( view, _Wrapped )
import Control.Monad ( Monad((>>=)), filterM )
import Control.Monad.IO.Class ( MonadIO(liftIO) )
import Control.Monad.Reader ( MonadReader(local, ask) )
import Data.Bool ( Bool(True) )
import Data.Foldable ( fold )
import Data.Functor ( Functor(fmap), (<$>) )
import Data.Semigroup ( Semigroup((<>)) )
import Data.Traversable ( Traversable(traverse) )
import System.FilePath ( FilePath, (</>) )
import System.FilePath.FilePather.Directory
    ( listDirectory, doesFileExist, doesDirectoryExist )
import System.FilePath.FilePather.ReadFilePath ( ReadFilePathT )
import System.IO ( IO )
import System.IO.Unsafe( unsafeInterleaveIO )

findWith ::
  Exception e =>
  ReadFilePathT e IO Bool
  -> ReadFilePathT e IO [FilePath]
findWith p =
  let setl =
        local . pure
  in  do  z <- ask
          a <- listDirectory
          b <- filterM (`setl` p) ((z </>) <$> a)
          d <- filterM (`setl` doesDirectoryExist) b
          case d of
            [] ->
              pure b
            _ ->
              do  n <- liftIO (unsafeInterleaveIO (fmap (>>= fold) (traverse (view _Wrapped (findWith p)) d)))
                  pure (b <> n)

findDirectories ::
  Exception e =>
  ReadFilePathT e IO [FilePath]
findDirectories =
  findWith doesDirectoryExist

findAll ::
  Exception e =>
  ReadFilePathT e IO [FilePath]
findAll =
  findWith (pure True)

findAllFiles ::
  Exception e =>
  ReadFilePathT e IO [FilePath]
findAllFiles =
  findAll >>= filterM (\p -> local (pure p) doesFileExist)