@@ -21,6 +21,7 @@ import Colog.Core (
2121 (<&) ,
2222 )
2323
24+ import Control.Concurrent.Extra as C
2425import Control.Concurrent.STM
2526import Control.Exception qualified as E
2627import Control.Lens hiding (Empty )
@@ -69,6 +70,8 @@ data LspProcessingLog
6970 | MessageProcessingError BSL. ByteString String
7071 | forall m . MissingHandler Bool (SClientMethod m )
7172 | ProgressCancel ProgressToken
73+ | forall m . MessageDuringShutdown (SClientMethod m )
74+ | ShuttingDown
7275 | Exiting
7376
7477deriving instance Show LspProcessingLog
@@ -85,7 +88,9 @@ instance Pretty LspProcessingLog where
8588 ]
8689 pretty (MissingHandler _ m) = " LSP: no handler for:" <+> pretty m
8790 pretty (ProgressCancel tid) = " LSP: cancelling action for token:" <+> pretty tid
88- pretty Exiting = " LSP: Got exit, exiting"
91+ pretty (MessageDuringShutdown m) = " LSP: received message during shutdown:" <+> pretty m
92+ pretty ShuttingDown = " LSP: received shutdown"
93+ pretty Exiting = " LSP: received exit"
8994
9095processMessage :: (m ~ LspM config ) => LogAction m (WithSeverity LspProcessingLog ) -> BSL. ByteString -> m ()
9196processMessage logger jsonStr = do
@@ -164,6 +169,7 @@ initializeRequestHandler logger ServerDefinition{..} vfs sendFunc req = do
164169 resRegistrationsNot <- newTVarIO mempty
165170 resRegistrationsReq <- newTVarIO mempty
166171 resLspId <- newTVarIO 0
172+ resShutdown <- C. newBarrier
167173 pure LanguageContextState {.. }
168174
169175 -- Call the 'duringInitialization' callback to let the server kick stuff up
@@ -414,13 +420,21 @@ inferServerCapabilities _clientCaps o h =
414420{- | Invokes the registered dynamic or static handlers for the given message and
415421 method, as well as doing some bookkeeping.
416422-}
417- handle :: (m ~ LspM config ) => LogAction m (WithSeverity LspProcessingLog ) -> SClientMethod meth -> TClientMessage meth -> m ()
423+ handle :: forall m config meth . (m ~ LspM config ) => LogAction m (WithSeverity LspProcessingLog ) -> SClientMethod meth -> TClientMessage meth -> m ()
418424handle logger m msg =
419425 case m of
420426 SMethod_WorkspaceDidChangeWorkspaceFolders -> handle' logger (Just updateWorkspaceFolders) m msg
421427 SMethod_WorkspaceDidChangeConfiguration -> handle' logger (Just $ handleDidChangeConfiguration logger) m msg
422428 -- See Note [LSP configuration]
423429 SMethod_Initialized -> handle' logger (Just $ \ _ -> initialDynamicRegistrations logger >> requestConfigUpdate (cmap (fmap LspCore ) logger)) m msg
430+ SMethod_Shutdown -> handle' logger (Just $ \ _ -> signalShutdown) m msg
431+ where
432+ -- See Note [Shutdown]
433+ signalShutdown :: LspM config ()
434+ signalShutdown = do
435+ logger <& ShuttingDown `WithSeverity ` Info
436+ b <- resShutdown . resState <$> getLspEnv
437+ liftIO $ signalBarrier b ()
424438 SMethod_TextDocumentDidOpen -> handle' logger (Just $ vfsFunc logger openVFS) m msg
425439 SMethod_TextDocumentDidChange -> handle' logger (Just $ vfsFunc logger changeFromClientVFS) m msg
426440 SMethod_TextDocumentDidClose -> handle' logger (Just $ vfsFunc logger closeVFS) m msg
@@ -445,48 +459,40 @@ handle' logger mAction m msg = do
445459
446460 env <- getLspEnv
447461 let Handlers {reqHandlers, notHandlers} = resHandlers env
448-
449- let mkRspCb :: TRequestMessage (m1 :: Method ClientToServer Request ) -> Either ResponseError (MessageResult m1 ) -> IO ()
450- mkRspCb req (Left err) =
451- runLspT env $
452- sendToClient $
453- FromServerRsp (req ^. L. method) $
454- TResponseMessage " 2.0" (Just (req ^. L. id )) (Left err)
455- mkRspCb req (Right rsp) =
456- runLspT env $
457- sendToClient $
458- FromServerRsp (req ^. L. method) $
459- TResponseMessage " 2.0" (Just (req ^. L. id )) (Right rsp)
462+ shutdown <- isShuttingDown
460463
461464 case splitClientMethod m of
465+ -- See Note [Shutdown]
466+ IsClientNot | shutdown, not (allowedMethod m) -> notificationDuringShutdown
467+ where
468+ allowedMethod SMethod_Exit = True
469+ allowedMethod _ = False
462470 IsClientNot -> case pickHandler dynNotHandlers notHandlers of
463471 Just h -> liftIO $ h msg
464472 Nothing
465473 | SMethod_Exit <- m -> exitNotificationHandler logger msg
466- | otherwise -> do
467- reportMissingHandler
474+ | otherwise -> missingNotificationHandler
475+ -- See Note [Shutdown]
476+ IsClientReq | shutdown, not (allowedMethod m) -> requestDuringShutdown msg
477+ where
478+ allowedMethod SMethod_Shutdown = True
479+ allowedMethod _ = False
468480 IsClientReq -> case pickHandler dynReqHandlers reqHandlers of
469- Just h -> liftIO $ h msg (mkRspCb msg)
481+ Just h -> liftIO $ h msg (runLspT env . sendResponse msg)
470482 Nothing
471- | SMethod_Shutdown <- m -> liftIO $ shutdownRequestHandler msg (mkRspCb msg)
472- | otherwise -> do
473- let errorMsg = T. pack $ unwords [" lsp:no handler for: " , show m]
474- err = ResponseError (InR ErrorCodes_MethodNotFound ) errorMsg Nothing
475- sendToClient $
476- FromServerRsp (msg ^. L. method) $
477- TResponseMessage " 2.0" (Just (msg ^. L. id )) (Left err)
483+ | SMethod_Shutdown <- m -> liftIO $ shutdownRequestHandler msg (runLspT env . sendResponse msg)
484+ | otherwise -> missingRequestHandler msg
478485 IsClientEither -> case msg of
486+ -- See Note [Shutdown]
487+ NotMess _ | shutdown -> notificationDuringShutdown
479488 NotMess noti -> case pickHandler dynNotHandlers notHandlers of
480489 Just h -> liftIO $ h noti
481- Nothing -> reportMissingHandler
490+ Nothing -> missingNotificationHandler
491+ -- See Note [Shutdown]
492+ ReqMess req | shutdown -> requestDuringShutdown req
482493 ReqMess req -> case pickHandler dynReqHandlers reqHandlers of
483- Just h -> liftIO $ h req (mkRspCb req)
484- Nothing -> do
485- let errorMsg = T. pack $ unwords [" lsp:no handler for: " , show m]
486- err = ResponseError (InR ErrorCodes_MethodNotFound ) errorMsg Nothing
487- sendToClient $
488- FromServerRsp (req ^. L. method) $
489- TResponseMessage " 2.0" (Just (req ^. L. id )) (Left err)
494+ Just h -> liftIO $ h req (runLspT env . sendResponse req)
495+ Nothing -> missingRequestHandler req
490496 where
491497 -- \| Checks to see if there's a dynamic handler, and uses it in favour of the
492498 -- static handler, if it exists.
@@ -496,14 +502,32 @@ handle' logger mAction m msg = do
496502 (Nothing , Just (ClientMessageHandler h)) -> Just h
497503 (Nothing , Nothing ) -> Nothing
498504
505+ sendResponse :: forall m1 . TRequestMessage (m1 :: Method ClientToServer Request ) -> Either ResponseError (MessageResult m1 ) -> m ()
506+ sendResponse req res = sendToClient $ FromServerRsp (req ^. L. method) $ TResponseMessage " 2.0" (Just (req ^. L. id )) res
507+
508+ requestDuringShutdown :: forall m1 . TRequestMessage (m1 :: Method ClientToServer Request ) -> m ()
509+ requestDuringShutdown req = do
510+ logger <& MessageDuringShutdown m `WithSeverity ` Warning
511+ sendResponse req (Left (ResponseError (InR ErrorCodes_InvalidRequest ) " Server is shutdown" Nothing ))
512+
513+ notificationDuringShutdown :: m ()
514+ notificationDuringShutdown = logger <& MessageDuringShutdown m `WithSeverity ` Warning
515+
499516 -- '$/' notifications should/could be ignored by server.
500517 -- Don't log errors in that case.
501518 -- See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#-notifications-and-requests.
502- reportMissingHandler :: m ()
503- reportMissingHandler =
519+ missingNotificationHandler :: m ()
520+ missingNotificationHandler =
504521 let optional = isOptionalMethod (SomeMethod m)
505522 in logger <& MissingHandler optional m `WithSeverity ` if optional then Warning else Error
506523
524+ missingRequestHandler :: TRequestMessage (m1 :: Method ClientToServer Request ) -> m ()
525+ missingRequestHandler req = do
526+ logger <& MissingHandler False m `WithSeverity ` Error
527+ let errorMsg = T. pack $ unwords [" No handler for: " , show m]
528+ err = ResponseError (InR ErrorCodes_MethodNotFound ) errorMsg Nothing
529+ sendResponse req (Left err)
530+
507531progressCancelHandler :: (m ~ LspM config ) => LogAction m (WithSeverity LspProcessingLog ) -> TMessage Method_WindowWorkDoneProgressCancel -> m ()
508532progressCancelHandler logger (TNotificationMessage _ _ (WorkDoneProgressCancelParams tid)) = do
509533 pdata <- getsState (progressCancel . resProgressData)
0 commit comments