1
+ defmodule DescribeBlock do
2
+ alias ElixirSense.Core.State.Env
3
+
4
+ @ struct_keys [ :line , :name , :body_scope_id ]
5
+
6
+ @ enforce_keys @ struct_keys
7
+ defstruct @ struct_keys
8
+
9
+ def find_block_info ( line , lines_to_env_list , lines_to_env_list_length , source_lines ) do
10
+ name = get_name ( source_lines , line )
11
+
12
+ body_scope_id =
13
+ get_body_scope_id (
14
+ line ,
15
+ lines_to_env_list ,
16
+ lines_to_env_list_length
17
+ )
18
+
19
+ % DescribeBlock { line: line , body_scope_id: body_scope_id , name: name }
20
+ end
21
+
22
+ defp get_name ( source_lines , declaration_line ) do
23
+ % { "name" => name } =
24
+ ~r/ ^\s *describe "(?<name>.*)" do/
25
+ |> Regex . named_captures ( Enum . at ( source_lines , declaration_line - 1 ) )
26
+
27
+ name
28
+ end
29
+
30
+ defp get_body_scope_id (
31
+ declaration_line ,
32
+ lines_to_env_list ,
33
+ lines_to_env_list_length
34
+ ) do
35
+ env_index =
36
+ lines_to_env_list
37
+ |> Enum . find_index ( fn { line , _env } -> line == declaration_line end )
38
+
39
+ { _line , % { scope_id: declaration_scope_id } } =
40
+ lines_to_env_list
41
+ |> Enum . at ( env_index )
42
+
43
+ with true = env_index + 1 < lines_to_env_list_length ,
44
+ next_env = Enum . at ( lines_to_env_list , env_index + 1 ) ,
45
+ { _line , % Env { scope_id: body_scope_id } } <- next_env ,
46
+ true = body_scope_id != declaration_scope_id do
47
+ body_scope_id
48
+ else
49
+ _ -> nil
50
+ end
51
+ end
52
+ end
53
+
54
+ defmodule TestBlock do
55
+ @ struct_keys [ :name , :describe , :line ]
56
+
57
+ @ enforce_keys @ struct_keys
58
+ defstruct @ struct_keys
59
+ end
60
+
1
61
defmodule ElixirLS.LanguageServer.Providers.CodeLens.Test do
2
62
alias ElixirLS.LanguageServer.Providers.CodeLens
3
63
alias ElixirLS.LanguageServer.SourceFile
4
64
alias ElixirSense.Core.Parser
5
65
alias ElixirSense.Core.Metadata
66
+ alias ElixirSense.Core.State.Env
6
67
7
68
@ run_test_command "elixir.test.run"
8
69
9
70
def code_lens ( uri , text ) do
10
71
with { :ok , buffer_file_metadata } <- parse_source ( text ) do
72
+ source_lines = SourceFile . lines ( text )
73
+
11
74
file_path = SourceFile . path_from_uri ( uri )
12
75
13
- function_lenses = get_function_lenses ( buffer_file_metadata , file_path )
14
- module_lenses = get_module_lenses ( buffer_file_metadata , file_path )
76
+ calls_list =
77
+ buffer_file_metadata . calls
78
+ |> Enum . map ( fn { _k , v } -> v end )
79
+ |> List . flatten ( )
80
+
81
+ lines_to_env_list = Map . to_list ( buffer_file_metadata . lines_to_env )
82
+
83
+ describe_blocks = find_describe_blocks ( lines_to_env_list , calls_list , source_lines )
84
+ describe_lenses = get_describe_lenses ( describe_blocks , file_path )
85
+
86
+ test_lenses =
87
+ lines_to_env_list
88
+ |> find_test_blocks ( calls_list , describe_blocks , source_lines )
89
+ |> get_test_lenses ( file_path )
15
90
16
- { :ok , function_lenses ++ module_lenses }
91
+ module_lenses =
92
+ buffer_file_metadata
93
+ |> get_test_modules ( )
94
+ |> get_module_lenses ( file_path )
95
+
96
+ { :ok , test_lenses ++ describe_lenses ++ module_lenses }
17
97
end
18
98
end
19
99
20
- defp get_module_lenses ( % Metadata { } = metadata , file_path ) do
21
- metadata
22
- |> get_test_modules ( )
23
- |> Enum . map ( & build_test_module_code_lens ( file_path , & 1 ) )
100
+ def get_test_lenses ( test_blocks , file_path ) do
101
+ test_blocks
102
+ |> Enum . map ( fn block ->
103
+ CodeLens . build_code_lens ( block . line , "Run test" , @ run_test_command , % {
104
+ "filePath" => file_path ,
105
+ "describe" =>
106
+ if block . describe != nil do
107
+ block . describe . name
108
+ else
109
+ nil
110
+ end ,
111
+ "testName" => block . name
112
+ } )
113
+ end )
24
114
end
25
115
26
- defp get_test_modules ( % Metadata { lines_to_env: lines_to_env } ) do
27
- lines_to_env
28
- |> Enum . group_by ( fn { _line , env } -> env . module end )
29
- |> Enum . filter ( fn { _module , module_lines_to_env } -> is_test_module? ( module_lines_to_env ) end )
30
- |> Enum . map ( fn { module , [ { line , _env } | _rest ] } -> { module , line } end )
116
+ def get_describe_lenses ( describe_blocks , file_path ) do
117
+ describe_blocks
118
+ |> Enum . map ( fn block ->
119
+ CodeLens . build_code_lens ( block . line , "Run tests" , @ run_test_command , % {
120
+ "filePath" => file_path ,
121
+ "describe" => block . name
122
+ } )
123
+ end )
31
124
end
32
125
33
- defp get_function_lenses ( % Metadata { } = metadata , file_path ) do
34
- runnable_functions = [ { :test , 3 } , { :test , 2 } , { :describe , 2 } ]
35
-
36
- calls_list =
37
- metadata . calls
38
- |> Enum . map ( fn { _k , v } -> v end )
39
- |> List . flatten ( )
40
-
41
- lines_to_env_list = Map . to_list ( metadata . lines_to_env )
126
+ defp find_test_blocks ( lines_to_env_list , calls_list , describe_blocks , source_lines ) do
127
+ runnable_functions = [ { :test , 3 } , { :test , 2 } ]
42
128
43
129
for func <- runnable_functions ,
44
130
{ line , _col } <- calls_to ( calls_list , func ) ,
45
131
is_test_module? ( lines_to_env_list , line ) do
46
- build_function_test_code_lens ( func , file_path , line )
132
+ { _line , % { scope_id: scope_id } } =
133
+ Enum . find ( lines_to_env_list , fn { env_line , _env } -> env_line == line end )
134
+
135
+ describe =
136
+ describe_blocks
137
+ |> Enum . find ( nil , fn describe ->
138
+ describe . body_scope_id == scope_id
139
+ end )
140
+
141
+ % { "name" => test_name } =
142
+ ~r/ ^\s *test "(?<name>.*)"(,.*)? do/
143
+ |> Regex . named_captures ( Enum . at ( source_lines , line - 1 ) )
144
+
145
+ % TestBlock { name: test_name , describe: describe , line: line }
146
+ end
147
+ end
148
+
149
+ defp find_describe_blocks ( lines_to_env_list , calls_list , source_lines ) do
150
+ lines_to_env_list_length = length ( lines_to_env_list )
151
+
152
+ for { line , _col } <- calls_to ( calls_list , { :describe , 2 } ) ,
153
+ is_test_module? ( lines_to_env_list , line ) do
154
+ DescribeBlock . find_block_info (
155
+ line ,
156
+ lines_to_env_list ,
157
+ lines_to_env_list_length ,
158
+ source_lines
159
+ )
47
160
end
48
161
end
49
162
163
+ defp get_module_lenses ( test_modules , file_path ) do
164
+ test_modules
165
+ |> Enum . map ( fn { module , line } ->
166
+ CodeLens . build_code_lens ( line , "Run tests in module" , @ run_test_command , % {
167
+ "filePath" => file_path ,
168
+ "module" => module
169
+ } )
170
+ end )
171
+ end
172
+
173
+ defp get_test_modules ( % Metadata { lines_to_env: lines_to_env } ) do
174
+ lines_to_env
175
+ |> Enum . group_by ( fn { _line , env } -> env . module end )
176
+ |> Enum . filter ( fn { _module , module_lines_to_env } -> is_test_module? ( module_lines_to_env ) end )
177
+ |> Enum . map ( fn { module , [ { line , _env } | _rest ] } -> { module , line } end )
178
+ end
179
+
50
180
defp is_test_module? ( lines_to_env ) , do: is_test_module? ( lines_to_env , :infinity )
51
181
52
182
defp is_test_module? ( lines_to_env , line ) when is_list ( lines_to_env ) do
@@ -65,32 +195,8 @@ defmodule ElixirLS.LanguageServer.Providers.CodeLens.Test do
65
195
call_info . func == function and call_info . arity === arity do
66
196
call_info . position
67
197
end
68
-
69
- # calls_list
70
- # |> Enum.filter(fn call_info -> call_info.func == function and call_info.arity === arity end)
71
- # |> Enum.map(fn call -> call.position end)
72
- end
73
-
74
- defp build_test_module_code_lens ( file_path , { module , line } ) do
75
- CodeLens . build_code_lens ( line , "Run tests in module" , @ run_test_command , % {
76
- "file_path" => file_path ,
77
- "module" => module
78
- } )
79
198
end
80
199
81
- defp build_function_test_code_lens ( title , file_path , line ) when is_binary ( title ) do
82
- CodeLens . build_code_lens ( line , title , @ run_test_command , % {
83
- "file_path" => file_path ,
84
- "line" => line
85
- } )
86
- end
87
-
88
- defp build_function_test_code_lens ( { :test , _arity } , file_path , line ) ,
89
- do: build_function_test_code_lens ( "Run test" , file_path , line )
90
-
91
- defp build_function_test_code_lens ( { :describe , _arity } , file_path , line ) ,
92
- do: build_function_test_code_lens ( "Run tests" , file_path , line )
93
-
94
200
defp parse_source ( text ) do
95
201
buffer_file_metadata =
96
202
text
0 commit comments