diff --git a/apps/remote_control/lib/lexical/remote_control/code_mod/rename.ex b/apps/remote_control/lib/lexical/remote_control/code_mod/rename.ex index 2d235f536..8a6adade8 100644 --- a/apps/remote_control/lib/lexical/remote_control/code_mod/rename.ex +++ b/apps/remote_control/lib/lexical/remote_control/code_mod/rename.ex @@ -1,8 +1,8 @@ defmodule Lexical.RemoteControl.CodeMod.Rename do alias Lexical.Ast.Analysis + alias Lexical.Document alias Lexical.Document.Position alias Lexical.Document.Range - alias Lexical.RemoteControl.CodeMod.Rename.DocumentChanges alias __MODULE__ @spec prepare(Analysis.t(), Position.t()) :: @@ -12,7 +12,7 @@ defmodule Lexical.RemoteControl.CodeMod.Rename do @rename_mapping %{module: Rename.Module} @spec rename(Analysis.t(), Position.t(), String.t()) :: - {:ok, [DocumentChanges.t()]} | {:error, term()} + {:ok, [Document.Changes.t()]} | {:error, term()} def rename(%Analysis{} = analysis, %Position{} = position, new_name) do with {:ok, {renamable, entity}, range} <- Rename.Prepare.resolve(analysis, position) do rename_module = @rename_mapping[renamable] diff --git a/apps/remote_control/lib/lexical/remote_control/code_mod/rename/document_changes.ex b/apps/remote_control/lib/lexical/remote_control/code_mod/rename/document_changes.ex deleted file mode 100644 index a3ef92ffd..000000000 --- a/apps/remote_control/lib/lexical/remote_control/code_mod/rename/document_changes.ex +++ /dev/null @@ -1,12 +0,0 @@ -defmodule Lexical.RemoteControl.CodeMod.Rename.DocumentChanges do - defstruct [:uri, :edits, :rename_file] - - @type t :: %__MODULE__{ - uri: Lexical.uri(), - edits: [Lexical.Document.Edit.t()], - rename_file: {Lexical.uri(), Lexical.uri()} | nil - } - def new(uri, edits, rename_file \\ nil) do - %__MODULE__{uri: uri, edits: edits, rename_file: rename_file} - end -end diff --git a/apps/remote_control/lib/lexical/remote_control/code_mod/rename/module.ex b/apps/remote_control/lib/lexical/remote_control/code_mod/rename/module.ex index 8ea35c2b3..06b9298a9 100644 --- a/apps/remote_control/lib/lexical/remote_control/code_mod/rename/module.ex +++ b/apps/remote_control/lib/lexical/remote_control/code_mod/rename/module.ex @@ -7,24 +7,22 @@ defmodule Lexical.RemoteControl.CodeMod.Rename.Module do alias Lexical.Document.Range alias Lexical.RemoteControl.CodeIntelligence.Entity alias Lexical.RemoteControl.CodeMod.Rename - alias Lexical.RemoteControl.CodeMod.Rename.DocumentChanges alias Lexical.RemoteControl.Search.Store require Logger import Line - @spec rename(Range.t(), String.t(), atom()) :: [DocumentChanges.t()] + @spec rename(Range.t(), String.t(), atom()) :: [Document.Changes.t()] def rename(%Range{} = old_range, new_name, entity) do {old_suffix, new_suffix} = old_range |> range_text() |> diff(new_name) results = exacts(entity, old_suffix) ++ descendants(entity, old_suffix) - results - |> Enum.group_by(&Document.Path.ensure_uri(&1.path)) - |> Enum.map(fn {uri, entries} -> - rename_file = maybe_rename_file(entries, new_suffix) - edits = Enum.map(entries, &Edit.new(new_suffix, &1.range)) - DocumentChanges.new(uri, edits, rename_file) - end) + for {uri, entries} <- Enum.group_by(results, &Document.Path.ensure_uri(&1.path)), + result = to_document_changes(uri, entries, new_suffix), + match?({:ok, _}, result) do + {:ok, document_changes} = result + document_changes + end end @spec resolve(Analysis.t() | Lexical.path(), Position.t()) :: @@ -172,4 +170,13 @@ defmodule Lexical.RemoteControl.CodeMod.Rename.Module do |> put_in([:start, :character], start_character) |> put_in([:end, :character], end_character) end + + defp to_document_changes(uri, entries, new_suffix) do + edits = Enum.map(entries, &Edit.new(new_suffix, &1.range)) + rename_file = maybe_rename_file(entries, new_suffix) + + with {:ok, document} <- Document.Store.open_temporary(uri) do + {:ok, Document.Changes.new(document, edits, rename_file)} + end + end end diff --git a/apps/remote_control/test/lexical/remote_control/code_mod/rename_test.exs b/apps/remote_control/test/lexical/remote_control/code_mod/rename_test.exs index b23d066b1..ea3b0b51d 100644 --- a/apps/remote_control/test/lexical/remote_control/code_mod/rename_test.exs +++ b/apps/remote_control/test/lexical/remote_control/code_mod/rename_test.exs @@ -485,13 +485,13 @@ defmodule Lexical.RemoteControl.CodeMod.RenameTest do {:ok, entries} <- Search.Indexer.Source.index(document.path, text), :ok <- Search.Store.replace(entries), analysis = Lexical.Ast.analyze(document), - {:ok, uri_with_changes} <- Rename.rename(analysis, position, new_name) do - changes = uri_with_changes |> Enum.map(& &1.edits) |> List.flatten() + {:ok, document_changes} <- Rename.rename(analysis, position, new_name) do + changes = document_changes |> Enum.map(& &1.edits) |> List.flatten() applied = apply_edits(document, changes) result = if path do - rename_file = uri_with_changes |> Enum.map(& &1.rename_file) |> List.first() + rename_file = document_changes |> Enum.map(& &1.rename_file) |> List.first() {applied, rename_file} else applied diff --git a/apps/server/lib/lexical/server/provider/handlers/rename.ex b/apps/server/lib/lexical/server/provider/handlers/rename.ex index 765b455b7..7291b2444 100644 --- a/apps/server/lib/lexical/server/provider/handlers/rename.ex +++ b/apps/server/lib/lexical/server/provider/handlers/rename.ex @@ -7,7 +7,6 @@ defmodule Lexical.Server.Provider.Handlers.Rename do alias Lexical.Protocol.Types.TextDocument alias Lexical.Protocol.Types.Workspace alias Lexical.RemoteControl.Api - alias Lexical.RemoteControl.CodeMod.Rename.DocumentChanges alias Lexical.Server.Provider.Env require Logger @@ -29,8 +28,8 @@ defmodule Lexical.Server.Provider.Handlers.Rename do {:ok, results} -> text_document_edits = - Enum.map(results, fn %DocumentChanges{edits: edits, uri: uri} -> - new_text_document_edit(uri, edits) + Enum.map(results, fn %Document.Changes{edits: edits, document: document} -> + new_text_document_edit(document.uri, edits) end) rename_files = diff --git a/apps/server/test/lexical/server/provider/handlers/rename_test.exs b/apps/server/test/lexical/server/provider/handlers/rename_test.exs index ffe160056..6b0063d18 100644 --- a/apps/server/test/lexical/server/provider/handlers/rename_test.exs +++ b/apps/server/test/lexical/server/provider/handlers/rename_test.exs @@ -4,7 +4,6 @@ defmodule Lexical.Server.Provider.Handlers.RenameTest do alias Lexical.Proto.Convert alias Lexical.Protocol.Requests.Rename alias Lexical.RemoteControl - alias Lexical.RemoteControl.CodeMod.Rename.DocumentChanges alias Lexical.Server alias Lexical.Server.Provider.Env @@ -74,6 +73,8 @@ defmodule Lexical.Server.Provider.Handlers.RenameTest do end test "returns edit when there are changes", %{project: project, uri: uri} do + document = %Document{uri: uri, version: 0} + patch(Document.Store, :fetch, fn ^uri, :analysis -> {:ok, nil, %Ast.Analysis{valid?: true}} end) @@ -81,15 +82,15 @@ defmodule Lexical.Server.Provider.Handlers.RenameTest do patch(RemoteControl.Api, :rename, fn ^project, _analysis, _position, _new_name -> {:ok, [ - DocumentChanges.new( - "file:///path/to/file.ex", + Document.Changes.new( + document, [ %{ new_text: "new_text", range: %{start: %{line: 1, character: 5}, end: %{line: 1, character: 10}} } ], - {"file:///path/to/file.ex", "file:///path/to/new_text.ex"} + {document.uri, "file:///path/to/new_text.ex"} ) ]} end) @@ -106,9 +107,9 @@ defmodule Lexical.Server.Provider.Handlers.RenameTest do } ] - assert edit.text_document.uri == "file:///path/to/file.ex" + assert edit.text_document.uri == document.uri assert edit.text_document.version == 0 - assert rename_file.old_uri == "file:///path/to/file.ex" + assert rename_file.old_uri == document.uri assert rename_file.new_uri == "file:///path/to/new_text.ex" end end diff --git a/projects/lexical_shared/lib/lexical/document/changes.ex b/projects/lexical_shared/lib/lexical/document/changes.ex index fc848452f..fb2fa8846 100644 --- a/projects/lexical_shared/lib/lexical/document/changes.ex +++ b/projects/lexical_shared/lib/lexical/document/changes.ex @@ -9,15 +9,17 @@ defmodule Lexical.Document.Changes do Using this struct allows efficient conversions at the language server border, as the document doesn't have to be looked up (and possibly read off the filesystem) by the language server. """ - defstruct [:document, :edits] + defstruct [:document, :edits, :rename_file] alias Lexical.Document use Lexical.StructAccess @type edits :: Document.Edit.t() | [Document.Edit.t()] + @type rename_file :: nil | {Lexical.uri(), Lexical.uri()} @type t :: %__MODULE__{ document: Document.t(), - edits: edits + edits: edits, + rename_file: rename_file() } @doc """ @@ -28,4 +30,9 @@ defmodule Lexical.Document.Changes do def new(document, edits) do %__MODULE__{document: document, edits: edits} end + + @spec new(Document.t(), edits(), rename_file()) :: t() + def new(document, edits, rename_file) do + %__MODULE__{document: document, edits: edits, rename_file: rename_file} + end end