@@ -14,6 +14,10 @@ module Stack.Ghci
14
14
, GhciException (.. )
15
15
, ghciSetup
16
16
, ghci
17
+
18
+ -- TODO: Address what should and should not be exported.
19
+ , renderScriptGhci
20
+ , renderScriptIntero
17
21
) where
18
22
19
23
import Control.Applicative
@@ -30,7 +34,6 @@ import Data.Either
30
34
import Data.Function
31
35
import Data.List
32
36
import Data.List.Extra (nubOrd )
33
- import Data.List.Split (splitOn )
34
37
import Data.Map.Strict (Map )
35
38
import qualified Data.Map.Strict as M
36
39
import Data.Maybe
@@ -42,7 +45,6 @@ import Data.Traversable (forM)
42
45
import Data.Text (Text )
43
46
import qualified Data.Text as T
44
47
import Data.Typeable (Typeable )
45
- import Distribution.ModuleName (ModuleName )
46
48
import Distribution.PackageDescription (updatePackageDescription )
47
49
import Distribution.Text (display )
48
50
import Network.HTTP.Client.Conduit
@@ -56,6 +58,7 @@ import Stack.Build.Source
56
58
import Stack.Build.Target
57
59
import Stack.Constants
58
60
import Stack.Exec
61
+ import Stack.Ghci.Script
59
62
import Stack.Package
60
63
import Stack.Types.PackageIdentifier
61
64
import Stack.Types.PackageName
@@ -64,7 +67,6 @@ import Stack.Types.Build
64
67
import Stack.Types.Package
65
68
import Stack.Types.Compiler
66
69
import Stack.Types.Internal
67
- import System.FilePath (takeBaseName )
68
70
import Text.Read (readMaybe )
69
71
70
72
#ifndef WINDOWS
@@ -142,25 +144,8 @@ ghci opts@GhciOpts{..} = do
142
144
$ logWarn
143
145
(" The following GHC options are incompatible with GHCi and have not been passed to it: " <>
144
146
T. unwords (map T. pack (nubOrd omittedOpts)))
145
- allModules <- checkForDuplicateModules ghciNoLoadModules pkgs
147
+ mainFile <- figureOutMainFile bopts mainIsTargets targets pkgs
146
148
oiDir <- objectInterfaceDir bconfig
147
- (modulesToLoad, mainFile) <- if ghciNoLoadModules then return ([] , Nothing ) else do
148
- mmainFile <- figureOutMainFile bopts mainIsTargets targets pkgs
149
- modulesToLoad <- case mmainFile of
150
- Just mainFile -> do
151
- let (_, mfDirs, mfName) = filePathPieces mainFile
152
- mainPathPieces = map toFilePath mfDirs ++ [takeBaseName (toFilePath mfName)]
153
- liftM catMaybes $ forM allModules $ \ mn -> do
154
- let matchesModule = splitOn " ." mn `isSuffixOf` mainPathPieces
155
- if matchesModule
156
- then do
157
- $ logWarn $ " Warning: Omitting load of module " <> T. pack mn <>
158
- " , because it matches the filepath of the Main target, " <>
159
- T. pack (toFilePath mainFile)
160
- return Nothing
161
- else return (Just mn)
162
- Nothing -> return allModules
163
- return (modulesToLoad, mmainFile)
164
149
let odir =
165
150
[ " -odir=" <> toFilePathNoTrailingSep oiDir
166
151
, " -hidir=" <> toFilePathNoTrailingSep oiDir ]
@@ -176,20 +161,68 @@ ghci opts@GhciOpts{..} = do
176
161
-- include CWD.
177
162
" -i" :
178
163
odir <> pkgopts <> ghciArgs <> extras)
179
- withSystemTempDir " ghci" $ \ tmpDir -> do
180
- let macrosFile = tmpDir </> $ (mkRelFile " cabal_macros.h" )
181
- macrosOpts <- preprocessCabalMacros pkgs macrosFile
182
- if ghciNoLoadModules
183
- then execGhci macrosOpts
184
- else do
185
- let scriptPath = tmpDir </> $ (mkRelFile " ghci-script" )
186
- fp = toFilePath scriptPath
187
- loadModules = " :add " <> unwords (map quoteFileName modulesToLoad)
188
- addMainFile = maybe " " ((" :add " <> ) . quoteFileName . toFilePath) mainFile
189
- bringIntoScope = " :module + " <> unwords modulesToLoad
190
- liftIO (writeFile fp (unlines [loadModules,addMainFile,bringIntoScope]))
191
- setScriptPerms fp
192
- execGhci (macrosOpts ++ [" -ghci-script=" <> fp])
164
+ interrogateExeForRenderFunction = do
165
+ menv <- liftIO $ configEnvOverride config defaultEnvSettings
166
+ output <- execObserve menv (fromMaybe (compilerExeName wc) ghciGhcCommand) [" --version" ]
167
+ if " Intero" `isPrefixOf` output
168
+ then return renderScriptIntero
169
+ else return renderScriptGhci
170
+
171
+ withSystemTempDir " ghci" $ \ tmpDirectory -> do
172
+ macrosOptions <- writeMacrosFile tmpDirectory pkgs
173
+ if ghciNoLoadModules
174
+ then execGhci macrosOptions
175
+ else do
176
+ checkForDuplicateModules pkgs
177
+ renderFn <- interrogateExeForRenderFunction
178
+ scriptPath <- writeGhciScript tmpDirectory (renderFn pkgs mainFile)
179
+ execGhci (macrosOptions ++ [" -ghci-script=" <> toFilePath scriptPath])
180
+
181
+ writeMacrosFile :: (MonadIO m ) => Path Abs Dir -> [GhciPkgInfo ] -> m [String ]
182
+ writeMacrosFile tmpDirectory packages = do
183
+ macrosOptions <- preprocessCabalMacros packages macrosFile
184
+ return macrosOptions
185
+ where
186
+ macrosFile = tmpDirectory </> $ (mkRelFile " cabal_macros.h" )
187
+
188
+ writeGhciScript :: (MonadIO m ) => Path Abs Dir -> GhciScript -> m (Path Abs File )
189
+ writeGhciScript tmpDirectory script = do
190
+ liftIO $ scriptToFile scriptPath script
191
+ setScriptPerms scriptFilePath
192
+ return scriptPath
193
+ where
194
+ scriptPath = tmpDirectory </> $ (mkRelFile " ghci-script" )
195
+ scriptFilePath = toFilePath scriptPath
196
+
197
+ findOwningPackageForMain :: [GhciPkgInfo ] -> Path Abs File -> Maybe GhciPkgInfo
198
+ findOwningPackageForMain pkgs mainFile =
199
+ find (\ pkg -> toFilePath (ghciPkgDir pkg) `isPrefixOf` toFilePath mainFile) pkgs
200
+
201
+ renderScriptGhci :: [GhciPkgInfo ] -> Maybe (Path Abs File ) -> GhciScript
202
+ renderScriptGhci pkgs mainFile =
203
+ let addPhase = mconcat $ fmap renderPkg pkgs
204
+ mainPhase = case mainFile of
205
+ Just path -> cmdAddFile path
206
+ Nothing -> mempty
207
+ modulePhase = cmdModule $ foldl' S. union S. empty (fmap ghciPkgModules pkgs)
208
+ in addPhase <> mainPhase <> modulePhase
209
+ where
210
+ renderPkg pkg = cmdAdd (ghciPkgModules pkg)
211
+
212
+ renderScriptIntero :: [GhciPkgInfo ] -> Maybe (Path Abs File ) -> GhciScript
213
+ renderScriptIntero pkgs mainFile =
214
+ let addPhase = mconcat $ fmap renderPkg pkgs
215
+ mainPhase = case mainFile of
216
+ Just path ->
217
+ case findOwningPackageForMain pkgs path of
218
+ Just mainPkg -> cmdCdGhc (ghciPkgDir mainPkg) <> cmdAddFile path
219
+ Nothing -> cmdAddFile path
220
+ Nothing -> mempty
221
+ modulePhase = cmdModule $ foldl' S. union S. empty (fmap ghciPkgModules pkgs)
222
+ in addPhase <> mainPhase <> modulePhase
223
+ where
224
+ renderPkg pkg = cmdCdGhc (ghciPkgDir pkg)
225
+ <> cmdAdd (ghciPkgModules pkg)
193
226
194
227
-- | Figure out the main-is file to load based on the targets. Sometimes there
195
228
-- is none, sometimes it's unambiguous, sometimes it's
@@ -503,15 +536,14 @@ borderedWarning f = do
503
536
$ logWarn " "
504
537
return x
505
538
506
- checkForDuplicateModules :: (MonadThrow m , MonadLogger m ) => Bool -> [GhciPkgInfo ] -> m [ String ]
507
- checkForDuplicateModules noLoadModules pkgs = do
539
+ checkForDuplicateModules :: (MonadThrow m , MonadLogger m ) => [GhciPkgInfo ] -> m ()
540
+ checkForDuplicateModules pkgs = do
508
541
unless (null duplicates) $ do
509
542
borderedWarning $ do
510
543
$ logWarn " The following modules are present in multiple packages:"
511
544
forM_ duplicates $ \ (mn, pns) -> do
512
545
$ logWarn (" * " <> T. pack mn <> " (in " <> T. intercalate " , " (map packageNameText pns) <> " )" )
513
- unless noLoadModules $ throwM LoadingDuplicateModules
514
- return (map fst allModules)
546
+ throwM LoadingDuplicateModules
515
547
where
516
548
duplicates , allModules :: [(String , [PackageName ])]
517
549
duplicates = filter (not . null . tail . snd ) allModules
@@ -584,13 +616,6 @@ setScriptPerms fp = do
584
616
]
585
617
#endif
586
618
587
- filePathPieces :: Path Abs File -> (Path Abs Dir , [Path Rel Dir ], Path Rel File )
588
- filePathPieces x0 = go (parent x0, [] , filename x0)
589
- where
590
- go (x, dirs, fp)
591
- | parent x == x = (x, dirs, fp)
592
- | otherwise = (parent x, dirname x : dirs, fp)
593
-
594
619
{- Copied from Stack.Ide, may be useful in the future
595
620
596
621
-- | Get options and target files for the given package info.
@@ -632,10 +657,3 @@ targetsCmd target go@GlobalOpts{..} =
632
657
(mapM (getPackageOptsAndTargetFiles pwd) pkgs)
633
658
forM_ targets (liftIO . putStrLn)
634
659
-}
635
-
636
- -- | Make sure that a filename with spaces in it gets the proper quotes.
637
- quoteFileName :: String -> String
638
- quoteFileName x =
639
- if any (== ' ' ) x
640
- then show x
641
- else x
0 commit comments