hsinspect-0.1.0: library/HsInspect/Util.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE NamedFieldPuns #-}
module HsInspect.Util where
#if MIN_VERSION_GLASGOW_HASKELL(9,1,0,0)
import qualified GHC.Utils.Outputable as GHC
#elif MIN_VERSION_GLASGOW_HASKELL(9,0,0,0)
import qualified GHC.Utils.Outputable as GHC
import qualified GHC.Driver.Session as GHC
#else
import qualified DynFlags as GHC
import qualified Outputable as GHC
#endif
import qualified GHC as GHC
import Control.Monad.IO.Class
import Data.List (find, isSuffixOf, nub)
import Data.Maybe (catMaybes)
import Data.Set (Set)
import qualified Data.Set as Set
import System.Directory (doesDirectoryExist, listDirectory, makeAbsolute)
import System.FilePath (takeDirectory, takeFileName, (</>))
homeSources :: GHC.GhcMonad m => m [FilePath]
homeSources = do
dflags <- GHC.getSessionDynFlags
paths <- liftIO . traverse makeAbsolute $ GHC.importPaths dflags
let infer dir = liftIO $ walkSuffix ".hs" dir
nub . concat <$> traverse infer paths
showGhc :: (GHC.Outputable a) => a -> String
#if MIN_VERSION_GLASGOW_HASKELL(9,1,0,0)
showGhc = GHC.showPprUnsafe
#else
showGhc = GHC.showPpr GHC.unsafeGlobalDynFlags
#endif
getTargetModules :: GHC.GhcMonad m => m (Set GHC.ModuleName)
getTargetModules = do
args <- GHC.getTargets
pure . Set.fromList . catMaybes $ getModule <$> args
where
getModule :: GHC.Target -> Maybe GHC.ModuleName
getModule GHC.Target{GHC.targetId} = case targetId of
GHC.TargetModule m -> Just m
GHC.TargetFile _ _ -> Nothing
-- returns the first file that matches the predicate
locateDominating :: (String -> Bool) -> FilePath -> IO (Maybe FilePath)
locateDominating p dir = do
files <- listDirectory dir
let parent = takeDirectory dir
case find p $ takeFileName <$> files of
Just file -> pure . Just $ dir </> file
Nothing ->
if parent == dir
then pure Nothing
else locateDominating p parent
-- the first parent directory where a file or directory name matches the predicate
locateDominatingDir :: (String -> Bool) -> FilePath -> IO (Maybe FilePath)
locateDominatingDir p dir = do
file' <- locateDominating p dir
pure $ takeDirectory <$> file'
walkSuffix :: String -> FilePath -> IO [FilePath]
walkSuffix suffix dir = filter (suffix `isSuffixOf`) <$> walk dir
walk :: FilePath -> IO [FilePath]
walk dir = do
isDir <- doesDirectoryExist dir
if isDir
then do
fs <- listDirectory dir
let base = dir <> "/"
qfs = (base <>) <$> fs
concatMapM walk qfs
else pure [dir]
-- from extra
concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
concatMapM op = foldr f (pure [])
where
f x xs = do
x' <- op x
if null x'
then xs
else do
xs' <- xs
pure $ x' ++ xs'
-- from extra
split :: (a -> Bool) -> [a] -> [[a]]
split _ [] = [[]]
split f (x : xs) | f x = [] : split f xs
| y : ys <- split f xs = (x : y) : ys
| otherwise = [[]] -- never happens