    -- | Adapted from how Shelly does finding in Shelly.Find
    -- (shelly is BSD-licensed)

    module System.FSNotify.Find where

    import Control.Monad
    import Control.Monad.IO.Class
    import System.Directory (doesDirectoryExist, listDirectory, pathIsSymbolicLink)
    import System.FilePath

    find :: Bool -> FilePath -> IO [FilePath]
    find :: Bool -> FilePath -> IO [FilePath]
    find Bool
    followSymlinks = Bool -> [FilePath] -> FilePath -> IO [FilePath]
    find' Bool
    followSymlinks  []

    find' :: Bool -> [FilePath] -> FilePath -> IO [FilePath]
    find' :: Bool -> [FilePath] -> FilePath -> IO [FilePath]
    find' Bool
    followSymlinks [FilePath]
    startValue FilePath
    dir = do
      (rPaths, aPaths) <- FilePath -> IO ([FilePath], [FilePath])
    lsRelAbs FilePath
    dir
      foldM visit startValue (zip rPaths aPaths)
      where
        visit :: [FilePath] -> (FilePath, FilePath) -> IO [FilePath]
    visit [FilePath]
    acc (FilePath
    relativePath, FilePath
    absolutePath) = do
          isDir <- IO Bool -> IO Bool
    forall a. IO a -> IO a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Bool -> IO Bool) -> IO Bool -> IO Bool
    forall a b. (a -> b) -> a -> b
    $ FilePath -> IO Bool
    doesDirectoryExist FilePath
    absolutePath
          sym <- liftIO $ pathIsSymbolicLink absolutePath
          let newAcc = FilePath
    relativePath FilePath -> [FilePath] -> [FilePath]
    forall a. a -> [a] -> [a]
    : [FilePath]
    acc
          if isDir && (followSymlinks || not sym)
            then find' followSymlinks newAcc relativePath
            else return newAcc

    lsRelAbs :: FilePath -> IO ([FilePath], [FilePath])
    lsRelAbs :: FilePath -> IO ([FilePath], [FilePath])
    lsRelAbs FilePath
    fp = do
      files <- IO [FilePath] -> IO [FilePath]
    forall a. IO a -> IO a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO [FilePath] -> IO [FilePath]) -> IO [FilePath] -> IO [FilePath]
    forall a b. (a -> b) -> a -> b
    $ FilePath -> IO [FilePath]
    listDirectory FilePath
    fp
      let absolute = (FilePath -> FilePath) -> [FilePath] -> [FilePath]
    forall a b. (a -> b) -> [a] -> [b]
    map (FilePath
    fp FilePath -> FilePath -> FilePath
    </>) [FilePath]
    files
      let relativized = (FilePath -> FilePath) -> [FilePath] -> [FilePath]
    forall a b. (a -> b) -> [a] -> [b]
    map (\FilePath
    p -> [FilePath] -> FilePath
    joinPath [FilePath
    fp, FilePath
    p]) [FilePath]
    files
      return (relativized, absolute)