ruby-lsp 0.19.0 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp-check +1 -1
  4. data/lib/core_ext/uri.rb +2 -2
  5. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +85 -36
  6. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +5 -1
  7. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +46 -98
  8. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +7 -6
  9. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +22 -0
  10. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +20 -5
  11. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +76 -14
  12. data/lib/ruby_indexer/test/classes_and_modules_test.rb +12 -0
  13. data/lib/ruby_indexer/test/enhancements_test.rb +5 -7
  14. data/lib/ruby_indexer/test/global_variable_test.rb +49 -0
  15. data/lib/ruby_indexer/test/index_test.rb +3 -0
  16. data/lib/ruby_indexer/test/rbs_indexer_test.rb +14 -0
  17. data/lib/ruby_indexer/test/reference_finder_test.rb +162 -6
  18. data/lib/ruby_lsp/erb_document.rb +20 -2
  19. data/lib/ruby_lsp/internal.rb +3 -1
  20. data/lib/ruby_lsp/listeners/definition.rb +20 -0
  21. data/lib/ruby_lsp/listeners/folding_ranges.rb +3 -3
  22. data/lib/ruby_lsp/requests/code_action_resolve.rb +16 -4
  23. data/lib/ruby_lsp/requests/completion.rb +1 -0
  24. data/lib/ruby_lsp/requests/definition.rb +2 -0
  25. data/lib/ruby_lsp/requests/document_highlight.rb +5 -1
  26. data/lib/ruby_lsp/requests/hover.rb +1 -0
  27. data/lib/ruby_lsp/requests/range_formatting.rb +57 -0
  28. data/lib/ruby_lsp/requests/references.rb +146 -0
  29. data/lib/ruby_lsp/requests/rename.rb +16 -9
  30. data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
  31. data/lib/ruby_lsp/requests/signature_help.rb +6 -1
  32. data/lib/ruby_lsp/requests/support/common.rb +1 -1
  33. data/lib/ruby_lsp/requests/support/formatter.rb +3 -0
  34. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +6 -0
  35. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +6 -6
  36. data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +8 -0
  37. data/lib/ruby_lsp/response_builders/document_symbol.rb +2 -2
  38. data/lib/ruby_lsp/response_builders/hover.rb +2 -2
  39. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +14 -8
  40. data/lib/ruby_lsp/response_builders/signature_help.rb +2 -2
  41. data/lib/ruby_lsp/ruby_document.rb +44 -8
  42. data/lib/ruby_lsp/server.rb +63 -2
  43. data/lib/ruby_lsp/type_inferrer.rb +1 -1
  44. metadata +8 -5
@@ -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 }
@@ -23,10 +23,11 @@ module RubyLsp
23
23
  end
24
24
  end
25
25
 
26
- sig { params(document: RubyDocument, code_action: T::Hash[Symbol, T.untyped]).void }
27
- def initialize(document, code_action)
26
+ sig { params(document: RubyDocument, global_state: GlobalState, code_action: T::Hash[Symbol, T.untyped]).void }
27
+ def initialize(document, global_state, code_action)
28
28
  super()
29
29
  @document = document
30
+ @global_state = global_state
30
31
  @code_action = code_action
31
32
  end
32
33
 
@@ -98,7 +99,13 @@ module RubyLsp
98
99
 
99
100
  # Find the closest statements node, so that we place the refactor in a valid position
100
101
  node_context = RubyDocument
101
- .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)
102
109
 
103
110
  closest_statements = node_context.node
104
111
  parent_statements = node_context.parent
@@ -191,7 +198,12 @@ module RubyLsp
191
198
  extracted_source = T.must(@document.source[start_index...end_index])
192
199
 
193
200
  # Find the closest method declaration node, so that we place the refactor in a valid position
194
- node_context = RubyDocument.locate(@document.parse_result.value, start_index, node_types: [Prism::DefNode])
201
+ node_context = RubyDocument.locate(
202
+ @document.parse_result.value,
203
+ start_index,
204
+ node_types: [Prism::DefNode],
205
+ code_units_cache: @document.code_units_cache,
206
+ )
195
207
  closest_node = node_context.node
196
208
  return Error::InvalidTargetRange unless closest_node
197
209
 
@@ -57,6 +57,7 @@ module RubyLsp
57
57
  Prism::InstanceVariableTargetNode,
58
58
  Prism::InstanceVariableWriteNode,
59
59
  ],
60
+ code_units_cache: document.code_units_cache,
60
61
  )
61
62
  @response_builder = T.let(
62
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,6 +58,7 @@ module RubyLsp
57
58
  Prism::SuperNode,
58
59
  Prism::ForwardingSuperNode,
59
60
  ],
61
+ code_units_cache: document.code_units_cache,
60
62
  )
61
63
 
62
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)
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,6 +41,7 @@ module RubyLsp
41
41
  document.parse_result.value,
42
42
  char_position,
43
43
  node_types: Listeners::Hover::ALLOWED_TARGETS,
44
+ code_units_cache: document.code_units_cache,
44
45
  )
45
46
  target = node_context.node
46
47
  parent = node_context.parent
@@ -0,0 +1,57 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ # The [range formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_rangeFormatting)
7
+ # is used to format a selection or to format on paste.
8
+ class RangeFormatting < Request
9
+ extend T::Sig
10
+
11
+ sig { params(global_state: GlobalState, document: RubyDocument, params: T::Hash[Symbol, T.untyped]).void }
12
+ def initialize(global_state, document, params)
13
+ super()
14
+ @document = document
15
+ @uri = T.let(document.uri, URI::Generic)
16
+ @params = params
17
+ @active_formatter = T.let(global_state.active_formatter, T.nilable(Support::Formatter))
18
+ end
19
+
20
+ sig { override.returns(T.nilable(T::Array[Interface::TextEdit])) }
21
+ def perform
22
+ return unless @active_formatter
23
+ return if @document.syntax_error?
24
+
25
+ target = @document.locate_first_within_range(@params[:range])
26
+ return unless target
27
+
28
+ location = target.location
29
+
30
+ formatted_text = @active_formatter.run_range_formatting(
31
+ @uri,
32
+ target.slice,
33
+ location.start_column / 2,
34
+ )
35
+ return unless formatted_text
36
+
37
+ code_units_cache = @document.code_units_cache
38
+
39
+ [
40
+ Interface::TextEdit.new(
41
+ range: Interface::Range.new(
42
+ start: Interface::Position.new(
43
+ line: location.start_line - 1,
44
+ character: location.cached_start_code_units_column(code_units_cache),
45
+ ),
46
+ end: Interface::Position.new(
47
+ line: location.end_line - 1,
48
+ character: location.cached_end_code_units_column(code_units_cache),
49
+ ),
50
+ ),
51
+ new_text: formatted_text.strip,
52
+ ),
53
+ ]
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,146 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ # The
7
+ # [references](https://microsoft.github.io/language-server-protocol/specification#textDocument_references)
8
+ # request finds all references for the selected symbol.
9
+ class References < Request
10
+ extend T::Sig
11
+ include Support::Common
12
+
13
+ sig do
14
+ params(
15
+ global_state: GlobalState,
16
+ store: Store,
17
+ document: T.any(RubyDocument, ERBDocument),
18
+ params: T::Hash[Symbol, T.untyped],
19
+ ).void
20
+ end
21
+ def initialize(global_state, store, document, params)
22
+ super()
23
+ @global_state = global_state
24
+ @store = store
25
+ @document = document
26
+ @params = params
27
+ @locations = T.let([], T::Array[Interface::Location])
28
+ end
29
+
30
+ sig { override.returns(T::Array[Interface::Location]) }
31
+ def perform
32
+ position = @params[:position]
33
+ char_position = @document.create_scanner.find_char_position(position)
34
+
35
+ node_context = RubyDocument.locate(
36
+ @document.parse_result.value,
37
+ char_position,
38
+ node_types: [
39
+ Prism::ConstantReadNode,
40
+ Prism::ConstantPathNode,
41
+ Prism::ConstantPathTargetNode,
42
+ Prism::CallNode,
43
+ Prism::DefNode,
44
+ ],
45
+ code_units_cache: @document.code_units_cache,
46
+ )
47
+ target = node_context.node
48
+ parent = node_context.parent
49
+ return @locations if !target || target.is_a?(Prism::ProgramNode)
50
+
51
+ if target.is_a?(Prism::ConstantReadNode) && parent.is_a?(Prism::ConstantPathNode)
52
+ target = determine_target(
53
+ target,
54
+ parent,
55
+ position,
56
+ )
57
+ end
58
+
59
+ target = T.cast(
60
+ target,
61
+ T.any(
62
+ Prism::ConstantReadNode,
63
+ Prism::ConstantPathNode,
64
+ Prism::ConstantPathTargetNode,
65
+ Prism::CallNode,
66
+ Prism::DefNode,
67
+ ),
68
+ )
69
+
70
+ reference_target = create_reference_target(target, node_context)
71
+ return @locations unless reference_target
72
+
73
+ Dir.glob(File.join(@global_state.workspace_path, "**/*.rb")).each do |path|
74
+ uri = URI::Generic.from_path(path: path)
75
+ # If the document is being managed by the client, then we should use whatever is present in the store instead
76
+ # of reading from disk
77
+ next if @store.key?(uri)
78
+
79
+ parse_result = Prism.parse_file(path)
80
+ collect_references(reference_target, parse_result, uri)
81
+ end
82
+
83
+ @store.each do |_uri, document|
84
+ collect_references(reference_target, document.parse_result, document.uri)
85
+ end
86
+
87
+ @locations
88
+ end
89
+
90
+ private
91
+
92
+ sig do
93
+ params(
94
+ target_node: T.any(
95
+ Prism::ConstantReadNode,
96
+ Prism::ConstantPathNode,
97
+ Prism::ConstantPathTargetNode,
98
+ Prism::CallNode,
99
+ Prism::DefNode,
100
+ ),
101
+ node_context: NodeContext,
102
+ ).returns(T.nilable(RubyIndexer::ReferenceFinder::Target))
103
+ end
104
+ def create_reference_target(target_node, node_context)
105
+ case target_node
106
+ when Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode
107
+ name = constant_name(target_node)
108
+ return unless name
109
+
110
+ entries = @global_state.index.resolve(name, node_context.nesting)
111
+ return unless entries
112
+
113
+ fully_qualified_name = T.must(entries.first).name
114
+ RubyIndexer::ReferenceFinder::ConstTarget.new(fully_qualified_name)
115
+ when Prism::CallNode, Prism::DefNode
116
+ RubyIndexer::ReferenceFinder::MethodTarget.new(target_node.name.to_s)
117
+ end
118
+ end
119
+
120
+ sig do
121
+ params(
122
+ target: RubyIndexer::ReferenceFinder::Target,
123
+ parse_result: Prism::ParseResult,
124
+ uri: URI::Generic,
125
+ ).void
126
+ end
127
+ def collect_references(target, parse_result, uri)
128
+ dispatcher = Prism::Dispatcher.new
129
+ finder = RubyIndexer::ReferenceFinder.new(
130
+ target,
131
+ @global_state.index,
132
+ dispatcher,
133
+ include_declarations: @params.dig(:context, :includeDeclaration) || true,
134
+ )
135
+ dispatcher.visit(parse_result.value)
136
+
137
+ finder.references.each do |reference|
138
+ @locations << Interface::Location.new(
139
+ uri: uri.to_s,
140
+ range: range_from_location(reference.location),
141
+ )
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -37,6 +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
+ code_units_cache: @document.code_units_cache,
40
41
  )
41
42
  target = node_context.node
42
43
  parent = node_context.parent
@@ -66,7 +67,8 @@ module RubyLsp
66
67
  end
67
68
 
68
69
  fully_qualified_name = T.must(entries.first).name
69
- changes = collect_text_edits(fully_qualified_name, name)
70
+ reference_target = RubyIndexer::ReferenceFinder::ConstTarget.new(fully_qualified_name)
71
+ changes = collect_text_edits(reference_target, name)
70
72
 
71
73
  # If the client doesn't support resource operations, such as renaming files, then we can only return the basic
72
74
  # text changes
@@ -127,8 +129,13 @@ module RubyLsp
127
129
  end
128
130
  end
129
131
 
130
- sig { params(fully_qualified_name: String, name: String).returns(T::Hash[String, T::Array[Interface::TextEdit]]) }
131
- def collect_text_edits(fully_qualified_name, name)
132
+ sig do
133
+ params(
134
+ target: RubyIndexer::ReferenceFinder::Target,
135
+ name: String,
136
+ ).returns(T::Hash[String, T::Array[Interface::TextEdit]])
137
+ end
138
+ def collect_text_edits(target, name)
132
139
  changes = {}
133
140
 
134
141
  Dir.glob(File.join(@global_state.workspace_path, "**/*.rb")).each do |path|
@@ -138,12 +145,12 @@ module RubyLsp
138
145
  next if @store.key?(uri)
139
146
 
140
147
  parse_result = Prism.parse_file(path)
141
- edits = collect_changes(fully_qualified_name, parse_result, name, uri)
148
+ edits = collect_changes(target, parse_result, name, uri)
142
149
  changes[uri.to_s] = edits unless edits.empty?
143
150
  end
144
151
 
145
152
  @store.each do |uri, document|
146
- edits = collect_changes(fully_qualified_name, document.parse_result, name, document.uri)
153
+ edits = collect_changes(target, document.parse_result, name, document.uri)
147
154
  changes[uri] = edits unless edits.empty?
148
155
  end
149
156
 
@@ -152,18 +159,18 @@ module RubyLsp
152
159
 
153
160
  sig do
154
161
  params(
155
- fully_qualified_name: String,
162
+ target: RubyIndexer::ReferenceFinder::Target,
156
163
  parse_result: Prism::ParseResult,
157
164
  name: String,
158
165
  uri: URI::Generic,
159
166
  ).returns(T::Array[Interface::TextEdit])
160
167
  end
161
- def collect_changes(fully_qualified_name, parse_result, name, uri)
168
+ def collect_changes(target, parse_result, name, uri)
162
169
  dispatcher = Prism::Dispatcher.new
163
- finder = RubyIndexer::ReferenceFinder.new(fully_qualified_name, @global_state.index, dispatcher)
170
+ finder = RubyIndexer::ReferenceFinder.new(target, @global_state.index, dispatcher)
164
171
  dispatcher.visit(parse_result.value)
165
172
 
166
- finder.references.uniq(&:location).map do |reference|
173
+ finder.references.map do |reference|
167
174
  adjust_reference_for_edit(name, reference)
168
175
  end
169
176
  end
@@ -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)
@@ -39,7 +39,12 @@ module RubyLsp
39
39
  char_position = document.create_scanner.find_char_position(position)
40
40
  delegate_request_if_needed!(global_state, document, char_position)
41
41
 
42
- node_context = RubyDocument.locate(document.parse_result.value, char_position, node_types: [Prism::CallNode])
42
+ node_context = RubyDocument.locate(
43
+ document.parse_result.value,
44
+ char_position,
45
+ node_types: [Prism::CallNode],
46
+ code_units_cache: document.code_units_cache,
47
+ )
43
48
 
44
49
  target = adjust_for_nested_target(node_context.node, node_context.parent, position)
45
50
 
@@ -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
@@ -13,6 +13,9 @@ module RubyLsp
13
13
  sig { abstract.params(uri: URI::Generic, document: RubyDocument).returns(T.nilable(String)) }
14
14
  def run_formatting(uri, document); end
15
15
 
16
+ sig { abstract.params(uri: URI::Generic, source: String, base_indentation: Integer).returns(T.nilable(String)) }
17
+ def run_range_formatting(uri, source, base_indentation); end
18
+
16
19
  sig do
17
20
  abstract.params(
18
21
  uri: URI::Generic,
@@ -28,6 +28,12 @@ module RubyLsp
28
28
  @format_runner.formatted_source
29
29
  end
30
30
 
31
+ # RuboCop does not support range formatting
32
+ sig { override.params(uri: URI::Generic, source: String, base_indentation: Integer).returns(T.nilable(String)) }
33
+ def run_range_formatting(uri, source, base_indentation)
34
+ nil
35
+ end
36
+
31
37
  sig do
32
38
  override.params(
33
39
  uri: URI::Generic,
@@ -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"
@@ -37,6 +37,14 @@ module RubyLsp
37
37
  SyntaxTree.format(document.source, @options.print_width, options: @options.formatter_options)
38
38
  end
39
39
 
40
+ sig { override.params(uri: URI::Generic, source: String, base_indentation: Integer).returns(T.nilable(String)) }
41
+ def run_range_formatting(uri, source, base_indentation)
42
+ path = uri.to_standardized_path
43
+ return if path && @options.ignore_files.any? { |pattern| File.fnmatch?("*/#{pattern}", path) }
44
+
45
+ SyntaxTree.format(source, @options.print_width, base_indentation, options: @options.formatter_options)
46
+ end
47
+
40
48
  sig do
41
49
  override.params(
42
50
  uri: URI::Generic,
@@ -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