withServer serverExe (logStdErr config) $ \serverIn serverOut serverProc ->
runSessionWithHandles serverIn serverOut serverProc listenServer config caps rootDir exitServer $ do
-- Wrap the session around initialize and shutdown calls
- initRspMsg <- request Initialize initializeParams :: Session InitializeResponse
+ -- initRspMsg <- sendRequest Initialize initializeParams :: Session InitializeResponse
+ initReqId <- sendRequest Initialize initializeParams
+
+ -- Because messages can be sent in between the request and response,
+ -- collect them and then...
+ (inBetween, initRspMsg) <- manyTill_ anyMessage (responseForId initReqId)
liftIO $ maybe (return ()) (putStrLn . ("Error while initializing: " ++) . show ) (initRspMsg ^. LSP.error)
Just cfg -> sendNotification WorkspaceDidChangeConfiguration (DidChangeConfigurationParams cfg)
Nothing -> return ()
+ -- ... relay them back to the user Session so they can match on them!
+ -- As long as they are allowed.
+ forM_ inBetween checkLegalBetweenMessage
+ msgChan <- asks messageChan
+ liftIO $ writeList2Chan msgChan (ServerMessage <$> inBetween)
+
-- Run the actual test
session
where
(RspShutdown _) -> return ()
_ -> listenServer serverOut context
+ -- | Is this message allowed to be sent by the server between the intialize
+ -- request and response?
+ -- https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/#initialize
+ checkLegalBetweenMessage :: FromServerMessage -> Session ()
+ checkLegalBetweenMessage (NotShowMessage _) = pure ()
+ checkLegalBetweenMessage (NotLogMessage _) = pure ()
+ checkLegalBetweenMessage (NotTelemetry _) = pure ()
+ checkLegalBetweenMessage (ReqShowMessage _) = pure ()
+ checkLegalBetweenMessage msg = throw (IllegalInitSequenceMessage msg)
+
-- | Check environment variables to override the config
envOverrideConfig :: SessionConfig -> IO SessionConfig
envOverrideConfig cfg = do
| IncorrectApplyEditRequest String
| UnexpectedResponseError LspIdRsp ResponseError
| UnexpectedServerTermination
+ | IllegalInitSequenceMessage FromServerMessage
deriving Eq
instance Exception SessionException
show (UnexpectedResponseError lid e) = "Received an exepected error in a response for id " ++ show lid ++ ":\n"
++ show e
show UnexpectedServerTermination = "Language server unexpectedly terminated"
+ show (IllegalInitSequenceMessage msg) =
+ "Received an illegal message between the initialize request and response:\n"
+ ++ B.unpack (encodePretty msg)
-- | A predicate that matches on any 'SessionException'
anySessionException :: SessionException -> Bool