Skip to content

Commit 0851d87

Browse files
Fixes and improvements around text synchronisation (elixir-editors#411)
* Purge consolidated protocols before compilation Fixes elixir-editors#395 * move to dialyzer_test.exs * dialyzer_enabled? is already asserted at call site * add argument type assertions * return invalid_param when handling a request involving not open uri * add tests for text synchronization fixes some issues when certain sequence of notifications would create nil entries in source_files map * warn when cancelling unknown request * fix difference in watched extensions * add tests to workspace/didChangeWatchedFiles fix some consistency issues: dirty? flag not updated when file modified outside (no didSave) rebuild not triggered when opened dirty file modified outside * add tests for SourceFile.apply_content_changes based on https://github.com/microsoft/vscode-languageserver-node fixes a few edge cases when dealing with invalid ranges * add test * add utf test * add test fix full_range invalid when last line with unicode * fix apply_content_changes not preserving windows line endings * wip * do not warn if consolidation path does not exist * fix tests * return invalid_request * handle invalid uri in async requests * return invalid_request for not matched commands * handle client request errors * run formatter * rename * Refactor implementation of SourceFile.lines_with_endings The previous implementation did not have any bugs (that I saw), but I did find it more difficult to read and understand. I expect performance to be comparable. For more comprehensive testing I have added StreamData which adds property-based testing. We can probably use that in other portions of the code base as well. * Update apps/language_server/test/source_file_test.exs Co-authored-by: Jason Axelson <[email protected]> * run formatter * add disclaimer * combine lines_with_endings test cases Co-authored-by: Jason Axelson <[email protected]> Co-authored-by: Jason Axelson <[email protected]>
1 parent 7c27bce commit 0851d87

File tree

14 files changed

+1436
-173
lines changed

14 files changed

+1436
-173
lines changed

apps/language_server/lib/language_server/build.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ defmodule ElixirLS.LanguageServer.Build do
215215
with {:ok, beams} <- File.ls(path) do
216216
Enum.map(beams, &(&1 |> Path.rootname(".beam") |> String.to_atom() |> purge_module()))
217217
else
218+
{:error, :enoent} ->
219+
# consolidation_path does not exist
220+
:ok
221+
218222
{:error, reason} ->
219223
JsonRpc.show_message(
220224
:warning,

apps/language_server/lib/language_server/mix_shell.ex

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,12 @@ defmodule ElixirLS.LanguageServer.MixShell do
4747
])
4848

4949
case response do
50-
{:ok, %{"result" => result}} -> result
51-
_ -> true
50+
{:ok, %{"result" => result}} ->
51+
result
52+
53+
other ->
54+
error("[ElixirLS] unexpected client response #{inspect(other)}, assuming yes")
55+
true
5256
end
5357
else
5458
Mix.Shell.IO.yes?(message)

apps/language_server/lib/language_server/providers/execute_command.ex

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ defmodule ElixirLS.LanguageServer.Providers.ExecuteCommand do
55

66
alias ElixirLS.LanguageServer.{JsonRpc, SourceFile}
77
import ElixirLS.LanguageServer.Protocol
8+
alias ElixirLS.LanguageServer.Server
89

910
@default_target_line_length 98
1011

11-
def execute("spec:" <> _, args, source_files) do
12+
def execute("spec:" <> _, args, state) do
1213
[
1314
%{
1415
"uri" => uri,
@@ -23,7 +24,9 @@ defmodule ElixirLS.LanguageServer.Providers.ExecuteCommand do
2324
mod = String.to_atom(mod)
2425
fun = String.to_atom(fun)
2526

26-
cur_text = source_files[uri].text
27+
source_file = Server.get_source_file(state, uri)
28+
29+
cur_text = source_file.text
2730

2831
# In case line has changed since this suggestion was generated, look for the function's current
2932
# line number and fall back to the previous line number if we can't guess the new one
@@ -67,15 +70,27 @@ defmodule ElixirLS.LanguageServer.Providers.ExecuteCommand do
6770
"#{indentation}@spec #{spec}\n"
6871
end
6972

70-
JsonRpc.send_request("workspace/applyEdit", %{
71-
"label" => "Add @spec to #{mod}.#{fun}/#{arity}",
72-
"edit" => %{
73-
"changes" => %{
74-
uri => [%{"range" => range(line - 1, 0, line - 1, 0), "newText" => formatted}]
73+
edit_result =
74+
JsonRpc.send_request("workspace/applyEdit", %{
75+
"label" => "Add @spec to #{mod}.#{fun}/#{arity}",
76+
"edit" => %{
77+
"changes" => %{
78+
uri => [%{"range" => range(line - 1, 0, line - 1, 0), "newText" => formatted}]
79+
}
7580
}
76-
}
77-
})
81+
})
82+
83+
case edit_result do
84+
{:ok, %{"applied" => true}} ->
85+
{:ok, nil}
86+
87+
other ->
88+
{:error, :server_error,
89+
"cannot insert spec, workspace/applyEdit returned #{inspect(other)}"}
90+
end
91+
end
7892

79-
{:ok, nil}
93+
def execute(_command, _args, _state) do
94+
{:error, :invalid_request, nil}
8095
end
8196
end

apps/language_server/lib/language_server/providers/formatting.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ defmodule ElixirLS.LanguageServer.Providers.Formatting do
66
function_exported?(Code, :format_string!, 2)
77
end
88

9-
def format(source_file, uri, project_dir) do
9+
def format(%SourceFile{} = source_file, uri, project_dir) do
1010
if can_format?(uri, project_dir) do
1111
case SourceFile.formatter_opts(uri) do
1212
{:ok, opts} ->

apps/language_server/lib/language_server/providers/on_type_formatting.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ defmodule ElixirLS.LanguageServer.Providers.OnTypeFormatting do
1010
alias ElixirLS.LanguageServer.SourceFile
1111
import ElixirLS.LanguageServer.Protocol
1212

13-
def format(source_file, line, character, "\n", _options) do
13+
def format(%SourceFile{} = source_file, line, character, "\n", _options) do
1414
lines = SourceFile.lines(source_file)
1515
prev_line = Enum.at(lines, line - 1)
1616

apps/language_server/lib/language_server/providers/signature_help.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule ElixirLS.LanguageServer.Providers.SignatureHelp do
22
alias ElixirLS.LanguageServer.SourceFile
33

4-
def signature(source_file, line, character) do
4+
def signature(%SourceFile{} = source_file, line, character) do
55
response =
66
case ElixirSense.signature(source_file.text, line + 1, character + 1) do
77
%{active_param: active_param, signatures: signatures} ->

0 commit comments

Comments
 (0)