From 2522d52bd23aea1ceef07d9db5affcf7fca3d8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20L=C3=B6scher?= Date: Mon, 27 Sep 2021 11:44:39 +0100 Subject: [PATCH 1/3] user background job for hover provider to avoid blocking request queue on large documents --- apps/els_lsp/src/els_hover_provider.erl | 70 ++++++++++++++++++++++--- apps/els_lsp/src/els_methods.erl | 4 +- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/apps/els_lsp/src/els_hover_provider.erl b/apps/els_lsp/src/els_hover_provider.erl index 555493c20..c66ed07b3 100644 --- a/apps/els_lsp/src/els_hover_provider.erl +++ b/apps/els_lsp/src/els_hover_provider.erl @@ -5,16 +5,24 @@ -behaviour(els_provider). --export([ handle_request/2 +-export([ handle_info/2 + , handle_request/2 , is_enabled/0 + , init/0 + , cancel_request/2 ]). -include("els_lsp.hrl"). +-include_lib("kernel/include/logger.hrl"). + +-define(SERVER, ?MODULE). %%============================================================================== %% Types %%============================================================================== --type state() :: any(). +-type state() :: #{in_progress => [progress_entry()]}. +-type progress_entry() :: {uri(), job()}. +-type job() :: pid(). %%============================================================================== %% els_provider functions @@ -23,24 +31,72 @@ is_enabled() -> true. +-spec init() -> state(). +init() -> + #{ in_progress => []}. + -spec handle_request(any(), state()) -> {any(), state()}. handle_request({hover, Params}, State) -> + #{in_progress := InProgress} = State, #{ <<"position">> := #{ <<"line">> := Line , <<"character">> := Character } , <<"textDocument">> := #{<<"uri">> := Uri} } = Params, + ?LOG_DEBUG("Starting hover job ""[uri=~p, line=~p, character=~p]" + , [Uri, Line, Character] + ), + Job = run_hover_job(Uri, Line, Character), + {Job, State#{in_progress => [{Uri, Job}|InProgress]}}. + + +-spec handle_info(any(), state()) -> state(). +handle_info({result, HoverResp, Job}, State) -> + ?LOG_DEBUG("Received hover result [job=~p]", [Job]), + #{ in_progress := InProgress } = State, + els_server:send_response(Job, HoverResp), + State#{ in_progress => lists:keydelete(Job, 2, InProgress) }. + +-spec cancel_request(job(), state()) -> state(). +cancel_request(Job, State) -> + ?LOG_DEBUG("Cancelling hover [job=~p]", [Job]), + els_background_job:stop(Job), + #{ in_progress := InProgress } = State, + State#{ in_progress => lists:keydelete(Job, 2, InProgress) }. + + +%%============================================================================== +%% Internal Functions +%%============================================================================== + +-spec run_hover_job(uri(), line(), column()) -> pid(). +run_hover_job(Uri, Line, Character) -> {ok, Doc} = els_utils:lookup_document(Uri), POIs = els_dt_document:get_element_at_pos(Doc, Line + 1, Character + 1), - {get_docs(Uri, POIs), State}. + Config = #{ task => fun get_docs/2 + , entries => [{Uri, POIs}] + , title => <<"Hover">> + , on_complete => + fun(HoverResp) -> + ?SERVER ! {result, HoverResp, self()}, + ok + end + }, + {ok, Pid} = els_background_job:new(Config), + Pid. + +-spec get_docs({uri(), [poi()]}, undefined) -> map() | null. +get_docs({Uri, POIs}, _) -> + do_get_docs(Uri, POIs). + --spec get_docs(uri(), [poi()]) -> map() | null. -get_docs(_Uri, []) -> +-spec do_get_docs(uri(), [poi()]) -> map() | null. +do_get_docs(_Uri, []) -> null; -get_docs(Uri, [POI|Rest]) -> +do_get_docs(Uri, [POI|Rest]) -> case els_docs:docs(Uri, POI) of [] -> - get_docs(Uri, Rest); + do_get_docs(Uri, Rest); Entries -> #{contents => els_markup_content:new(Entries)} end. diff --git a/apps/els_lsp/src/els_methods.erl b/apps/els_lsp/src/els_methods.erl index 5fa7b9e57..a1fcb5f29 100644 --- a/apps/els_lsp/src/els_methods.erl +++ b/apps/els_lsp/src/els_methods.erl @@ -231,8 +231,8 @@ textdocument_documentsymbol(Params, State) -> -spec textdocument_hover(params(), state()) -> result(). textdocument_hover(Params, State) -> Provider = els_hover_provider, - Response = els_provider:handle_request(Provider, {hover, Params}), - {response, Response, State}. + Job = els_provider:handle_request(Provider, {hover, Params}), + {noresponse, {Provider, Job}, State}. %%============================================================================== %% textDocument/completion From 995068059a474bdf49bc6b8930ece720cbe4e674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20L=C3=B6scher?= Date: Mon, 27 Sep 2021 13:37:05 +0100 Subject: [PATCH 2/3] move db operations of hover provider into background job --- apps/els_lsp/src/els_hover_provider.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/els_lsp/src/els_hover_provider.erl b/apps/els_lsp/src/els_hover_provider.erl index c66ed07b3..b6922bb54 100644 --- a/apps/els_lsp/src/els_hover_provider.erl +++ b/apps/els_lsp/src/els_hover_provider.erl @@ -71,10 +71,8 @@ cancel_request(Job, State) -> -spec run_hover_job(uri(), line(), column()) -> pid(). run_hover_job(Uri, Line, Character) -> - {ok, Doc} = els_utils:lookup_document(Uri), - POIs = els_dt_document:get_element_at_pos(Doc, Line + 1, Character + 1), Config = #{ task => fun get_docs/2 - , entries => [{Uri, POIs}] + , entries => [{Uri, Line, Character}] , title => <<"Hover">> , on_complete => fun(HoverResp) -> @@ -86,7 +84,9 @@ run_hover_job(Uri, Line, Character) -> Pid. -spec get_docs({uri(), [poi()]}, undefined) -> map() | null. -get_docs({Uri, POIs}, _) -> +get_docs({Uri, Line, Character}, _) -> + {ok, Doc} = els_utils:lookup_document(Uri), + POIs = els_dt_document:get_element_at_pos(Doc, Line + 1, Character + 1), do_get_docs(Uri, POIs). From 63162f5d3c1ba7e46b0faad945986490f31e7b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20L=C3=B6scher?= Date: Mon, 27 Sep 2021 17:28:47 +0100 Subject: [PATCH 3/3] fix dialyzer warnings in els_hover_provider --- apps/els_lsp/src/els_hover_provider.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/els_lsp/src/els_hover_provider.erl b/apps/els_lsp/src/els_hover_provider.erl index b6922bb54..b46b90b9c 100644 --- a/apps/els_lsp/src/els_hover_provider.erl +++ b/apps/els_lsp/src/els_hover_provider.erl @@ -83,7 +83,7 @@ run_hover_job(Uri, Line, Character) -> {ok, Pid} = els_background_job:new(Config), Pid. --spec get_docs({uri(), [poi()]}, undefined) -> map() | null. +-spec get_docs({uri(), integer(), integer()}, undefined) -> map() | null. get_docs({Uri, Line, Character}, _) -> {ok, Doc} = els_utils:lookup_document(Uri), POIs = els_dt_document:get_element_at_pos(Doc, Line + 1, Character + 1),