@@ -21,6 +21,7 @@ import Colog.Core (
21
21
(<&) ,
22
22
)
23
23
24
+ import Control.Concurrent.Extra as C
24
25
import Control.Concurrent.STM
25
26
import Control.Exception qualified as E
26
27
import Control.Lens hiding (Empty )
@@ -69,6 +70,8 @@ data LspProcessingLog
69
70
| MessageProcessingError BSL. ByteString String
70
71
| forall m . MissingHandler Bool (SClientMethod m )
71
72
| ProgressCancel ProgressToken
73
+ | forall m . MessageDuringShutdown (SClientMethod m )
74
+ | ShuttingDown
72
75
| Exiting
73
76
74
77
deriving instance Show LspProcessingLog
@@ -85,7 +88,9 @@ instance Pretty LspProcessingLog where
85
88
]
86
89
pretty (MissingHandler _ m) = " LSP: no handler for:" <+> pretty m
87
90
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"
89
94
90
95
processMessage :: (m ~ LspM config ) => LogAction m (WithSeverity LspProcessingLog ) -> BSL. ByteString -> m ()
91
96
processMessage logger jsonStr = do
@@ -164,6 +169,7 @@ initializeRequestHandler logger ServerDefinition{..} vfs sendFunc req = do
164
169
resRegistrationsNot <- newTVarIO mempty
165
170
resRegistrationsReq <- newTVarIO mempty
166
171
resLspId <- newTVarIO 0
172
+ resShutdown <- C. newBarrier
167
173
pure LanguageContextState {.. }
168
174
169
175
-- Call the 'duringInitialization' callback to let the server kick stuff up
@@ -414,13 +420,21 @@ inferServerCapabilities _clientCaps o h =
414
420
{- | Invokes the registered dynamic or static handlers for the given message and
415
421
method, as well as doing some bookkeeping.
416
422
-}
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 ()
418
424
handle logger m msg =
419
425
case m of
420
426
SMethod_WorkspaceDidChangeWorkspaceFolders -> handle' logger (Just updateWorkspaceFolders) m msg
421
427
SMethod_WorkspaceDidChangeConfiguration -> handle' logger (Just $ handleDidChangeConfiguration logger) m msg
422
428
-- See Note [LSP configuration]
423
429
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 ()
424
438
SMethod_TextDocumentDidOpen -> handle' logger (Just $ vfsFunc logger openVFS) m msg
425
439
SMethod_TextDocumentDidChange -> handle' logger (Just $ vfsFunc logger changeFromClientVFS) m msg
426
440
SMethod_TextDocumentDidClose -> handle' logger (Just $ vfsFunc logger closeVFS) m msg
@@ -445,48 +459,40 @@ handle' logger mAction m msg = do
445
459
446
460
env <- getLspEnv
447
461
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
460
463
461
464
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
462
470
IsClientNot -> case pickHandler dynNotHandlers notHandlers of
463
471
Just h -> liftIO $ h msg
464
472
Nothing
465
473
| 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
468
480
IsClientReq -> case pickHandler dynReqHandlers reqHandlers of
469
- Just h -> liftIO $ h msg (mkRspCb msg)
481
+ Just h -> liftIO $ h msg (runLspT env . sendResponse msg)
470
482
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
478
485
IsClientEither -> case msg of
486
+ -- See Note [Shutdown]
487
+ NotMess _ | shutdown -> notificationDuringShutdown
479
488
NotMess noti -> case pickHandler dynNotHandlers notHandlers of
480
489
Just h -> liftIO $ h noti
481
- Nothing -> reportMissingHandler
490
+ Nothing -> missingNotificationHandler
491
+ -- See Note [Shutdown]
492
+ ReqMess req | shutdown -> requestDuringShutdown req
482
493
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
490
496
where
491
497
-- \| Checks to see if there's a dynamic handler, and uses it in favour of the
492
498
-- static handler, if it exists.
@@ -496,14 +502,32 @@ handle' logger mAction m msg = do
496
502
(Nothing , Just (ClientMessageHandler h)) -> Just h
497
503
(Nothing , Nothing ) -> Nothing
498
504
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
+
499
516
-- '$/' notifications should/could be ignored by server.
500
517
-- Don't log errors in that case.
501
518
-- See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#-notifications-and-requests.
502
- reportMissingHandler :: m ()
503
- reportMissingHandler =
519
+ missingNotificationHandler :: m ()
520
+ missingNotificationHandler =
504
521
let optional = isOptionalMethod (SomeMethod m)
505
522
in logger <& MissingHandler optional m `WithSeverity ` if optional then Warning else Error
506
523
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
+
507
531
progressCancelHandler :: (m ~ LspM config ) => LogAction m (WithSeverity LspProcessingLog ) -> TMessage Method_WindowWorkDoneProgressCancel -> m ()
508
532
progressCancelHandler logger (TNotificationMessage _ _ (WorkDoneProgressCancelParams tid)) = do
509
533
pdata <- getsState (progressCancel . resProgressData)
0 commit comments