ruby-lsp 0.19.1 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
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