{-# LANGUAGE RecordWildCards, CPP #-}
module HIE.Bios.Environment (initSession, getRuntimeGhcLibDir, getRuntimeGhcVersion, makeDynFlagsAbsolute, makeTargetsAbsolute, getCacheDir, addCmdOpts) where
import CoreMonad (liftIO)
import GHC (GhcMonad)
import qualified GHC as G
import qualified DriverPhases as G
import qualified Util as G
import DynFlags
import Control.Applicative
import Control.Monad (void)
import System.Directory
import System.FilePath
import System.Environment (lookupEnv)
import qualified Crypto.Hash.SHA1 as H
import qualified Data.ByteString.Char8 as B
import Data.ByteString.Base16
import Data.List
import Data.Char (isSpace)
import Text.ParserCombinators.ReadP hiding (optional)
import HIE.Bios.Types
import HIE.Bios.Ghc.Gap
initSession :: (GhcMonad m)
=> ComponentOptions
-> m [G.Target]
initSession :: ComponentOptions -> m [Target]
initSession ComponentOptions {FilePath
[FilePath]
componentDependencies :: ComponentOptions -> [FilePath]
componentRoot :: ComponentOptions -> FilePath
componentOptions :: ComponentOptions -> [FilePath]
componentDependencies :: [FilePath]
componentRoot :: FilePath
componentOptions :: [FilePath]
..} = do
DynFlags
df <- m DynFlags
forall (m :: * -> *). GhcMonad m => m DynFlags
G.getSessionDynFlags
let opts_hash :: FilePath
opts_hash = ByteString -> FilePath
B.unpack (ByteString -> FilePath) -> ByteString -> FilePath
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
encode (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Ctx -> ByteString
H.finalize (Ctx -> ByteString) -> Ctx -> ByteString
forall a b. (a -> b) -> a -> b
$ Ctx -> [ByteString] -> Ctx
H.updates Ctx
H.init ((FilePath -> ByteString) -> [FilePath] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map FilePath -> ByteString
B.pack [FilePath]
componentOptions)
FilePath
cache_dir <- IO FilePath -> m FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> m FilePath) -> IO FilePath -> m FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> IO FilePath
getCacheDir FilePath
opts_hash
(DynFlags
df', [Target]
targets) <- [FilePath] -> DynFlags -> m (DynFlags, [Target])
forall (m :: * -> *).
GhcMonad m =>
[FilePath] -> DynFlags -> m (DynFlags, [Target])
addCmdOpts [FilePath]
componentOptions DynFlags
df
let df'' :: DynFlags
df'' = FilePath -> DynFlags -> DynFlags
makeDynFlagsAbsolute FilePath
componentRoot DynFlags
df'
m [InstalledUnitId] -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m [InstalledUnitId] -> m ()) -> m [InstalledUnitId] -> m ()
forall a b. (a -> b) -> a -> b
$ DynFlags -> m [InstalledUnitId]
forall (m :: * -> *). GhcMonad m => DynFlags -> m [InstalledUnitId]
G.setSessionDynFlags
(DynFlags -> DynFlags
disableOptimisation
(DynFlags -> DynFlags) -> DynFlags -> DynFlags
forall a b. (a -> b) -> a -> b
$ DynFlags -> DynFlags
setIgnoreInterfacePragmas
(DynFlags -> DynFlags) -> DynFlags -> DynFlags
forall a b. (a -> b) -> a -> b
$ Maybe FilePath -> DynFlags -> DynFlags
writeInterfaceFiles (FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
cache_dir)
(DynFlags -> DynFlags) -> DynFlags -> DynFlags
forall a b. (a -> b) -> a -> b
$ Int -> DynFlags -> DynFlags
setVerbosity Int
0
(DynFlags -> DynFlags) -> DynFlags -> DynFlags
forall a b. (a -> b) -> a -> b
$ DynFlags -> DynFlags
setLinkerOptions DynFlags
df''
)
let targets' :: [Target]
targets' = FilePath -> [Target] -> [Target]
makeTargetsAbsolute FilePath
componentRoot [Target]
targets
m ()
forall (m :: * -> *). GhcMonad m => m ()
unsetLogAction
[Target] -> m [Target]
forall (m :: * -> *) a. Monad m => a -> m a
return [Target]
targets'
makeTargetsAbsolute :: FilePath -> [G.Target] -> [G.Target]
makeTargetsAbsolute :: FilePath -> [Target] -> [Target]
makeTargetsAbsolute FilePath
wdir = (Target -> Target) -> [Target] -> [Target]
forall a b. (a -> b) -> [a] -> [b]
map (\Target
target -> Target
target {targetId :: TargetId
G.targetId = FilePath -> TargetId -> TargetId
makeTargetIdAbsolute FilePath
wdir (Target -> TargetId
G.targetId Target
target)})
makeTargetIdAbsolute :: FilePath -> G.TargetId -> G.TargetId
makeTargetIdAbsolute :: FilePath -> TargetId -> TargetId
makeTargetIdAbsolute FilePath
wdir (G.TargetFile FilePath
fp Maybe Phase
phase) = FilePath -> Maybe Phase -> TargetId
G.TargetFile (FilePath
wdir FilePath -> FilePath -> FilePath
</> FilePath
fp) Maybe Phase
phase
makeTargetIdAbsolute FilePath
_ TargetId
tid = TargetId
tid
getRuntimeGhcLibDir :: Cradle a
-> IO (CradleLoadResult FilePath)
getRuntimeGhcLibDir :: Cradle a -> IO (CradleLoadResult FilePath)
getRuntimeGhcLibDir Cradle a
cradle = do
Maybe FilePath
maybeNixLibDir <- FilePath -> IO (Maybe FilePath)
lookupEnv FilePath
"NIX_GHC_LIBDIR"
case Maybe FilePath
maybeNixLibDir of
Just FilePath
ld -> CradleLoadResult FilePath -> IO (CradleLoadResult FilePath)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (FilePath -> CradleLoadResult FilePath
forall r. r -> CradleLoadResult r
CradleSuccess FilePath
ld)
Maybe FilePath
Nothing -> (CradleLoadResult FilePath -> CradleLoadResult FilePath)
-> IO (CradleLoadResult FilePath) -> IO (CradleLoadResult FilePath)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((FilePath -> FilePath)
-> CradleLoadResult FilePath -> CradleLoadResult FilePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FilePath -> FilePath
trim) (IO (CradleLoadResult FilePath) -> IO (CradleLoadResult FilePath))
-> IO (CradleLoadResult FilePath) -> IO (CradleLoadResult FilePath)
forall a b. (a -> b) -> a -> b
$
CradleAction a -> [FilePath] -> IO (CradleLoadResult FilePath)
forall a.
CradleAction a -> [FilePath] -> IO (CradleLoadResult FilePath)
runGhcCmd (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
cradle) [FilePath
"--print-libdir"]
getRuntimeGhcVersion :: Cradle a
-> IO (CradleLoadResult String)
getRuntimeGhcVersion :: Cradle a -> IO (CradleLoadResult FilePath)
getRuntimeGhcVersion Cradle a
cradle =
(CradleLoadResult FilePath -> CradleLoadResult FilePath)
-> IO (CradleLoadResult FilePath) -> IO (CradleLoadResult FilePath)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((FilePath -> FilePath)
-> CradleLoadResult FilePath -> CradleLoadResult FilePath
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap FilePath -> FilePath
trim) (IO (CradleLoadResult FilePath) -> IO (CradleLoadResult FilePath))
-> IO (CradleLoadResult FilePath) -> IO (CradleLoadResult FilePath)
forall a b. (a -> b) -> a -> b
$ CradleAction a -> [FilePath] -> IO (CradleLoadResult FilePath)
forall a.
CradleAction a -> [FilePath] -> IO (CradleLoadResult FilePath)
runGhcCmd (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
cradle) [FilePath
"--numeric-version"]
cacheDir :: String
cacheDir :: FilePath
cacheDir = FilePath
"hie-bios"
getCacheDir :: FilePath -> IO FilePath
getCacheDir :: FilePath -> IO FilePath
getCacheDir FilePath
fp = do
Maybe FilePath
mbEnvCacheDirectory <- FilePath -> IO (Maybe FilePath)
lookupEnv FilePath
"HIE_BIOS_CACHE_DIR"
FilePath
cacheBaseDir <- IO FilePath
-> (FilePath -> IO FilePath) -> Maybe FilePath -> IO FilePath
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (XdgDirectory -> FilePath -> IO FilePath
getXdgDirectory XdgDirectory
XdgCache FilePath
cacheDir) FilePath -> IO FilePath
forall (m :: * -> *) a. Monad m => a -> m a
return
Maybe FilePath
mbEnvCacheDirectory
FilePath -> IO FilePath
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath
cacheBaseDir FilePath -> FilePath -> FilePath
</> FilePath
fp)
setLinkerOptions :: DynFlags -> DynFlags
setLinkerOptions :: DynFlags -> DynFlags
setLinkerOptions DynFlags
df = DynFlags
df {
ghcLink :: GhcLink
ghcLink = GhcLink
LinkInMemory
, hscTarget :: HscTarget
hscTarget = HscTarget
HscNothing
, ghcMode :: GhcMode
ghcMode = GhcMode
CompManager
}
setIgnoreInterfacePragmas :: DynFlags -> DynFlags
setIgnoreInterfacePragmas :: DynFlags -> DynFlags
setIgnoreInterfacePragmas DynFlags
df = DynFlags -> GeneralFlag -> DynFlags
gopt_set DynFlags
df GeneralFlag
Opt_IgnoreInterfacePragmas
setVerbosity :: Int -> DynFlags -> DynFlags
setVerbosity :: Int -> DynFlags -> DynFlags
setVerbosity Int
n DynFlags
df = DynFlags
df { verbosity :: Int
verbosity = Int
n }
writeInterfaceFiles :: Maybe FilePath -> DynFlags -> DynFlags
writeInterfaceFiles :: Maybe FilePath -> DynFlags -> DynFlags
writeInterfaceFiles Maybe FilePath
Nothing DynFlags
df = DynFlags
df
writeInterfaceFiles (Just FilePath
hi_dir) DynFlags
df = FilePath -> DynFlags -> DynFlags
setHiDir FilePath
hi_dir (DynFlags -> GeneralFlag -> DynFlags
gopt_set DynFlags
df GeneralFlag
Opt_WriteInterface)
setHiDir :: FilePath -> DynFlags -> DynFlags
setHiDir :: FilePath -> DynFlags -> DynFlags
setHiDir FilePath
f DynFlags
d = DynFlags
d { hiDir :: Maybe FilePath
hiDir = FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
f}
addCmdOpts :: (GhcMonad m)
=> [String] -> DynFlags -> m (DynFlags, [G.Target])
addCmdOpts :: [FilePath] -> DynFlags -> m (DynFlags, [Target])
addCmdOpts [FilePath]
cmdOpts DynFlags
df1 = do
(DynFlags
df2, [Located FilePath]
leftovers', [Warn]
_warns) <- DynFlags
-> [Located FilePath] -> m (DynFlags, [Located FilePath], [Warn])
forall (m :: * -> *).
MonadIO m =>
DynFlags
-> [Located FilePath] -> m (DynFlags, [Located FilePath], [Warn])
G.parseDynamicFlags DynFlags
df1 ((FilePath -> Located FilePath) -> [FilePath] -> [Located FilePath]
forall a b. (a -> b) -> [a] -> [b]
map FilePath -> Located FilePath
forall a. HasSrcSpan a => SrcSpanLess a -> a
G.noLoc [FilePath]
cmdOpts)
[FilePath]
additionalTargets <- [[FilePath]] -> [FilePath]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[FilePath]] -> [FilePath]) -> m [[FilePath]] -> m [FilePath]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (FilePath -> m [FilePath]) -> [FilePath] -> m [[FilePath]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (IO [FilePath] -> m [FilePath]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [FilePath] -> m [FilePath])
-> (FilePath -> IO [FilePath]) -> FilePath -> m [FilePath]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO [FilePath]
getTargetsFromGhciScript) (DynFlags -> [FilePath]
ghciScripts DynFlags
df2)
let leftovers :: [Located FilePath]
leftovers = [Located FilePath]
leftovers' [Located FilePath] -> [Located FilePath] -> [Located FilePath]
forall a. [a] -> [a] -> [a]
++ (FilePath -> Located FilePath) -> [FilePath] -> [Located FilePath]
forall a b. (a -> b) -> [a] -> [b]
map FilePath -> Located FilePath
forall a. HasSrcSpan a => SrcSpanLess a -> a
G.noLoc [FilePath]
additionalTargets
let
normalise_hyp :: FilePath -> FilePath
normalise_hyp FilePath
fp
| Bool
strt_dot_sl Bool -> Bool -> Bool
&& FilePath
"-" FilePath -> FilePath -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` FilePath
nfp = FilePath
cur_dir FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
nfp
| Bool
otherwise = FilePath
nfp
where
#if defined(mingw32_HOST_OS)
strt_dot_sl = "./" `isPrefixOf` fp || ".\\" `isPrefixOf` fp
#else
strt_dot_sl :: Bool
strt_dot_sl = FilePath
"./" FilePath -> FilePath -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` FilePath
fp
#endif
cur_dir :: FilePath
cur_dir = Char
'.' Char -> FilePath -> FilePath
forall a. a -> [a] -> [a]
: [Char
pathSeparator]
nfp :: FilePath
nfp = FilePath -> FilePath
normalise FilePath
fp
normal_fileish_paths :: [FilePath]
normal_fileish_paths = (Located FilePath -> FilePath) -> [Located FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath -> FilePath
normalise_hyp (FilePath -> FilePath)
-> (Located FilePath -> FilePath) -> Located FilePath -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Located FilePath -> FilePath
forall a. HasSrcSpan a => a -> SrcSpanLess a
G.unLoc) [Located FilePath]
leftovers
let
([(FilePath, Maybe Phase)]
srcs, [FilePath]
objs) = [FilePath]
-> [(FilePath, Maybe Phase)]
-> [FilePath]
-> ([(FilePath, Maybe Phase)], [FilePath])
partition_args [FilePath]
normal_fileish_paths [] []
df3 :: DynFlags
df3 = DynFlags
df2 { ldInputs :: [Option]
ldInputs = (FilePath -> Option) -> [FilePath] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath -> FilePath -> Option
FileOption FilePath
"") [FilePath]
objs [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ DynFlags -> [Option]
ldInputs DynFlags
df2 }
[Target]
ts <- ((FilePath, Maybe Phase) -> m Target)
-> [(FilePath, Maybe Phase)] -> m [Target]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ((FilePath -> Maybe Phase -> m Target)
-> (FilePath, Maybe Phase) -> m Target
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry FilePath -> Maybe Phase -> m Target
forall (m :: * -> *).
GhcMonad m =>
FilePath -> Maybe Phase -> m Target
G.guessTarget) [(FilePath, Maybe Phase)]
srcs
(DynFlags, [Target]) -> m (DynFlags, [Target])
forall (m :: * -> *) a. Monad m => a -> m a
return (DynFlags
df3, [Target]
ts)
makeDynFlagsAbsolute :: FilePath -> DynFlags -> DynFlags
makeDynFlagsAbsolute :: FilePath -> DynFlags -> DynFlags
makeDynFlagsAbsolute FilePath
work_dir DynFlags
df =
(FilePath -> FilePath) -> DynFlags -> DynFlags
mapOverIncludePaths (FilePath
work_dir FilePath -> FilePath -> FilePath
</>)
(DynFlags -> DynFlags) -> DynFlags -> DynFlags
forall a b. (a -> b) -> a -> b
$ DynFlags
df
{ importPaths :: [FilePath]
importPaths = (FilePath -> FilePath) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map (FilePath
work_dir FilePath -> FilePath -> FilePath
</>) (DynFlags -> [FilePath]
importPaths DynFlags
df)
, packageDBFlags :: [PackageDBFlag]
packageDBFlags =
let makePackageDbAbsolute :: PackageDBFlag -> PackageDBFlag
makePackageDbAbsolute (PackageDB PkgConfRef
pkgConfRef) = PkgConfRef -> PackageDBFlag
PackageDB
(PkgConfRef -> PackageDBFlag) -> PkgConfRef -> PackageDBFlag
forall a b. (a -> b) -> a -> b
$ case PkgConfRef
pkgConfRef of
PkgConfFile FilePath
fp -> FilePath -> PkgConfRef
PkgConfFile (FilePath
work_dir FilePath -> FilePath -> FilePath
</> FilePath
fp)
PkgConfRef
conf -> PkgConfRef
conf
makePackageDbAbsolute PackageDBFlag
db = PackageDBFlag
db
in (PackageDBFlag -> PackageDBFlag)
-> [PackageDBFlag] -> [PackageDBFlag]
forall a b. (a -> b) -> [a] -> [b]
map PackageDBFlag -> PackageDBFlag
makePackageDbAbsolute (DynFlags -> [PackageDBFlag]
packageDBFlags DynFlags
df)
}
partition_args :: [String] -> [(String, Maybe G.Phase)] -> [String]
-> ([(String, Maybe G.Phase)], [String])
partition_args :: [FilePath]
-> [(FilePath, Maybe Phase)]
-> [FilePath]
-> ([(FilePath, Maybe Phase)], [FilePath])
partition_args [] [(FilePath, Maybe Phase)]
srcs [FilePath]
objs = ([(FilePath, Maybe Phase)] -> [(FilePath, Maybe Phase)]
forall a. [a] -> [a]
reverse [(FilePath, Maybe Phase)]
srcs, [FilePath] -> [FilePath]
forall a. [a] -> [a]
reverse [FilePath]
objs)
partition_args (FilePath
"-x":FilePath
suff:[FilePath]
args) [(FilePath, Maybe Phase)]
srcs [FilePath]
objs
| FilePath
"none" <- FilePath
suff = [FilePath]
-> [(FilePath, Maybe Phase)]
-> [FilePath]
-> ([(FilePath, Maybe Phase)], [FilePath])
partition_args [FilePath]
args [(FilePath, Maybe Phase)]
srcs [FilePath]
objs
| Phase
G.StopLn <- Phase
phase = [FilePath]
-> [(FilePath, Maybe Phase)]
-> [FilePath]
-> ([(FilePath, Maybe Phase)], [FilePath])
partition_args [FilePath]
args [(FilePath, Maybe Phase)]
srcs ([FilePath]
slurp [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ [FilePath]
objs)
| Bool
otherwise = [FilePath]
-> [(FilePath, Maybe Phase)]
-> [FilePath]
-> ([(FilePath, Maybe Phase)], [FilePath])
partition_args [FilePath]
rest ([(FilePath, Maybe Phase)]
these_srcs [(FilePath, Maybe Phase)]
-> [(FilePath, Maybe Phase)] -> [(FilePath, Maybe Phase)]
forall a. [a] -> [a] -> [a]
++ [(FilePath, Maybe Phase)]
srcs) [FilePath]
objs
where phase :: Phase
phase = FilePath -> Phase
G.startPhase FilePath
suff
([FilePath]
slurp,[FilePath]
rest) = (FilePath -> Bool) -> [FilePath] -> ([FilePath], [FilePath])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
"-x") [FilePath]
args
these_srcs :: [(FilePath, Maybe Phase)]
these_srcs = [FilePath] -> [Maybe Phase] -> [(FilePath, Maybe Phase)]
forall a b. [a] -> [b] -> [(a, b)]
zip [FilePath]
slurp (Maybe Phase -> [Maybe Phase]
forall a. a -> [a]
repeat (Phase -> Maybe Phase
forall a. a -> Maybe a
Just Phase
phase))
partition_args (FilePath
arg:[FilePath]
args) [(FilePath, Maybe Phase)]
srcs [FilePath]
objs
| FilePath -> Bool
looks_like_an_input FilePath
arg = [FilePath]
-> [(FilePath, Maybe Phase)]
-> [FilePath]
-> ([(FilePath, Maybe Phase)], [FilePath])
partition_args [FilePath]
args ((FilePath
arg,Maybe Phase
forall a. Maybe a
Nothing)(FilePath, Maybe Phase)
-> [(FilePath, Maybe Phase)] -> [(FilePath, Maybe Phase)]
forall a. a -> [a] -> [a]
:[(FilePath, Maybe Phase)]
srcs) [FilePath]
objs
| Bool
otherwise = [FilePath]
-> [(FilePath, Maybe Phase)]
-> [FilePath]
-> ([(FilePath, Maybe Phase)], [FilePath])
partition_args [FilePath]
args [(FilePath, Maybe Phase)]
srcs (FilePath
argFilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
:[FilePath]
objs)
looks_like_an_input :: String -> Bool
looks_like_an_input :: FilePath -> Bool
looks_like_an_input FilePath
m = FilePath -> Bool
G.isSourceFilename FilePath
m
Bool -> Bool -> Bool
|| FilePath -> Bool
G.looksLikeModuleName FilePath
m
Bool -> Bool -> Bool
|| FilePath
"-" FilePath -> FilePath -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` FilePath
m
Bool -> Bool -> Bool
|| Bool -> Bool
not (FilePath -> Bool
hasExtension FilePath
m)
disableOptimisation :: DynFlags -> DynFlags
disableOptimisation :: DynFlags -> DynFlags
disableOptimisation DynFlags
df = Int -> DynFlags -> DynFlags
updOptLevel Int
0 DynFlags
df
getTargetsFromGhciScript :: FilePath -> IO [String]
getTargetsFromGhciScript :: FilePath -> IO [FilePath]
getTargetsFromGhciScript FilePath
script = do
[FilePath]
contents <- FilePath -> [FilePath]
lines (FilePath -> [FilePath]) -> IO FilePath -> IO [FilePath]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> FilePath -> IO FilePath
readFile FilePath
script
let parseGhciLine :: FilePath -> [FilePath]
parseGhciLine = (([FilePath], FilePath) -> [FilePath])
-> [([FilePath], FilePath)] -> [FilePath]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([FilePath], FilePath) -> [FilePath]
forall a b. (a, b) -> a
fst ([([FilePath], FilePath)] -> [FilePath])
-> (FilePath -> [([FilePath], FilePath)]) -> FilePath -> [FilePath]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (([FilePath], FilePath) -> Bool)
-> [([FilePath], FilePath)] -> [([FilePath], FilePath)]
forall a. (a -> Bool) -> [a] -> [a]
filter (FilePath -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (FilePath -> Bool)
-> (([FilePath], FilePath) -> FilePath)
-> ([FilePath], FilePath)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([FilePath], FilePath) -> FilePath
forall a b. (a, b) -> b
snd) ([([FilePath], FilePath)] -> [([FilePath], FilePath)])
-> (FilePath -> [([FilePath], FilePath)])
-> FilePath
-> [([FilePath], FilePath)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReadP [FilePath] -> FilePath -> [([FilePath], FilePath)]
forall a. ReadP a -> ReadS a
readP_to_S ReadP [FilePath]
parser
[FilePath] -> IO [FilePath]
forall (m :: * -> *) a. Monad m => a -> m a
return ([FilePath] -> IO [FilePath]) -> [FilePath] -> IO [FilePath]
forall a b. (a -> b) -> a -> b
$ (FilePath -> [FilePath]) -> [FilePath] -> [FilePath]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap FilePath -> [FilePath]
parseGhciLine [FilePath]
contents
parser :: ReadP [String]
parser :: ReadP [FilePath]
parser = do
FilePath
_ <- FilePath -> ReadP FilePath
string FilePath
":add" ReadP FilePath -> ReadP FilePath -> ReadP FilePath
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ReadP FilePath
space1
ReadP FilePath
scriptword ReadP FilePath -> ReadP FilePath -> ReadP [FilePath]
forall a sep. ReadP a -> ReadP sep -> ReadP [a]
`sepBy` ReadP FilePath
space1
space1 :: ReadP [Char]
space1 :: ReadP FilePath
space1 = ReadP Char -> ReadP FilePath
forall a. ReadP a -> ReadP [a]
many1 (Char -> ReadP Char
char Char
' ')
scriptword :: ReadP String
scriptword :: ReadP FilePath
scriptword = ReadP FilePath
quoted ReadP FilePath -> ReadP FilePath -> ReadP FilePath
forall a. ReadP a -> ReadP a -> ReadP a
<++ ReadP FilePath
value
quoted :: ReadP String
quoted :: ReadP FilePath
quoted = do
Char
_ <- Char -> ReadP Char
char Char
'"'
ReadP Char -> ReadP Char -> ReadP FilePath
forall a sep. ReadP a -> ReadP sep -> ReadP [a]
manyTill (Char -> ReadP Char
escaped Char
'"' ReadP Char -> ReadP Char -> ReadP Char
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ReadP Char
anyToken) (ReadP Char -> ReadP FilePath) -> ReadP Char -> ReadP FilePath
forall a b. (a -> b) -> a -> b
$ Char -> ReadP Char
char Char
'"'
escaped :: Char -> ReadP Char
escaped :: Char -> ReadP Char
escaped Char
c = Char
c Char -> ReadP FilePath -> ReadP Char
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ FilePath -> ReadP FilePath
string (FilePath
"\\" FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> [Char
c])
value :: ReadP String
value :: ReadP FilePath
value = ReadP Char -> ReadP FilePath
forall a. ReadP a -> ReadP [a]
many1 ((Char -> Bool) -> ReadP Char
satisfy (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace))
anyToken :: ReadP Char
anyToken :: ReadP Char
anyToken = (Char -> Bool) -> ReadP Char
satisfy ((Char -> Bool) -> ReadP Char) -> (Char -> Bool) -> ReadP Char
forall a b. (a -> b) -> a -> b
$ Bool -> Char -> Bool
forall a b. a -> b -> a
const Bool
True
trim :: String -> String
trim :: FilePath -> FilePath
trim FilePath
s = case FilePath -> [FilePath]
lines FilePath
s of
[] -> FilePath
s
[FilePath]
ls -> (Char -> Bool) -> FilePath -> FilePath
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd Char -> Bool
isSpace (FilePath -> FilePath) -> FilePath -> FilePath
forall a b. (a -> b) -> a -> b
$ [FilePath] -> FilePath
forall a. [a] -> a
last [FilePath]
ls