@@ -6,10 +6,9 @@ defmodule ElixirLS.LanguageServer.Providers.CodeAction.ReplaceRemoteFunction do
6
6
7
7
use ElixirLS.LanguageServer.Protocol
8
8
9
+ alias ElixirLS.LanguageServer.Protocol.TextEdit
9
10
alias ElixirLS.LanguageServer.Providers.CodeAction.CodeActionResult
10
11
alias ElixirLS.LanguageServer.Providers.CodeMod.Ast
11
- alias ElixirLS.LanguageServer.Providers.CodeMod.Diff
12
- alias ElixirLS.LanguageServer.Providers.CodeMod.Text
13
12
alias ElixirLS.LanguageServer.SourceFile
14
13
alias ElixirSense.Core.Parser
15
14
@@ -18,11 +17,14 @@ defmodule ElixirLS.LanguageServer.Providers.CodeAction.ReplaceRemoteFunction do
18
17
@ spec apply ( SourceFile . t ( ) , String . t ( ) , [ map ( ) ] ) :: [ CodeActionResult . t ( ) ]
19
18
def apply ( % SourceFile { } = source_file , uri , diagnostics ) do
20
19
Enum . flat_map ( diagnostics , fn diagnostic ->
21
- with { :ok , module , function , arity , line_number } <- extract_function_and_line ( diagnostic ) ,
22
- { :ok , suggestions } <- prepare_suggestions ( module , function , arity ) do
23
- to_code_actions ( source_file , line_number , module , function , suggestions , uri )
24
- else
25
- _ -> [ ]
20
+ case extract_function_and_line ( diagnostic ) do
21
+ { :ok , module , function , arity , line } ->
22
+ suggestions = prepare_suggestions ( module , function , arity )
23
+
24
+ build_code_actions ( source_file , line , module , function , suggestions , uri )
25
+
26
+ :error ->
27
+ [ ]
26
28
end
27
29
end )
28
30
end
@@ -38,6 +40,9 @@ defmodule ElixirLS.LanguageServer.Providers.CodeAction.ReplaceRemoteFunction do
38
40
with [ [ _ , module_and_function , arity ] ] <- Regex . scan ( @ function_re , message ) ,
39
41
{ :ok , module , function_name } <- separate_module_from_function ( module_and_function ) do
40
42
{ :ok , module , function_name , String . to_integer ( arity ) }
43
+ else
44
+ _ ->
45
+ :error
41
46
end
42
47
end
43
48
@@ -65,17 +70,14 @@ defmodule ElixirLS.LanguageServer.Providers.CodeAction.ReplaceRemoteFunction do
65
70
@ function_threshold 0.77
66
71
@ max_suggestions 5
67
72
defp prepare_suggestions ( module , function , arity ) do
68
- suggestions =
69
- for { module_function , ^ arity } <- module_functions ( module ) ,
70
- distance = module_function |> Atom . to_string ( ) |> String . jaro_distance ( function ) ,
71
- distance >= @ function_threshold do
72
- { distance , module_function }
73
- end
74
- |> Enum . sort ( :desc )
75
- |> Enum . take ( @ max_suggestions )
76
- |> Enum . map ( fn { _distance , module_function } -> module_function end )
77
-
78
- { :ok , suggestions }
73
+ for { module_function , ^ arity } <- module_functions ( module ) ,
74
+ distance = module_function |> Atom . to_string ( ) |> String . jaro_distance ( function ) ,
75
+ distance >= @ function_threshold do
76
+ { distance , module_function }
77
+ end
78
+ |> Enum . sort ( :desc )
79
+ |> Enum . take ( @ max_suggestions )
80
+ |> Enum . map ( fn { _distance , module_function } -> module_function end )
79
81
end
80
82
81
83
defp module_functions ( module ) do
@@ -86,12 +88,12 @@ defmodule ElixirLS.LanguageServer.Providers.CodeAction.ReplaceRemoteFunction do
86
88
end
87
89
end
88
90
89
- defp to_code_actions ( % SourceFile { } = source_file , line_number , module , name , suggestions , uri ) do
91
+ defp build_code_actions ( % SourceFile { } = source_file , line , module , name , suggestions , uri ) do
90
92
suggestions
91
93
|> Enum . reduce ( [ ] , fn suggestion , acc ->
92
- case apply_transform ( source_file , line_number , module , name , suggestion ) do
94
+ case text_edits ( source_file , line , module , name , suggestion ) do
93
95
{ :ok , [ _ | _ ] = text_edits } ->
94
- text_edits = Enum . map ( text_edits , & update_line ( & 1 , line_number ) )
96
+ text_edits = Enum . map ( text_edits , & update_line ( & 1 , line ) )
95
97
96
98
code_action =
97
99
CodeActionResult . new ( "Rename to #{ suggestion } " , "quickfix" , text_edits , uri )
@@ -105,58 +107,51 @@ defmodule ElixirLS.LanguageServer.Providers.CodeAction.ReplaceRemoteFunction do
105
107
|> Enum . reverse ( )
106
108
end
107
109
108
- defp apply_transform ( source_file , line_number , module , name , suggestion ) do
109
- with { :ok , text } <- fetch_line ( source_file , line_number ) ,
110
- { :ok , ast } <- Ast . from ( text ) do
111
- function_atom = String . to_atom ( name )
112
-
113
- leading_indent = Text . leading_indent ( text )
114
- trailing_comment = Text . trailing_comment ( text )
115
-
116
- ast
117
- |> Macro . postwalk ( fn
118
- { :. , function_meta , [ { :__aliases__ , module_meta , module_alias } , ^ function_atom ] } ->
119
- case expand_alias ( source_file , module_alias , line_number ) do
120
- { :ok , ^ module } ->
121
- { :. , function_meta , [ { :__aliases__ , module_meta , module_alias } , suggestion ] }
122
-
123
- _ ->
124
- { :. , function_meta , [ { :__aliases__ , module_meta , module_alias } , function_atom ] }
125
- end
126
-
127
- # erlang call
128
- { :. , function_meta , [ ^ module , ^ function_atom ] } ->
129
- { :. , function_meta , [ module , suggestion ] }
130
-
131
- other ->
132
- other
133
- end )
134
- |> to_one_line_string ( )
135
- |> case do
136
- { :ok , updated_text } ->
137
- text_edits = Diff . diff ( text , "#{ leading_indent } #{ updated_text } #{ trailing_comment } " )
138
-
139
- { :ok , text_edits }
140
-
141
- :error ->
142
- :error
143
- end
110
+ @ spec text_edits ( SourceFile . t ( ) , non_neg_integer ( ) , atom ( ) , String . t ( ) , atom ( ) ) ::
111
+ { :ok , [ TextEdit . t ( ) ] } | :error
112
+ defp text_edits ( % SourceFile { } = source_file , line , module , name , suggestion ) do
113
+ with { :ok , updated_text } <- apply_transform ( source_file , line , module , name , suggestion ) do
114
+ to_text_edits ( source_file . text , updated_text )
144
115
end
145
116
end
146
117
147
- defp fetch_line ( % SourceFile { } = source_file , line_number ) do
148
- lines = SourceFile . lines ( source_file )
118
+ defp apply_transform ( source_file , line , module , name , suggestion ) do
119
+ with { :ok , ast , comments } <- Ast . from ( source_file ) do
120
+ function_atom = String . to_atom ( name )
149
121
150
- if length ( lines ) > line_number do
151
- { :ok , Enum . at ( lines , line_number ) }
152
- else
153
- :error
122
+ one_based_line = line + 1
123
+
124
+ updated_text =
125
+ ast
126
+ |> Macro . postwalk ( fn
127
+ { :. , [ line: ^ one_based_line ] ,
128
+ [ { :__aliases__ , module_meta , module_alias } , ^ function_atom ] } ->
129
+ case expand_alias ( source_file , module_alias , line ) do
130
+ { :ok , ^ module } ->
131
+ { :. , [ line: one_based_line ] ,
132
+ [ { :__aliases__ , module_meta , module_alias } , suggestion ] }
133
+
134
+ _ ->
135
+ { :. , [ line: one_based_line ] ,
136
+ [ { :__aliases__ , module_meta , module_alias } , function_atom ] }
137
+ end
138
+
139
+ # erlang call
140
+ { :. , [ line: ^ one_based_line ] , [ { :__block__ , module_meta , [ ^ module ] } , ^ function_atom ] } ->
141
+ { :. , [ line: one_based_line ] , [ { :__block__ , module_meta , [ module ] } , suggestion ] }
142
+
143
+ other ->
144
+ other
145
+ end )
146
+ |> Ast . to_string ( comments )
147
+
148
+ { :ok , updated_text }
154
149
end
155
150
end
156
151
157
152
@ spec expand_alias ( SourceFile . t ( ) , [ atom ( ) ] , non_neg_integer ( ) ) :: { :ok , atom ( ) } | :error
158
- defp expand_alias ( source_file , module_alias , line_number ) do
159
- with { :ok , aliases } <- aliases_at ( source_file , line_number ) do
153
+ defp expand_alias ( source_file , module_alias , line ) do
154
+ with { :ok , aliases } <- aliases_at ( source_file , line ) do
160
155
aliases
161
156
|> Enum . map ( fn { module , aliased } ->
162
157
module = module |> module_to_alias ( ) |> List . first ( )
@@ -177,8 +172,8 @@ defmodule ElixirLS.LanguageServer.Providers.CodeAction.ReplaceRemoteFunction do
177
172
end
178
173
end
179
174
180
- defp aliases_at ( source_file , line_number ) do
181
- one_based_line = line_number + 1
175
+ defp aliases_at ( source_file , line ) do
176
+ one_based_line = line + 1
182
177
183
178
metadata = Parser . parse_string ( source_file . text , true , true , { one_based_line , 1 } )
184
179
0 commit comments