ruby-lsp 0.19.1 → 0.20.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +7 -1
  4. data/lib/core_ext/uri.rb +2 -2
  5. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +63 -12
  6. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +85 -36
  7. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +5 -1
  8. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +39 -98
  9. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +12 -19
  10. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +22 -0
  11. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +2 -7
  12. data/lib/ruby_indexer/test/enhancements_test.rb +5 -7
  13. data/lib/ruby_indexer/test/global_variable_test.rb +49 -0
  14. data/lib/ruby_indexer/test/index_test.rb +89 -0
  15. data/lib/ruby_lsp/erb_document.rb +15 -2
  16. data/lib/ruby_lsp/listeners/definition.rb +20 -0
  17. data/lib/ruby_lsp/listeners/folding_ranges.rb +3 -3
  18. data/lib/ruby_lsp/requests/code_action_resolve.rb +8 -2
  19. data/lib/ruby_lsp/requests/completion.rb +1 -1
  20. data/lib/ruby_lsp/requests/definition.rb +2 -1
  21. data/lib/ruby_lsp/requests/document_highlight.rb +5 -1
  22. data/lib/ruby_lsp/requests/hover.rb +1 -1
  23. data/lib/ruby_lsp/requests/range_formatting.rb +4 -2
  24. data/lib/ruby_lsp/requests/references.rb +3 -1
  25. data/lib/ruby_lsp/requests/rename.rb +3 -1
  26. data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
  27. data/lib/ruby_lsp/requests/signature_help.rb +1 -1
  28. data/lib/ruby_lsp/requests/support/common.rb +1 -1
  29. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +6 -6
  30. data/lib/ruby_lsp/response_builders/document_symbol.rb +2 -2
  31. data/lib/ruby_lsp/response_builders/hover.rb +2 -2
  32. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +14 -8
  33. data/lib/ruby_lsp/response_builders/signature_help.rb +2 -2
  34. data/lib/ruby_lsp/ruby_document.rb +33 -12
  35. data/lib/ruby_lsp/setup_bundler.rb +30 -8
  36. data/lib/ruby_lsp/type_inferrer.rb +1 -1
  37. metadata +6 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d900634d5328c8b4b5fcf799f807456bec3cdb94d6294c80fa9152bcf45aedde
4
- data.tar.gz: b7661867d38331ec158312b10c7f530cbd58994ee94e8ff592f478e7e05efcb7
3
+ metadata.gz: 58327a9f9a3d85375cbbf81e3e170a948d5c8dfbdcdcac0a1fdef5f685d20c95
4
+ data.tar.gz: 45572eb6645bce73d2079bed65f0d92c98921517926b968bba96788769a3aada
5
5
  SHA512:
6
- metadata.gz: 8f7955f676bc5f231f990f04d8aea1a767165d4f2cac1e9514928014cd8a09eb68c60b4cd226a94b554dac88d77c2117ae3a3ea76bb66e68980974f1685d8970
7
- data.tar.gz: 1b914d5607e5730139780cd1f172923db7878a7a0a4098daa1e17df8a1a7a2d8b6731b092baf7eeefc9f55605305e4d70d8cca8489f68a17bab532026c38e8b2
6
+ metadata.gz: c506eeff4d24060e3afdb4ad9da319c12b725050c8f25a9348ec7dea9082f8adced7671b7b1eb8f7f09412942139e47a2df5059b5672d2b6a75f0ffc5a59885d
7
+ data.tar.gz: d9a89ce24946e5f9cc47b5a48086f6fd977176d31332a0b634950dc00a41fc9a36e4753eae2896e2da0129e92bff4278265eaa970252a5292c783e5bc82258e9
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.19.1
1
+ 0.20.1
data/exe/ruby-lsp CHANGED
@@ -63,7 +63,13 @@ if ENV["BUNDLE_GEMFILE"].nil?
63
63
  exit(78)
64
64
  end
65
65
 
66
- exit exec(env, "bundle exec ruby-lsp #{original_args.join(" ")}")
66
+ base_bundle = if env["BUNDLER_VERSION"]
67
+ "bundle _#{env["BUNDLER_VERSION"]}_"
68
+ else
69
+ "bundle"
70
+ end
71
+
72
+ exit exec(env, "#{base_bundle} exec ruby-lsp #{original_args.join(" ")}")
67
73
  end
68
74
 
69
75
  require "ruby_lsp/load_sorbet"
data/lib/core_ext/uri.rb CHANGED
@@ -3,6 +3,8 @@
3
3
 
4
4
  module URI
5
5
  class Generic
6
+ extend T::Sig
7
+
6
8
  # Avoid a deprecation warning with Ruby 3.4 where the default parser was changed to RFC3986.
7
9
  # This condition must remain even after support for 3.4 has been dropped for users that have
8
10
  # `uri` in their lockfile, decoupling it from the ruby version.
@@ -27,8 +29,6 @@ module URI
27
29
  end
28
30
  end
29
31
 
30
- extend T::Sig
31
-
32
32
  sig { returns(T.nilable(String)) }
33
33
  def to_standardized_path
34
34
  parsed_path = path
@@ -28,7 +28,17 @@ module RubyIndexer
28
28
  @encoding = T.let(Encoding::UTF_8, Encoding)
29
29
  @excluded_gems = T.let(initial_excluded_gems, T::Array[String])
30
30
  @included_gems = T.let([], T::Array[String])
31
- @excluded_patterns = T.let([File.join("**", "*_test.rb"), File.join("tmp", "**", "*")], T::Array[String])
31
+
32
+ @excluded_patterns = T.let(
33
+ [
34
+ File.join("**", "*_test.rb"),
35
+ File.join("node_modules", "**", "*"),
36
+ File.join("spec", "**", "*"),
37
+ File.join("test", "**", "*"),
38
+ File.join("tmp", "**", "*"),
39
+ ],
40
+ T::Array[String],
41
+ )
32
42
 
33
43
  path = Bundler.settings["path"]
34
44
  if path
@@ -56,6 +66,21 @@ module RubyIndexer
56
66
  )
57
67
  end
58
68
 
69
+ sig { returns(String) }
70
+ def merged_excluded_file_pattern
71
+ # This regex looks for @excluded_patterns that follow the format of "something/**/*", where
72
+ # "something" is one or more non-"/"
73
+ #
74
+ # Returns "/path/to/workspace/{tmp,node_modules}/**/*"
75
+ @excluded_patterns
76
+ .filter_map do |pattern|
77
+ next if File.absolute_path?(pattern)
78
+
79
+ pattern.match(%r{\A([^/]+)/\*\*/\*\z})&.captures&.first
80
+ end
81
+ .then { |dirs| File.join(@workspace_path, "{#{dirs.join(",")}}/**/*") }
82
+ end
83
+
59
84
  sig { returns(T::Array[IndexablePath]) }
60
85
  def indexables
61
86
  excluded_gems = @excluded_gems - @included_gems
@@ -64,21 +89,47 @@ module RubyIndexer
64
89
  # NOTE: indexing the patterns (both included and excluded) needs to happen before indexing gems, otherwise we risk
65
90
  # having duplicates if BUNDLE_PATH is set to a folder inside the project structure
66
91
 
92
+ flags = File::FNM_PATHNAME | File::FNM_EXTGLOB
93
+
94
+ # In order to speed up indexing, only traverse into top-level directories that are not entirely excluded.
95
+ # For example, if "tmp/**/*" is excluded, we don't need to traverse into "tmp" at all. However, if
96
+ # "vendor/bundle/**/*" is excluded, we will traverse all of "vendor" and `reject!` out all "vendor/bundle" entries
97
+ # later.
98
+ excluded_pattern = merged_excluded_file_pattern
99
+ included_paths = Dir.glob(File.join(@workspace_path, "*/"), flags)
100
+ .filter_map do |included_path|
101
+ next if File.fnmatch?(excluded_pattern, included_path, flags)
102
+
103
+ relative_path = included_path
104
+ .delete_prefix(@workspace_path)
105
+ .tap { |path| path.delete_prefix!("/") }
106
+
107
+ [included_path, relative_path]
108
+ end
109
+
110
+ indexables = T.let([], T::Array[IndexablePath])
111
+
67
112
  # Add user specified patterns
68
- indexables = @included_patterns.flat_map do |pattern|
113
+ @included_patterns.each do |pattern|
69
114
  load_path_entry = T.let(nil, T.nilable(String))
70
115
 
71
- Dir.glob(File.join(@workspace_path, pattern), File::FNM_PATHNAME | File::FNM_EXTGLOB).map! do |path|
72
- path = File.expand_path(path)
73
- # All entries for the same pattern match the same $LOAD_PATH entry. Since searching the $LOAD_PATH for every
74
- # entry is expensive, we memoize it until we find a path that doesn't belong to that $LOAD_PATH. This happens
75
- # on repositories that define multiple gems, like Rails. All frameworks are defined inside the current
76
- # workspace directory, but each one of them belongs to a different $LOAD_PATH entry
77
- if load_path_entry.nil? || !path.start_with?(load_path_entry)
78
- load_path_entry = $LOAD_PATH.find { |load_path| path.start_with?(load_path) }
79
- end
116
+ included_paths.each do |included_path, relative_path|
117
+ relative_pattern = pattern.delete_prefix(File.join(relative_path, "/"))
118
+
119
+ next unless pattern.start_with?("**") || pattern.start_with?(relative_path)
80
120
 
81
- IndexablePath.new(load_path_entry, path)
121
+ Dir.glob(File.join(included_path, relative_pattern), flags).each do |path|
122
+ path = File.expand_path(path)
123
+ # All entries for the same pattern match the same $LOAD_PATH entry. Since searching the $LOAD_PATH for every
124
+ # entry is expensive, we memoize it until we find a path that doesn't belong to that $LOAD_PATH. This
125
+ # happens on repositories that define multiple gems, like Rails. All frameworks are defined inside the
126
+ # current workspace directory, but each one of them belongs to a different $LOAD_PATH entry
127
+ if load_path_entry.nil? || !path.start_with?(load_path_entry)
128
+ load_path_entry = $LOAD_PATH.find { |load_path| path.start_with?(load_path) }
129
+ end
130
+
131
+ indexables << IndexablePath.new(load_path_entry, path)
132
+ end
82
133
  end
83
134
  end
84
135
 
@@ -33,6 +33,10 @@ module RubyIndexer
33
33
  T::Hash[Integer, Prism::Comment],
34
34
  )
35
35
  @inside_def = T.let(false, T::Boolean)
36
+ @code_units_cache = T.let(
37
+ parse_result.code_units_cache(@index.configuration.encoding),
38
+ T.any(T.proc.params(arg0: Integer).returns(Integer), Prism::CodeUnitsCache),
39
+ )
36
40
 
37
41
  # The nesting stack we're currently inside. Used to determine the fully qualified name of constants, but only
38
42
  # stored by unresolved aliases which need the original nesting to be lazily resolved
@@ -65,6 +69,11 @@ module RubyIndexer
65
69
  :on_constant_or_write_node_enter,
66
70
  :on_constant_and_write_node_enter,
67
71
  :on_constant_operator_write_node_enter,
72
+ :on_global_variable_and_write_node_enter,
73
+ :on_global_variable_operator_write_node_enter,
74
+ :on_global_variable_or_write_node_enter,
75
+ :on_global_variable_target_node_enter,
76
+ :on_global_variable_write_node_enter,
68
77
  :on_instance_variable_write_node_enter,
69
78
  :on_instance_variable_and_write_node_enter,
70
79
  :on_instance_variable_operator_write_node_enter,
@@ -106,10 +115,9 @@ module RubyIndexer
106
115
  entry = Entry::Class.new(
107
116
  nesting,
108
117
  @file_path,
109
- node.location,
110
- constant_path.location,
118
+ Location.from_prism_location(node.location, @code_units_cache),
119
+ Location.from_prism_location(constant_path.location, @code_units_cache),
111
120
  comments,
112
- @index.configuration.encoding,
113
121
  parent_class,
114
122
  )
115
123
 
@@ -136,10 +144,9 @@ module RubyIndexer
136
144
  entry = Entry::Module.new(
137
145
  actual_nesting(name),
138
146
  @file_path,
139
- node.location,
140
- constant_path.location,
147
+ Location.from_prism_location(node.location, @code_units_cache),
148
+ Location.from_prism_location(constant_path.location, @code_units_cache),
141
149
  comments,
142
- @index.configuration.encoding,
143
150
  )
144
151
 
145
152
  @owner_stack << entry
@@ -170,19 +177,17 @@ module RubyIndexer
170
177
  if existing_entries
171
178
  entry = T.must(existing_entries.first)
172
179
  entry.update_singleton_information(
173
- node.location,
174
- expression.location,
180
+ Location.from_prism_location(node.location, @code_units_cache),
181
+ Location.from_prism_location(expression.location, @code_units_cache),
175
182
  collect_comments(node),
176
- @index.configuration.encoding,
177
183
  )
178
184
  else
179
185
  entry = Entry::SingletonClass.new(
180
186
  real_nesting,
181
187
  @file_path,
182
- node.location,
183
- expression.location,
188
+ Location.from_prism_location(node.location, @code_units_cache),
189
+ Location.from_prism_location(expression.location, @code_units_cache),
184
190
  collect_comments(node),
185
- @index.configuration.encoding,
186
191
  nil,
187
192
  )
188
193
  @index.add(entry, skip_prefix_tree: true)
@@ -310,7 +315,7 @@ module RubyIndexer
310
315
  end
311
316
 
312
317
  @enhancements.each do |enhancement|
313
- enhancement.on_call_node(@index, @owner_stack.last, node, @file_path)
318
+ enhancement.on_call_node(@index, @owner_stack.last, node, @file_path, @code_units_cache)
314
319
  rescue StandardError => e
315
320
  @indexing_errors << "Indexing error in #{@file_path} with '#{enhancement.class.name}' enhancement: #{e.message}"
316
321
  end
@@ -340,10 +345,9 @@ module RubyIndexer
340
345
  @index.add(Entry::Method.new(
341
346
  method_name,
342
347
  @file_path,
343
- node.location,
344
- node.name_loc,
348
+ Location.from_prism_location(node.location, @code_units_cache),
349
+ Location.from_prism_location(node.name_loc, @code_units_cache),
345
350
  comments,
346
- @index.configuration.encoding,
347
351
  [Entry::Signature.new(list_params(node.parameters))],
348
352
  current_visibility,
349
353
  @owner_stack.last,
@@ -357,10 +361,9 @@ module RubyIndexer
357
361
  @index.add(Entry::Method.new(
358
362
  method_name,
359
363
  @file_path,
360
- node.location,
361
- node.name_loc,
364
+ Location.from_prism_location(node.location, @code_units_cache),
365
+ Location.from_prism_location(node.name_loc, @code_units_cache),
362
366
  comments,
363
- @index.configuration.encoding,
364
367
  [Entry::Signature.new(list_params(node.parameters))],
365
368
  current_visibility,
366
369
  singleton,
@@ -382,6 +385,31 @@ module RubyIndexer
382
385
  end
383
386
  end
384
387
 
388
+ sig { params(node: Prism::GlobalVariableAndWriteNode).void }
389
+ def on_global_variable_and_write_node_enter(node)
390
+ handle_global_variable(node, node.name_loc)
391
+ end
392
+
393
+ sig { params(node: Prism::GlobalVariableOperatorWriteNode).void }
394
+ def on_global_variable_operator_write_node_enter(node)
395
+ handle_global_variable(node, node.name_loc)
396
+ end
397
+
398
+ sig { params(node: Prism::GlobalVariableOrWriteNode).void }
399
+ def on_global_variable_or_write_node_enter(node)
400
+ handle_global_variable(node, node.name_loc)
401
+ end
402
+
403
+ sig { params(node: Prism::GlobalVariableTargetNode).void }
404
+ def on_global_variable_target_node_enter(node)
405
+ handle_global_variable(node, node.location)
406
+ end
407
+
408
+ sig { params(node: Prism::GlobalVariableWriteNode).void }
409
+ def on_global_variable_write_node_enter(node)
410
+ handle_global_variable(node, node.name_loc)
411
+ end
412
+
385
413
  sig { params(node: Prism::InstanceVariableWriteNode).void }
386
414
  def on_instance_variable_write_node_enter(node)
387
415
  handle_instance_variable(node, node.name_loc)
@@ -417,15 +445,38 @@ module RubyIndexer
417
445
  node.old_name.slice,
418
446
  @owner_stack.last,
419
447
  @file_path,
420
- node.new_name.location,
448
+ Location.from_prism_location(node.new_name.location, @code_units_cache),
421
449
  comments,
422
- @index.configuration.encoding,
423
450
  ),
424
451
  )
425
452
  end
426
453
 
427
454
  private
428
455
 
456
+ sig do
457
+ params(
458
+ node: T.any(
459
+ Prism::GlobalVariableAndWriteNode,
460
+ Prism::GlobalVariableOperatorWriteNode,
461
+ Prism::GlobalVariableOrWriteNode,
462
+ Prism::GlobalVariableTargetNode,
463
+ Prism::GlobalVariableWriteNode,
464
+ ),
465
+ loc: Prism::Location,
466
+ ).void
467
+ end
468
+ def handle_global_variable(node, loc)
469
+ name = node.name.to_s
470
+ comments = collect_comments(node)
471
+
472
+ @index.add(Entry::GlobalVariable.new(
473
+ name,
474
+ @file_path,
475
+ Location.from_prism_location(loc, @code_units_cache),
476
+ comments,
477
+ ))
478
+ end
479
+
429
480
  sig do
430
481
  params(
431
482
  node: T.any(
@@ -453,9 +504,8 @@ module RubyIndexer
453
504
  @index.add(Entry::InstanceVariable.new(
454
505
  name,
455
506
  @file_path,
456
- loc,
507
+ Location.from_prism_location(loc, @code_units_cache),
457
508
  collect_comments(node),
458
- @index.configuration.encoding,
459
509
  owner,
460
510
  ))
461
511
  end
@@ -518,9 +568,8 @@ module RubyIndexer
518
568
  old_name_value,
519
569
  @owner_stack.last,
520
570
  @file_path,
521
- new_name.location,
571
+ Location.from_prism_location(new_name.location, @code_units_cache),
522
572
  comments,
523
- @index.configuration.encoding,
524
573
  ),
525
574
  )
526
575
  end
@@ -555,9 +604,8 @@ module RubyIndexer
555
604
  @stack.dup,
556
605
  name,
557
606
  @file_path,
558
- node.location,
607
+ Location.from_prism_location(node.location, @code_units_cache),
559
608
  comments,
560
- @index.configuration.encoding,
561
609
  )
562
610
  when Prism::ConstantWriteNode, Prism::ConstantAndWriteNode, Prism::ConstantOrWriteNode,
563
611
  Prism::ConstantOperatorWriteNode
@@ -569,9 +617,8 @@ module RubyIndexer
569
617
  @stack.dup,
570
618
  name,
571
619
  @file_path,
572
- node.location,
620
+ Location.from_prism_location(node.location, @code_units_cache),
573
621
  comments,
574
- @index.configuration.encoding,
575
622
  )
576
623
  when Prism::ConstantPathWriteNode, Prism::ConstantPathOrWriteNode, Prism::ConstantPathOperatorWriteNode,
577
624
  Prism::ConstantPathAndWriteNode
@@ -581,12 +628,16 @@ module RubyIndexer
581
628
  @stack.dup,
582
629
  name,
583
630
  @file_path,
584
- node.location,
631
+ Location.from_prism_location(node.location, @code_units_cache),
585
632
  comments,
586
- @index.configuration.encoding,
587
633
  )
588
634
  else
589
- Entry::Constant.new(name, @file_path, node.location, comments, @index.configuration.encoding)
635
+ Entry::Constant.new(
636
+ name,
637
+ @file_path,
638
+ Location.from_prism_location(node.location, @code_units_cache),
639
+ comments,
640
+ )
590
641
  end,
591
642
  )
592
643
  end
@@ -652,9 +703,8 @@ module RubyIndexer
652
703
  @index.add(Entry::Accessor.new(
653
704
  name,
654
705
  @file_path,
655
- loc,
706
+ Location.from_prism_location(loc, @code_units_cache),
656
707
  comments,
657
- @index.configuration.encoding,
658
708
  current_visibility,
659
709
  @owner_stack.last,
660
710
  ))
@@ -665,9 +715,8 @@ module RubyIndexer
665
715
  @index.add(Entry::Accessor.new(
666
716
  "#{name}=",
667
717
  @file_path,
668
- loc,
718
+ Location.from_prism_location(loc, @code_units_cache),
669
719
  comments,
670
- @index.configuration.encoding,
671
720
  current_visibility,
672
721
  @owner_stack.last,
673
722
  ))
@@ -19,8 +19,12 @@ module RubyIndexer
19
19
  owner: T.nilable(Entry::Namespace),
20
20
  node: Prism::CallNode,
21
21
  file_path: String,
22
+ code_units_cache: T.any(
23
+ T.proc.params(arg0: Integer).returns(Integer),
24
+ Prism::CodeUnitsCache,
25
+ ),
22
26
  ).void
23
27
  end
24
- def on_call_node(index, owner, node, file_path); end
28
+ def on_call_node(index, owner, node, file_path, code_units_cache); end
25
29
  end
26
30
  end