Skip to content

Commit

Permalink
Merge pull request #1 from timgent/poc_rename_symbol_tg
Browse files Browse the repository at this point in the history
Fix renaming functions with multiple headers and across multiple files
  • Loading branch information
Tuxified committed Oct 25, 2022
2 parents 8945480 + 987456e commit fa399be
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 182 deletions.
79 changes: 61 additions & 18 deletions apps/language_server/lib/language_server/providers/rename.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,37 @@ defmodule ElixirLS.LanguageServer.Providers.Rename do
"""

alias ElixirLS.LanguageServer.SourceFile
#import ElixirLS.LanguageServer.Protocol

def rename(%SourceFile{} = source_file, start_uri, line, character, new_name) do
edits =
with %{context: {context, char_ident}} when context in [:local_or_var, :local_call] <-
Code.Fragment.surround_context(source_file.text, {line, character}),
with char_ident when not is_nil(char_ident) <-
get_char_ident(source_file.text, line, character),
%ElixirSense.Location{} = definition <-
ElixirSense.definition(source_file.text, line, character),
references <- ElixirSense.references(source_file.text, line, character) do


length_old = length(char_ident)

[
%{
uri: start_uri,
range:
adjust_range(
definition.line,
definition.column,
definition.line,
definition.column + length_old
definition_references =
case definition do
%{file: nil, type: :function} ->
parse_definition_source_code(source_file.text)
|> get_all_fn_header_positions(char_ident)
|> positions_to_references(start_uri, length_old)

%{file: separate_file_path, type: :function} ->
parse_definition_source_code(definition)
|> get_all_fn_header_positions(char_ident)
|> positions_to_references(SourceFile.path_to_uri(separate_file_path), length_old)

_ ->
positions_to_references(
[{definition.line, definition.column}],
start_uri,
length_old
)
}
| repack_references(references, start_uri)
]
end

definition_references ++ repack_references(references, start_uri)
else
_ ->
[]
Expand Down Expand Up @@ -62,7 +67,9 @@ defmodule ElixirLS.LanguageServer.Providers.Rename do
begin: {start_line, start_col},
end: {end_line, end_col},
context: {context, char_ident}
} when context in [:local_or_var, :local_call] <- Code.Fragment.surround_context(source_file.text, {line, character}) do
}
when context in [:local_or_var, :local_call] <-
Code.Fragment.surround_context(source_file.text, {line, character}) do
%{
range: adjust_range(start_line, start_col, end_line, end_col),
placeholder: to_string(char_ident)
Expand Down Expand Up @@ -91,10 +98,46 @@ defmodule ElixirLS.LanguageServer.Providers.Rename do
end
end

defp parse_definition_source_code(%{file: file}) do
ElixirSense.Core.Parser.parse_file(file, true, true, 0)
end

defp parse_definition_source_code(source_text) when is_binary(source_text) do
ElixirSense.Core.Parser.parse_string(source_text, true, true, 0)
end

defp get_all_fn_header_positions(parsed_source, char_ident) do
parsed_source.mods_funs_to_positions
|> Map.filter(fn
{{_, fn_name, _}, _} -> Atom.to_charlist(fn_name) == char_ident
end)
|> Enum.flat_map(fn {_, %{positions: positions}} -> positions end)
|> Enum.uniq()
end

defp positions_to_references(header_positions, start_uri, length_old)
when is_list(header_positions) do
header_positions
|> Enum.map(fn {line, column} ->
%{
uri: start_uri,
range: adjust_range(line, column, line, column + length_old)
}
end)
end

defp adjust_range(start_line, start_character, end_line, end_character) do
%{
start: %{line: start_line - 1, character: start_character - 1},
end: %{line: end_line - 1, character: end_character - 1}
}
end

defp get_char_ident(text, line, character) do
case Code.Fragment.surround_context(text, {line, character}) do
%{context: {context, char_ident}} when context in [:local_or_var, :local_call] -> char_ident
%{context: {:dot, _, char_ident}} -> char_ident
_ -> nil
end
end
end
Loading

0 comments on commit fa399be

Please sign in to comment.