Skip to content

Commit fe6ccbe

Browse files
authored
Fix CreateWorkDoneProgress for VScode and Emacs (lexical-lsp#161)
CreateWorkDoneProgress is a request, not a notification, requiring a unique ID and expecting a response.
1 parent 67238ef commit fe6ccbe

File tree

8 files changed

+62
-28
lines changed

8 files changed

+62
-28
lines changed

apps/protocol/lib/lexical/protocol/notifications.ex

-6
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,6 @@ defmodule Lexical.Protocol.Notifications do
8787
end
8888
end
8989

90-
defmodule WorkDone.Progress.Create do
91-
use Proto
92-
93-
defnotification "window/workDoneProgress/create", Types.WorkDone.Progress.Create.Params
94-
end
95-
9690
defmodule Progress do
9791
use Proto
9892

apps/protocol/lib/lexical/protocol/requests.ex

+6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ defmodule Lexical.Protocol.Requests do
3333
defrequest "textDocument/definition", Types.Definition.Params
3434
end
3535

36+
defmodule CreateWorkDoneProgress do
37+
use Proto
38+
39+
defrequest "window/workDoneProgress/create", Types.WorkDone.Progress.Create.Params
40+
end
41+
3642
defmodule Formatting do
3743
use Proto
3844

apps/server/lib/lexical/server.ex

+7-1
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,15 @@ defmodule Lexical.Server do
106106
State.apply(state, message)
107107
end
108108

109+
def handle_message(nil, %State{} = state) do
110+
# NOTE: This deals with the response after a request is requested by the server,
111+
# such as the response of `CreateWorkDoneProgress`.
112+
{:ok, state}
113+
end
114+
109115
def handle_message(request, %State{} = state) do
110116
Provider.Queue.add(request, state.configuration)
111117

112-
{:ok, %State{} = state}
118+
{:ok, state}
113119
end
114120
end

apps/server/lib/lexical/server/configuration.ex

+16-11
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ defmodule Lexical.Server.Configuration do
2121
def new(root_uri, %ClientCapabilities{} = client_capabilities) do
2222
support = Support.new(client_capabilities)
2323
project = Project.new(root_uri)
24-
%__MODULE__{support: support, project: project}
24+
%__MODULE__{support: support, project: project} |> tap(&set/1)
2525
end
2626

2727
@spec default(t | nil) ::
@@ -53,20 +53,11 @@ defmodule Lexical.Server.Configuration do
5353
end
5454

5555
defp apply_config_change(%__MODULE__{} = old_config, %{} = settings) do
56-
with {:ok, new_config} <- maybe_set_env_vars(old_config, settings),
57-
{:ok, new_config} <- maybe_enable_dialyzer(new_config, settings) do
56+
with {:ok, new_config} <- maybe_enable_dialyzer(old_config, settings) do
5857
maybe_add_watched_extensions(new_config, settings)
5958
end
6059
end
6160

62-
defp maybe_set_env_vars(%__MODULE__{} = old_config, settings) do
63-
env_vars = Map.get(settings, "envVariables")
64-
65-
with {:ok, new_project} <- Project.set_env_vars(old_config.project, env_vars) do
66-
{:ok, %__MODULE__{old_config | project: new_project}}
67-
end
68-
end
69-
7061
defp maybe_enable_dialyzer(%__MODULE__{} = old_config, settings) do
7162
enabled? =
7263
case Dialyzer.check_support() do
@@ -110,4 +101,18 @@ defmodule Lexical.Server.Configuration do
110101
defp maybe_add_watched_extensions(%__MODULE__{} = old_config, _) do
111102
{:ok, old_config}
112103
end
104+
105+
@supports_keys ~w(work_done_progress?)a
106+
107+
def supports?(key) when key in @supports_keys do
108+
get_in(get(), [Access.key(:support), Access.key(key)]) || false
109+
end
110+
111+
def get do
112+
:persistent_term.get(__MODULE__, %__MODULE__{})
113+
end
114+
115+
defp set(%__MODULE__{} = config) do
116+
:persistent_term.put(__MODULE__, config)
117+
end
113118
end

apps/server/lib/lexical/server/configuration/support.ex

+9-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ defmodule Lexical.Server.Configuration.Support do
66
snippet?: false,
77
deprecated?: false,
88
tags?: false,
9-
signature_help?: false
9+
signature_help?: false,
10+
work_done_progress?: false
1011

1112
def new(%ClientCapabilities{} = client_capabilities) do
1213
dynamic_registration? =
@@ -39,13 +40,19 @@ defmodule Lexical.Server.Configuration.Support do
3940
|> get_in([:text_document, :signature_help])
4041
|> bool()
4142

43+
work_done_progress? =
44+
client_capabilities
45+
|> get_in([:window, :work_done_progress])
46+
|> bool()
47+
4248
%__MODULE__{
4349
code_action_dynamic_registration?: dynamic_registration?,
4450
hierarchical_document_symbols?: hierarchical_symbols?,
4551
snippet?: snippet?,
4652
deprecated?: deprecated?,
4753
tags?: tags?,
48-
signature_help?: signature_help?
54+
signature_help?: signature_help?,
55+
work_done_progress?: work_done_progress?
4956
}
5057
end
5158

apps/server/lib/lexical/server/project/progress/state.ex

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
defmodule Lexical.Server.Project.Progress.State do
22
alias Lexical.Project
3-
alias Lexical.Protocol.Notifications
3+
alias Lexical.Protocol.Id
4+
alias Lexical.Protocol.Requests
5+
alias Lexical.Server.Configuration
46
alias Lexical.Server.Project.Progress.Value
57
alias Lexical.Server.Transport
68

@@ -42,12 +44,16 @@ defmodule Lexical.Server.Project.Progress.State do
4244
end
4345

4446
defp write_work_done(token) do
45-
progress = Notifications.WorkDone.Progress.Create.new(token: token)
46-
Transport.write(progress)
47+
if Configuration.supports?(:work_done_progress?) do
48+
progress = Requests.CreateWorkDoneProgress.new(id: Id.next(), token: token)
49+
Transport.write(progress)
50+
end
4751
end
4852

4953
defp write(%{token: token} = progress) when not is_nil(token) do
50-
progress |> Value.to_protocol() |> Transport.write()
54+
if Configuration.supports?(:work_done_progress?) do
55+
progress |> Value.to_protocol() |> Transport.write()
56+
end
5157
end
5258

5359
defp write(_), do: :ok

apps/server/lib/lexical/server/state.ex

-3
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,6 @@ defmodule Lexical.Server.State do
8787
{:ok, config, response} ->
8888
Transport.write(response)
8989
{:ok, %__MODULE__{state | configuration: config}}
90-
91-
error ->
92-
error
9390
end
9491

9592
{:ok, state}

apps/server/test/lexical/server/project/progress_test.exs

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
defmodule Lexical.Server.Project.ProgressTest do
22
alias Lexical.Protocol.Notifications
3+
alias Lexical.Protocol.Requests
34
alias Lexical.RemoteControl
5+
alias Lexical.Server.Configuration
46
alias Lexical.Server.Project
57
alias Lexical.Server.Transport
68

@@ -38,10 +40,12 @@ defmodule Lexical.Server.Project.ProgressTest do
3840
setup [:with_patched_tranport]
3941

4042
test "it should be able to send the report progress", %{project: project} do
43+
patch(Configuration, :supports?, fn :work_done_progress? -> true end)
44+
4145
begin_message = progress(:begin, "mix compile")
4246
Project.Dispatch.broadcast(project, begin_message)
4347

44-
assert_receive {:transport, %Notifications.WorkDone.Progress.Create{lsp: %{token: token}}}
48+
assert_receive {:transport, %Requests.CreateWorkDoneProgress{lsp: %{token: token}}}
4549
assert_receive {:transport, %Notifications.Progress{}}
4650

4751
report_message = progress(:report, "mix compile", "lib/file.ex")
@@ -53,5 +57,14 @@ defmodule Lexical.Server.Project.ProgressTest do
5357
assert value.percentage == nil
5458
assert value.cancellable == nil
5559
end
60+
61+
test "it should write nothing when the client does not support work done", %{project: project} do
62+
patch(Configuration, :supports?, fn :work_done_progress? -> false end)
63+
64+
begin_message = progress(:begin, "mix compile")
65+
Project.Dispatch.broadcast(project, begin_message)
66+
67+
refute_receive {:transport, %Requests.CreateWorkDoneProgress{lsp: %{}}}
68+
end
5669
end
5770
end

0 commit comments

Comments
 (0)