@@ -58,6 +58,7 @@ defmodule ElixirLS.LanguageServer.Server do
58
58
analysis_ready?: false ,
59
59
received_shutdown?: false ,
60
60
requests: % { } ,
61
+ requests_ids_by_pid: % { } ,
61
62
# Tracks source files that are currently open in the editor
62
63
source_files: % { } ,
63
64
awaiting_contracts: [ ] ,
@@ -160,39 +161,48 @@ defmodule ElixirLS.LanguageServer.Server do
160
161
def handle_call ( { :request_finished , id , result } , _from , state = % __MODULE__ { } ) do
161
162
# in case the request has been cancelled we silently ignore
162
163
{ popped_request , updated_requests } = Map . pop ( state . requests , id )
163
- if popped_request do
164
- { { _pid , command , start_time } , requests } = popped_request
165
- case result do
166
- { :error , type , msg , send_telemetry } ->
167
- JsonRpc . respond_with_error ( id , type , msg )
168
164
169
- if send_telemetry do
165
+ requests_ids_by_pid =
166
+ if popped_request do
167
+ { pid , ref , command , start_time } = popped_request
168
+ # we are no longer interested in :DOWN message
169
+ Process . demonitor ( ref , [ :flush ] )
170
+
171
+ case result do
172
+ { :error , type , msg , send_telemetry } ->
173
+ JsonRpc . respond_with_error ( id , type , msg )
174
+
175
+ if send_telemetry do
176
+ JsonRpc . telemetry (
177
+ "lsp_request_error" ,
178
+ % {
179
+ "elixir_ls.lsp_command" => String . replace ( command , "/" , "_" ) ,
180
+ "elixir_ls.lsp_error" => to_string ( type ) ,
181
+ "elixir_ls.lsp_error_message" => msg || to_string ( type )
182
+ } ,
183
+ % { }
184
+ )
185
+ end
186
+
187
+ { :ok , result } ->
188
+ elapsed = System . monotonic_time ( :millisecond ) - start_time
189
+ JsonRpc . respond ( id , result )
190
+
170
191
JsonRpc . telemetry (
171
- "lsp_request_error" ,
192
+ "lsp_request" ,
193
+ % { "elixir_ls.lsp_command" => String . replace ( command , "/" , "_" ) } ,
172
194
% {
173
- "elixir_ls.lsp_command" => String . replace ( command , "/" , "_" ) ,
174
- "elixir_ls.lsp_error" => type ,
175
- "elixir_ls.lsp_error_message" => msg
176
- } ,
177
- % { }
195
+ "elixir_ls.lsp_request_time" => elapsed
196
+ }
178
197
)
179
- end
180
-
181
- { :ok , result } ->
182
- elapsed = System . monotonic_time ( :millisecond ) - start_time
183
- JsonRpc . respond ( id , result )
198
+ end
184
199
185
- JsonRpc . telemetry (
186
- "lsp_request" ,
187
- % { "elixir_ls.lsp_command" => String . replace ( command , "/" , "_" ) } ,
188
- % {
189
- "elixir_ls.lsp_request_time" => elapsed
190
- }
191
- )
200
+ Map . delete ( state . requests_ids_by_pid , pid )
201
+ else
202
+ state . requests_ids_by_pid
192
203
end
193
- end
194
204
195
- state = % { state | requests: updated_requests }
205
+ state = % { state | requests: updated_requests , requests_ids_by_pid: requests_ids_by_pid }
196
206
{ :reply , :ok , state }
197
207
end
198
208
@@ -314,30 +324,35 @@ defmodule ElixirLS.LanguageServer.Server do
314
324
end
315
325
316
326
@ impl GenServer
317
- def handle_info ( { :DOWN , _ref , :process , pid , reason } , % __MODULE__ { requests: requests } = state ) do
318
- state =
319
- case Enum . find ( requests , & match? ( { _ , { ^ pid , _ , _ } } , & 1 ) ) do
320
- { id , { ^ pid , command , _start_time } } ->
321
- error_msg = Exception . format_exit ( reason )
322
- JsonRpc . respond_with_error ( id , :server_error , error_msg )
327
+ def handle_info (
328
+ { :DOWN , ref , :process , pid , reason } ,
329
+ % __MODULE__ { requests: requests , requests_ids_by_pid: requests_ids_by_pid } = state
330
+ ) do
331
+ { id , updated_requests_ids_by_pid } = Map . pop ( requests_ids_by_pid , pid )
323
332
324
- JsonRpc . telemetry (
325
- "lsp_request_error" ,
326
- % {
327
- "elixir_ls.lsp_command" => String . replace ( command , "/" , "_" ) ,
328
- "elixir_ls.lsp_error" => :server_error ,
329
- "elixir_ls.lsp_error_message" => error_msg
330
- } ,
331
- % { }
332
- )
333
+ updated_requests =
334
+ if id do
335
+ { { ^ pid , ^ ref , command , _start_time } , updated_requests } = Map . pop! ( requests , id )
336
+ error_msg = Exception . format_exit ( reason )
337
+ JsonRpc . respond_with_error ( id , :server_error , error_msg )
333
338
334
- % { state | requests: Map . delete ( requests , id ) }
339
+ JsonRpc . telemetry (
340
+ "lsp_request_error" ,
341
+ % {
342
+ "elixir_ls.lsp_command" => String . replace ( command , "/" , "_" ) ,
343
+ "elixir_ls.lsp_error" => :server_error ,
344
+ "elixir_ls.lsp_error_message" => error_msg
345
+ } ,
346
+ % { }
347
+ )
335
348
336
- nil ->
337
- state
349
+ updated_requests
350
+ else
351
+ requests
338
352
end
339
353
340
- { :noreply , state }
354
+ { :noreply ,
355
+ % { state | requests: updated_requests , requests_ids_by_pid: updated_requests_ids_by_pid } }
341
356
end
342
357
343
358
@ impl GenServer
@@ -426,19 +441,26 @@ defmodule ElixirLS.LanguageServer.Server do
426
441
state
427
442
end
428
443
429
- defp handle_notification ( cancel_request ( id ) , % __MODULE__ { requests: requests } = state ) do
430
- case requests do
431
- % { ^ id => { pid , _command , _start_time } } ->
444
+ defp handle_notification (
445
+ cancel_request ( id ) ,
446
+ % __MODULE__ { requests: requests , requests_ids_by_pid: requests_ids_by_pid } = state
447
+ ) do
448
+ { request , updated_requests } = Map . pop ( requests , id )
449
+
450
+ updated_requests_ids_by_pid =
451
+ if request do
452
+ { pid , ref , _command , _start_time } = request
453
+ # we are no longer interested in :DOWN message
454
+ Process . demonitor ( ref , [ :flush ] )
432
455
Process . exit ( pid , :cancelled )
433
456
JsonRpc . respond_with_error ( id , :request_cancelled , "Request cancelled" )
457
+ Map . delete ( requests_ids_by_pid , pid )
458
+ else
459
+ Logger . debug ( "Received $/cancelRequest for unknown request id: #{ inspect ( id ) } " )
460
+ requests_ids_by_pid
461
+ end
434
462
435
- % { state | requests: Map . delete ( requests , id ) }
436
-
437
- _ ->
438
- Logger . warning ( "Received $/cancelRequest for unknown request id: #{ inspect ( id ) } " )
439
-
440
- state
441
- end
463
+ % { state | requests: updated_requests , requests_ids_by_pid: updated_requests_ids_by_pid }
442
464
end
443
465
444
466
# We don't start performing builds until we receive settings from the client in case they've set
@@ -729,8 +751,13 @@ defmodule ElixirLS.LanguageServer.Server do
729
751
state
730
752
731
753
{ :async , fun , state } ->
732
- { pid , _ref } = handle_request_async ( id , fun )
733
- % { state | requests: Map . put ( state . requests , id , { pid , command , start_time } ) }
754
+ { pid , ref } = handle_request_async ( id , fun )
755
+
756
+ % {
757
+ state
758
+ | requests: Map . put ( state . requests , id , { pid , ref , command , start_time } ) ,
759
+ requests_ids_by_pid: Map . put ( state . requests_ids_by_pid , pid , id )
760
+ }
734
761
end
735
762
rescue
736
763
e in InvalidParamError ->
0 commit comments