@@ -76,6 +76,9 @@ runLanguageServer options userHandlers getIdeState = do
76
76
atomically $ modifyTVar pendingRequests (Set. insert _id)
77
77
writeChan clientMsgChan $ Response r wrap f
78
78
let withNotification old f = Just $ \ r -> writeChan clientMsgChan $ Notification r (\ lsp ide x -> f lsp ide x >> whenJust old ($ r))
79
+ let withResponseAndRequest wrap wrapNewReq f = Just $ \ r@ RequestMessage {_id} -> do
80
+ atomically $ modifyTVar pendingRequests (Set. insert _id)
81
+ writeChan clientMsgChan $ ResponseAndRequest r wrap wrapNewReq f
79
82
let cancelRequest reqId = atomically $ do
80
83
queued <- readTVar pendingRequests
81
84
-- We want to avoid that the list of cancelled requests
@@ -93,13 +96,14 @@ runLanguageServer options userHandlers getIdeState = do
93
96
unless (reqId `Set.member` cancelled) retry
94
97
let PartialHandlers parts =
95
98
setHandlersIgnore <> -- least important
96
- setHandlersDefinition <> setHandlersHover <> setHandlersCodeAction <> -- useful features someone may override
99
+ setHandlersDefinition <> setHandlersHover <>
100
+ setHandlersCodeAction <> setHandlersCodeLens <> -- useful features someone may override
97
101
userHandlers <>
98
102
setHandlersNotifications <> -- absolutely critical, join them with user notifications
99
103
cancelHandler cancelRequest
100
104
-- Cancel requests are special since they need to be handled
101
105
-- out of order to be useful. Existing handlers are run afterwards.
102
- handlers <- parts WithMessage {withResponse, withNotification} def
106
+ handlers <- parts WithMessage {withResponse, withNotification, withResponseAndRequest } def
103
107
104
108
let initializeCallbacks = LSP. InitializeCallbacks
105
109
{ LSP. onInitialConfiguration = const $ Right ()
@@ -131,30 +135,42 @@ runLanguageServer options userHandlers getIdeState = do
131
135
" Message: " ++ show x ++ " \n " ++
132
136
" Exception: " ++ show e
133
137
Response x@ RequestMessage {_id, _params} wrap act ->
134
- flip finally (clearReqId _id) $
135
- catch (do
136
- -- We could optimize this by first checking if the id
137
- -- is in the cancelled set. However, this is unlikely to be a
138
- -- bottleneck and the additional check might hide
139
- -- issues with async exceptions that need to be fixed.
140
- cancelOrRes <- race (waitForCancel _id) $ act lspFuncs ide _params
141
- case cancelOrRes of
142
- Left () -> do
143
- logDebug (ideLogger ide) $ T. pack $
144
- " Cancelled request " <> show _id
145
- sendFunc $ wrap $ ResponseMessage " 2.0" (responseId _id) Nothing $
146
- Just $ ResponseError RequestCancelled " " Nothing
147
- Right res ->
148
- sendFunc $ wrap $ ResponseMessage " 2.0" (responseId _id) (Just res) Nothing
149
- ) $ \ (e :: SomeException ) -> do
150
- logError (ideLogger ide) $ T. pack $
151
- " Unexpected exception on request, please report!\n " ++
152
- " Message: " ++ show x ++ " \n " ++
153
- " Exception: " ++ show e
154
- sendFunc $ wrap $ ResponseMessage " 2.0" (responseId _id) Nothing $
155
- Just $ ResponseError InternalError (T. pack $ show e) Nothing
138
+ checkCancelled ide clearReqId waitForCancel lspFuncs wrap act x _id _params $
139
+ \ res -> sendFunc $ wrap $ ResponseMessage " 2.0" (responseId _id) (Just res) Nothing
140
+ ResponseAndRequest x@ RequestMessage {_id, _params} wrap wrapNewReq act ->
141
+ checkCancelled ide clearReqId waitForCancel lspFuncs wrap act x _id _params $
142
+ \ (res, newReq) -> do
143
+ sendFunc $ wrap $ ResponseMessage " 2.0" (responseId _id) (Just res) Nothing
144
+ case newReq of
145
+ Nothing -> return ()
146
+ Just (rm, newReqParams) -> do
147
+ reqId <- getNextReqId
148
+ sendFunc $ wrapNewReq $ RequestMessage " 2.0" reqId rm newReqParams
156
149
pure Nothing
157
150
151
+ checkCancelled ide clearReqId waitForCancel lspFuncs@ LSP. LspFuncs {.. } wrap act msg _id _params k =
152
+ flip finally (clearReqId _id) $
153
+ catch (do
154
+ -- We could optimize this by first checking if the id
155
+ -- is in the cancelled set. However, this is unlikely to be a
156
+ -- bottleneck and the additional check might hide
157
+ -- issues with async exceptions that need to be fixed.
158
+ cancelOrRes <- race (waitForCancel _id) $ act lspFuncs ide _params
159
+ case cancelOrRes of
160
+ Left () -> do
161
+ logDebug (ideLogger ide) $ T. pack $
162
+ " Cancelled request " <> show _id
163
+ sendFunc $ wrap $ ResponseMessage " 2.0" (responseId _id) Nothing $
164
+ Just $ ResponseError RequestCancelled " " Nothing
165
+ Right res -> k res
166
+ ) $ \ (e :: SomeException ) -> do
167
+ logError (ideLogger ide) $ T. pack $
168
+ " Unexpected exception on request, please report!\n " ++
169
+ " Message: " ++ show msg ++ " \n " ++
170
+ " Exception: " ++ show e
171
+ sendFunc $ wrap $ ResponseMessage " 2.0" (responseId _id) Nothing $
172
+ Just $ ResponseError InternalError (T. pack $ show e) Nothing
173
+
158
174
159
175
-- | Things that get sent to us, but we don't deal with.
160
176
-- Set them to avoid a warning in VS Code output.
@@ -177,11 +193,16 @@ cancelHandler cancelRequest = PartialHandlers $ \_ x -> return x
177
193
-- and defer precise processing until later (allows us to keep at a higher level of abstraction slightly longer)
178
194
data Message
179
195
= forall m req resp . (Show m , Show req ) => Response (RequestMessage m req resp ) (ResponseMessage resp -> FromServerMessage ) (LSP. LspFuncs () -> IdeState -> req -> IO resp )
196
+ -- | Used for cases in which we need to send not only a response,
197
+ -- but also an additional request to the client.
198
+ -- For example, 'executeCommand' may generate an 'applyWorkspaceEdit' request.
199
+ | forall m rm req resp newReqParams newReqBody . (Show m , Show rm , Show req ) => ResponseAndRequest (RequestMessage m req resp ) (ResponseMessage resp -> FromServerMessage ) (RequestMessage rm newReqParams newReqBody -> FromServerMessage ) (LSP. LspFuncs () -> IdeState -> req -> IO (resp , Maybe (rm , newReqParams )))
180
200
| forall m req . (Show m , Show req ) => Notification (NotificationMessage m req ) (LSP. LspFuncs () -> IdeState -> req -> IO () )
181
201
182
202
183
203
modifyOptions :: LSP. Options -> LSP. Options
184
204
modifyOptions x = x{ LSP. textDocumentSync = Just $ tweakTDS origTDS
205
+ , LSP. executeCommandCommands = Just [" typesignature.add" ]
185
206
}
186
207
where
187
208
tweakTDS tds = tds{_openClose= Just True , _change= Just TdSyncIncremental , _save= Just $ SaveOptions Nothing }
0 commit comments