ruby-lsp 0.22.1 → 0.23.1

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.
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: d4a7b6b44dae357ccbc6a9f6494bd892d890bebf1287aa6c989ef4f2aee14e82
4
+ data.tar.gz: cbfc554b33a2cf45663ab394e4fb81e27eb2ec4309907943e3fe67d591222d63
5
5
  SHA512:
6
- metadata.gz: 8fbcdfaac508788a17fb3b7e939ce290e33049a0080ff6260abfaeb609ee76a033234ccc2efa5724587e9c4cbf4552e2cd5d2cb0af1186971b8ed06fec290cb3
7
- data.tar.gz: 3e37acf250618e60df2addbce7f9acf86df4bf3e771b7b49c4cd8f4ad326ea82e3d41ad80c5ce71e3b0429dab98385df51f4645824cd419e32dac5ea13778760
6
+ metadata.gz: bee0f714bd2f2865eeefa2de4eeb2f31bbf55d1fb106cb2a19af208bfc8c868815e2fcad86dcd58a119c9494c6a8254b01fcacdbeb02ce4379a8242ad94d2fcb
7
+ data.tar.gz: 690d71bce5781f0de3ff170782d76e1d6ef34afd6801525c9ebbb92cfc64c2b9adc25b591710eaf4100c138706a8a358bfe6959d133a0da96e7cdd16279549c7
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.22.1
1
+ 0.23.1
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 = (!Gem.win_platform? && 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
  )