@@ -8,7 +8,6 @@
88module Main(main) where
99
1010import Arguments
11−import Data.Functor ((<&>))
1211import Data.Maybe
1312import Data.List.Extra
1413import System.FilePath
@@ -16,9 +15,6 @@ import Control.Concurrent.Extra
1615import Control.Exception
1716import Control.Monad.Extra
1817import Control.Monad.IO.Class
19−import qualified Crypto.Hash.SHA1 as H
20−import qualified Data.ByteString.Char8 as B
21−import Data.ByteString.Base16
2218import Data.Default
2319import System.Time.Extra
2420import Development.IDE.Core.Debouncer
@@ -41,7 +37,6 @@ import qualified Data.Text as T
4137import qualified Data.Text.IO as T
4238import Language.Haskell.LSP.Messages
4339import Language.Haskell.LSP.Types (LspId(IdInt))
44−import Linker
4540import Data.Version
4641import Development.IDE.LSP.LanguageServer
4742import qualified System.Directory.Extra as IO
@@ -50,35 +45,13 @@ import System.IO
5045import System.Exit
5146import Paths_ghcide
5247import Development.GitRev
53−import Development.Shake (doesDirectoryExist, Action, Rules, action, doesFileExist, need)
48+import Development.Shake (Action, Rules, action)
5449import qualified Data.HashSet as HashSet
5550import qualified Data.Map.Strict as Map
56−
57−import GHC hiding (def)
58−import qualified GHC.Paths
59−import DynFlags
60−
61−import HIE.Bios.Environment
6251import HIE.Bios
63−import HIE.Bios.Cradle
64−import HIE.Bios.Types
52+import Rules
6553import RuleTypes
6654
67−-- Prefix for the cache path
68−cacheDir :: String
69−cacheDir = "ghcide"
70−
71−-- Set the GHC libdir to the nix libdir if it's present.
72−getLibdir :: IO FilePath
73−getLibdir = fromMaybe GHC.Paths.libdir <$> lookupEnv "NIX_GHC_LIBDIR"
74−
75−getCacheDir :: [String] -> IO FilePath
76−getCacheDir opts = IO.getXdgDirectory IO.XdgCache (cacheDir </> opts_hash)
77− where
78− -- Create a unique folder per set of different GHC options, assuming that each different set of
79− -- GHC options will create incompatible interface files.
80− opts_hash = B.unpack $ encode $ H.finalize $ H.updates H.init (map B.pack opts)
81−
8255ghcideVersion :: IO String
8356ghcideVersion = do
8457 path <- getExecutablePath
@@ -122,6 +95,7 @@ main = do
12295 let options = (defaultIdeOptions $ loadSession dir)
12396 { optReportProgress = clientSupportsProgress caps
12497 , optShakeProfiling = argsShakeProfiling
98+ , optTesting = IdeTesting argsTesting
12599 }
126100 debouncer <- newAsyncDebouncer
127101 initialise caps (cradleRules >> mainRule >> pluginRules plugins >> action kick)
@@ -177,7 +151,7 @@ main = do
177151
178152cradleRules :: Rules ()
179153cradleRules = do
180− loadGhcSessionIO
154+ loadGhcSession
181155 cradleToSession
182156
183157expandFiles :: [FilePath] -> IO [FilePath]
@@ -205,93 +179,6 @@ showEvent lock (EventFileDiagnostics (toNormalizedFilePath -> file) diags) =
205179 withLock lock $ T.putStrLn $ showDiagnosticsColored $ map (file,ShowDiag,) diags
206180showEvent lock e = withLock lock $ print e
207181
208−loadGhcSessionIO :: Rules ()
209−loadGhcSessionIO =
210− -- This rule is for caching the GHC session. E.g., even when the cabal file
211− -- changed, if the resulting flags did not change, we would continue to use
212− -- the existing session.
213− defineNoFile $ \(GetHscEnv opts deps) ->
214− liftIO $ createSession $ ComponentOptions opts deps
215−
216−getComponentOptions :: Cradle a -> IO ComponentOptions
217−getComponentOptions cradle = do
218− let showLine s = putStrLn ("> " ++ s)
219− -- WARNING 'runCradle is very expensive and must be called as few times as possible
220− cradleRes <- runCradle (cradleOptsProg cradle) showLine ""
221− case cradleRes of
222− CradleSuccess r -> pure r
223− CradleFail err -> throwIO err
224− -- TODO Rather than failing here, we should ignore any files that use this cradle.
225− -- That will require some more changes.
226− CradleNone -> fail "'none' cradle is not yet supported"
227−
228−
229−createSession :: ComponentOptions -> IO HscEnvEq
230−createSession (ComponentOptions theOpts _) = do
231− libdir <- getLibdir
232−
233− cacheDir <- Main.getCacheDir theOpts
234−
235− env <- runGhc (Just libdir) $ do
236− dflags <- getSessionDynFlags
237− (dflags', _targets) <- addCmdOpts theOpts dflags
238− _ <- setSessionDynFlags $
239− -- disabled, generated directly by ghcide instead
240− flip gopt_unset Opt_WriteInterface $
241− -- disabled, generated directly by ghcide instead
242− -- also, it can confuse the interface stale check
243− dontWriteHieFiles $
244− setHiDir cacheDir $
245− setDefaultHieDir cacheDir $
246− setIgnoreInterfacePragmas $
247− setLinkerOptions $
248− disableOptimisation dflags'
249− getSession
250− initDynLinker env
251− newHscEnvEq env
252−
253−-- we don't want to generate object code so we compile to bytecode
254−-- (HscInterpreted) which implies LinkInMemory
255−-- HscInterpreted
256−setLinkerOptions :: DynFlags -> DynFlags
257−setLinkerOptions df = df {
258− ghcLink = LinkInMemory
259− , hscTarget = HscNothing
260− , ghcMode = CompManager
261− }
262−
263−setIgnoreInterfacePragmas :: DynFlags -> DynFlags
264−setIgnoreInterfacePragmas df =
265− gopt_set (gopt_set df Opt_IgnoreInterfacePragmas) Opt_IgnoreOptimChanges
266−
267−disableOptimisation :: DynFlags -> DynFlags
268−disableOptimisation df = updOptLevel 0 df
269−
270−setHiDir :: FilePath -> DynFlags -> DynFlags
271−setHiDir f d =
272− -- override user settings to avoid conflicts leading to recompilation
273− d { hiDir = Just f}
274−
275−cradleToSession :: Rules ()
276−cradleToSession = define $ \LoadCradle nfp -> do
277− let f = fromNormalizedFilePath nfp
278−
279− -- If the path points to a directory, load the implicit cradle
280− mbYaml <- doesDirectoryExist f <&> \isDir -> if isDir then Nothing else Just f
281− cradle <- liftIO $ maybe (loadImplicitCradle $ addTrailingPathSeparator f) loadCradle mbYaml
282−
283− cmpOpts <- liftIO $ getComponentOptions cradle
284− let opts = componentOptions cmpOpts
285− deps = componentDependencies cmpOpts
286− deps' = case mbYaml of
287− -- For direct cradles, the hie.yaml file itself must be watched.
288− Just yaml | isDirectCradle cradle -> yaml : deps
289− _ -> deps
290− existingDeps <- filterM doesFileExist deps'
291− need existingDeps
292− ([],) . pure <$> useNoFile_ (GetHscEnv opts deps)
293−
294−
295182loadSession :: FilePath -> Action (FilePath -> Action HscEnvEq)
296183loadSession dir = liftIO $ do
297184 cradleLoc <- memoIO $ \v -> do