From 2db7a34b31f617796aece133e23c1e1f8d2591f9 Mon Sep 17 00:00:00 2001 From: scottming Date: Sat, 18 Feb 2023 13:09:19 +0800 Subject: [PATCH 01/11] Support go to definition in experimental project --- .../experimental/protocol/requests.ex | 8 + .../experimental/protocol/responses.ex | 6 + .../provider/handlers/goto_definition.ex | 49 ++++ .../handlers/goto_definition_test.exs | 215 ++++++++++++++++++ 4 files changed, 278 insertions(+) create mode 100644 apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex create mode 100644 apps/language_server/test/language_server/experimental/provider/handlers/goto_definition_test.exs diff --git a/apps/language_server/lib/language_server/experimental/protocol/requests.ex b/apps/language_server/lib/language_server/experimental/protocol/requests.ex index 7094ea3e2..9b7e42101 100644 --- a/apps/language_server/lib/language_server/experimental/protocol/requests.ex +++ b/apps/language_server/lib/language_server/experimental/protocol/requests.ex @@ -27,6 +27,14 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Requests do position: Types.Position end + defmodule GotoDefinition do + use Proto + + defrequest "textDocument/definition", :exclusive, + text_document: Types.TextDocument.Identifier, + position: Types.Position + end + defmodule Formatting do use Proto diff --git a/apps/language_server/lib/language_server/experimental/protocol/responses.ex b/apps/language_server/lib/language_server/experimental/protocol/responses.ex index beebeac88..0d18db2ee 100644 --- a/apps/language_server/lib/language_server/experimental/protocol/responses.ex +++ b/apps/language_server/lib/language_server/experimental/protocol/responses.ex @@ -8,6 +8,12 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Responses do defresponse optional(list_of(Types.Location)) end + defmodule GotoDefinition do + use Proto + + defresponse optional(Types.Location) + end + defmodule Formatting do use Proto diff --git a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex new file mode 100644 index 000000000..16370e495 --- /dev/null +++ b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex @@ -0,0 +1,49 @@ +defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition do + alias ElixirLS.LanguageServer.Experimental.Protocol.Requests.GotoDefinition + alias ElixirLS.LanguageServer.Experimental.Protocol.Responses + alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Location + alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Range, as: LSRange + alias ElixirLS.LanguageServer.Experimental.SourceFile + alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions + + def handle(%GotoDefinition{} = request, _) do + source_file = request.source_file + pos = request.position + + source_file_string = source_file |> SourceFile.to_string() + + with %ElixirSense.Location{} = location <- + ElixirSense.definition(source_file_string, pos.line, pos.character + 1), + {:ok, definition} <- build_definition(location, source_file) do + {:reply, Responses.GotoDefinition.new(request.id, definition)} + else + nil -> + {:reply, nil} + + {:error, reason} -> + {:error, Responses.GotoDefinition.error(request.id, :request_failed, reason)} + end + end + + defp build_definition( + %{line: line, column: column} = elixir_sense_definition, + current_source_file + ) do + position = SourceFile.Position.new(line, column - 1) + + with {:ok, source_file} <- get_source_file(elixir_sense_definition, current_source_file), + {:ok, ls_position} <- Conversions.to_lsp(position, source_file) do + ls_range = %LSRange{start: ls_position, end: ls_position} + {:ok, Location.new(uri: source_file.uri, range: ls_range)} + end + end + + defp get_source_file(%{file: nil}, current_source_file) do + {:ok, current_source_file} + end + + defp get_source_file(%{file: path}, _) do + uri = Conversions.ensure_uri(path) + SourceFile.Store.open_temporary(uri) + end +end diff --git a/apps/language_server/test/language_server/experimental/provider/handlers/goto_definition_test.exs b/apps/language_server/test/language_server/experimental/provider/handlers/goto_definition_test.exs new file mode 100644 index 000000000..9779a38e2 --- /dev/null +++ b/apps/language_server/test/language_server/experimental/provider/handlers/goto_definition_test.exs @@ -0,0 +1,215 @@ +defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinitionTest do + use ExUnit.Case, async: true + + alias ElixirLS.LanguageServer.Experimental.Protocol.Requests.GotoDefinition + alias ElixirLS.LanguageServer.Experimental.Protocol.Responses + alias ElixirLS.LanguageServer.Experimental.Provider.Env + alias ElixirLS.LanguageServer.Experimental.Provider.Handlers + alias ElixirLS.LanguageServer.Experimental.SourceFile + alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions + + alias ElixirLS.LanguageServer.Fixtures.LspProtocol + alias ElixirLS.LanguageServer.Test.FixtureHelpers + + import LspProtocol + import ElixirLS.Test.TextLoc, only: [annotate_assert: 4] + + setup do + {:ok, _} = start_supervised(SourceFile.Store) + :ok + end + + def request(file_path, line, char) do + uri = Conversions.ensure_uri(file_path) + + params = [ + text_document: [uri: uri], + position: [line: line, character: char] + ] + + with {:ok, contents} <- File.read(file_path), + :ok <- SourceFile.Store.open(uri, contents, 1), + {:ok, _source_file} <- SourceFile.Store.fetch(uri), + {:ok, req} <- build(GotoDefinition, params) do + GotoDefinition.to_elixir(req) + end + end + + def handle(request) do + Handlers.GotoDefinition.handle(request, Env.new()) + end + + defp arrange_referenced_file do + file_path = FixtureHelpers.get_path("references_referenced.ex") + uri = Conversions.ensure_uri(file_path) + %{uri: uri} + end + + test "find definition remote function call" do + b_file = arrange_referenced_file() + file_path = FixtureHelpers.get_path("references_remote.ex") + {line, char} = {4, 28} + + {:ok, request} = request(file_path, line, char) + + annotate_assert(file_path, line, char, """ + ReferencesReferenced.referenced_fun() + ^ + """) + + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + + assert definition.uri == b_file.uri + assert definition.range.start.line == 1 + assert definition.range.start.character == 6 + assert definition.range.end.line == 1 + assert definition.range.end.character == 6 + end + + test "find definition remote macro call" do + b_file = arrange_referenced_file() + file_path = FixtureHelpers.get_path("references_remote.ex") + {line, char} = {8, 28} + + {:ok, request} = request(file_path, line, char) + + annotate_assert(file_path, line, char, """ + ReferencesReferenced.referenced_macro a do + ^ + """) + + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + + assert definition.uri == b_file.uri + assert definition.range.start.line == 8 + assert definition.range.start.character == 11 + assert definition.range.end.line == 8 + assert definition.range.end.character == 11 + end + + test "find definition imported function call" do + b_file = arrange_referenced_file() + file_path = FixtureHelpers.get_path("references_imported.ex") + {line, char} = {4, 5} + + {:ok, request} = request(file_path, line, char) + + annotate_assert(file_path, line, char, """ + referenced_fun() + ^ + """) + + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + + assert definition.uri == b_file.uri + assert definition.range.start.line == 1 + assert definition.range.start.character == 6 + assert definition.range.end.line == 1 + assert definition.range.end.character == 6 + end + + test "find definition imported macro call" do + b_file = arrange_referenced_file() + file_path = FixtureHelpers.get_path("references_imported.ex") + {line, char} = {8, 5} + + {:ok, request} = request(file_path, line, char) + + annotate_assert(file_path, line, char, """ + referenced_macro a do + ^ + """) + + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + + assert definition.uri == b_file.uri + assert definition.range.start.line == 8 + assert definition.range.start.character == 11 + assert definition.range.end.line == 8 + assert definition.range.end.character == 11 + end + + test "find definition local function call" do + b_file = arrange_referenced_file() + file_path = FixtureHelpers.get_path("references_referenced.ex") + {line, char} = {15, 5} + + {:ok, request} = request(file_path, line, char) + + annotate_assert(file_path, line, char, """ + referenced_fun() + ^ + """) + + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + + assert definition.uri == b_file.uri + assert definition.range.start.line == 1 + assert definition.range.start.character == 6 + assert definition.range.end.line == 1 + assert definition.range.end.character == 6 + end + + test "find definition local macro call" do + b_file = arrange_referenced_file() + file_path = FixtureHelpers.get_path("references_referenced.ex") + {line, char} = {19, 5} + + {:ok, request} = request(file_path, line, char) + + annotate_assert(file_path, line, char, """ + referenced_macro a do + ^ + """) + + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + + assert definition.uri == b_file.uri + assert definition.range.start.line == 8 + assert definition.range.start.character == 11 + assert definition.range.end.line == 8 + assert definition.range.end.character == 11 + end + + test "find definition variable" do + b_file = arrange_referenced_file() + file_path = FixtureHelpers.get_path("references_referenced.ex") + {line, char} = {4, 13} + + {:ok, request} = request(file_path, line, char) + + annotate_assert(file_path, line, char, """ + IO.puts(referenced_variable + 1) + ^ + """) + + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + + assert definition.uri == b_file.uri + assert definition.range.start.line == 2 + assert definition.range.start.character == 4 + assert definition.range.end.line == 2 + assert definition.range.end.character == 4 + end + + test "find definition attribute" do + b_file = arrange_referenced_file() + file_path = FixtureHelpers.get_path("references_referenced.ex") + {line, char} = {27, 5} + + {:ok, request} = request(file_path, line, char) + + annotate_assert(file_path, line, char, """ + @referenced_attribute + ^ + """) + + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + + assert definition.uri == b_file.uri + assert definition.range.start.line == 24 + assert definition.range.start.character == 2 + assert definition.range.end.line == 24 + assert definition.range.end.character == 2 + end +end From 5470d2415b51dcd055f51debb63c0053ad11ecd7 Mon Sep 17 00:00:00 2001 From: scottming Date: Sat, 18 Feb 2023 15:43:10 +0800 Subject: [PATCH 02/11] Fix the nil bug and add the request->handler to the queue --- .../experimental/provider/handlers/goto_definition.ex | 4 +++- .../lib/language_server/experimental/provider/queue.ex | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex index 16370e495..b22313816 100644 --- a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex +++ b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex @@ -5,6 +5,7 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Range, as: LSRange alias ElixirLS.LanguageServer.Experimental.SourceFile alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions + require Logger def handle(%GotoDefinition{} = request, _) do source_file = request.source_file @@ -18,9 +19,10 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition {:reply, Responses.GotoDefinition.new(request.id, definition)} else nil -> - {:reply, nil} + {:reply, Responses.GotoDefinition.new(request.id, nil)} {:error, reason} -> + Logger.error("GotoDefinition failed: #{inspect(reason)}") {:error, Responses.GotoDefinition.error(request.id, :request_failed, reason)} end end diff --git a/apps/language_server/lib/language_server/experimental/provider/queue.ex b/apps/language_server/lib/language_server/experimental/provider/queue.ex index 834594b93..0284bbb8e 100644 --- a/apps/language_server/lib/language_server/experimental/provider/queue.ex +++ b/apps/language_server/lib/language_server/experimental/provider/queue.ex @@ -15,7 +15,8 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Queue do @requests_to_handler %{ Requests.FindReferences => Handlers.FindReferences, Requests.Formatting => Handlers.Formatting, - Requests.CodeAction => Handlers.CodeAction + Requests.CodeAction => Handlers.CodeAction, + Requests.GotoDefinition => Handlers.GotoDefinition } def new do From e3984887bf3fdb07505dde3a407943700b0d0c06 Mon Sep 17 00:00:00 2001 From: scottming Date: Sun, 19 Feb 2023 21:58:19 +0800 Subject: [PATCH 03/11] Remove a unneed line --- .../experimental/provider/handlers/goto_definition.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex index b22313816..e0bb9c28e 100644 --- a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex +++ b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex @@ -45,7 +45,6 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition end defp get_source_file(%{file: path}, _) do - uri = Conversions.ensure_uri(path) - SourceFile.Store.open_temporary(uri) + SourceFile.Store.open_temporary(path) end end From 39190a36d289ffbff20e0423935e0e02465d3edb Mon Sep 17 00:00:00 2001 From: scottming Date: Mon, 20 Feb 2023 11:26:14 +0800 Subject: [PATCH 04/11] Rename the test file and move the duplicated logic to code_mod folder --- .../experimental/code_mod/location.ex | 28 +++++++++++++++++++ .../provider/handlers/goto_definition.ex | 27 ++---------------- .../handlers/goto_definition_test.exs | 2 +- 3 files changed, 31 insertions(+), 26 deletions(-) create mode 100644 apps/language_server/lib/language_server/experimental/code_mod/location.ex rename apps/language_server/test/{language_server => }/experimental/provider/handlers/goto_definition_test.exs (98%) diff --git a/apps/language_server/lib/language_server/experimental/code_mod/location.ex b/apps/language_server/lib/language_server/experimental/code_mod/location.ex new file mode 100644 index 000000000..76f3d8c9a --- /dev/null +++ b/apps/language_server/lib/language_server/experimental/code_mod/location.ex @@ -0,0 +1,28 @@ +defmodule ElixirLS.LanguageServer.Experimental.CodeMod.Location do + @moduledoc """ + A module that converts ElixirSense location to LSP location. + """ + alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Location, as: LSLocation + alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Range, as: LSRange + alias ElixirLS.LanguageServer.Experimental.SourceFile + alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions + + def to_lsp(%{line: line, column: column} = elixir_sense_definition, current_source_file) do + {:ok, current_source_file} + position = SourceFile.Position.new(line, column - 1) + + with {:ok, source_file} <- fetch_source_file(elixir_sense_definition, current_source_file), + {:ok, ls_position} <- Conversions.to_lsp(position, source_file) do + ls_range = %LSRange{start: ls_position, end: ls_position} + {:ok, LSLocation.new(uri: source_file.uri, range: ls_range)} + end + end + + defp fetch_source_file(%{file: nil}, current_source_file) do + {:ok, current_source_file} + end + + defp fetch_source_file(%{file: path}, _) do + SourceFile.Store.open_temporary(path) + end +end diff --git a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex index e0bb9c28e..217e4130c 100644 --- a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex +++ b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex @@ -1,10 +1,8 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition do alias ElixirLS.LanguageServer.Experimental.Protocol.Requests.GotoDefinition alias ElixirLS.LanguageServer.Experimental.Protocol.Responses - alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Location - alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Range, as: LSRange + alias ElixirLS.LanguageServer.Experimental.CodeMod.Location, as: CodeModLocation alias ElixirLS.LanguageServer.Experimental.SourceFile - alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions require Logger def handle(%GotoDefinition{} = request, _) do @@ -15,7 +13,7 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition with %ElixirSense.Location{} = location <- ElixirSense.definition(source_file_string, pos.line, pos.character + 1), - {:ok, definition} <- build_definition(location, source_file) do + {:ok, definition} <- CodeModLocation.to_lsp(location, source_file) do {:reply, Responses.GotoDefinition.new(request.id, definition)} else nil -> @@ -26,25 +24,4 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition {:error, Responses.GotoDefinition.error(request.id, :request_failed, reason)} end end - - defp build_definition( - %{line: line, column: column} = elixir_sense_definition, - current_source_file - ) do - position = SourceFile.Position.new(line, column - 1) - - with {:ok, source_file} <- get_source_file(elixir_sense_definition, current_source_file), - {:ok, ls_position} <- Conversions.to_lsp(position, source_file) do - ls_range = %LSRange{start: ls_position, end: ls_position} - {:ok, Location.new(uri: source_file.uri, range: ls_range)} - end - end - - defp get_source_file(%{file: nil}, current_source_file) do - {:ok, current_source_file} - end - - defp get_source_file(%{file: path}, _) do - SourceFile.Store.open_temporary(path) - end end diff --git a/apps/language_server/test/language_server/experimental/provider/handlers/goto_definition_test.exs b/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs similarity index 98% rename from apps/language_server/test/language_server/experimental/provider/handlers/goto_definition_test.exs rename to apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs index 9779a38e2..3b531e15b 100644 --- a/apps/language_server/test/language_server/experimental/provider/handlers/goto_definition_test.exs +++ b/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs @@ -1,4 +1,4 @@ -defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinitionTest do +defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do use ExUnit.Case, async: true alias ElixirLS.LanguageServer.Experimental.Protocol.Requests.GotoDefinition From f0e60f4308a0758bd08f4b527aac5964e0b50558 Mon Sep 17 00:00:00 2001 From: scottming Date: Mon, 20 Feb 2023 11:46:35 +0800 Subject: [PATCH 05/11] Rename location variables --- .../lib/language_server/experimental/code_mod/location.ex | 4 ++-- .../experimental/provider/handlers/goto_definition.ex | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/language_server/lib/language_server/experimental/code_mod/location.ex b/apps/language_server/lib/language_server/experimental/code_mod/location.ex index 76f3d8c9a..55704f98c 100644 --- a/apps/language_server/lib/language_server/experimental/code_mod/location.ex +++ b/apps/language_server/lib/language_server/experimental/code_mod/location.ex @@ -7,11 +7,11 @@ defmodule ElixirLS.LanguageServer.Experimental.CodeMod.Location do alias ElixirLS.LanguageServer.Experimental.SourceFile alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions - def to_lsp(%{line: line, column: column} = elixir_sense_definition, current_source_file) do + def to_lsp(%{line: line, column: column} = elixir_sense_location, current_source_file) do {:ok, current_source_file} position = SourceFile.Position.new(line, column - 1) - with {:ok, source_file} <- fetch_source_file(elixir_sense_definition, current_source_file), + with {:ok, source_file} <- fetch_source_file(elixir_sense_location, current_source_file), {:ok, ls_position} <- Conversions.to_lsp(position, source_file) do ls_range = %LSRange{start: ls_position, end: ls_position} {:ok, LSLocation.new(uri: source_file.uri, range: ls_range)} diff --git a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex index 217e4130c..b350f4c6c 100644 --- a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex +++ b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex @@ -13,8 +13,8 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition with %ElixirSense.Location{} = location <- ElixirSense.definition(source_file_string, pos.line, pos.character + 1), - {:ok, definition} <- CodeModLocation.to_lsp(location, source_file) do - {:reply, Responses.GotoDefinition.new(request.id, definition)} + {:ok, lsp_location} <- CodeModLocation.to_lsp(location, source_file) do + {:reply, Responses.GotoDefinition.new(request.id, lsp_location)} else nil -> {:reply, Responses.GotoDefinition.new(request.id, nil)} From f4a35fca20f5b284097786f548a9de05c583e5ed Mon Sep 17 00:00:00 2001 From: Scott Ming Date: Wed, 22 Feb 2023 07:46:19 +0800 Subject: [PATCH 06/11] Apply suggestions from code review Co-authored-by: Steve Cohen --- .../lib/language_server/experimental/code_mod/location.ex | 2 +- .../experimental/provider/handlers/goto_definition.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/language_server/lib/language_server/experimental/code_mod/location.ex b/apps/language_server/lib/language_server/experimental/code_mod/location.ex index 55704f98c..e8e8bf774 100644 --- a/apps/language_server/lib/language_server/experimental/code_mod/location.ex +++ b/apps/language_server/lib/language_server/experimental/code_mod/location.ex @@ -7,7 +7,7 @@ defmodule ElixirLS.LanguageServer.Experimental.CodeMod.Location do alias ElixirLS.LanguageServer.Experimental.SourceFile alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions - def to_lsp(%{line: line, column: column} = elixir_sense_location, current_source_file) do + def to_lsp(%{line: line, column: column} = elixir_sense_location, %SourceFile{} = source_file) do {:ok, current_source_file} position = SourceFile.Position.new(line, column - 1) diff --git a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex index b350f4c6c..8e6920b10 100644 --- a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex +++ b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex @@ -9,7 +9,7 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition source_file = request.source_file pos = request.position - source_file_string = source_file |> SourceFile.to_string() + source_file_string = SourceFile.to_string(source_file) with %ElixirSense.Location{} = location <- ElixirSense.definition(source_file_string, pos.line, pos.character + 1), From d9b2abed765d5955144022143514ac3a4a9e5b6b Mon Sep 17 00:00:00 2001 From: scottming Date: Wed, 22 Feb 2023 10:45:59 +0800 Subject: [PATCH 07/11] Apply the remaining suggestions --- .../experimental/code_mod/location.ex | 28 ------------- .../provider/handlers/goto_definition.ex | 6 +-- .../experimental/source_file/conversions.ex | 21 ++++++++++ .../handlers/goto_definition_test.exs | 39 +++++++++---------- 4 files changed, 43 insertions(+), 51 deletions(-) delete mode 100644 apps/language_server/lib/language_server/experimental/code_mod/location.ex diff --git a/apps/language_server/lib/language_server/experimental/code_mod/location.ex b/apps/language_server/lib/language_server/experimental/code_mod/location.ex deleted file mode 100644 index e8e8bf774..000000000 --- a/apps/language_server/lib/language_server/experimental/code_mod/location.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule ElixirLS.LanguageServer.Experimental.CodeMod.Location do - @moduledoc """ - A module that converts ElixirSense location to LSP location. - """ - alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Location, as: LSLocation - alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Range, as: LSRange - alias ElixirLS.LanguageServer.Experimental.SourceFile - alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions - - def to_lsp(%{line: line, column: column} = elixir_sense_location, %SourceFile{} = source_file) do - {:ok, current_source_file} - position = SourceFile.Position.new(line, column - 1) - - with {:ok, source_file} <- fetch_source_file(elixir_sense_location, current_source_file), - {:ok, ls_position} <- Conversions.to_lsp(position, source_file) do - ls_range = %LSRange{start: ls_position, end: ls_position} - {:ok, LSLocation.new(uri: source_file.uri, range: ls_range)} - end - end - - defp fetch_source_file(%{file: nil}, current_source_file) do - {:ok, current_source_file} - end - - defp fetch_source_file(%{file: path}, _) do - SourceFile.Store.open_temporary(path) - end -end diff --git a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex index 8e6920b10..5a15cd468 100644 --- a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex +++ b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex @@ -1,8 +1,8 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition do alias ElixirLS.LanguageServer.Experimental.Protocol.Requests.GotoDefinition alias ElixirLS.LanguageServer.Experimental.Protocol.Responses - alias ElixirLS.LanguageServer.Experimental.CodeMod.Location, as: CodeModLocation alias ElixirLS.LanguageServer.Experimental.SourceFile + alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions require Logger def handle(%GotoDefinition{} = request, _) do @@ -13,7 +13,7 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition with %ElixirSense.Location{} = location <- ElixirSense.definition(source_file_string, pos.line, pos.character + 1), - {:ok, lsp_location} <- CodeModLocation.to_lsp(location, source_file) do + {:ok, lsp_location} <- Conversions.to_lsp(location, source_file) do {:reply, Responses.GotoDefinition.new(request.id, lsp_location)} else nil -> @@ -21,7 +21,7 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition {:error, reason} -> Logger.error("GotoDefinition failed: #{inspect(reason)}") - {:error, Responses.GotoDefinition.error(request.id, :request_failed, reason)} + {:error, Responses.GotoDefinition.error(request.id, :request_failed, inspect(reason))} end end end diff --git a/apps/language_server/lib/language_server/experimental/source_file/conversions.ex b/apps/language_server/lib/language_server/experimental/source_file/conversions.ex index c019b74fb..6cbfa5c8c 100644 --- a/apps/language_server/lib/language_server/experimental/source_file/conversions.ex +++ b/apps/language_server/lib/language_server/experimental/source_file/conversions.ex @@ -15,6 +15,7 @@ defmodule ElixirLS.LanguageServer.Experimental.SourceFile.Conversions do alias ElixirLS.LanguageServer.Experimental.SourceFile.Position, as: ElixirPosition alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Position, as: LSPosition alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Range, as: LSRange + alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Location, as: LSLocation alias ElixirLS.LanguageServer.Protocol import Line @@ -102,6 +103,19 @@ defmodule ElixirLS.LanguageServer.Experimental.SourceFile.Conversions do {:ok, range} end + def to_lsp( + %ElixirSense.Location{line: line, column: column} = elixir_sense_location, + %SourceFile{} = source_file + ) do + position = SourceFile.Position.new(line, column - 1) + + with {:ok, source_file} <- fetch_source_file(elixir_sense_location, source_file), + {:ok, ls_position} <- to_lsp(position, source_file) do + ls_range = %LSRange{start: ls_position, end: ls_position} + {:ok, LSLocation.new(uri: source_file.uri, range: ls_range)} + end + end + def to_lsp(%ElixirRange{} = ex_range, %SourceFile{} = source) do with {:ok, start_pos} <- to_lsp(ex_range.start, source.document), {:ok, end_pos} <- to_lsp(ex_range.end, source.document) do @@ -128,6 +142,13 @@ defmodule ElixirLS.LanguageServer.Experimental.SourceFile.Conversions do end # Private + defp fetch_source_file(%{file: nil}, source_file) do + {:ok, source_file} + end + + defp fetch_source_file(%{file: path}, _) do + SourceFile.Store.open_temporary(path) + end defp extract_lsp_character(%ElixirPosition{} = position, line(ascii?: true, text: text)) do character = min(position.character, byte_size(text)) diff --git a/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs b/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs index 3b531e15b..eead74f8f 100644 --- a/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs +++ b/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs @@ -29,7 +29,6 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do with {:ok, contents} <- File.read(file_path), :ok <- SourceFile.Store.open(uri, contents, 1), - {:ok, _source_file} <- SourceFile.Store.fetch(uri), {:ok, req} <- build(GotoDefinition, params) do GotoDefinition.to_elixir(req) end @@ -40,13 +39,13 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end defp arrange_referenced_file do - file_path = FixtureHelpers.get_path("references_referenced.ex") - uri = Conversions.ensure_uri(file_path) - %{uri: uri} + "references_referenced.ex" + |> FixtureHelpers.get_path() + |> Conversions.ensure_uri() end test "find definition remote function call" do - b_file = arrange_referenced_file() + referenced_uri = arrange_referenced_file() file_path = FixtureHelpers.get_path("references_remote.ex") {line, char} = {4, 28} @@ -59,7 +58,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == b_file.uri + assert definition.uri == referenced_uri assert definition.range.start.line == 1 assert definition.range.start.character == 6 assert definition.range.end.line == 1 @@ -67,7 +66,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition remote macro call" do - b_file = arrange_referenced_file() + referenced_uri = arrange_referenced_file() file_path = FixtureHelpers.get_path("references_remote.ex") {line, char} = {8, 28} @@ -80,7 +79,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == b_file.uri + assert definition.uri == referenced_uri assert definition.range.start.line == 8 assert definition.range.start.character == 11 assert definition.range.end.line == 8 @@ -88,7 +87,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition imported function call" do - b_file = arrange_referenced_file() + referenced_uri = arrange_referenced_file() file_path = FixtureHelpers.get_path("references_imported.ex") {line, char} = {4, 5} @@ -101,7 +100,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == b_file.uri + assert definition.uri == referenced_uri assert definition.range.start.line == 1 assert definition.range.start.character == 6 assert definition.range.end.line == 1 @@ -109,7 +108,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition imported macro call" do - b_file = arrange_referenced_file() + referenced_uri = arrange_referenced_file() file_path = FixtureHelpers.get_path("references_imported.ex") {line, char} = {8, 5} @@ -122,7 +121,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == b_file.uri + assert definition.uri == referenced_uri assert definition.range.start.line == 8 assert definition.range.start.character == 11 assert definition.range.end.line == 8 @@ -130,7 +129,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition local function call" do - b_file = arrange_referenced_file() + referenced_uri = arrange_referenced_file() file_path = FixtureHelpers.get_path("references_referenced.ex") {line, char} = {15, 5} @@ -143,7 +142,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == b_file.uri + assert definition.uri == referenced_uri assert definition.range.start.line == 1 assert definition.range.start.character == 6 assert definition.range.end.line == 1 @@ -151,7 +150,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition local macro call" do - b_file = arrange_referenced_file() + referenced_uri = arrange_referenced_file() file_path = FixtureHelpers.get_path("references_referenced.ex") {line, char} = {19, 5} @@ -164,7 +163,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == b_file.uri + assert definition.uri == referenced_uri assert definition.range.start.line == 8 assert definition.range.start.character == 11 assert definition.range.end.line == 8 @@ -172,7 +171,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition variable" do - b_file = arrange_referenced_file() + referenced_uri = arrange_referenced_file() file_path = FixtureHelpers.get_path("references_referenced.ex") {line, char} = {4, 13} @@ -185,7 +184,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == b_file.uri + assert definition.uri == referenced_uri assert definition.range.start.line == 2 assert definition.range.start.character == 4 assert definition.range.end.line == 2 @@ -193,7 +192,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition attribute" do - b_file = arrange_referenced_file() + referenced_uri = arrange_referenced_file() file_path = FixtureHelpers.get_path("references_referenced.ex") {line, char} = {27, 5} @@ -206,7 +205,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == b_file.uri + assert definition.uri == referenced_uri assert definition.range.start.line == 24 assert definition.range.start.character == 2 assert definition.range.end.line == 24 From ac492903d8094250f0a3e70259b7194eef50e7a6 Mon Sep 17 00:00:00 2001 From: scottming Date: Thu, 23 Feb 2023 09:55:21 +0800 Subject: [PATCH 08/11] Apply flowing suggestions --- .../provider/handlers/goto_definition.ex | 25 ++++++++++++------- .../experimental/source_file/conversions.ex | 9 +++---- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex index 5a15cd468..02c1e7212 100644 --- a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex +++ b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex @@ -9,19 +9,26 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition source_file = request.source_file pos = request.position - source_file_string = SourceFile.to_string(source_file) + maybe_location = + source_file |> SourceFile.to_string() |> ElixirSense.definition(pos.line, pos.character + 1) - with %ElixirSense.Location{} = location <- - ElixirSense.definition(source_file_string, pos.line, pos.character + 1), - {:ok, lsp_location} <- Conversions.to_lsp(location, source_file) do - {:reply, Responses.GotoDefinition.new(request.id, lsp_location)} - else - nil -> - {:reply, Responses.GotoDefinition.new(request.id, nil)} + case to_response(request.id, maybe_location, source_file) do + {:ok, response} -> + {:reply, response} {:error, reason} -> - Logger.error("GotoDefinition failed: #{inspect(reason)}") + Logger.error("GotoDefinition conversion failed: #{inspect(reason)}") {:error, Responses.GotoDefinition.error(request.id, :request_failed, inspect(reason))} end end + + defp to_response(request_id, %ElixirSense.Location{} = location, %SourceFile{} = source_file) do + with {:ok, lsp_location} <- Conversions.to_lsp(location, source_file) do + {:ok, Responses.GotoDefinition.new(request_id, lsp_location)} + end + end + + defp to_response(request_id, nil, _source_file) do + {:ok, Responses.GoToDefinition.new(request_id, nil)} + end end diff --git a/apps/language_server/lib/language_server/experimental/source_file/conversions.ex b/apps/language_server/lib/language_server/experimental/source_file/conversions.ex index 6cbfa5c8c..514f41086 100644 --- a/apps/language_server/lib/language_server/experimental/source_file/conversions.ex +++ b/apps/language_server/lib/language_server/experimental/source_file/conversions.ex @@ -103,13 +103,10 @@ defmodule ElixirLS.LanguageServer.Experimental.SourceFile.Conversions do {:ok, range} end - def to_lsp( - %ElixirSense.Location{line: line, column: column} = elixir_sense_location, - %SourceFile{} = source_file - ) do - position = SourceFile.Position.new(line, column - 1) + def to_lsp(%ElixirSense.Location{} = location, %SourceFile{} = source_file) do + position = SourceFile.Position.new(location.line, location.column - 1) - with {:ok, source_file} <- fetch_source_file(elixir_sense_location, source_file), + with {:ok, source_file} <- fetch_source_file(location, source_file), {:ok, ls_position} <- to_lsp(position, source_file) do ls_range = %LSRange{start: ls_position, end: ls_position} {:ok, LSLocation.new(uri: source_file.uri, range: ls_range)} From e30e11f02326cd4f969329a4248740ad8c54e75e Mon Sep 17 00:00:00 2001 From: scottming Date: Thu, 23 Feb 2023 10:23:14 +0800 Subject: [PATCH 09/11] Fix typo --- .../experimental/provider/handlers/goto_definition.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex index 02c1e7212..23904cc94 100644 --- a/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex +++ b/apps/language_server/lib/language_server/experimental/provider/handlers/goto_definition.ex @@ -29,6 +29,6 @@ defmodule ElixirLS.LanguageServer.Experimental.Provider.Handlers.GotoDefinition end defp to_response(request_id, nil, _source_file) do - {:ok, Responses.GoToDefinition.new(request_id, nil)} + {:ok, Responses.GotoDefinition.new(request_id, nil)} end end From 59c101bc16c617cc64e672a55dfc49c031c956e2 Mon Sep 17 00:00:00 2001 From: scottming Date: Thu, 23 Feb 2023 23:38:19 +0800 Subject: [PATCH 10/11] Rename an arrange function name --- .../provider/handlers/goto_definition_test.exs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs b/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs index eead74f8f..01229513a 100644 --- a/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs +++ b/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs @@ -38,14 +38,14 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do Handlers.GotoDefinition.handle(request, Env.new()) end - defp arrange_referenced_file do + defp get_referenced_file_uri do "references_referenced.ex" |> FixtureHelpers.get_path() |> Conversions.ensure_uri() end test "find definition remote function call" do - referenced_uri = arrange_referenced_file() + referenced_uri = get_referenced_file_uri() file_path = FixtureHelpers.get_path("references_remote.ex") {line, char} = {4, 28} @@ -66,7 +66,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition remote macro call" do - referenced_uri = arrange_referenced_file() + referenced_uri = get_referenced_file_uri() file_path = FixtureHelpers.get_path("references_remote.ex") {line, char} = {8, 28} @@ -87,7 +87,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition imported function call" do - referenced_uri = arrange_referenced_file() + referenced_uri = get_referenced_file_uri() file_path = FixtureHelpers.get_path("references_imported.ex") {line, char} = {4, 5} @@ -108,7 +108,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition imported macro call" do - referenced_uri = arrange_referenced_file() + referenced_uri = get_referenced_file_uri() file_path = FixtureHelpers.get_path("references_imported.ex") {line, char} = {8, 5} @@ -129,7 +129,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition local function call" do - referenced_uri = arrange_referenced_file() + referenced_uri = get_referenced_file_uri() file_path = FixtureHelpers.get_path("references_referenced.ex") {line, char} = {15, 5} @@ -150,7 +150,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition local macro call" do - referenced_uri = arrange_referenced_file() + referenced_uri = get_referenced_file_uri() file_path = FixtureHelpers.get_path("references_referenced.ex") {line, char} = {19, 5} @@ -171,7 +171,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition variable" do - referenced_uri = arrange_referenced_file() + referenced_uri = get_referenced_file_uri() file_path = FixtureHelpers.get_path("references_referenced.ex") {line, char} = {4, 13} @@ -192,7 +192,7 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do end test "find definition attribute" do - referenced_uri = arrange_referenced_file() + referenced_uri = get_referenced_file_uri() file_path = FixtureHelpers.get_path("references_referenced.ex") {line, char} = {27, 5} From a3ed3666bb6e70a356eaedab6c4d5a7433deabbf Mon Sep 17 00:00:00 2001 From: scottming Date: Sat, 25 Feb 2023 08:30:16 +0800 Subject: [PATCH 11/11] Use setup instead of private_function in the definition test --- .../handlers/goto_definition_test.exs | 258 +++++++++--------- 1 file changed, 127 insertions(+), 131 deletions(-) diff --git a/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs b/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs index 01229513a..387f293b4 100644 --- a/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs +++ b/apps/language_server/test/experimental/provider/handlers/goto_definition_test.exs @@ -38,177 +38,173 @@ defmodule ElixirLS.Experimental.Provider.Handlers.GotoDefinitionTest do Handlers.GotoDefinition.handle(request, Env.new()) end - defp get_referenced_file_uri do - "references_referenced.ex" - |> FixtureHelpers.get_path() - |> Conversions.ensure_uri() + def with_referenced_file(_) do + path = FixtureHelpers.get_path("references_referenced.ex") + uri = Conversions.ensure_uri(path) + {:ok, file_uri: uri, file_path: path} end - test "find definition remote function call" do - referenced_uri = get_referenced_file_uri() - file_path = FixtureHelpers.get_path("references_remote.ex") - {line, char} = {4, 28} + describe "when a file contains references" do + setup [:with_referenced_file] - {:ok, request} = request(file_path, line, char) + test "find definition remote function call", %{file_uri: uri} do + file_path = FixtureHelpers.get_path("references_remote.ex") + {line, char} = {4, 28} - annotate_assert(file_path, line, char, """ - ReferencesReferenced.referenced_fun() - ^ - """) + {:ok, request} = request(file_path, line, char) - {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + annotate_assert(file_path, line, char, """ + ReferencesReferenced.referenced_fun() + ^ + """) - assert definition.uri == referenced_uri - assert definition.range.start.line == 1 - assert definition.range.start.character == 6 - assert definition.range.end.line == 1 - assert definition.range.end.character == 6 - end + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + + assert definition.uri == uri + assert definition.range.start.line == 1 + assert definition.range.start.character == 6 + assert definition.range.end.line == 1 + assert definition.range.end.character == 6 + end - test "find definition remote macro call" do - referenced_uri = get_referenced_file_uri() - file_path = FixtureHelpers.get_path("references_remote.ex") - {line, char} = {8, 28} + test "find definition remote macro call", %{file_uri: uri} do + file_path = FixtureHelpers.get_path("references_remote.ex") + {line, char} = {8, 28} - {:ok, request} = request(file_path, line, char) + {:ok, request} = request(file_path, line, char) - annotate_assert(file_path, line, char, """ - ReferencesReferenced.referenced_macro a do - ^ - """) + annotate_assert(file_path, line, char, """ + ReferencesReferenced.referenced_macro a do + ^ + """) - {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == referenced_uri - assert definition.range.start.line == 8 - assert definition.range.start.character == 11 - assert definition.range.end.line == 8 - assert definition.range.end.character == 11 - end + assert definition.uri == uri + assert definition.range.start.line == 8 + assert definition.range.start.character == 11 + assert definition.range.end.line == 8 + assert definition.range.end.character == 11 + end - test "find definition imported function call" do - referenced_uri = get_referenced_file_uri() - file_path = FixtureHelpers.get_path("references_imported.ex") - {line, char} = {4, 5} + test "find definition imported function call", %{file_uri: uri} do + file_path = FixtureHelpers.get_path("references_imported.ex") + {line, char} = {4, 5} - {:ok, request} = request(file_path, line, char) + {:ok, request} = request(file_path, line, char) - annotate_assert(file_path, line, char, """ - referenced_fun() - ^ - """) + annotate_assert(file_path, line, char, """ + referenced_fun() + ^ + """) - {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == referenced_uri - assert definition.range.start.line == 1 - assert definition.range.start.character == 6 - assert definition.range.end.line == 1 - assert definition.range.end.character == 6 - end + assert definition.uri == uri + assert definition.range.start.line == 1 + assert definition.range.start.character == 6 + assert definition.range.end.line == 1 + assert definition.range.end.character == 6 + end - test "find definition imported macro call" do - referenced_uri = get_referenced_file_uri() - file_path = FixtureHelpers.get_path("references_imported.ex") - {line, char} = {8, 5} + test "find definition imported macro call", %{file_uri: uri} do + file_path = FixtureHelpers.get_path("references_imported.ex") + {line, char} = {8, 5} - {:ok, request} = request(file_path, line, char) + {:ok, request} = request(file_path, line, char) - annotate_assert(file_path, line, char, """ - referenced_macro a do - ^ - """) + annotate_assert(file_path, line, char, """ + referenced_macro a do + ^ + """) - {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == referenced_uri - assert definition.range.start.line == 8 - assert definition.range.start.character == 11 - assert definition.range.end.line == 8 - assert definition.range.end.character == 11 - end + assert definition.uri == uri + assert definition.range.start.line == 8 + assert definition.range.start.character == 11 + assert definition.range.end.line == 8 + assert definition.range.end.character == 11 + end - test "find definition local function call" do - referenced_uri = get_referenced_file_uri() - file_path = FixtureHelpers.get_path("references_referenced.ex") - {line, char} = {15, 5} + test "find definition local function call", %{file_uri: uri} do + file_path = FixtureHelpers.get_path("references_referenced.ex") + {line, char} = {15, 5} - {:ok, request} = request(file_path, line, char) + {:ok, request} = request(file_path, line, char) - annotate_assert(file_path, line, char, """ - referenced_fun() - ^ - """) + annotate_assert(file_path, line, char, """ + referenced_fun() + ^ + """) - {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == referenced_uri - assert definition.range.start.line == 1 - assert definition.range.start.character == 6 - assert definition.range.end.line == 1 - assert definition.range.end.character == 6 - end + assert definition.uri == uri + assert definition.range.start.line == 1 + assert definition.range.start.character == 6 + assert definition.range.end.line == 1 + assert definition.range.end.character == 6 + end - test "find definition local macro call" do - referenced_uri = get_referenced_file_uri() - file_path = FixtureHelpers.get_path("references_referenced.ex") - {line, char} = {19, 5} + test "find definition local macro call", %{file_uri: uri} do + file_path = FixtureHelpers.get_path("references_referenced.ex") + {line, char} = {19, 5} - {:ok, request} = request(file_path, line, char) + {:ok, request} = request(file_path, line, char) - annotate_assert(file_path, line, char, """ - referenced_macro a do - ^ - """) + annotate_assert(file_path, line, char, """ + referenced_macro a do + ^ + """) - {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == referenced_uri - assert definition.range.start.line == 8 - assert definition.range.start.character == 11 - assert definition.range.end.line == 8 - assert definition.range.end.character == 11 - end + assert definition.uri == uri + assert definition.range.start.line == 8 + assert definition.range.start.character == 11 + assert definition.range.end.line == 8 + assert definition.range.end.character == 11 + end - test "find definition variable" do - referenced_uri = get_referenced_file_uri() - file_path = FixtureHelpers.get_path("references_referenced.ex") - {line, char} = {4, 13} + test "find definition variable", %{file_uri: uri} do + file_path = FixtureHelpers.get_path("references_referenced.ex") + {line, char} = {4, 13} - {:ok, request} = request(file_path, line, char) + {:ok, request} = request(file_path, line, char) - annotate_assert(file_path, line, char, """ - IO.puts(referenced_variable + 1) - ^ - """) + annotate_assert(file_path, line, char, """ + IO.puts(referenced_variable + 1) + ^ + """) - {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == referenced_uri - assert definition.range.start.line == 2 - assert definition.range.start.character == 4 - assert definition.range.end.line == 2 - assert definition.range.end.character == 4 - end + assert definition.uri == uri + assert definition.range.start.line == 2 + assert definition.range.start.character == 4 + assert definition.range.end.line == 2 + assert definition.range.end.character == 4 + end - test "find definition attribute" do - referenced_uri = get_referenced_file_uri() - file_path = FixtureHelpers.get_path("references_referenced.ex") - {line, char} = {27, 5} + test "find definition attribute", %{file_uri: uri} do + file_path = FixtureHelpers.get_path("references_referenced.ex") + {line, char} = {27, 5} - {:ok, request} = request(file_path, line, char) + {:ok, request} = request(file_path, line, char) - annotate_assert(file_path, line, char, """ - @referenced_attribute - ^ - """) + annotate_assert(file_path, line, char, """ + @referenced_attribute + ^ + """) - {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) + {:reply, %Responses.GotoDefinition{result: definition}} = handle(request) - assert definition.uri == referenced_uri - assert definition.range.start.line == 24 - assert definition.range.start.character == 2 - assert definition.range.end.line == 24 - assert definition.range.end.character == 2 + assert definition.uri == uri + assert definition.range.start.line == 24 + assert definition.range.start.character == 2 + assert definition.range.end.line == 24 + assert definition.range.end.character == 2 + end end end