Skip to content

Commit fa399be

Browse files
authored
Merge pull request elixir-lsp#1 from timgent/poc_rename_symbol_tg
Fix renaming functions with multiple headers and across multiple files
2 parents 8945480 + 987456e commit fa399be

File tree

5 files changed

+234
-182
lines changed

5 files changed

+234
-182
lines changed

apps/language_server/lib/language_server/providers/rename.ex

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,37 @@ defmodule ElixirLS.LanguageServer.Providers.Rename do
66
"""
77

88
alias ElixirLS.LanguageServer.SourceFile
9-
#import ElixirLS.LanguageServer.Protocol
109

1110
def rename(%SourceFile{} = source_file, start_uri, line, character, new_name) do
1211
edits =
13-
with %{context: {context, char_ident}} when context in [:local_or_var, :local_call] <-
14-
Code.Fragment.surround_context(source_file.text, {line, character}),
12+
with char_ident when not is_nil(char_ident) <-
13+
get_char_ident(source_file.text, line, character),
1514
%ElixirSense.Location{} = definition <-
1615
ElixirSense.definition(source_file.text, line, character),
1716
references <- ElixirSense.references(source_file.text, line, character) do
18-
19-
2017
length_old = length(char_ident)
2118

22-
[
23-
%{
24-
uri: start_uri,
25-
range:
26-
adjust_range(
27-
definition.line,
28-
definition.column,
29-
definition.line,
30-
definition.column + length_old
19+
definition_references =
20+
case definition do
21+
%{file: nil, type: :function} ->
22+
parse_definition_source_code(source_file.text)
23+
|> get_all_fn_header_positions(char_ident)
24+
|> positions_to_references(start_uri, length_old)
25+
26+
%{file: separate_file_path, type: :function} ->
27+
parse_definition_source_code(definition)
28+
|> get_all_fn_header_positions(char_ident)
29+
|> positions_to_references(SourceFile.path_to_uri(separate_file_path), length_old)
30+
31+
_ ->
32+
positions_to_references(
33+
[{definition.line, definition.column}],
34+
start_uri,
35+
length_old
3136
)
32-
}
33-
| repack_references(references, start_uri)
34-
]
37+
end
38+
39+
definition_references ++ repack_references(references, start_uri)
3540
else
3641
_ ->
3742
[]
@@ -62,7 +67,9 @@ defmodule ElixirLS.LanguageServer.Providers.Rename do
6267
begin: {start_line, start_col},
6368
end: {end_line, end_col},
6469
context: {context, char_ident}
65-
} when context in [:local_or_var, :local_call] <- Code.Fragment.surround_context(source_file.text, {line, character}) do
70+
}
71+
when context in [:local_or_var, :local_call] <-
72+
Code.Fragment.surround_context(source_file.text, {line, character}) do
6673
%{
6774
range: adjust_range(start_line, start_col, end_line, end_col),
6875
placeholder: to_string(char_ident)
@@ -91,10 +98,46 @@ defmodule ElixirLS.LanguageServer.Providers.Rename do
9198
end
9299
end
93100

101+
defp parse_definition_source_code(%{file: file}) do
102+
ElixirSense.Core.Parser.parse_file(file, true, true, 0)
103+
end
104+
105+
defp parse_definition_source_code(source_text) when is_binary(source_text) do
106+
ElixirSense.Core.Parser.parse_string(source_text, true, true, 0)
107+
end
108+
109+
defp get_all_fn_header_positions(parsed_source, char_ident) do
110+
parsed_source.mods_funs_to_positions
111+
|> Map.filter(fn
112+
{{_, fn_name, _}, _} -> Atom.to_charlist(fn_name) == char_ident
113+
end)
114+
|> Enum.flat_map(fn {_, %{positions: positions}} -> positions end)
115+
|> Enum.uniq()
116+
end
117+
118+
defp positions_to_references(header_positions, start_uri, length_old)
119+
when is_list(header_positions) do
120+
header_positions
121+
|> Enum.map(fn {line, column} ->
122+
%{
123+
uri: start_uri,
124+
range: adjust_range(line, column, line, column + length_old)
125+
}
126+
end)
127+
end
128+
94129
defp adjust_range(start_line, start_character, end_line, end_character) do
95130
%{
96131
start: %{line: start_line - 1, character: start_character - 1},
97132
end: %{line: end_line - 1, character: end_character - 1}
98133
}
99134
end
135+
136+
defp get_char_ident(text, line, character) do
137+
case Code.Fragment.surround_context(text, {line, character}) do
138+
%{context: {context, char_ident}} when context in [:local_or_var, :local_call] -> char_ident
139+
%{context: {:dot, _, char_ident}} -> char_ident
140+
_ -> nil
141+
end
142+
end
100143
end

0 commit comments

Comments
 (0)