@@ -8,7 +8,6 @@
8module Main(main) where
8module Main(main) where
10import Arguments
10import Arguments
11−import Data.Functor ((<&>))
12import Data.Maybe
11import Data.Maybe
13import Data.List.Extra
12import Data.List.Extra
14import System.FilePath
13import System.FilePath
@@ -16,9 +15,6 @@ import Control.Concurrent.Extra
16import Control.Exception
15import Control.Exception
17import Control.Monad.Extra
16import Control.Monad.Extra
18import Control.Monad.IO.Class
17import 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
22import Data.Default
18import Data.Default
23import System.Time.Extra
19import System.Time.Extra
24import Development.IDE.Core.Debouncer
20import Development.IDE.Core.Debouncer
@@ -41,7 +37,6 @@ import qualified Data.Text as T
41import qualified Data.Text.IO as T
37import qualified Data.Text.IO as T
42import Language.Haskell.LSP.Messages
38import Language.Haskell.LSP.Messages
43import Language.Haskell.LSP.Types (LspId(IdInt))
39import Language.Haskell.LSP.Types (LspId(IdInt))
45import Data.Version
40import Data.Version
46import Development.IDE.LSP.LanguageServer
41import Development.IDE.LSP.LanguageServer
47import qualified System.Directory.Extra as IO
42import qualified System.Directory.Extra as IO
@@ -50,35 +45,13 @@ import System.IO
50import System.Exit
45import System.Exit
51import Paths_ghcide
46import Paths_ghcide
52import Development.GitRev
47import Development.GitRev
53−import Development.Shake (doesDirectoryExist, Action, Rules, action, doesFileExist, need)
48+import Development.Shake (Action, Rules, action)
54import qualified Data.HashSet as HashSet
49import qualified Data.HashSet as HashSet
55import qualified Data.Map.Strict as Map
50import qualified Data.Map.Strict as Map
57−import GHC hiding (def)
58−import qualified GHC.Paths
61−import HIE.Bios.Environment
62import HIE.Bios
51import HIE.Bios
63−import HIE.Bios.Cradle
52+import Rules
65import RuleTypes
53import RuleTypes
67−-- Prefix for the cache path
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"
75−getCacheDir :: [String] -> IO FilePath
76−getCacheDir opts = IO.getXdgDirectory IO.XdgCache (cacheDir </> opts_hash)
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)
82ghcideVersion :: IO String
55ghcideVersion :: IO String
83ghcideVersion = do
56ghcideVersion = do
84 path <- getExecutablePath
57 path <- getExecutablePath
@@ -122,6 +95,7 @@ main = do
122 let options = (defaultIdeOptions $ loadSession dir)
95 let options = (defaultIdeOptions $ loadSession dir)
123 { optReportProgress = clientSupportsProgress caps
96 { optReportProgress = clientSupportsProgress caps
124 , optShakeProfiling = argsShakeProfiling
97 , optShakeProfiling = argsShakeProfiling
98+ , optTesting = IdeTesting argsTesting
126 debouncer <- newAsyncDebouncer
100 debouncer <- newAsyncDebouncer
127 initialise caps (cradleRules >> mainRule >> pluginRules plugins >> action kick)
101 initialise caps (cradleRules >> mainRule >> pluginRules plugins >> action kick)
@@ -177,7 +151,7 @@ main = do
178cradleRules :: Rules ()
152cradleRules :: Rules ()
179cradleRules = do
153cradleRules = do
180− loadGhcSessionIO
154+ loadGhcSession
181 cradleToSession
155 cradleToSession
183expandFiles :: [FilePath] -> IO [FilePath]
157expandFiles :: [FilePath] -> IO [FilePath]
@@ -205,93 +179,6 @@ showEvent lock (EventFileDiagnostics (toNormalizedFilePath -> file) diags) =
205 withLock lock $ T.putStrLn $ showDiagnosticsColored $ map (file,ShowDiag,) diags
179 withLock lock $ T.putStrLn $ showDiagnosticsColored $ map (file,ShowDiag,) diags
206showEvent lock e = withLock lock $ print e
180showEvent lock e = withLock lock $ print e
208−loadGhcSessionIO :: Rules ()
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
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 ""
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"
229−createSession :: ComponentOptions -> IO HscEnvEq
230−createSession (ComponentOptions theOpts _) = do
233− cacheDir <- Main.getCacheDir theOpts
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
245− setDefaultHieDir cacheDir $
246− setIgnoreInterfacePragmas $
248− disableOptimisation dflags'
253−-- we don't want to generate object code so we compile to bytecode
254−-- (HscInterpreted) which implies LinkInMemory
256−setLinkerOptions :: DynFlags -> DynFlags
257−setLinkerOptions df = df {
258− ghcLink = LinkInMemory
259− , hscTarget = HscNothing
260− , ghcMode = CompManager
263−setIgnoreInterfacePragmas :: DynFlags -> DynFlags
264−setIgnoreInterfacePragmas df =
265− gopt_set (gopt_set df Opt_IgnoreInterfacePragmas) Opt_IgnoreOptimChanges
267−disableOptimisation :: DynFlags -> DynFlags
268−disableOptimisation df = updOptLevel 0 df
270−setHiDir :: FilePath -> DynFlags -> DynFlags
272− -- override user settings to avoid conflicts leading to recompilation
275−cradleToSession :: Rules ()
276−cradleToSession = define $ \LoadCradle nfp -> do
277− let f = fromNormalizedFilePath nfp
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
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
290− existingDeps <- filterM doesFileExist deps'
292− ([],) . pure <$> useNoFile_ (GetHscEnv opts deps)
295loadSession :: FilePath -> Action (FilePath -> Action HscEnvEq)
182loadSession :: FilePath -> Action (FilePath -> Action HscEnvEq)
296loadSession dir = liftIO $ do
183loadSession dir = liftIO $ do
297 cradleLoc <- memoIO $ \v -> do
184 cradleLoc <- memoIO $ \v -> do