Skip to content

Commit 35a22ad

Browse files
committed
Allow users to specify whether to use cabal's multi-repl feature
We add an option to `Config` that allows clients to specify how HLS should load components. The three options are: * SessionLoadSingleComponent: Always load only a single component when a new component is discovered. * SessionLoadMultipleComponents: Always allow the cradle to load multiple components at once. This might not be always possible, e.g., if the tool doesn't support multiple components loading. The cradle can decide how to handle these situations. * SessionAuto: Leave the decision to the individual cradle type. Some cradles have good support for loading multiple components, while others do not. So use multiple components loading for tools, such as cabal, and force single component loading for tools that do not support multiple components, such as stack.
1 parent 334b4d4 commit 35a22ad

File tree

4 files changed

+67
-6
lines changed

4 files changed

+67
-6
lines changed

cabal.project

+5
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,8 @@ constraints:
4242
-- We want to be able to benefit from the performance optimisations
4343
-- in the future, thus: TODO: remove this flag.
4444
bitvec -simd
45+
46+
source-repository-package
47+
type: git
48+
location: https://github.com/fendor/hie-bios
49+
tag: 10afd5b50475b7f8877296cd65614a1a72253941

ghcide/session-loader/Development/IDE/Session.hs

+18-5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import Development.IDE.Types.Location
6969
import Development.IDE.Types.Options
7070
import GHC.Check
7171
import qualified HIE.Bios as HieBios
72+
import qualified HIE.Bios.Cradle as HieBios
7273
import HIE.Bios.Environment hiding (getCacheDir)
7374
import HIE.Bios.Types hiding (Log)
7475
import qualified HIE.Bios.Types as HieBios
@@ -79,6 +80,8 @@ import Ide.Logger (Pretty (pretty),
7980
nest,
8081
toCologActionWithPrio,
8182
vcat, viaShow, (<+>))
83+
import Ide.Types (SessionLoadingConfig (..),
84+
sessionLoading)
8285
import Language.LSP.Protocol.Message
8386
import Language.LSP.Server
8487
import System.Directory
@@ -461,6 +464,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do
461464
runningCradle <- newVar dummyAs :: IO (Var (Async (IdeResult HscEnvEq,[FilePath])))
462465

463466
return $ do
467+
clientConfig <- getClientConfigAction
464468
extras@ShakeExtras{restartShakeSession, ideNc, knownTargetsVar, lspEnv
465469
} <- getShakeExtras
466470
let invalidateShakeCache :: IO ()
@@ -651,7 +655,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do
651655
withTrace "Load cradle" $ \addTag -> do
652656
addTag "file" lfp
653657
old_files <- readIORef cradle_files
654-
res <- cradleToOptsAndLibDir recorder cradle cfp old_files
658+
res <- cradleToOptsAndLibDir recorder (sessionLoading clientConfig) cradle cfp old_files
655659
addTag "result" (show res)
656660
return res
657661

@@ -713,7 +717,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do
713717
return (([renderPackageSetupException file e], Nothing), maybe [] pure hieYaml)
714718

715719
returnWithVersion $ \file -> do
716-
opts <- liftIO $ join $ mask_ $ modifyVar runningCradle $ \as -> do
720+
opts <- join $ mask_ $ modifyVar runningCradle $ \as -> do
717721
-- If the cradle is not finished, then wait for it to finish.
718722
void $ wait as
719723
asyncRes <- async $ getOptions file
@@ -723,14 +727,15 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} dir = do
723727
-- | Run the specific cradle on a specific FilePath via hie-bios.
724728
-- This then builds dependencies or whatever based on the cradle, gets the
725729
-- GHC options/dynflags needed for the session and the GHC library directory
726-
cradleToOptsAndLibDir :: Recorder (WithPriority Log) -> Cradle Void -> FilePath -> [FilePath]
730+
cradleToOptsAndLibDir :: Recorder (WithPriority Log) -> SessionLoadingConfig -> Cradle Void -> FilePath -> [FilePath]
727731
-> IO (Either [CradleError] (ComponentOptions, FilePath))
728-
cradleToOptsAndLibDir recorder cradle file old_files = do
732+
cradleToOptsAndLibDir recorder loadConfig cradle file old_fps = do
729733
-- let noneCradleFoundMessage :: FilePath -> T.Text
730734
-- noneCradleFoundMessage f = T.pack $ "none cradle found for " <> f <> ", ignoring the file"
731735
-- Start off by getting the session options
732736
logWith recorder Debug $ LogCradle cradle
733-
cradleRes <- HieBios.getCompilerOptions file old_files cradle
737+
loadStyle <- decideLoadStyle
738+
cradleRes <- HieBios.getCompilerOptions file loadStyle cradle
734739
case cradleRes of
735740
CradleSuccess r -> do
736741
-- Now get the GHC lib dir
@@ -748,6 +753,14 @@ cradleToOptsAndLibDir recorder cradle file old_files = do
748753
logWith recorder Info $ LogNoneCradleFound file
749754
return (Left [])
750755

756+
where
757+
decideLoadStyle = case loadConfig of
758+
SessionLoadSingleComponent -> pure SingleComponent
759+
SessionLoadMultipleComponents -> pure $ LoadWithContext old_fps
760+
SessionAuto
761+
| HieBios.isCabalCradle cradle -> pure $ LoadWithContext old_fps
762+
| otherwise -> pure SingleComponent
763+
751764
#if MIN_VERSION_ghc(9,3,0)
752765
emptyHscEnv :: NameCache -> FilePath -> IO HscEnv
753766
#else

hls-plugin-api/src/Ide/Plugin/Config.hs

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ parseConfig idePlugins defValue = A.withObject "settings" $ \o ->
4242
<*> o .:? "formattingProvider" .!= formattingProvider defValue
4343
<*> o .:? "cabalFormattingProvider" .!= cabalFormattingProvider defValue
4444
<*> o .:? "maxCompletions" .!= maxCompletions defValue
45+
<*> o .:? "sessionLoading" .!= sessionLoading defValue
4546
<*> A.explicitParseFieldMaybe (parsePlugins idePlugins) o "plugin" .!= plugins defValue
4647

4748
-- | Parse the 'PluginConfig'.

hls-plugin-api/src/Ide/Types.hs

+43-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ module Ide.Types
2222
, IdeNotification(..)
2323
, IdePlugins(IdePlugins, ipMap)
2424
, DynFlagsModifications(..)
25-
, Config(..), PluginConfig(..), CheckParents(..)
25+
, Config(..), PluginConfig(..), CheckParents(..), SessionLoadingConfig(..)
2626
, ConfigDescriptor(..), defaultConfigDescriptor, configForPlugin
2727
, CustomConfig(..), mkCustomConfig
2828
, FallbackCodeActionParams(..)
@@ -65,6 +65,7 @@ import Control.Monad.Error.Class (MonadError (throwError))
6565
import Control.Monad.Trans.Class (MonadTrans (lift))
6666
import Control.Monad.Trans.Except (ExceptT, runExceptT)
6767
import Data.Aeson hiding (Null, defaultOptions)
68+
import qualified Data.Aeson.Types as A
6869
import Data.Default
6970
import Data.Dependent.Map (DMap)
7071
import qualified Data.Dependent.Map as DMap
@@ -170,6 +171,7 @@ data Config =
170171
, formattingProvider :: !T.Text
171172
, cabalFormattingProvider :: !T.Text
172173
, maxCompletions :: !Int
174+
, sessionLoading :: !SessionLoadingConfig
173175
, plugins :: !(Map.Map PluginId PluginConfig)
174176
} deriving (Show,Eq)
175177

@@ -180,6 +182,7 @@ instance ToJSON Config where
180182
, "formattingProvider" .= formattingProvider
181183
, "cabalFormattingProvider" .= cabalFormattingProvider
182184
, "maxCompletions" .= maxCompletions
185+
, "sessionLoading" .= sessionLoading
183186
, "plugin" .= Map.mapKeysMonotonic (\(PluginId p) -> p) plugins
184187
]
185188

@@ -194,6 +197,7 @@ instance Default Config where
194197
-- , cabalFormattingProvider = "cabal-fmt"
195198
-- this string value needs to kept in sync with the value provided in HlsPlugins
196199
, maxCompletions = 40
200+
, sessionLoading = SessionAuto
197201
, plugins = mempty
198202
}
199203

@@ -206,6 +210,44 @@ data CheckParents
206210
deriving stock (Eq, Ord, Show, Generic)
207211
deriving anyclass (FromJSON, ToJSON)
208212

213+
214+
data SessionLoadingConfig
215+
= SessionLoadSingleComponent
216+
-- ^ Always load only a single component when a new component
217+
-- is discovered.
218+
| SessionLoadMultipleComponents
219+
-- ^ Always allow the cradle to load multiple components
220+
-- at once. This might not be always possible, if the tool doesn't
221+
-- support multiple components loading.
222+
--
223+
-- The cradle can decide how to handle these situations.
224+
| SessionAuto
225+
-- ^ Leave the decision to the individual cradle type.
226+
-- Some cradles have good support for loading multiple components,
227+
-- while others do not.
228+
-- So use multiple components loading for tools, such as cabal,
229+
-- and force single component loading for tools that do not support
230+
-- multiple components, such as stack.
231+
deriving stock (Eq, Ord, Show, Generic)
232+
233+
instance ToJSON SessionLoadingConfig where
234+
toJSON SessionLoadSingleComponent =
235+
String "Single Component"
236+
toJSON SessionLoadMultipleComponents =
237+
String "Multiple Components"
238+
toJSON SessionAuto =
239+
String "Auto"
240+
241+
instance FromJSON SessionLoadingConfig where
242+
parseJSON (String val) = case val of
243+
"Single Component" -> pure SessionLoadSingleComponent
244+
"Multiple Components" -> pure SessionLoadMultipleComponents
245+
"Auto" -> pure SessionAuto
246+
_ -> A.prependFailure "parsing SessionLoadingConfig failed, "
247+
(A.parseFail $ "Expected one of \"Single Component\", \"Multiple Components\" or \"Auto\" but got " <> T.unpack val )
248+
parseJSON o = A.prependFailure "parsing SessionLoadingConfig failed, "
249+
(A.typeMismatch "String" o)
250+
209251
-- | A PluginConfig is a generic configuration for a given HLS plugin. It
210252
-- provides a "big switch" to turn it on or off as a whole, as well as small
211253
-- switches per feature, and a slot for custom config.

0 commit comments

Comments
 (0)