ruby-lsp 0.22.0 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp +10 -9
- data/exe/ruby-lsp-check +5 -5
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +26 -20
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +131 -23
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +60 -30
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +73 -55
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +16 -14
- data/lib/{core_ext → ruby_indexer/lib/ruby_indexer}/uri.rb +29 -3
- data/lib/ruby_indexer/ruby_indexer.rb +1 -1
- data/lib/ruby_indexer/test/class_variables_test.rb +140 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +11 -6
- data/lib/ruby_indexer/test/configuration_test.rb +116 -51
- data/lib/ruby_indexer/test/enhancements_test.rb +2 -2
- data/lib/ruby_indexer/test/index_test.rb +72 -43
- data/lib/ruby_indexer/test/method_test.rb +80 -0
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_indexer/test/reference_finder_test.rb +1 -1
- data/lib/ruby_indexer/test/test_case.rb +2 -2
- data/lib/ruby_indexer/test/uri_test.rb +72 -0
- data/lib/ruby_lsp/addon.rb +9 -0
- data/lib/ruby_lsp/base_server.rb +15 -6
- data/lib/ruby_lsp/document.rb +10 -1
- data/lib/ruby_lsp/global_state.rb +1 -1
- data/lib/ruby_lsp/internal.rb +1 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +8 -4
- data/lib/ruby_lsp/listeners/completion.rb +73 -4
- data/lib/ruby_lsp/listeners/definition.rb +73 -17
- data/lib/ruby_lsp/listeners/document_symbol.rb +49 -5
- data/lib/ruby_lsp/listeners/folding_ranges.rb +1 -1
- data/lib/ruby_lsp/listeners/hover.rb +57 -0
- data/lib/ruby_lsp/requests/completion.rb +6 -0
- data/lib/ruby_lsp/requests/completion_resolve.rb +2 -1
- data/lib/ruby_lsp/requests/definition.rb +6 -0
- data/lib/ruby_lsp/requests/prepare_rename.rb +51 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
- data/lib/ruby_lsp/requests/rename.rb +14 -4
- data/lib/ruby_lsp/requests/support/common.rb +1 -5
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +1 -1
- data/lib/ruby_lsp/requests/workspace_symbol.rb +3 -2
- data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
- data/lib/ruby_lsp/server.rb +42 -7
- data/lib/ruby_lsp/setup_bundler.rb +54 -46
- data/lib/ruby_lsp/test_helper.rb +45 -11
- data/lib/ruby_lsp/type_inferrer.rb +22 -0
- data/lib/ruby_lsp/utils.rb +3 -0
- metadata +7 -8
- data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +0 -29
@@ -6,11 +6,11 @@ require_relative "test_case"
|
|
6
6
|
module RubyIndexer
|
7
7
|
class IndexTest < TestCase
|
8
8
|
def test_deleting_one_entry_for_a_class
|
9
|
-
@index.index_single(
|
9
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
10
10
|
class Foo
|
11
11
|
end
|
12
12
|
RUBY
|
13
|
-
@index.index_single(
|
13
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/other_foo.rb"), <<~RUBY)
|
14
14
|
class Foo
|
15
15
|
end
|
16
16
|
RUBY
|
@@ -18,13 +18,13 @@ module RubyIndexer
|
|
18
18
|
entries = @index["Foo"]
|
19
19
|
assert_equal(2, entries.length)
|
20
20
|
|
21
|
-
@index.delete(
|
21
|
+
@index.delete(URI::Generic.from_path(path: "/fake/path/other_foo.rb"))
|
22
22
|
entries = @index["Foo"]
|
23
23
|
assert_equal(1, entries.length)
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_deleting_all_entries_for_a_class
|
27
|
-
@index.index_single(
|
27
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
28
28
|
class Foo
|
29
29
|
end
|
30
30
|
RUBY
|
@@ -32,13 +32,13 @@ module RubyIndexer
|
|
32
32
|
entries = @index["Foo"]
|
33
33
|
assert_equal(1, entries.length)
|
34
34
|
|
35
|
-
@index.delete(
|
35
|
+
@index.delete(URI::Generic.from_path(path: "/fake/path/foo.rb"))
|
36
36
|
entries = @index["Foo"]
|
37
37
|
assert_nil(entries)
|
38
38
|
end
|
39
39
|
|
40
40
|
def test_index_resolve
|
41
|
-
@index.index_single(
|
41
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
42
42
|
class Bar; end
|
43
43
|
|
44
44
|
module Foo
|
@@ -72,7 +72,7 @@ module RubyIndexer
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def test_accessing_with_colon_colon_prefix
|
75
|
-
@index.index_single(
|
75
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
76
76
|
class Bar; end
|
77
77
|
|
78
78
|
module Foo
|
@@ -92,7 +92,7 @@ module RubyIndexer
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def test_fuzzy_search
|
95
|
-
@index.index_single(
|
95
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
96
96
|
class Zws; end
|
97
97
|
|
98
98
|
module Qtl
|
@@ -120,18 +120,22 @@ module RubyIndexer
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def test_index_single_ignores_directories
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
123
|
+
path = "#{Dir.pwd}/lib/this_is_a_dir.rb"
|
124
|
+
FileUtils.mkdir(path)
|
125
|
+
|
126
|
+
begin
|
127
|
+
@index.index_file(URI::Generic.from_path(path: path))
|
128
|
+
ensure
|
129
|
+
FileUtils.rm_r(path)
|
130
|
+
end
|
127
131
|
end
|
128
132
|
|
129
133
|
def test_searching_for_require_paths
|
130
|
-
@index.index_single(
|
134
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
131
135
|
class Foo
|
132
136
|
end
|
133
137
|
RUBY
|
134
|
-
@index.index_single(
|
138
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/other_foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
135
139
|
class Foo
|
136
140
|
end
|
137
141
|
RUBY
|
@@ -140,11 +144,11 @@ module RubyIndexer
|
|
140
144
|
end
|
141
145
|
|
142
146
|
def test_searching_for_entries_based_on_prefix
|
143
|
-
@index.index_single(
|
147
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
144
148
|
class Foo::Bizw
|
145
149
|
end
|
146
150
|
RUBY
|
147
|
-
@index.index_single(
|
151
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/other_foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
148
152
|
class Foo::Bizw
|
149
153
|
end
|
150
154
|
|
@@ -160,7 +164,7 @@ module RubyIndexer
|
|
160
164
|
end
|
161
165
|
|
162
166
|
def test_resolve_normalizes_top_level_names
|
163
|
-
@index.index_single(
|
167
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
164
168
|
class Bar; end
|
165
169
|
|
166
170
|
module Foo
|
@@ -180,7 +184,7 @@ module RubyIndexer
|
|
180
184
|
end
|
181
185
|
|
182
186
|
def test_resolving_aliases_to_non_existing_constants_with_conflicting_names
|
183
|
-
@index.index_single(
|
187
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb", load_path_entry: "/fake"), <<~RUBY)
|
184
188
|
class Bar
|
185
189
|
end
|
186
190
|
|
@@ -343,18 +347,18 @@ module RubyIndexer
|
|
343
347
|
raise "Prism fixtures not found. Run `git submodule update --init` to fetch them."
|
344
348
|
end
|
345
349
|
|
346
|
-
fixtures = Dir.glob("test/fixtures/prism/test/prism/fixtures/**/*.txt")
|
350
|
+
fixtures = Dir.glob("#{Dir.pwd}/test/fixtures/prism/test/prism/fixtures/**/*.txt")
|
347
351
|
|
348
352
|
fixtures.each do |fixture|
|
349
|
-
|
350
|
-
@index.
|
353
|
+
uri = URI::Generic.from_path(path: fixture)
|
354
|
+
@index.index_file(uri)
|
351
355
|
end
|
352
356
|
|
353
357
|
refute_empty(@index)
|
354
358
|
end
|
355
359
|
|
356
360
|
def test_index_single_does_not_fail_for_non_existing_file
|
357
|
-
@index.
|
361
|
+
@index.index_file(URI::Generic.from_path(path: "/fake/path/foo.rb"))
|
358
362
|
entries_after_indexing = @index.names
|
359
363
|
assert_equal(@default_indexed_entries.keys, entries_after_indexing)
|
360
364
|
end
|
@@ -782,8 +786,8 @@ module RubyIndexer
|
|
782
786
|
end
|
783
787
|
RUBY
|
784
788
|
|
785
|
-
|
786
|
-
@index.
|
789
|
+
uri = URI::Generic.from_path(path: File.join(dir, "foo.rb"))
|
790
|
+
@index.index_file(uri)
|
787
791
|
|
788
792
|
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
789
793
|
|
@@ -796,7 +800,7 @@ module RubyIndexer
|
|
796
800
|
end
|
797
801
|
RUBY
|
798
802
|
|
799
|
-
@index.handle_change(
|
803
|
+
@index.handle_change(uri, File.read(T.must(uri.full_path)))
|
800
804
|
assert_empty(@index.instance_variable_get(:@ancestors))
|
801
805
|
assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
802
806
|
end
|
@@ -816,8 +820,8 @@ module RubyIndexer
|
|
816
820
|
end
|
817
821
|
RUBY
|
818
822
|
|
819
|
-
|
820
|
-
@index.
|
823
|
+
uri = URI::Generic.from_path(path: File.join(dir, "foo.rb"))
|
824
|
+
@index.index_file(uri)
|
821
825
|
|
822
826
|
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
823
827
|
|
@@ -833,7 +837,7 @@ module RubyIndexer
|
|
833
837
|
end
|
834
838
|
RUBY
|
835
839
|
|
836
|
-
@index.handle_change(
|
840
|
+
@index.handle_change(uri, File.read(T.must(uri.full_path)))
|
837
841
|
refute_empty(@index.instance_variable_get(:@ancestors))
|
838
842
|
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
839
843
|
end
|
@@ -852,8 +856,8 @@ module RubyIndexer
|
|
852
856
|
end
|
853
857
|
RUBY
|
854
858
|
|
855
|
-
|
856
|
-
@index.
|
859
|
+
uri = URI::Generic.from_path(path: File.join(dir, "foo.rb"))
|
860
|
+
@index.index_file(uri)
|
857
861
|
|
858
862
|
assert_equal(["Bar", "Foo", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
859
863
|
|
@@ -866,7 +870,7 @@ module RubyIndexer
|
|
866
870
|
end
|
867
871
|
RUBY
|
868
872
|
|
869
|
-
@index.handle_change(
|
873
|
+
@index.handle_change(uri, File.read(T.must(uri.full_path)))
|
870
874
|
assert_empty(@index.instance_variable_get(:@ancestors))
|
871
875
|
assert_equal(["Bar", "Object", "Kernel", "BasicObject"], @index.linearized_ancestors_of("Bar"))
|
872
876
|
end
|
@@ -1300,7 +1304,7 @@ module RubyIndexer
|
|
1300
1304
|
end
|
1301
1305
|
|
1302
1306
|
def test_resolving_method_inside_singleton_context
|
1303
|
-
@index.index_single(
|
1307
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1304
1308
|
module Foo
|
1305
1309
|
class Bar
|
1306
1310
|
class << self
|
@@ -1321,7 +1325,7 @@ module RubyIndexer
|
|
1321
1325
|
end
|
1322
1326
|
|
1323
1327
|
def test_resolving_constants_in_singleton_contexts
|
1324
|
-
@index.index_single(
|
1328
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1325
1329
|
module Foo
|
1326
1330
|
class Bar
|
1327
1331
|
CONST = 3
|
@@ -1346,7 +1350,7 @@ module RubyIndexer
|
|
1346
1350
|
end
|
1347
1351
|
|
1348
1352
|
def test_resolving_instance_variables_in_singleton_contexts
|
1349
|
-
@index.index_single(
|
1353
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1350
1354
|
module Foo
|
1351
1355
|
class Bar
|
1352
1356
|
@a = 123
|
@@ -1376,7 +1380,7 @@ module RubyIndexer
|
|
1376
1380
|
end
|
1377
1381
|
|
1378
1382
|
def test_instance_variable_completion_in_singleton_contexts
|
1379
|
-
@index.index_single(
|
1383
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1380
1384
|
module Foo
|
1381
1385
|
class Bar
|
1382
1386
|
@a = 123
|
@@ -1622,7 +1626,7 @@ module RubyIndexer
|
|
1622
1626
|
end
|
1623
1627
|
|
1624
1628
|
def test_linearizing_singleton_ancestors_of_singleton_when_class_has_parent
|
1625
|
-
@index.index_single(
|
1629
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1626
1630
|
class Foo; end
|
1627
1631
|
|
1628
1632
|
class Bar < Foo
|
@@ -1673,7 +1677,7 @@ module RubyIndexer
|
|
1673
1677
|
end
|
1674
1678
|
|
1675
1679
|
def test_extend_self
|
1676
|
-
@index.index_single(
|
1680
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1677
1681
|
module Foo
|
1678
1682
|
def bar
|
1679
1683
|
end
|
@@ -1705,7 +1709,7 @@ module RubyIndexer
|
|
1705
1709
|
end
|
1706
1710
|
|
1707
1711
|
def test_linearizing_singleton_ancestors
|
1708
|
-
@index.index_single(
|
1712
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1709
1713
|
module First
|
1710
1714
|
end
|
1711
1715
|
|
@@ -1746,7 +1750,7 @@ module RubyIndexer
|
|
1746
1750
|
end
|
1747
1751
|
|
1748
1752
|
def test_linearizing_singleton_ancestors_when_class_has_parent
|
1749
|
-
@index.index_single(
|
1753
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1750
1754
|
class Foo; end
|
1751
1755
|
|
1752
1756
|
class Bar < Foo
|
@@ -1776,7 +1780,7 @@ module RubyIndexer
|
|
1776
1780
|
end
|
1777
1781
|
|
1778
1782
|
def test_linearizing_a_module_singleton_class
|
1779
|
-
@index.index_single(
|
1783
|
+
@index.index_single(URI::Generic.from_path(path: "/fake/path/foo.rb"), <<~RUBY)
|
1780
1784
|
module A; end
|
1781
1785
|
RUBY
|
1782
1786
|
|
@@ -1885,13 +1889,13 @@ module RubyIndexer
|
|
1885
1889
|
end
|
1886
1890
|
RUBY
|
1887
1891
|
|
1888
|
-
entries = @index.entries_for("
|
1892
|
+
entries = @index.entries_for("file:///fake/path/foo.rb", Entry)
|
1889
1893
|
assert_equal(["Foo", "Bar", "my_def", "Bar::<Class:Bar>", "my_singleton_def"], entries.map(&:name))
|
1890
1894
|
|
1891
|
-
entries = @index.entries_for("
|
1895
|
+
entries = @index.entries_for("file:///fake/path/foo.rb", RubyIndexer::Entry::Namespace)
|
1892
1896
|
assert_equal(["Foo", "Bar", "Bar::<Class:Bar>"], entries.map(&:name))
|
1893
1897
|
|
1894
|
-
entries = @index.entries_for("
|
1898
|
+
entries = @index.entries_for("file:///fake/path/foo.rb")
|
1895
1899
|
assert_equal(["Foo", "Bar", "my_def", "Bar::<Class:Bar>", "my_singleton_def"], entries.map(&:name))
|
1896
1900
|
end
|
1897
1901
|
|
@@ -2062,5 +2066,30 @@ module RubyIndexer
|
|
2062
2066
|
@index.index_all
|
2063
2067
|
end
|
2064
2068
|
end
|
2069
|
+
|
2070
|
+
def test_index_can_handle_entries_from_untitled_scheme
|
2071
|
+
uri = URI("untitled:Untitled-1")
|
2072
|
+
|
2073
|
+
index(<<~RUBY, uri: uri)
|
2074
|
+
class Foo
|
2075
|
+
end
|
2076
|
+
RUBY
|
2077
|
+
|
2078
|
+
entry = @index["Foo"]&.first
|
2079
|
+
refute_nil(entry, "Expected indexer to be able to handle unsaved URIs")
|
2080
|
+
assert_equal("untitled:Untitled-1", entry.uri.to_s)
|
2081
|
+
assert_equal("Untitled-1", entry.file_name)
|
2082
|
+
assert_nil(entry.file_path)
|
2083
|
+
|
2084
|
+
@index.handle_change(uri, <<~RUBY)
|
2085
|
+
# I added this comment!
|
2086
|
+
class Foo
|
2087
|
+
end
|
2088
|
+
RUBY
|
2089
|
+
|
2090
|
+
entry = @index["Foo"]&.first
|
2091
|
+
refute_nil(entry, "Expected indexer to be able to handle unsaved URIs")
|
2092
|
+
assert_equal("I added this comment!", entry.comments)
|
2093
|
+
end
|
2065
2094
|
end
|
2066
2095
|
end
|
@@ -149,6 +149,86 @@ module RubyIndexer
|
|
149
149
|
end
|
150
150
|
end
|
151
151
|
|
152
|
+
def test_private_class_method_visibility_tracking_string_symbol_arguments
|
153
|
+
index(<<~RUBY)
|
154
|
+
class Test
|
155
|
+
def self.foo
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.bar
|
159
|
+
end
|
160
|
+
|
161
|
+
private_class_method("foo", :bar)
|
162
|
+
|
163
|
+
def self.baz
|
164
|
+
end
|
165
|
+
end
|
166
|
+
RUBY
|
167
|
+
|
168
|
+
["foo", "bar"].each do |keyword|
|
169
|
+
entries = T.must(@index[keyword])
|
170
|
+
assert_equal(1, entries.size)
|
171
|
+
entry = entries.first
|
172
|
+
assert_predicate(entry, :private?)
|
173
|
+
end
|
174
|
+
|
175
|
+
entries = T.must(@index["baz"])
|
176
|
+
assert_equal(1, entries.size)
|
177
|
+
entry = entries.first
|
178
|
+
assert_predicate(entry, :public?)
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_private_class_method_visibility_tracking_array_argument
|
182
|
+
index(<<~RUBY)
|
183
|
+
class Test
|
184
|
+
def self.foo
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.bar
|
188
|
+
end
|
189
|
+
|
190
|
+
private_class_method(["foo", :bar])
|
191
|
+
|
192
|
+
def self.baz
|
193
|
+
end
|
194
|
+
end
|
195
|
+
RUBY
|
196
|
+
|
197
|
+
["foo", "bar"].each do |keyword|
|
198
|
+
entries = T.must(@index[keyword])
|
199
|
+
assert_equal(1, entries.size)
|
200
|
+
entry = entries.first
|
201
|
+
assert_predicate(entry, :private?)
|
202
|
+
end
|
203
|
+
|
204
|
+
entries = T.must(@index["baz"])
|
205
|
+
assert_equal(1, entries.size)
|
206
|
+
entry = entries.first
|
207
|
+
assert_predicate(entry, :public?)
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_private_class_method_visibility_tracking_method_argument
|
211
|
+
index(<<~RUBY)
|
212
|
+
class Test
|
213
|
+
private_class_method def self.foo
|
214
|
+
end
|
215
|
+
|
216
|
+
def self.bar
|
217
|
+
end
|
218
|
+
end
|
219
|
+
RUBY
|
220
|
+
|
221
|
+
entries = T.must(@index["foo"])
|
222
|
+
assert_equal(1, entries.size)
|
223
|
+
entry = entries.first
|
224
|
+
assert_predicate(entry, :private?)
|
225
|
+
|
226
|
+
entries = T.must(@index["bar"])
|
227
|
+
assert_equal(1, entries.size)
|
228
|
+
entry = entries.first
|
229
|
+
assert_predicate(entry, :public?)
|
230
|
+
end
|
231
|
+
|
152
232
|
def test_comments_documentation
|
153
233
|
index(<<~RUBY)
|
154
234
|
# Documentation for Foo
|
@@ -377,7 +377,7 @@ module RubyIndexer
|
|
377
377
|
_, _, declarations = RBS::Parser.parse_signature(buffer)
|
378
378
|
index = RubyIndexer::Index.new
|
379
379
|
indexer = RubyIndexer::RBSIndexer.new(index)
|
380
|
-
pathname = Pathname.new("file.rbs")
|
380
|
+
pathname = Pathname.new("/file.rbs")
|
381
381
|
indexer.process_signature(pathname, declarations)
|
382
382
|
entry = T.must(index[method_name]).first
|
383
383
|
T.cast(entry, Entry::Method).signatures
|
@@ -231,7 +231,7 @@ module RubyIndexer
|
|
231
231
|
def find_references(target, source)
|
232
232
|
file_path = "/fake.rb"
|
233
233
|
index = Index.new
|
234
|
-
index.index_single(
|
234
|
+
index.index_single(URI::Generic.from_path(path: file_path), source)
|
235
235
|
parse_result = Prism.parse(source)
|
236
236
|
dispatcher = Prism::Dispatcher.new
|
237
237
|
finder = ReferenceFinder.new(target, index, dispatcher)
|
@@ -13,8 +13,8 @@ module RubyIndexer
|
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
def index(source)
|
17
|
-
@index.index_single(
|
16
|
+
def index(source, uri: URI::Generic.from_path(path: "/fake/path/foo.rb"))
|
17
|
+
@index.index_single(uri, source)
|
18
18
|
end
|
19
19
|
|
20
20
|
def assert_entry(expected_name, type, expected_location, visibility: nil)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "test_helper"
|
5
|
+
|
6
|
+
module RubyIndexer
|
7
|
+
class URITest < Minitest::Test
|
8
|
+
def test_from_path_on_unix
|
9
|
+
uri = URI::Generic.from_path(path: "/some/unix/path/to/file.rb")
|
10
|
+
assert_equal("/some/unix/path/to/file.rb", uri.path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_from_path_on_windows
|
14
|
+
uri = URI::Generic.from_path(path: "C:/some/windows/path/to/file.rb")
|
15
|
+
assert_equal("/C:/some/windows/path/to/file.rb", uri.path)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_from_path_on_windows_with_lowercase_drive
|
19
|
+
uri = URI::Generic.from_path(path: "c:/some/windows/path/to/file.rb")
|
20
|
+
assert_equal("/c:/some/windows/path/to/file.rb", uri.path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_to_standardized_path_on_unix
|
24
|
+
uri = URI::Generic.from_path(path: "/some/unix/path/to/file.rb")
|
25
|
+
assert_equal(uri.path, uri.to_standardized_path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_to_standardized_path_on_windows
|
29
|
+
uri = URI::Generic.from_path(path: "C:/some/windows/path/to/file.rb")
|
30
|
+
assert_equal("C:/some/windows/path/to/file.rb", uri.to_standardized_path)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_to_standardized_path_on_windows_with_lowercase_drive
|
34
|
+
uri = URI::Generic.from_path(path: "c:/some/windows/path/to/file.rb")
|
35
|
+
assert_equal("c:/some/windows/path/to/file.rb", uri.to_standardized_path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_to_standardized_path_on_windows_with_received_uri
|
39
|
+
uri = URI("file:///c%3A/some/windows/path/to/file.rb")
|
40
|
+
assert_equal("c:/some/windows/path/to/file.rb", uri.to_standardized_path)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_plus_signs_are_properly_unescaped
|
44
|
+
path = "/opt/rubies/3.3.0/lib/ruby/3.3.0+0/pathname.rb"
|
45
|
+
uri = URI::Generic.from_path(path: path)
|
46
|
+
assert_equal(path, uri.to_standardized_path)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_from_path_with_fragment
|
50
|
+
uri = URI::Generic.from_path(path: "/some/unix/path/to/file.rb", fragment: "L1,3-2,9")
|
51
|
+
assert_equal("file:///some/unix/path/to/file.rb#L1,3-2,9", uri.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_from_path_windows_long_file_paths
|
55
|
+
uri = URI::Generic.from_path(path: "//?/C:/hostedtoolcache/windows/Ruby/3.3.1/x64/lib/ruby/3.3.0/open-uri.rb")
|
56
|
+
assert_equal("C:/hostedtoolcache/windows/Ruby/3.3.1/x64/lib/ruby/3.3.0/open-uri.rb", uri.to_standardized_path)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_from_path_computes_require_path_when_load_path_entry_is_given
|
60
|
+
uri = URI::Generic.from_path(path: "/some/unix/path/to/file.rb", load_path_entry: "/some/unix/path")
|
61
|
+
assert_equal("to/file", uri.require_path)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_allows_adding_require_path_with_load_path_entry
|
65
|
+
uri = URI::Generic.from_path(path: "/some/unix/path/to/file.rb")
|
66
|
+
assert_nil(uri.require_path)
|
67
|
+
|
68
|
+
uri.add_require_path_from_load_entry("/some/unix/path")
|
69
|
+
assert_equal("to/file", uri.require_path)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/ruby_lsp/addon.rb
CHANGED
@@ -97,6 +97,15 @@ module RubyLsp
|
|
97
97
|
errors
|
98
98
|
end
|
99
99
|
|
100
|
+
# Unloads all add-ons. Only intended to be invoked once when shutting down the Ruby LSP server
|
101
|
+
sig { void }
|
102
|
+
def unload_addons
|
103
|
+
@addons.each(&:deactivate)
|
104
|
+
@addons.clear
|
105
|
+
@addon_classes.clear
|
106
|
+
@file_watcher_addons.clear
|
107
|
+
end
|
108
|
+
|
100
109
|
# Get a reference to another add-on object by name and version. If an add-on exports an API that can be used by
|
101
110
|
# other add-ons, this is the way to get access to that API.
|
102
111
|
#
|
data/lib/ruby_lsp/base_server.rb
CHANGED
@@ -91,14 +91,13 @@ module RubyLsp
|
|
91
91
|
# The following requests need to be executed in the main thread directly to avoid concurrency issues. Everything
|
92
92
|
# else is pushed into the incoming queue
|
93
93
|
case method
|
94
|
-
when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
|
94
|
+
when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange",
|
95
|
+
"$/cancelRequest"
|
95
96
|
process_message(message)
|
96
97
|
when "shutdown"
|
97
|
-
send_log_message("Shutting down Ruby LSP...")
|
98
|
-
|
99
|
-
shutdown
|
100
|
-
|
101
98
|
@mutex.synchronize do
|
99
|
+
send_log_message("Shutting down Ruby LSP...")
|
100
|
+
shutdown
|
102
101
|
run_shutdown
|
103
102
|
@writer.write(Result.new(id: message[:id], response: nil).to_hash)
|
104
103
|
end
|
@@ -133,6 +132,12 @@ module RubyLsp
|
|
133
132
|
@outgoing_queue.pop
|
134
133
|
end
|
135
134
|
|
135
|
+
# This method is only intended to be used in tests! Pushes a message to the incoming queue directly
|
136
|
+
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
137
|
+
def push_message(message)
|
138
|
+
@incoming_queue << message
|
139
|
+
end
|
140
|
+
|
136
141
|
sig { abstract.params(message: T::Hash[Symbol, T.untyped]).void }
|
137
142
|
def process_message(message); end
|
138
143
|
|
@@ -154,7 +159,11 @@ module RubyLsp
|
|
154
159
|
# Check if the request was cancelled before trying to process it
|
155
160
|
@mutex.synchronize do
|
156
161
|
if id && @cancelled_requests.include?(id)
|
157
|
-
send_message(
|
162
|
+
send_message(Error.new(
|
163
|
+
id: id,
|
164
|
+
code: Constant::ErrorCodes::REQUEST_CANCELLED,
|
165
|
+
message: "Request #{id} was cancelled",
|
166
|
+
))
|
158
167
|
@cancelled_requests.delete(id)
|
159
168
|
next
|
160
169
|
end
|
data/lib/ruby_lsp/document.rb
CHANGED
@@ -15,6 +15,7 @@ module RubyLsp
|
|
15
15
|
extend T::Helpers
|
16
16
|
extend T::Generic
|
17
17
|
|
18
|
+
class LocationNotFoundError < StandardError; end
|
18
19
|
ParseResultType = type_member
|
19
20
|
|
20
21
|
# This maximum number of characters for providing expensive features, like semantic highlighting and diagnostics.
|
@@ -144,7 +145,15 @@ module RubyLsp
|
|
144
145
|
def find_char_position(position)
|
145
146
|
# Find the character index for the beginning of the requested line
|
146
147
|
until @current_line == position[:line]
|
147
|
-
|
148
|
+
until LINE_BREAK == @source[@pos]
|
149
|
+
@pos += 1
|
150
|
+
|
151
|
+
if @pos >= @source.length
|
152
|
+
# Pack the code points back into the original string to provide context in the error message
|
153
|
+
raise LocationNotFoundError, "Requested position: #{position}\nSource:\n\n#{@source.pack("U*")}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
148
157
|
@pos += 1
|
149
158
|
@current_line += 1
|
150
159
|
end
|
data/lib/ruby_lsp/internal.rb
CHANGED
@@ -26,7 +26,6 @@ require "fileutils"
|
|
26
26
|
require "ruby-lsp"
|
27
27
|
require "ruby_lsp/base_server"
|
28
28
|
require "ruby_indexer/ruby_indexer"
|
29
|
-
require "core_ext/uri"
|
30
29
|
require "ruby_lsp/utils"
|
31
30
|
require "ruby_lsp/static_docs"
|
32
31
|
require "ruby_lsp/scope"
|
@@ -78,6 +77,7 @@ require "ruby_lsp/requests/hover"
|
|
78
77
|
require "ruby_lsp/requests/inlay_hints"
|
79
78
|
require "ruby_lsp/requests/on_type_formatting"
|
80
79
|
require "ruby_lsp/requests/prepare_type_hierarchy"
|
80
|
+
require "ruby_lsp/requests/prepare_rename"
|
81
81
|
require "ruby_lsp/requests/range_formatting"
|
82
82
|
require "ruby_lsp/requests/references"
|
83
83
|
require "ruby_lsp/requests/rename"
|
@@ -15,7 +15,7 @@ module RubyLsp
|
|
15
15
|
"bundle exec ruby"
|
16
16
|
rescue Bundler::GemfileNotFound
|
17
17
|
"ruby"
|
18
|
-
end
|
18
|
+
end,
|
19
19
|
String,
|
20
20
|
)
|
21
21
|
ACCESS_MODIFIERS = T.let([:public, :private, :protected], T::Array[Symbol])
|
@@ -198,7 +198,7 @@ module RubyLsp
|
|
198
198
|
|
199
199
|
@response_builder << create_code_lens(
|
200
200
|
node,
|
201
|
-
title: "Run",
|
201
|
+
title: "▶ Run",
|
202
202
|
command_name: "rubyLsp.runTest",
|
203
203
|
arguments: arguments,
|
204
204
|
data: { type: "test", **grouping_data },
|
@@ -206,7 +206,7 @@ module RubyLsp
|
|
206
206
|
|
207
207
|
@response_builder << create_code_lens(
|
208
208
|
node,
|
209
|
-
title: "Run In Terminal",
|
209
|
+
title: "▶ Run In Terminal",
|
210
210
|
command_name: "rubyLsp.runTestInTerminal",
|
211
211
|
arguments: arguments,
|
212
212
|
data: { type: "test_in_terminal", **grouping_data },
|
@@ -229,7 +229,11 @@ module RubyLsp
|
|
229
229
|
).returns(String)
|
230
230
|
end
|
231
231
|
def generate_test_command(group_stack: [], spec_name: nil, method_name: nil)
|
232
|
-
|
232
|
+
path = T.must(@path)
|
233
|
+
command = BASE_COMMAND
|
234
|
+
command += " -Itest" if File.fnmatch?("**/test/**/*", path, File::FNM_PATHNAME)
|
235
|
+
command += " -Ispec" if File.fnmatch?("**/spec/**/*", path, File::FNM_PATHNAME)
|
236
|
+
command += " #{path}"
|
233
237
|
|
234
238
|
case @global_state.test_library
|
235
239
|
when "minitest"
|