ruby-lsp 0.19.1 → 0.20.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/core_ext/uri.rb +2 -2
  4. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +85 -36
  5. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +5 -1
  6. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +39 -98
  7. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +2 -3
  8. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +22 -0
  9. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +2 -7
  10. data/lib/ruby_indexer/test/enhancements_test.rb +5 -7
  11. data/lib/ruby_indexer/test/global_variable_test.rb +49 -0
  12. data/lib/ruby_lsp/erb_document.rb +15 -2
  13. data/lib/ruby_lsp/listeners/definition.rb +20 -0
  14. data/lib/ruby_lsp/listeners/folding_ranges.rb +3 -3
  15. data/lib/ruby_lsp/requests/code_action_resolve.rb +8 -2
  16. data/lib/ruby_lsp/requests/completion.rb +1 -1
  17. data/lib/ruby_lsp/requests/definition.rb +2 -1
  18. data/lib/ruby_lsp/requests/document_highlight.rb +5 -1
  19. data/lib/ruby_lsp/requests/hover.rb +1 -1
  20. data/lib/ruby_lsp/requests/range_formatting.rb +4 -2
  21. data/lib/ruby_lsp/requests/references.rb +1 -1
  22. data/lib/ruby_lsp/requests/rename.rb +1 -1
  23. data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
  24. data/lib/ruby_lsp/requests/signature_help.rb +1 -1
  25. data/lib/ruby_lsp/requests/support/common.rb +1 -1
  26. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +6 -6
  27. data/lib/ruby_lsp/response_builders/document_symbol.rb +2 -2
  28. data/lib/ruby_lsp/response_builders/hover.rb +2 -2
  29. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +14 -8
  30. data/lib/ruby_lsp/response_builders/signature_help.rb +2 -2
  31. data/lib/ruby_lsp/ruby_document.rb +33 -12
  32. data/lib/ruby_lsp/type_inferrer.rb +1 -1
  33. metadata +6 -5
@@ -9,14 +9,14 @@ module RubyIndexer
9
9
  enhancement_class = Class.new do
10
10
  include Enhancement
11
11
 
12
- def on_call_node(index, owner, node, file_path)
12
+ def on_call_node(index, owner, node, file_path, code_units_cache)
13
13
  return unless owner
14
14
  return unless node.name == :extend
15
15
 
16
16
  arguments = node.arguments&.arguments
17
17
  return unless arguments
18
18
 
19
- location = node.location
19
+ location = Location.from_prism_location(node.location, code_units_cache)
20
20
 
21
21
  arguments.each do |node|
22
22
  next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode)
@@ -39,7 +39,6 @@ module RubyIndexer
39
39
  location,
40
40
  location,
41
41
  nil,
42
- index.configuration.encoding,
43
42
  [Entry::Signature.new([Entry::RequiredParameter.new(name: :a)])],
44
43
  Entry::Visibility::PUBLIC,
45
44
  owner,
@@ -102,7 +101,7 @@ module RubyIndexer
102
101
  enhancement_class = Class.new do
103
102
  include Enhancement
104
103
 
105
- def on_call_node(index, owner, node, file_path)
104
+ def on_call_node(index, owner, node, file_path, code_units_cache)
106
105
  return unless owner
107
106
 
108
107
  name = node.name
@@ -114,7 +113,7 @@ module RubyIndexer
114
113
  association_name = arguments.first
115
114
  return unless association_name.is_a?(Prism::SymbolNode)
116
115
 
117
- location = association_name.location
116
+ location = Location.from_prism_location(association_name.location, code_units_cache)
118
117
 
119
118
  index.add(Entry::Method.new(
120
119
  T.must(association_name.value),
@@ -122,7 +121,6 @@ module RubyIndexer
122
121
  location,
123
122
  location,
124
123
  nil,
125
- index.configuration.encoding,
126
124
  [],
127
125
  Entry::Visibility::PUBLIC,
128
126
  owner,
@@ -166,7 +164,7 @@ module RubyIndexer
166
164
  enhancement_class = Class.new do
167
165
  include Enhancement
168
166
 
169
- def on_call_node(index, owner, node, file_path)
167
+ def on_call_node(index, owner, node, file_path, code_units_cache)
170
168
  raise "Error"
171
169
  end
172
170
 
@@ -0,0 +1,49 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "test_case"
5
+
6
+ module RubyIndexer
7
+ class GlobalVariableTest < TestCase
8
+ def test_global_variable_and_write
9
+ index(<<~RUBY)
10
+ $foo &&= 1
11
+ RUBY
12
+
13
+ assert_entry("$foo", Entry::GlobalVariable, "/fake/path/foo.rb:0-0:0-4")
14
+ end
15
+
16
+ def test_global_variable_operator_write
17
+ index(<<~RUBY)
18
+ $foo += 1
19
+ RUBY
20
+
21
+ assert_entry("$foo", Entry::GlobalVariable, "/fake/path/foo.rb:0-0:0-4")
22
+ end
23
+
24
+ def test_global_variable_or_write
25
+ index(<<~RUBY)
26
+ $foo ||= 1
27
+ RUBY
28
+
29
+ assert_entry("$foo", Entry::GlobalVariable, "/fake/path/foo.rb:0-0:0-4")
30
+ end
31
+
32
+ def test_global_variable_target_node
33
+ index(<<~RUBY)
34
+ $foo, $bar = 1
35
+ RUBY
36
+
37
+ assert_entry("$foo", Entry::GlobalVariable, "/fake/path/foo.rb:0-0:0-4")
38
+ assert_entry("$bar", Entry::GlobalVariable, "/fake/path/foo.rb:0-6:0-10")
39
+ end
40
+
41
+ def test_global_variable_write
42
+ index(<<~RUBY)
43
+ $foo = 1
44
+ RUBY
45
+
46
+ assert_entry("$foo", Entry::GlobalVariable, "/fake/path/foo.rb:0-0:0-4")
47
+ end
48
+ end
49
+ end
@@ -6,10 +6,18 @@ module RubyLsp
6
6
  extend T::Sig
7
7
  extend T::Generic
8
8
 
9
+ ParseResultType = type_member { { fixed: Prism::ParseResult } }
10
+
9
11
  sig { returns(String) }
10
12
  attr_reader :host_language_source
11
13
 
12
- ParseResultType = type_member { { fixed: Prism::ParseResult } }
14
+ sig do
15
+ returns(T.any(
16
+ T.proc.params(arg0: Integer).returns(Integer),
17
+ Prism::CodeUnitsCache,
18
+ ))
19
+ end
20
+ attr_reader :code_units_cache
13
21
 
14
22
  sig { params(source: String, version: Integer, uri: URI::Generic, encoding: Encoding).void }
15
23
  def initialize(source:, version:, uri:, encoding: Encoding::UTF_8)
@@ -17,6 +25,10 @@ module RubyLsp
17
25
  # overrides this with the proper virtual host language source
18
26
  @host_language_source = T.let("", String)
19
27
  super
28
+ @code_units_cache = T.let(@parse_result.code_units_cache(@encoding), T.any(
29
+ T.proc.params(arg0: Integer).returns(Integer),
30
+ Prism::CodeUnitsCache,
31
+ ))
20
32
  end
21
33
 
22
34
  sig { override.returns(T::Boolean) }
@@ -30,6 +42,7 @@ module RubyLsp
30
42
  # Use partial script to avoid syntax errors in ERB files where keywords may be used without the full context in
31
43
  # which they will be evaluated
32
44
  @parse_result = Prism.parse(scanner.ruby, partial_script: true)
45
+ @code_units_cache = @parse_result.code_units_cache(@encoding)
33
46
  true
34
47
  end
35
48
 
@@ -53,8 +66,8 @@ module RubyLsp
53
66
  RubyDocument.locate(
54
67
  @parse_result.value,
55
68
  create_scanner.find_char_position(position),
69
+ code_units_cache: @code_units_cache,
56
70
  node_types: node_types,
57
- encoding: @encoding,
58
71
  )
59
72
  end
60
73
 
@@ -39,6 +39,7 @@ module RubyLsp
39
39
  :on_block_argument_node_enter,
40
40
  :on_constant_read_node_enter,
41
41
  :on_constant_path_node_enter,
42
+ :on_global_variable_read_node_enter,
42
43
  :on_instance_variable_read_node_enter,
43
44
  :on_instance_variable_write_node_enter,
44
45
  :on_instance_variable_and_write_node_enter,
@@ -120,6 +121,25 @@ module RubyLsp
120
121
  find_in_index(name)
121
122
  end
122
123
 
124
+ sig { params(node: Prism::GlobalVariableReadNode).void }
125
+ def on_global_variable_read_node_enter(node)
126
+ entries = @index[node.name.to_s]
127
+
128
+ return unless entries
129
+
130
+ entries.each do |entry|
131
+ location = entry.location
132
+
133
+ @response_builder << Interface::Location.new(
134
+ uri: URI::Generic.from_path(path: entry.file_path).to_s,
135
+ range: Interface::Range.new(
136
+ start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
137
+ end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
138
+ ),
139
+ )
140
+ end
141
+ end
142
+
123
143
  sig { params(node: Prism::InstanceVariableReadNode).void }
124
144
  def on_instance_variable_read_node_enter(node)
125
145
  handle_instance_variable_definition(node.name.to_s)
@@ -239,10 +239,10 @@ module RubyLsp
239
239
  statements = node.statements
240
240
  return unless statements
241
241
 
242
- body = statements.body
243
- return if body.empty?
242
+ statement = statements.body.last
243
+ return unless statement
244
244
 
245
- add_lines_range(node.location.start_line, body.last.location.end_line)
245
+ add_lines_range(node.location.start_line, statement.location.end_line)
246
246
  end
247
247
 
248
248
  sig { params(node: Prism::Node).void }
@@ -99,7 +99,13 @@ module RubyLsp
99
99
 
100
100
  # Find the closest statements node, so that we place the refactor in a valid position
101
101
  node_context = RubyDocument
102
- .locate(@document.parse_result.value, start_index, node_types: [Prism::StatementsNode, Prism::BlockNode])
102
+ .locate(@document.parse_result.value,
103
+ start_index,
104
+ node_types: [
105
+ Prism::StatementsNode,
106
+ Prism::BlockNode,
107
+ ],
108
+ code_units_cache: @document.code_units_cache)
103
109
 
104
110
  closest_statements = node_context.node
105
111
  parent_statements = node_context.parent
@@ -196,7 +202,7 @@ module RubyLsp
196
202
  @document.parse_result.value,
197
203
  start_index,
198
204
  node_types: [Prism::DefNode],
199
- encoding: @global_state.encoding,
205
+ code_units_cache: @document.code_units_cache,
200
206
  )
201
207
  closest_node = node_context.node
202
208
  return Error::InvalidTargetRange unless closest_node
@@ -57,7 +57,7 @@ module RubyLsp
57
57
  Prism::InstanceVariableTargetNode,
58
58
  Prism::InstanceVariableWriteNode,
59
59
  ],
60
- encoding: global_state.encoding,
60
+ code_units_cache: document.code_units_cache,
61
61
  )
62
62
  @response_builder = T.let(
63
63
  ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem].new,
@@ -46,6 +46,7 @@ module RubyLsp
46
46
  Prism::ConstantReadNode,
47
47
  Prism::ConstantPathNode,
48
48
  Prism::BlockArgumentNode,
49
+ Prism::GlobalVariableReadNode,
49
50
  Prism::InstanceVariableReadNode,
50
51
  Prism::InstanceVariableAndWriteNode,
51
52
  Prism::InstanceVariableOperatorWriteNode,
@@ -57,7 +58,7 @@ module RubyLsp
57
58
  Prism::SuperNode,
58
59
  Prism::ForwardingSuperNode,
59
60
  ],
60
- encoding: global_state.encoding,
61
+ code_units_cache: document.code_units_cache,
61
62
  )
62
63
 
63
64
  target = node_context.node
@@ -28,7 +28,11 @@ module RubyLsp
28
28
  char_position = document.create_scanner.find_char_position(position)
29
29
  delegate_request_if_needed!(global_state, document, char_position)
30
30
 
31
- node_context = RubyDocument.locate(document.parse_result.value, char_position, encoding: global_state.encoding)
31
+ node_context = RubyDocument.locate(
32
+ document.parse_result.value,
33
+ char_position,
34
+ code_units_cache: document.code_units_cache,
35
+ )
32
36
 
33
37
  @response_builder = T.let(
34
38
  ResponseBuilders::CollectionResponseBuilder[Interface::DocumentHighlight].new,
@@ -41,7 +41,7 @@ module RubyLsp
41
41
  document.parse_result.value,
42
42
  char_position,
43
43
  node_types: Listeners::Hover::ALLOWED_TARGETS,
44
- encoding: global_state.encoding,
44
+ code_units_cache: document.code_units_cache,
45
45
  )
46
46
  target = node_context.node
47
47
  parent = node_context.parent
@@ -34,16 +34,18 @@ module RubyLsp
34
34
  )
35
35
  return unless formatted_text
36
36
 
37
+ code_units_cache = @document.code_units_cache
38
+
37
39
  [
38
40
  Interface::TextEdit.new(
39
41
  range: Interface::Range.new(
40
42
  start: Interface::Position.new(
41
43
  line: location.start_line - 1,
42
- character: location.start_code_units_column(@document.encoding),
44
+ character: location.cached_start_code_units_column(code_units_cache),
43
45
  ),
44
46
  end: Interface::Position.new(
45
47
  line: location.end_line - 1,
46
- character: location.end_code_units_column(@document.encoding),
48
+ character: location.cached_end_code_units_column(code_units_cache),
47
49
  ),
48
50
  ),
49
51
  new_text: formatted_text.strip,
@@ -42,7 +42,7 @@ module RubyLsp
42
42
  Prism::CallNode,
43
43
  Prism::DefNode,
44
44
  ],
45
- encoding: @global_state.encoding,
45
+ code_units_cache: @document.code_units_cache,
46
46
  )
47
47
  target = node_context.node
48
48
  parent = node_context.parent
@@ -37,7 +37,7 @@ module RubyLsp
37
37
  @document.parse_result.value,
38
38
  char_position,
39
39
  node_types: [Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode],
40
- encoding: @global_state.encoding,
40
+ code_units_cache: @document.code_units_cache,
41
41
  )
42
42
  target = node_context.node
43
43
  parent = node_context.parent
@@ -101,7 +101,7 @@ module RubyLsp
101
101
  @range = range
102
102
  @result_id = T.let(SemanticHighlighting.next_result_id.to_s, String)
103
103
  @response_builder = T.let(
104
- ResponseBuilders::SemanticHighlighting.new(global_state.encoding),
104
+ ResponseBuilders::SemanticHighlighting.new(document.code_units_cache),
105
105
  ResponseBuilders::SemanticHighlighting,
106
106
  )
107
107
  Listeners::SemanticHighlighting.new(dispatcher, @response_builder)
@@ -43,7 +43,7 @@ module RubyLsp
43
43
  document.parse_result.value,
44
44
  char_position,
45
45
  node_types: [Prism::CallNode],
46
- encoding: global_state.encoding,
46
+ code_units_cache: document.code_units_cache,
47
47
  )
48
48
 
49
49
  target = adjust_for_nested_target(node_context.node, node_context.parent, position)
@@ -159,7 +159,7 @@ module RubyLsp
159
159
  def namespace_constant_name(node)
160
160
  path = node.constant_path
161
161
  case path
162
- when Prism::ConstantPathNode, Prism::ConstantReadNode, Prism::ConstantPathTargetNode
162
+ when Prism::ConstantPathNode, Prism::ConstantReadNode
163
163
  constant_name(path)
164
164
  end
165
165
  end
@@ -47,12 +47,6 @@ module RubyLsp
47
47
 
48
48
  class ConfigurationError < StandardError; end
49
49
 
50
- sig { returns(T::Array[RuboCop::Cop::Offense]) }
51
- attr_reader :offenses
52
-
53
- sig { returns(::RuboCop::Config) }
54
- attr_reader :config_for_working_directory
55
-
56
50
  DEFAULT_ARGS = T.let(
57
51
  [
58
52
  "--stderr", # Print any output to stderr so that our stdout does not get polluted
@@ -63,6 +57,12 @@ module RubyLsp
63
57
  T::Array[String],
64
58
  )
65
59
 
60
+ sig { returns(T::Array[RuboCop::Cop::Offense]) }
61
+ attr_reader :offenses
62
+
63
+ sig { returns(::RuboCop::Config) }
64
+ attr_reader :config_for_working_directory
65
+
66
66
  begin
67
67
  RuboCop::Options.new.parse(["--raise-cop-error"])
68
68
  DEFAULT_ARGS << "--raise-cop-error"
@@ -4,6 +4,8 @@
4
4
  module RubyLsp
5
5
  module ResponseBuilders
6
6
  class DocumentSymbol < ResponseBuilder
7
+ extend T::Sig
8
+
7
9
  ResponseType = type_member { { fixed: T::Array[Interface::DocumentSymbol] } }
8
10
 
9
11
  class SymbolHierarchyRoot
@@ -18,8 +20,6 @@ module RubyLsp
18
20
  end
19
21
  end
20
22
 
21
- extend T::Sig
22
-
23
23
  sig { void }
24
24
  def initialize
25
25
  super
@@ -4,11 +4,11 @@
4
4
  module RubyLsp
5
5
  module ResponseBuilders
6
6
  class Hover < ResponseBuilder
7
- ResponseType = type_member { { fixed: String } }
8
-
9
7
  extend T::Sig
10
8
  extend T::Generic
11
9
 
10
+ ResponseType = type_member { { fixed: String } }
11
+
12
12
  sig { void }
13
13
  def initialize
14
14
  super
@@ -6,6 +6,8 @@ module RubyLsp
6
6
  class SemanticHighlighting < ResponseBuilder
7
7
  class UndefinedTokenType < StandardError; end
8
8
 
9
+ extend T::Sig
10
+
9
11
  TOKEN_TYPES = T.let(
10
12
  {
11
13
  namespace: 0,
@@ -51,25 +53,29 @@ module RubyLsp
51
53
  T::Hash[Symbol, Integer],
52
54
  )
53
55
 
54
- extend T::Sig
55
-
56
56
  ResponseType = type_member { { fixed: Interface::SemanticTokens } }
57
57
 
58
- sig { params(encoding: Encoding).void }
59
- def initialize(encoding)
58
+ sig do
59
+ params(code_units_cache: T.any(
60
+ T.proc.params(arg0: Integer).returns(Integer),
61
+ Prism::CodeUnitsCache,
62
+ )).void
63
+ end
64
+ def initialize(code_units_cache)
60
65
  super()
61
- @encoding = encoding
66
+ @code_units_cache = code_units_cache
62
67
  @stack = T.let([], T::Array[SemanticToken])
63
68
  end
64
69
 
65
70
  sig { params(location: Prism::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
66
71
  def add_token(location, type, modifiers = [])
67
- length = location.end_code_units_offset(@encoding) - location.start_code_units_offset(@encoding)
72
+ end_code_unit = location.cached_end_code_units_offset(@code_units_cache)
73
+ length = end_code_unit - location.cached_start_code_units_offset(@code_units_cache)
68
74
  modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
69
75
  @stack.push(
70
76
  SemanticToken.new(
71
77
  start_line: location.start_line,
72
- start_code_unit_column: location.start_code_units_column(@encoding),
78
+ start_code_unit_column: location.cached_start_code_units_column(@code_units_cache),
73
79
  length: length,
74
80
  type: T.must(TOKEN_TYPES[type]),
75
81
  modifier: modifiers_indices,
@@ -83,7 +89,7 @@ module RubyLsp
83
89
  return false unless token
84
90
 
85
91
  token.start_line == location.start_line &&
86
- token.start_code_unit_column == location.start_code_units_column(@encoding)
92
+ token.start_code_unit_column == location.cached_start_code_units_column(@code_units_cache)
87
93
  end
88
94
 
89
95
  sig { returns(T.nilable(SemanticToken)) }
@@ -4,10 +4,10 @@
4
4
  module RubyLsp
5
5
  module ResponseBuilders
6
6
  class SignatureHelp < ResponseBuilder
7
- ResponseType = type_member { { fixed: T.nilable(Interface::SignatureHelp) } }
8
-
9
7
  extend T::Sig
10
8
 
9
+ ResponseType = type_member { { fixed: T.nilable(Interface::SignatureHelp) } }
10
+
11
11
  sig { void }
12
12
  def initialize
13
13
  super
@@ -25,11 +25,14 @@ module RubyLsp
25
25
  params(
26
26
  node: Prism::Node,
27
27
  char_position: Integer,
28
+ code_units_cache: T.any(
29
+ T.proc.params(arg0: Integer).returns(Integer),
30
+ Prism::CodeUnitsCache,
31
+ ),
28
32
  node_types: T::Array[T.class_of(Prism::Node)],
29
- encoding: Encoding,
30
33
  ).returns(NodeContext)
31
34
  end
32
- def locate(node, char_position, node_types: [], encoding: Encoding::UTF_8)
35
+ def locate(node, char_position, code_units_cache:, node_types: [])
33
36
  queue = T.let(node.child_nodes.compact, T::Array[T.nilable(Prism::Node)])
34
37
  closest = node
35
38
  parent = T.let(nil, T.nilable(Prism::Node))
@@ -62,8 +65,8 @@ module RubyLsp
62
65
 
63
66
  # Skip if the current node doesn't cover the desired position
64
67
  loc = candidate.location
65
- loc_start_offset = loc.start_code_units_offset(encoding)
66
- loc_end_offset = loc.end_code_units_offset(encoding)
68
+ loc_start_offset = loc.cached_start_code_units_offset(code_units_cache)
69
+ loc_end_offset = loc.cached_end_code_units_offset(code_units_cache)
67
70
  next unless (loc_start_offset...loc_end_offset).cover?(char_position)
68
71
 
69
72
  # If the node's start character is already past the position, then we should've found the closest node
@@ -74,7 +77,7 @@ module RubyLsp
74
77
  # and need to pop the stack
75
78
  previous_level = nesting_nodes.last
76
79
  if previous_level &&
77
- (loc_start_offset > previous_level.location.end_code_units_offset(encoding))
80
+ (loc_start_offset > previous_level.location.cached_end_code_units_offset(code_units_cache))
78
81
  nesting_nodes.pop
79
82
  end
80
83
 
@@ -89,10 +92,10 @@ module RubyLsp
89
92
  if candidate.is_a?(Prism::CallNode)
90
93
  arg_loc = candidate.arguments&.location
91
94
  blk_loc = candidate.block&.location
92
- if (arg_loc && (arg_loc.start_code_units_offset(encoding)...
93
- arg_loc.end_code_units_offset(encoding)).cover?(char_position)) ||
94
- (blk_loc && (blk_loc.start_code_units_offset(encoding)...
95
- blk_loc.end_code_units_offset(encoding)).cover?(char_position))
95
+ if (arg_loc && (arg_loc.cached_start_code_units_offset(code_units_cache)...
96
+ arg_loc.cached_end_code_units_offset(code_units_cache)).cover?(char_position)) ||
97
+ (blk_loc && (blk_loc.cached_start_code_units_offset(code_units_cache)...
98
+ blk_loc.cached_end_code_units_offset(code_units_cache)).cover?(char_position))
96
99
  call_node = candidate
97
100
  end
98
101
  end
@@ -102,8 +105,8 @@ module RubyLsp
102
105
 
103
106
  # If the current node is narrower than or equal to the previous closest node, then it is more precise
104
107
  closest_loc = closest.location
105
- closest_node_start_offset = closest_loc.start_code_units_offset(encoding)
106
- closest_node_end_offset = closest_loc.end_code_units_offset(encoding)
108
+ closest_node_start_offset = closest_loc.cached_start_code_units_offset(code_units_cache)
109
+ closest_node_end_offset = closest_loc.cached_end_code_units_offset(code_units_cache)
107
110
  if loc_end_offset - loc_start_offset <= closest_node_end_offset - closest_node_start_offset
108
111
  parent = closest
109
112
  closest = candidate
@@ -131,12 +134,30 @@ module RubyLsp
131
134
  end
132
135
  end
133
136
 
137
+ sig do
138
+ returns(T.any(
139
+ T.proc.params(arg0: Integer).returns(Integer),
140
+ Prism::CodeUnitsCache,
141
+ ))
142
+ end
143
+ attr_reader :code_units_cache
144
+
145
+ sig { params(source: String, version: Integer, uri: URI::Generic, encoding: Encoding).void }
146
+ def initialize(source:, version:, uri:, encoding: Encoding::UTF_8)
147
+ super
148
+ @code_units_cache = T.let(@parse_result.code_units_cache(@encoding), T.any(
149
+ T.proc.params(arg0: Integer).returns(Integer),
150
+ Prism::CodeUnitsCache,
151
+ ))
152
+ end
153
+
134
154
  sig { override.returns(T::Boolean) }
135
155
  def parse!
136
156
  return false unless @needs_parsing
137
157
 
138
158
  @needs_parsing = false
139
159
  @parse_result = Prism.parse(@source)
160
+ @code_units_cache = @parse_result.code_units_cache(@encoding)
140
161
  true
141
162
  end
142
163
 
@@ -214,8 +235,8 @@ module RubyLsp
214
235
  RubyDocument.locate(
215
236
  @parse_result.value,
216
237
  create_scanner.find_char_position(position),
238
+ code_units_cache: @code_units_cache,
217
239
  node_types: node_types,
218
- encoding: @encoding,
219
240
  )
220
241
  end
221
242
  end
@@ -93,7 +93,7 @@ module RubyLsp
93
93
  raw_receiver = if receiver.is_a?(Prism::CallNode)
94
94
  receiver.message
95
95
  else
96
- receiver&.slice
96
+ receiver.slice
97
97
  end
98
98
 
99
99
  if raw_receiver
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.1
4
+ version: 0.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-04 00:00:00.000000000 Z
11
+ date: 2024-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: language_server-protocol
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.1'
33
+ version: '1.2'
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
36
  version: '2.0'
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: '1.1'
43
+ version: '1.2'
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '2.0'
@@ -111,6 +111,7 @@ files:
111
111
  - lib/ruby_indexer/test/configuration_test.rb
112
112
  - lib/ruby_indexer/test/constant_test.rb
113
113
  - lib/ruby_indexer/test/enhancements_test.rb
114
+ - lib/ruby_indexer/test/global_variable_test.rb
114
115
  - lib/ruby_indexer/test/index_test.rb
115
116
  - lib/ruby_indexer/test/instance_variables_test.rb
116
117
  - lib/ruby_indexer/test/method_test.rb
@@ -211,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
212
  - !ruby/object:Gem::Version
212
213
  version: '0'
213
214
  requirements: []
214
- rubygems_version: 3.5.20
215
+ rubygems_version: 3.5.21
215
216
  signing_key:
216
217
  specification_version: 4
217
218
  summary: An opinionated language server for Ruby