ruby-lsp 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|