ruby-lsp 0.22.1 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +10 -9
  4. data/exe/ruby-lsp-check +5 -5
  5. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +26 -20
  6. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +88 -22
  7. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +60 -30
  8. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +73 -55
  9. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +16 -14
  10. data/lib/{core_ext → ruby_indexer/lib/ruby_indexer}/uri.rb +29 -3
  11. data/lib/ruby_indexer/ruby_indexer.rb +1 -1
  12. data/lib/ruby_indexer/test/class_variables_test.rb +140 -0
  13. data/lib/ruby_indexer/test/classes_and_modules_test.rb +11 -6
  14. data/lib/ruby_indexer/test/configuration_test.rb +116 -51
  15. data/lib/ruby_indexer/test/enhancements_test.rb +2 -2
  16. data/lib/ruby_indexer/test/index_test.rb +72 -43
  17. data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
  18. data/lib/ruby_indexer/test/reference_finder_test.rb +1 -1
  19. data/lib/ruby_indexer/test/test_case.rb +2 -2
  20. data/lib/ruby_indexer/test/uri_test.rb +72 -0
  21. data/lib/ruby_lsp/addon.rb +9 -0
  22. data/lib/ruby_lsp/base_server.rb +15 -6
  23. data/lib/ruby_lsp/document.rb +10 -1
  24. data/lib/ruby_lsp/internal.rb +1 -1
  25. data/lib/ruby_lsp/listeners/code_lens.rb +8 -4
  26. data/lib/ruby_lsp/listeners/completion.rb +73 -4
  27. data/lib/ruby_lsp/listeners/definition.rb +73 -17
  28. data/lib/ruby_lsp/listeners/document_symbol.rb +12 -1
  29. data/lib/ruby_lsp/listeners/folding_ranges.rb +1 -1
  30. data/lib/ruby_lsp/listeners/hover.rb +57 -0
  31. data/lib/ruby_lsp/requests/completion.rb +6 -0
  32. data/lib/ruby_lsp/requests/completion_resolve.rb +2 -1
  33. data/lib/ruby_lsp/requests/definition.rb +6 -0
  34. data/lib/ruby_lsp/requests/prepare_rename.rb +51 -0
  35. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
  36. data/lib/ruby_lsp/requests/rename.rb +14 -4
  37. data/lib/ruby_lsp/requests/support/common.rb +1 -5
  38. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +1 -1
  39. data/lib/ruby_lsp/requests/workspace_symbol.rb +3 -2
  40. data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
  41. data/lib/ruby_lsp/server.rb +42 -7
  42. data/lib/ruby_lsp/setup_bundler.rb +31 -41
  43. data/lib/ruby_lsp/test_helper.rb +45 -11
  44. data/lib/ruby_lsp/type_inferrer.rb +22 -0
  45. data/lib/ruby_lsp/utils.rb +3 -0
  46. metadata +7 -8
  47. data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: efd5671eae595026a17c3114a00de1053865ac828726dd7ac5a66548f6b1ad56
4
- data.tar.gz: ccf5b7af12a6e1e327cc2d458be11f39a9ac7319ab9049863ed5a74e333e8a6f
3
+ metadata.gz: 3792653083ea45143ce56ff51f68ced5217a52e9172c2cb33e03d012eda30ee8
4
+ data.tar.gz: 7d798218889b1add42189e08013a3503d9140a6504144fd0edfd8de00827c7f0
5
5
  SHA512:
6
- metadata.gz: 8fbcdfaac508788a17fb3b7e939ce290e33049a0080ff6260abfaeb609ee76a033234ccc2efa5724587e9c4cbf4552e2cd5d2cb0af1186971b8ed06fec290cb3
7
- data.tar.gz: 3e37acf250618e60df2addbce7f9acf86df4bf3e771b7b49c4cd8f4ad326ea82e3d41ad80c5ce71e3b0429dab98385df51f4645824cd419e32dac5ea13778760
6
+ metadata.gz: ec313c0971ed544bfb14904105345d8a4843e8aa4eeefaccbcbdb69e40ff2da2f618b4d95f89cf86ed51a90a9e3f2cb7aca93d56dca352de6f1ac2b4aff29dfe
7
+ data.tar.gz: 1fb2034291a4ca052d91c03095dcea32165dd2deaeafdbda59dfd67142d6380fcf9f1306879b9b516c8ba14605223042625fca5ecc1b7b9eb2137c0777ebc32f
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.22.1
1
+ 0.23.0
data/exe/ruby-lsp CHANGED
@@ -64,7 +64,7 @@ if ENV["BUNDLE_GEMFILE"].nil?
64
64
  # which gives us the opportunity to control which specs are activated and enter degraded mode if any gems failed to
65
65
  # install rather than failing to boot the server completely
66
66
  if options[:launcher]
67
- command = +File.expand_path("ruby-lsp-launcher", __dir__)
67
+ command = +"#{Gem.ruby} #{File.expand_path("ruby-lsp-launcher", __dir__)}"
68
68
  command << " --debug" if options[:debug]
69
69
  exit exec(command)
70
70
  end
@@ -78,13 +78,14 @@ if ENV["BUNDLE_GEMFILE"].nil?
78
78
  exit(78)
79
79
  end
80
80
 
81
- base_bundle = if env["BUNDLER_VERSION"]
82
- "bundle _#{env["BUNDLER_VERSION"]}_"
83
- else
84
- "bundle"
81
+ bundler_path = File.join(Gem.default_bindir, "bundle")
82
+ base_command = (File.exist?(bundler_path) ? "#{Gem.ruby} #{bundler_path}" : "bundle").dup
83
+
84
+ if env["BUNDLER_VERSION"]
85
+ base_command << " _#{env["BUNDLER_VERSION"]}_"
85
86
  end
86
87
 
87
- exit exec(env, "#{base_bundle} exec ruby-lsp #{original_args.join(" ")}".strip)
88
+ exit exec(env, "#{base_command} exec ruby-lsp #{original_args.join(" ")}".strip)
88
89
  end
89
90
 
90
91
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
@@ -139,9 +140,9 @@ if options[:doctor]
139
140
 
140
141
  puts "Globbing for indexable files"
141
142
 
142
- index.configuration.indexables.each do |indexable|
143
- puts "indexing: #{indexable.full_path}"
144
- index.index_single(indexable)
143
+ index.configuration.indexable_uris.each do |uri|
144
+ puts "indexing: #{uri}"
145
+ index.index_file(uri)
145
146
  end
146
147
  return
147
148
  end
data/exe/ruby-lsp-check CHANGED
@@ -44,14 +44,14 @@ puts "\n"
44
44
  puts "Verifying that indexing executes successfully. This may take a while..."
45
45
 
46
46
  index = RubyIndexer::Index.new
47
- indexables = index.configuration.indexables
47
+ uris = index.configuration.indexable_uris
48
48
 
49
- indexables.each_with_index do |indexable, i|
50
- index.index_single(indexable)
49
+ uris.each_with_index do |uri, i|
50
+ index.index_file(uri)
51
51
  rescue => e
52
- errors[indexable.full_path] = e
52
+ errors[uri.full_path] = e
53
53
  ensure
54
- print("\033[M\033[0KIndexed #{i + 1}/#{indexables.length}") unless ENV["CI"]
54
+ print("\033[M\033[0KIndexed #{i + 1}/#{uris.length}") unless ENV["CI"]
55
55
  end
56
56
  puts "\n"
57
57
 
@@ -81,8 +81,8 @@ module RubyIndexer
81
81
  .then { |dirs| File.join(@workspace_path, "{#{dirs.join(",")}}/**/*") }
82
82
  end
83
83
 
84
- sig { returns(T::Array[IndexablePath]) }
85
- def indexables
84
+ sig { returns(T::Array[URI::Generic]) }
85
+ def indexable_uris
86
86
  excluded_gems = @excluded_gems - @included_gems
87
87
  locked_gems = Bundler.locked_gems&.specs
88
88
 
@@ -107,12 +107,12 @@ module RubyIndexer
107
107
  [included_path, relative_path]
108
108
  end
109
109
 
110
- indexables = T.let([], T::Array[IndexablePath])
110
+ uris = T.let([], T::Array[URI::Generic])
111
111
 
112
112
  # Handle top level files separately. The path below is an optimization to prevent descending down directories that
113
113
  # are going to be excluded anyway, so we need to handle top level scripts separately
114
114
  Dir.glob(File.join(@workspace_path, "*.rb"), flags).each do |path|
115
- indexables << IndexablePath.new(nil, path)
115
+ uris << URI::Generic.from_path(path: path)
116
116
  end
117
117
 
118
118
  # Add user specified patterns
@@ -134,7 +134,7 @@ module RubyIndexer
134
134
  load_path_entry = $LOAD_PATH.find { |load_path| path.start_with?(load_path) }
135
135
  end
136
136
 
137
- indexables << IndexablePath.new(load_path_entry, path)
137
+ uris << URI::Generic.from_path(path: path, load_path_entry: load_path_entry)
138
138
  end
139
139
  end
140
140
  end
@@ -150,9 +150,9 @@ module RubyIndexer
150
150
  end
151
151
 
152
152
  # Remove user specified patterns
153
- indexables.reject! do |indexable|
153
+ uris.reject! do |indexable|
154
154
  excluded_patterns.any? do |pattern|
155
- File.fnmatch?(pattern, indexable.full_path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
155
+ File.fnmatch?(pattern, T.must(indexable.full_path), File::FNM_PATHNAME | File::FNM_EXTGLOB)
156
156
  end
157
157
  end
158
158
 
@@ -182,14 +182,14 @@ module RubyIndexer
182
182
 
183
183
  if pathname.directory?
184
184
  # If the default_path is a directory, we index all the Ruby files in it
185
- indexables.concat(
185
+ uris.concat(
186
186
  Dir.glob(File.join(default_path, "**", "*.rb"), File::FNM_PATHNAME | File::FNM_EXTGLOB).map! do |path|
187
- IndexablePath.new(RbConfig::CONFIG["rubylibdir"], path)
187
+ URI::Generic.from_path(path: path, load_path_entry: RbConfig::CONFIG["rubylibdir"])
188
188
  end,
189
189
  )
190
190
  elsif pathname.extname == ".rb"
191
191
  # If the default_path is a Ruby file, we index it
192
- indexables << IndexablePath.new(RbConfig::CONFIG["rubylibdir"], default_path)
192
+ uris << URI::Generic.from_path(path: default_path, load_path_entry: RbConfig::CONFIG["rubylibdir"])
193
193
  end
194
194
  end
195
195
 
@@ -204,10 +204,12 @@ module RubyIndexer
204
204
  # duplicates or accidentally ignoring exclude patterns
205
205
  next if spec.full_gem_path == @workspace_path
206
206
 
207
- indexables.concat(
207
+ uris.concat(
208
208
  spec.require_paths.flat_map do |require_path|
209
209
  load_path_entry = File.join(spec.full_gem_path, require_path)
210
- Dir.glob(File.join(load_path_entry, "**", "*.rb")).map! { |path| IndexablePath.new(load_path_entry, path) }
210
+ Dir.glob(File.join(load_path_entry, "**", "*.rb")).map! do |path|
211
+ URI::Generic.from_path(path: path, load_path_entry: load_path_entry)
212
+ end
211
213
  end,
212
214
  )
213
215
  rescue Gem::MissingSpecError
@@ -216,8 +218,8 @@ module RubyIndexer
216
218
  # just ignore if they're missing
217
219
  end
218
220
 
219
- indexables.uniq!(&:full_path)
220
- indexables
221
+ uris.uniq!(&:to_s)
222
+ uris
221
223
  end
222
224
 
223
225
  sig { returns(Regexp) }
@@ -271,6 +273,15 @@ module RubyIndexer
271
273
  end
272
274
 
273
275
  others.concat(this_gem.to_spec.dependencies) if this_gem
276
+ others.concat(
277
+ others.filter_map do |d|
278
+ d.to_spec&.dependencies
279
+ rescue Gem::MissingSpecError
280
+ nil
281
+ end.flatten,
282
+ )
283
+ others.uniq!
284
+ others.map!(&:name)
274
285
 
275
286
  excluded.each do |dependency|
276
287
  next unless dependency.runtime?
@@ -279,12 +290,7 @@ module RubyIndexer
279
290
  next unless spec
280
291
 
281
292
  spec.dependencies.each do |transitive_dependency|
282
- # If the transitive dependency is included in other groups, skip it
283
- next if others.any? { |d| d.name == transitive_dependency.name }
284
-
285
- # If the transitive dependency is included as a transitive dependency of a gem outside of the development
286
- # group, skip it
287
- next if others.any? { |d| d.to_spec&.dependencies&.include?(transitive_dependency) }
293
+ next if others.include?(transitive_dependency.name)
288
294
 
289
295
  excluded << transitive_dependency
290
296
  end
@@ -16,13 +16,13 @@ module RubyIndexer
16
16
  index: Index,
17
17
  dispatcher: Prism::Dispatcher,
18
18
  parse_result: Prism::ParseResult,
19
- file_path: String,
19
+ uri: URI::Generic,
20
20
  collect_comments: T::Boolean,
21
21
  ).void
22
22
  end
23
- def initialize(index, dispatcher, parse_result, file_path, collect_comments: false)
23
+ def initialize(index, dispatcher, parse_result, uri, collect_comments: false)
24
24
  @index = index
25
- @file_path = file_path
25
+ @uri = uri
26
26
  @enhancements = T.let(Enhancement.all(self), T::Array[Enhancement])
27
27
  @visibility_stack = T.let([Entry::Visibility::PUBLIC], T::Array[Entry::Visibility])
28
28
  @comments_by_line = T.let(
@@ -80,6 +80,11 @@ module RubyIndexer
80
80
  :on_instance_variable_or_write_node_enter,
81
81
  :on_instance_variable_target_node_enter,
82
82
  :on_alias_method_node_enter,
83
+ :on_class_variable_and_write_node_enter,
84
+ :on_class_variable_operator_write_node_enter,
85
+ :on_class_variable_or_write_node_enter,
86
+ :on_class_variable_target_node_enter,
87
+ :on_class_variable_write_node_enter,
83
88
  )
84
89
  end
85
90
 
@@ -154,7 +159,7 @@ module RubyIndexer
154
159
  else
155
160
  entry = Entry::SingletonClass.new(
156
161
  real_nesting,
157
- @file_path,
162
+ @uri,
158
163
  Location.from_prism_location(node.location, @code_units_cache),
159
164
  Location.from_prism_location(expression.location, @code_units_cache),
160
165
  collect_comments(node),
@@ -291,7 +296,7 @@ module RubyIndexer
291
296
  enhancement.on_call_node_enter(node)
292
297
  rescue StandardError => e
293
298
  @indexing_errors << <<~MSG
294
- Indexing error in #{@file_path} with '#{enhancement.class.name}' on call node enter enhancement: #{e.message}
299
+ Indexing error in #{@uri} with '#{enhancement.class.name}' on call node enter enhancement: #{e.message}
295
300
  MSG
296
301
  end
297
302
  end
@@ -312,7 +317,7 @@ module RubyIndexer
312
317
  enhancement.on_call_node_leave(node)
313
318
  rescue StandardError => e
314
319
  @indexing_errors << <<~MSG
315
- Indexing error in #{@file_path} with '#{enhancement.class.name}' on call node leave enhancement: #{e.message}
320
+ Indexing error in #{@uri} with '#{enhancement.class.name}' on call node leave enhancement: #{e.message}
316
321
  MSG
317
322
  end
318
323
  end
@@ -327,7 +332,7 @@ module RubyIndexer
327
332
  when nil
328
333
  @index.add(Entry::Method.new(
329
334
  method_name,
330
- @file_path,
335
+ @uri,
331
336
  Location.from_prism_location(node.location, @code_units_cache),
332
337
  Location.from_prism_location(node.name_loc, @code_units_cache),
333
338
  comments,
@@ -343,7 +348,7 @@ module RubyIndexer
343
348
 
344
349
  @index.add(Entry::Method.new(
345
350
  method_name,
346
- @file_path,
351
+ @uri,
347
352
  Location.from_prism_location(node.location, @code_units_cache),
348
353
  Location.from_prism_location(node.name_loc, @code_units_cache),
349
354
  comments,
@@ -427,13 +432,38 @@ module RubyIndexer
427
432
  method_name,
428
433
  node.old_name.slice,
429
434
  @owner_stack.last,
430
- @file_path,
435
+ @uri,
431
436
  Location.from_prism_location(node.new_name.location, @code_units_cache),
432
437
  comments,
433
438
  ),
434
439
  )
435
440
  end
436
441
 
442
+ sig { params(node: Prism::ClassVariableAndWriteNode).void }
443
+ def on_class_variable_and_write_node_enter(node)
444
+ handle_class_variable(node, node.name_loc)
445
+ end
446
+
447
+ sig { params(node: Prism::ClassVariableOperatorWriteNode).void }
448
+ def on_class_variable_operator_write_node_enter(node)
449
+ handle_class_variable(node, node.name_loc)
450
+ end
451
+
452
+ sig { params(node: Prism::ClassVariableOrWriteNode).void }
453
+ def on_class_variable_or_write_node_enter(node)
454
+ handle_class_variable(node, node.name_loc)
455
+ end
456
+
457
+ sig { params(node: Prism::ClassVariableTargetNode).void }
458
+ def on_class_variable_target_node_enter(node)
459
+ handle_class_variable(node, node.location)
460
+ end
461
+
462
+ sig { params(node: Prism::ClassVariableWriteNode).void }
463
+ def on_class_variable_write_node_enter(node)
464
+ handle_class_variable(node, node.name_loc)
465
+ end
466
+
437
467
  sig do
438
468
  params(
439
469
  name: String,
@@ -448,7 +478,7 @@ module RubyIndexer
448
478
 
449
479
  @index.add(Entry::Method.new(
450
480
  name,
451
- @file_path,
481
+ @uri,
452
482
  location,
453
483
  location,
454
484
  comments,
@@ -472,7 +502,7 @@ module RubyIndexer
472
502
 
473
503
  entry = Entry::Module.new(
474
504
  actual_nesting(name),
475
- @file_path,
505
+ @uri,
476
506
  location,
477
507
  name_loc,
478
508
  comments,
@@ -494,7 +524,7 @@ module RubyIndexer
494
524
  nesting = name_or_nesting.is_a?(Array) ? name_or_nesting : actual_nesting(name_or_nesting)
495
525
  entry = Entry::Class.new(
496
526
  nesting,
497
- @file_path,
527
+ @uri,
498
528
  Location.from_prism_location(full_location, @code_units_cache),
499
529
  Location.from_prism_location(name_location, @code_units_cache),
500
530
  comments,
@@ -546,9 +576,45 @@ module RubyIndexer
546
576
 
547
577
  @index.add(Entry::GlobalVariable.new(
548
578
  name,
549
- @file_path,
579
+ @uri,
580
+ Location.from_prism_location(loc, @code_units_cache),
581
+ comments,
582
+ ))
583
+ end
584
+
585
+ sig do
586
+ params(
587
+ node: T.any(
588
+ Prism::ClassVariableAndWriteNode,
589
+ Prism::ClassVariableOperatorWriteNode,
590
+ Prism::ClassVariableOrWriteNode,
591
+ Prism::ClassVariableTargetNode,
592
+ Prism::ClassVariableWriteNode,
593
+ ),
594
+ loc: Prism::Location,
595
+ ).void
596
+ end
597
+ def handle_class_variable(node, loc)
598
+ name = node.name.to_s
599
+ # Ignore incomplete class variable names, which aren't valid Ruby syntax.
600
+ # This could occur if the code is in an incomplete or temporary state.
601
+ return if name == "@@"
602
+
603
+ comments = collect_comments(node)
604
+
605
+ owner = @owner_stack.last
606
+
607
+ # set the class variable's owner to the attached context when defined within a singleton scope.
608
+ if owner.is_a?(Entry::SingletonClass)
609
+ owner = @owner_stack.reverse.find { |entry| !entry.name.include?("<Class:") }
610
+ end
611
+
612
+ @index.add(Entry::ClassVariable.new(
613
+ name,
614
+ @uri,
550
615
  Location.from_prism_location(loc, @code_units_cache),
551
616
  comments,
617
+ owner,
552
618
  ))
553
619
  end
554
620
 
@@ -578,7 +644,7 @@ module RubyIndexer
578
644
 
579
645
  @index.add(Entry::InstanceVariable.new(
580
646
  name,
581
- @file_path,
647
+ @uri,
582
648
  Location.from_prism_location(loc, @code_units_cache),
583
649
  collect_comments(node),
584
650
  owner,
@@ -642,7 +708,7 @@ module RubyIndexer
642
708
  new_name_value,
643
709
  old_name_value,
644
710
  @owner_stack.last,
645
- @file_path,
711
+ @uri,
646
712
  Location.from_prism_location(new_name.location, @code_units_cache),
647
713
  comments,
648
714
  ),
@@ -678,7 +744,7 @@ module RubyIndexer
678
744
  value.slice,
679
745
  @stack.dup,
680
746
  name,
681
- @file_path,
747
+ @uri,
682
748
  Location.from_prism_location(node.location, @code_units_cache),
683
749
  comments,
684
750
  )
@@ -691,7 +757,7 @@ module RubyIndexer
691
757
  value.name.to_s,
692
758
  @stack.dup,
693
759
  name,
694
- @file_path,
760
+ @uri,
695
761
  Location.from_prism_location(node.location, @code_units_cache),
696
762
  comments,
697
763
  )
@@ -702,14 +768,14 @@ module RubyIndexer
702
768
  value.target.slice,
703
769
  @stack.dup,
704
770
  name,
705
- @file_path,
771
+ @uri,
706
772
  Location.from_prism_location(node.location, @code_units_cache),
707
773
  comments,
708
774
  )
709
775
  else
710
776
  Entry::Constant.new(
711
777
  name,
712
- @file_path,
778
+ @uri,
713
779
  Location.from_prism_location(node.location, @code_units_cache),
714
780
  comments,
715
781
  )
@@ -781,7 +847,7 @@ module RubyIndexer
781
847
  if reader
782
848
  @index.add(Entry::Accessor.new(
783
849
  name,
784
- @file_path,
850
+ @uri,
785
851
  Location.from_prism_location(loc, @code_units_cache),
786
852
  comments,
787
853
  current_visibility,
@@ -793,7 +859,7 @@ module RubyIndexer
793
859
 
794
860
  @index.add(Entry::Accessor.new(
795
861
  "#{name}=",
796
- @file_path,
862
+ @uri,
797
863
  Location.from_prism_location(loc, @code_units_cache),
798
864
  comments,
799
865
  current_visibility,
@@ -866,7 +932,7 @@ module RubyIndexer
866
932
  location = Location.from_prism_location(argument.location, @code_units_cache)
867
933
  @index.add(Entry::Method.new(
868
934
  method_name,
869
- @file_path,
935
+ @uri,
870
936
  location,
871
937
  location,
872
938
  collect_comments(node)&.concat(entry.comments),
@@ -16,8 +16,8 @@ module RubyIndexer
16
16
  sig { returns(String) }
17
17
  attr_reader :name
18
18
 
19
- sig { returns(String) }
20
- attr_reader :file_path
19
+ sig { returns(URI::Generic) }
20
+ attr_reader :uri
21
21
 
22
22
  sig { returns(RubyIndexer::Location) }
23
23
  attr_reader :location
@@ -30,14 +30,14 @@ module RubyIndexer
30
30
  sig do
31
31
  params(
32
32
  name: String,
33
- file_path: String,
33
+ uri: URI::Generic,
34
34
  location: Location,
35
35
  comments: T.nilable(String),
36
36
  ).void
37
37
  end
38
- def initialize(name, file_path, location, comments)
38
+ def initialize(name, uri, location, comments)
39
39
  @name = name
40
- @file_path = file_path
40
+ @uri = uri
41
41
  @comments = comments
42
42
  @visibility = T.let(Visibility::PUBLIC, Visibility)
43
43
  @location = location
@@ -60,14 +60,24 @@ module RubyIndexer
60
60
 
61
61
  sig { returns(String) }
62
62
  def file_name
63
- File.basename(@file_path)
63
+ if @uri.scheme == "untitled"
64
+ T.must(@uri.opaque)
65
+ else
66
+ File.basename(T.must(file_path))
67
+ end
68
+ end
69
+
70
+ sig { returns(T.nilable(String)) }
71
+ def file_path
72
+ @uri.full_path
64
73
  end
65
74
 
66
75
  sig { returns(String) }
67
76
  def comments
68
77
  @comments ||= begin
69
78
  # Parse only the comments based on the file path, which is much faster than parsing the entire file
70
- parsed_comments = Prism.parse_file_comments(@file_path)
79
+ path = file_path
80
+ parsed_comments = path ? Prism.parse_file_comments(path) : []
71
81
 
72
82
  # Group comments based on whether they belong to a single block of comments
73
83
  grouped = parsed_comments.slice_when do |left, right|
@@ -137,18 +147,18 @@ module RubyIndexer
137
147
  sig do
138
148
  params(
139
149
  nesting: T::Array[String],
140
- file_path: String,
150
+ uri: URI::Generic,
141
151
  location: Location,
142
152
  name_location: Location,
143
153
  comments: T.nilable(String),
144
154
  ).void
145
155
  end
146
- def initialize(nesting, file_path, location, name_location, comments)
156
+ def initialize(nesting, uri, location, name_location, comments)
147
157
  @name = T.let(nesting.join("::"), String)
148
158
  # The original nesting where this namespace was discovered
149
159
  @nesting = nesting
150
160
 
151
- super(@name, file_path, location, comments)
161
+ super(@name, uri, location, comments)
152
162
 
153
163
  @name_location = name_location
154
164
  end
@@ -186,15 +196,15 @@ module RubyIndexer
186
196
  sig do
187
197
  params(
188
198
  nesting: T::Array[String],
189
- file_path: String,
199
+ uri: URI::Generic,
190
200
  location: Location,
191
201
  name_location: Location,
192
202
  comments: T.nilable(String),
193
203
  parent_class: T.nilable(String),
194
204
  ).void
195
205
  end
196
- def initialize(nesting, file_path, location, name_location, comments, parent_class) # rubocop:disable Metrics/ParameterLists
197
- super(nesting, file_path, location, name_location, comments)
206
+ def initialize(nesting, uri, location, name_location, comments, parent_class) # rubocop:disable Metrics/ParameterLists
207
+ super(nesting, uri, location, name_location, comments)
198
208
  @parent_class = parent_class
199
209
  end
200
210
 
@@ -332,15 +342,15 @@ module RubyIndexer
332
342
  sig do
333
343
  params(
334
344
  name: String,
335
- file_path: String,
345
+ uri: URI::Generic,
336
346
  location: Location,
337
347
  comments: T.nilable(String),
338
348
  visibility: Visibility,
339
349
  owner: T.nilable(Entry::Namespace),
340
350
  ).void
341
351
  end
342
- def initialize(name, file_path, location, comments, visibility, owner) # rubocop:disable Metrics/ParameterLists
343
- super(name, file_path, location, comments)
352
+ def initialize(name, uri, location, comments, visibility, owner) # rubocop:disable Metrics/ParameterLists
353
+ super(name, uri, location, comments)
344
354
  @visibility = visibility
345
355
  @owner = owner
346
356
  end
@@ -399,7 +409,7 @@ module RubyIndexer
399
409
  sig do
400
410
  params(
401
411
  name: String,
402
- file_path: String,
412
+ uri: URI::Generic,
403
413
  location: Location,
404
414
  name_location: Location,
405
415
  comments: T.nilable(String),
@@ -408,8 +418,8 @@ module RubyIndexer
408
418
  owner: T.nilable(Entry::Namespace),
409
419
  ).void
410
420
  end
411
- def initialize(name, file_path, location, name_location, comments, signatures, visibility, owner) # rubocop:disable Metrics/ParameterLists
412
- super(name, file_path, location, comments, visibility, owner)
421
+ def initialize(name, uri, location, name_location, comments, signatures, visibility, owner) # rubocop:disable Metrics/ParameterLists
422
+ super(name, uri, location, comments, visibility, owner)
413
423
  @signatures = signatures
414
424
  @name_location = name_location
415
425
  end
@@ -439,13 +449,13 @@ module RubyIndexer
439
449
  target: String,
440
450
  nesting: T::Array[String],
441
451
  name: String,
442
- file_path: String,
452
+ uri: URI::Generic,
443
453
  location: Location,
444
454
  comments: T.nilable(String),
445
455
  ).void
446
456
  end
447
- def initialize(target, nesting, name, file_path, location, comments) # rubocop:disable Metrics/ParameterLists
448
- super(name, file_path, location, comments)
457
+ def initialize(target, nesting, name, uri, location, comments) # rubocop:disable Metrics/ParameterLists
458
+ super(name, uri, location, comments)
449
459
 
450
460
  @target = target
451
461
  @nesting = nesting
@@ -463,7 +473,7 @@ module RubyIndexer
463
473
  def initialize(target, unresolved_alias)
464
474
  super(
465
475
  unresolved_alias.name,
466
- unresolved_alias.file_path,
476
+ unresolved_alias.uri,
467
477
  unresolved_alias.location,
468
478
  unresolved_alias.comments,
469
479
  )
@@ -476,6 +486,26 @@ module RubyIndexer
476
486
  # Represents a global variable e.g.: $DEBUG
477
487
  class GlobalVariable < Entry; end
478
488
 
489
+ # Represents a class variable e.g.: @@a = 1
490
+ class ClassVariable < Entry
491
+ sig { returns(T.nilable(Entry::Namespace)) }
492
+ attr_reader :owner
493
+
494
+ sig do
495
+ params(
496
+ name: String,
497
+ uri: URI::Generic,
498
+ location: Location,
499
+ comments: T.nilable(String),
500
+ owner: T.nilable(Entry::Namespace),
501
+ ).void
502
+ end
503
+ def initialize(name, uri, location, comments, owner)
504
+ super(name, uri, location, comments)
505
+ @owner = owner
506
+ end
507
+ end
508
+
479
509
  # Represents an instance variable e.g.: @a = 1
480
510
  class InstanceVariable < Entry
481
511
  sig { returns(T.nilable(Entry::Namespace)) }
@@ -484,14 +514,14 @@ module RubyIndexer
484
514
  sig do
485
515
  params(
486
516
  name: String,
487
- file_path: String,
517
+ uri: URI::Generic,
488
518
  location: Location,
489
519
  comments: T.nilable(String),
490
520
  owner: T.nilable(Entry::Namespace),
491
521
  ).void
492
522
  end
493
- def initialize(name, file_path, location, comments, owner)
494
- super(name, file_path, location, comments)
523
+ def initialize(name, uri, location, comments, owner)
524
+ super(name, uri, location, comments)
495
525
  @owner = owner
496
526
  end
497
527
  end
@@ -513,13 +543,13 @@ module RubyIndexer
513
543
  new_name: String,
514
544
  old_name: String,
515
545
  owner: T.nilable(Entry::Namespace),
516
- file_path: String,
546
+ uri: URI::Generic,
517
547
  location: Location,
518
548
  comments: T.nilable(String),
519
549
  ).void
520
550
  end
521
- def initialize(new_name, old_name, owner, file_path, location, comments) # rubocop:disable Metrics/ParameterLists
522
- super(new_name, file_path, location, comments)
551
+ def initialize(new_name, old_name, owner, uri, location, comments) # rubocop:disable Metrics/ParameterLists
552
+ super(new_name, uri, location, comments)
523
553
 
524
554
  @new_name = new_name
525
555
  @old_name = old_name
@@ -547,7 +577,7 @@ module RubyIndexer
547
577
 
548
578
  super(
549
579
  unresolved_alias.new_name,
550
- unresolved_alias.file_path,
580
+ unresolved_alias.uri,
551
581
  unresolved_alias.location,
552
582
  full_comments,
553
583
  )