import Data.Aeson
import Data.Default
import qualified Data.HashMap.Strict as HashMap
-import Data.IORef
import qualified Data.Map as Map
import Data.Maybe
import Language.Haskell.LSP.Types
-> IO a
runSessionWithConfig config serverExe caps rootDir session = do
-- We use this IORef to make exception non-fatal when the server is supposed to shutdown.
- exitOk <- newIORef False
pid <- getCurrentProcessID
absRootDir <- canonicalizePath rootDir
(Just TraceOff)
Nothing
withServer serverExe (logStdErr config) $ \serverIn serverOut _ ->
- runSessionWithHandles serverIn serverOut (\h c -> catchWhenTrue exitOk $ listenServer h c) config caps rootDir $ do
-
+ runSessionWithHandles serverIn serverOut (\h c -> listenServer h c) config caps rootDir $ do
-- Wrap the session around initialize and shutdown calls
initRspMsg <- request Initialize initializeParams :: Session InitializeResponse
-- Run the actual test
result <- session
-
- liftIO $ atomicWriteIORef exitOk True
- sendNotification Exit ExitParams
-
return result
where
- catchWhenTrue :: IORef Bool -> IO () -> IO ()
- catchWhenTrue exitOk a =
- a `catch` (\e -> do
- x <- readIORef exitOk
- unless x $ throw (e :: SomeException))
-
-- | Listens to the server output, makes sure it matches the record and
-- signals any semaphores
-- Note that on Windows, we cannot kill a thread stuck in getNextMessage.
initState = SessionState (IdInt 0) mempty mempty 0 False Nothing
launchServerHandler = forkIO $ catch (serverHandler serverOut context)
(throwTo mainThreadId :: SessionException -> IO())
- (result, _) <- bracket launchServerHandler killThread $
- const $ runSession context initState session
-
+ (result, _) <- bracket
+ launchServerHandler
+ (\tid -> do runSession context initState sendExitMessage
+ killThread tid)
+ (const $ runSession context initState session)
return result
updateStateC :: ConduitM FromServerMessage FromServerMessage (StateT SessionState (ReaderT SessionContext IO)) ()
logMsg LogClient msg
liftIO $ B.hPut h (addHeader $ encode msg)
+sendExitMessage :: (MonadIO m, HasReader SessionContext m) => m ()
+sendExitMessage = sendMessage (NotificationMessage "2.0" Exit ExitParams)
+
-- | Execute a block f that will throw a 'Timeout' exception
-- after duration seconds. This will override the global timeout
-- for waiting for messages to arrive defined in 'SessionConfig'.