ruby-lsp 0.10.1 → 0.11.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/README.md +4 -4
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp-check +1 -1
  5. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +40 -5
  6. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +141 -5
  7. data/lib/ruby_indexer/lib/ruby_indexer/visitor.rb +66 -18
  8. data/lib/ruby_indexer/test/classes_and_modules_test.rb +23 -0
  9. data/lib/ruby_indexer/test/configuration_test.rb +2 -0
  10. data/lib/ruby_indexer/test/constant_test.rb +202 -0
  11. data/lib/ruby_indexer/test/index_test.rb +20 -0
  12. data/lib/ruby_lsp/{extension.rb → addon.rb} +27 -25
  13. data/lib/ruby_lsp/check_docs.rb +7 -8
  14. data/lib/ruby_lsp/document.rb +35 -38
  15. data/lib/ruby_lsp/event_emitter.rb +239 -77
  16. data/lib/ruby_lsp/executor.rb +45 -55
  17. data/lib/ruby_lsp/internal.rb +2 -3
  18. data/lib/ruby_lsp/listener.rb +8 -7
  19. data/lib/ruby_lsp/parameter_scope.rb +33 -0
  20. data/lib/ruby_lsp/requests/base_request.rb +3 -3
  21. data/lib/ruby_lsp/requests/code_action_resolve.rb +14 -14
  22. data/lib/ruby_lsp/requests/code_lens.rb +39 -63
  23. data/lib/ruby_lsp/requests/completion.rb +54 -32
  24. data/lib/ruby_lsp/requests/definition.rb +30 -27
  25. data/lib/ruby_lsp/requests/diagnostics.rb +26 -3
  26. data/lib/ruby_lsp/requests/document_highlight.rb +18 -19
  27. data/lib/ruby_lsp/requests/document_link.rb +50 -9
  28. data/lib/ruby_lsp/requests/document_symbol.rb +82 -75
  29. data/lib/ruby_lsp/requests/folding_ranges.rb +199 -222
  30. data/lib/ruby_lsp/requests/formatting.rb +5 -6
  31. data/lib/ruby_lsp/requests/hover.rb +33 -22
  32. data/lib/ruby_lsp/requests/inlay_hints.rb +2 -3
  33. data/lib/ruby_lsp/requests/selection_ranges.rb +65 -40
  34. data/lib/ruby_lsp/requests/semantic_highlighting.rb +187 -145
  35. data/lib/ruby_lsp/requests/show_syntax_tree.rb +3 -4
  36. data/lib/ruby_lsp/requests/support/annotation.rb +18 -17
  37. data/lib/ruby_lsp/requests/support/common.rb +17 -26
  38. data/lib/ruby_lsp/requests/support/dependency_detector.rb +67 -42
  39. data/lib/ruby_lsp/requests/support/highlight_target.rb +64 -45
  40. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +9 -4
  41. data/lib/ruby_lsp/requests/support/selection_range.rb +5 -4
  42. data/lib/ruby_lsp/requests/support/sorbet.rb +2 -57
  43. data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +7 -1
  44. data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -1
  45. data/lib/ruby_lsp/server.rb +6 -44
  46. data/lib/ruby_lsp/utils.rb +2 -12
  47. metadata +11 -30
@@ -28,10 +28,10 @@ module RubyLsp
28
28
  @uri = T.let(document.uri, URI::Generic)
29
29
  end
30
30
 
31
- sig { override.returns(T.nilable(T.all(T::Array[Support::RuboCopDiagnostic], Object))) }
31
+ sig { override.returns(T.nilable(T.all(T::Array[Interface::Diagnostic], Object))) }
32
32
  def run
33
33
  # Running RuboCop is slow, so to avoid excessive runs we only do so if the file is syntactically valid
34
- return if @document.syntax_error?
34
+ return syntax_error_diagnostics if @document.syntax_error?
35
35
 
36
36
  return unless defined?(Support::RuboCopDiagnosticsRunner)
37
37
 
@@ -39,7 +39,30 @@ module RubyLsp
39
39
  path = @uri.to_standardized_path
40
40
  return unless path.nil? || path.start_with?(T.must(WORKSPACE_URI.to_standardized_path))
41
41
 
42
- Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document)
42
+ Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document).map!(&:to_lsp_diagnostic)
43
+ end
44
+
45
+ private
46
+
47
+ sig { returns(T.nilable(T::Array[Interface::Diagnostic])) }
48
+ def syntax_error_diagnostics
49
+ @document.parse_result.errors.map do |error|
50
+ Interface::Diagnostic.new(
51
+ range: Interface::Range.new(
52
+ start: Interface::Position.new(
53
+ line: error.location.start_line - 1,
54
+ character: error.location.start_column,
55
+ ),
56
+ end: Interface::Position.new(
57
+ line: error.location.end_line - 1,
58
+ character: error.location.end_column,
59
+ ),
60
+ ),
61
+ message: error.message,
62
+ severity: Constant::DiagnosticSeverity::ERROR,
63
+ source: "YARP",
64
+ )
65
+ end
43
66
  end
44
67
  end
45
68
  end
@@ -32,8 +32,8 @@ module RubyLsp
32
32
 
33
33
  sig do
34
34
  params(
35
- target: T.nilable(SyntaxTree::Node),
36
- parent: T.nilable(SyntaxTree::Node),
35
+ target: T.nilable(YARP::Node),
36
+ parent: T.nilable(YARP::Node),
37
37
  emitter: EventEmitter,
38
38
  message_queue: Thread::Queue,
39
39
  ).void
@@ -47,11 +47,21 @@ module RubyLsp
47
47
 
48
48
  highlight_target =
49
49
  case target
50
- when *DIRECT_HIGHLIGHTS
50
+ when YARP::GlobalVariableReadNode, YARP::GlobalVariableAndWriteNode, YARP::GlobalVariableOperatorWriteNode,
51
+ YARP::GlobalVariableOrWriteNode, YARP::GlobalVariableTargetNode, YARP::GlobalVariableWriteNode,
52
+ YARP::InstanceVariableAndWriteNode, YARP::InstanceVariableOperatorWriteNode,
53
+ YARP::InstanceVariableOrWriteNode, YARP::InstanceVariableReadNode, YARP::InstanceVariableTargetNode,
54
+ YARP::InstanceVariableWriteNode, YARP::ConstantAndWriteNode, YARP::ConstantOperatorWriteNode,
55
+ YARP::ConstantOrWriteNode, YARP::ConstantPathAndWriteNode, YARP::ConstantPathNode,
56
+ YARP::ConstantPathOperatorWriteNode, YARP::ConstantPathOrWriteNode, YARP::ConstantPathTargetNode,
57
+ YARP::ConstantPathWriteNode, YARP::ConstantReadNode, YARP::ConstantTargetNode, YARP::ConstantWriteNode,
58
+ YARP::ClassVariableAndWriteNode, YARP::ClassVariableOperatorWriteNode, YARP::ClassVariableOrWriteNode,
59
+ YARP::ClassVariableReadNode, YARP::ClassVariableTargetNode, YARP::ClassVariableWriteNode,
60
+ YARP::LocalVariableAndWriteNode, YARP::LocalVariableOperatorWriteNode, YARP::LocalVariableOrWriteNode,
61
+ YARP::LocalVariableReadNode, YARP::LocalVariableTargetNode, YARP::LocalVariableWriteNode, YARP::CallNode,
62
+ YARP::BlockParameterNode, YARP::KeywordParameterNode, YARP::KeywordRestParameterNode,
63
+ YARP::OptionalParameterNode, YARP::RequiredParameterNode, YARP::RestParameterNode
51
64
  Support::HighlightTarget.new(target)
52
- when SyntaxTree::Ident
53
- relevant_node = parent.is_a?(SyntaxTree::Params) ? target : parent
54
- Support::HighlightTarget.new(relevant_node)
55
65
  end
56
66
 
57
67
  @target = T.let(highlight_target, T.nilable(Support::HighlightTarget))
@@ -59,7 +69,7 @@ module RubyLsp
59
69
  emitter.register(self, :on_node) if @target
60
70
  end
61
71
 
62
- sig { params(node: T.nilable(SyntaxTree::Node)).void }
72
+ sig { params(node: T.nilable(YARP::Node)).void }
63
73
  def on_node(node)
64
74
  return if node.nil?
65
75
 
@@ -69,20 +79,9 @@ module RubyLsp
69
79
 
70
80
  private
71
81
 
72
- DIRECT_HIGHLIGHTS = T.let(
73
- [
74
- SyntaxTree::GVar,
75
- SyntaxTree::IVar,
76
- SyntaxTree::Const,
77
- SyntaxTree::CVar,
78
- SyntaxTree::VarField,
79
- ],
80
- T::Array[T.class_of(SyntaxTree::Node)],
81
- )
82
-
83
82
  sig { params(match: Support::HighlightTarget::HighlightMatch).void }
84
83
  def add_highlight(match)
85
- range = range_from_syntax_tree_node(match.node)
84
+ range = range_from_location(match.location)
86
85
  @_response << Interface::DocumentHighlight.new(range: range, kind: match.type)
87
86
  end
88
87
  end
@@ -75,8 +75,15 @@ module RubyLsp
75
75
  sig { override.returns(ResponseType) }
76
76
  attr_reader :_response
77
77
 
78
- sig { params(uri: URI::Generic, emitter: EventEmitter, message_queue: Thread::Queue).void }
79
- def initialize(uri, emitter, message_queue)
78
+ sig do
79
+ params(
80
+ uri: URI::Generic,
81
+ comments: T::Array[YARP::Comment],
82
+ emitter: EventEmitter,
83
+ message_queue: Thread::Queue,
84
+ ).void
85
+ end
86
+ def initialize(uri, comments, emitter, message_queue)
80
87
  super(emitter, message_queue)
81
88
 
82
89
  # Match the version based on the version in the RBI file name. Notice that the `@` symbol is sanitized to `%40`
@@ -85,13 +92,49 @@ module RubyLsp
85
92
  version_match = path ? /(?<=%40)[\d.]+(?=\.rbi$)/.match(path) : nil
86
93
  @gem_version = T.let(version_match && version_match[0], T.nilable(String))
87
94
  @_response = T.let([], T::Array[Interface::DocumentLink])
95
+ @lines_to_comments = T.let(
96
+ comments.to_h do |comment|
97
+ [comment.location.end_line, comment]
98
+ end,
99
+ T::Hash[Integer, YARP::Comment],
100
+ )
88
101
 
89
- emitter.register(self, :on_comment)
102
+ emitter.register(self, :on_def, :on_class, :on_module, :on_constant_write, :on_constant_path_write)
90
103
  end
91
104
 
92
- sig { params(node: SyntaxTree::Comment).void }
93
- def on_comment(node)
94
- match = node.value.match(%r{source://.*#\d+$})
105
+ sig { params(node: YARP::DefNode).void }
106
+ def on_def(node)
107
+ extract_document_link(node)
108
+ end
109
+
110
+ sig { params(node: YARP::ClassNode).void }
111
+ def on_class(node)
112
+ extract_document_link(node)
113
+ end
114
+
115
+ sig { params(node: YARP::ModuleNode).void }
116
+ def on_module(node)
117
+ extract_document_link(node)
118
+ end
119
+
120
+ sig { params(node: YARP::ConstantWriteNode).void }
121
+ def on_constant_write(node)
122
+ extract_document_link(node)
123
+ end
124
+
125
+ sig { params(node: YARP::ConstantPathWriteNode).void }
126
+ def on_constant_path_write(node)
127
+ extract_document_link(node)
128
+ end
129
+
130
+ private
131
+
132
+ sig { params(node: YARP::Node).void }
133
+ def extract_document_link(node)
134
+ comment = @lines_to_comments[node.location.start_line - 1]
135
+ return unless comment
136
+
137
+ match = comment.location.slice.match(%r{source://.*#\d+$})
95
138
  return unless match
96
139
 
97
140
  uri = T.cast(URI(T.must(match[0])), URI::Source)
@@ -102,14 +145,12 @@ module RubyLsp
102
145
  return if file_path.nil?
103
146
 
104
147
  @_response << Interface::DocumentLink.new(
105
- range: range_from_syntax_tree_node(node),
148
+ range: range_from_location(comment.location),
106
149
  target: "file://#{file_path}##{uri.line_number}",
107
150
  tooltip: "Jump to #{file_path}##{uri.line_number}",
108
151
  )
109
152
  end
110
153
 
111
- private
112
-
113
154
  # Try to figure out the gem version for a source:// link. The order of precedence is:
114
155
  # 1. The version in the URI
115
156
  # 2. The version in the RBI file name
@@ -64,20 +64,21 @@ module RubyLsp
64
64
  self,
65
65
  :on_class,
66
66
  :after_class,
67
- :on_command,
68
- :on_const_path_field,
67
+ :on_call,
68
+ :on_constant_path_write,
69
+ :on_constant_write,
69
70
  :on_def,
70
71
  :after_def,
71
72
  :on_module,
72
73
  :after_module,
73
- :on_top_const_field,
74
- :on_var_field,
74
+ :on_instance_variable_write,
75
+ :on_class_variable_write,
75
76
  )
76
77
  end
77
78
 
78
- sig { override.params(extension: RubyLsp::Extension).returns(T.nilable(Listener[ResponseType])) }
79
- def initialize_external_listener(extension)
80
- extension.create_document_symbol_listener(@emitter, @message_queue)
79
+ sig { override.params(addon: Addon).returns(T.nilable(Listener[ResponseType])) }
80
+ def initialize_external_listener(addon)
81
+ addon.create_document_symbol_listener(@emitter, @message_queue)
81
82
  end
82
83
 
83
84
  # Merges responses from other listeners
@@ -87,116 +88,122 @@ module RubyLsp
87
88
  self
88
89
  end
89
90
 
90
- sig { params(node: SyntaxTree::ClassDeclaration).void }
91
+ sig { params(node: YARP::ClassNode).void }
91
92
  def on_class(node)
92
93
  @stack << create_document_symbol(
93
- name: full_constant_name(node.constant),
94
+ name: node.constant_path.location.slice,
94
95
  kind: Constant::SymbolKind::CLASS,
95
- range_node: node,
96
- selection_range_node: node.constant,
96
+ range_location: node.location,
97
+ selection_range_location: node.constant_path.location,
97
98
  )
98
99
  end
99
100
 
100
- sig { params(node: SyntaxTree::ClassDeclaration).void }
101
+ sig { params(node: YARP::ClassNode).void }
101
102
  def after_class(node)
102
103
  @stack.pop
103
104
  end
104
105
 
105
- sig { params(node: SyntaxTree::Command).void }
106
- def on_command(node)
107
- return unless ATTR_ACCESSORS.include?(node.message.value)
106
+ sig { params(node: YARP::CallNode).void }
107
+ def on_call(node)
108
+ return unless ATTR_ACCESSORS.include?(node.name) && node.receiver.nil?
108
109
 
109
- node.arguments.parts.each do |argument|
110
- next unless argument.is_a?(SyntaxTree::SymbolLiteral)
110
+ arguments = node.arguments
111
+ return unless arguments
112
+
113
+ arguments.arguments.each do |argument|
114
+ next unless argument.is_a?(YARP::SymbolNode)
115
+
116
+ name = argument.value
117
+ next unless name
111
118
 
112
119
  create_document_symbol(
113
- name: argument.value.value,
120
+ name: name,
114
121
  kind: Constant::SymbolKind::FIELD,
115
- range_node: argument,
116
- selection_range_node: argument.value,
122
+ range_location: argument.location,
123
+ selection_range_location: T.must(argument.value_loc),
117
124
  )
118
125
  end
119
126
  end
120
127
 
121
- sig { params(node: SyntaxTree::ConstPathField).void }
122
- def on_const_path_field(node)
128
+ sig { params(node: YARP::ConstantPathWriteNode).void }
129
+ def on_constant_path_write(node)
130
+ create_document_symbol(
131
+ name: node.target.location.slice,
132
+ kind: Constant::SymbolKind::CONSTANT,
133
+ range_location: node.location,
134
+ selection_range_location: node.target.location,
135
+ )
136
+ end
137
+
138
+ sig { params(node: YARP::ConstantWriteNode).void }
139
+ def on_constant_write(node)
123
140
  create_document_symbol(
124
- name: node.constant.value,
141
+ name: node.name.to_s,
125
142
  kind: Constant::SymbolKind::CONSTANT,
126
- range_node: node,
127
- selection_range_node: node.constant,
143
+ range_location: node.location,
144
+ selection_range_location: node.name_loc,
145
+ )
146
+ end
147
+
148
+ sig { params(node: YARP::DefNode).void }
149
+ def after_def(node)
150
+ @stack.pop
151
+ end
152
+
153
+ sig { params(node: YARP::ModuleNode).void }
154
+ def on_module(node)
155
+ @stack << create_document_symbol(
156
+ name: node.constant_path.location.slice,
157
+ kind: Constant::SymbolKind::MODULE,
158
+ range_location: node.location,
159
+ selection_range_location: node.constant_path.location,
128
160
  )
129
161
  end
130
162
 
131
- sig { params(node: SyntaxTree::DefNode).void }
163
+ sig { params(node: YARP::DefNode).void }
132
164
  def on_def(node)
133
- target = node.target
165
+ receiver = node.receiver
134
166
 
135
- if target.is_a?(SyntaxTree::VarRef) && target.value.is_a?(SyntaxTree::Kw) && target.value.value == "self"
136
- name = "self.#{node.name.value}"
167
+ if receiver.is_a?(YARP::SelfNode)
168
+ name = "self.#{node.name}"
137
169
  kind = Constant::SymbolKind::METHOD
138
170
  else
139
- name = node.name.value
171
+ name = node.name.to_s
140
172
  kind = name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
141
173
  end
142
174
 
143
175
  symbol = create_document_symbol(
144
176
  name: name,
145
177
  kind: kind,
146
- range_node: node,
147
- selection_range_node: node.name,
178
+ range_location: node.location,
179
+ selection_range_location: node.name_loc,
148
180
  )
149
181
 
150
182
  @stack << symbol
151
183
  end
152
184
 
153
- sig { params(node: SyntaxTree::DefNode).void }
154
- def after_def(node)
155
- @stack.pop
156
- end
157
-
158
- sig { params(node: SyntaxTree::ModuleDeclaration).void }
159
- def on_module(node)
160
- @stack << create_document_symbol(
161
- name: full_constant_name(node.constant),
162
- kind: Constant::SymbolKind::MODULE,
163
- range_node: node,
164
- selection_range_node: node.constant,
165
- )
166
- end
167
-
168
- sig { params(node: SyntaxTree::ModuleDeclaration).void }
185
+ sig { params(node: YARP::ModuleNode).void }
169
186
  def after_module(node)
170
187
  @stack.pop
171
188
  end
172
189
 
173
- sig { params(node: SyntaxTree::TopConstField).void }
174
- def on_top_const_field(node)
190
+ sig { params(node: YARP::InstanceVariableWriteNode).void }
191
+ def on_instance_variable_write(node)
175
192
  create_document_symbol(
176
- name: node.constant.value,
177
- kind: Constant::SymbolKind::CONSTANT,
178
- range_node: node,
179
- selection_range_node: node.constant,
193
+ name: node.name.to_s,
194
+ kind: Constant::SymbolKind::VARIABLE,
195
+ range_location: node.name_loc,
196
+ selection_range_location: node.name_loc,
180
197
  )
181
198
  end
182
199
 
183
- sig { params(node: SyntaxTree::VarField).void }
184
- def on_var_field(node)
185
- value = node.value
186
- kind = case value
187
- when SyntaxTree::Const
188
- Constant::SymbolKind::CONSTANT
189
- when SyntaxTree::CVar, SyntaxTree::IVar
190
- Constant::SymbolKind::VARIABLE
191
- else
192
- return
193
- end
194
-
200
+ sig { params(node: YARP::ClassVariableWriteNode).void }
201
+ def on_class_variable_write(node)
195
202
  create_document_symbol(
196
- name: value.value,
197
- kind: kind,
198
- range_node: node,
199
- selection_range_node: value,
203
+ name: node.name.to_s,
204
+ kind: Constant::SymbolKind::VARIABLE,
205
+ range_location: node.name_loc,
206
+ selection_range_location: node.name_loc,
200
207
  )
201
208
  end
202
209
 
@@ -206,16 +213,16 @@ module RubyLsp
206
213
  params(
207
214
  name: String,
208
215
  kind: Integer,
209
- range_node: SyntaxTree::Node,
210
- selection_range_node: SyntaxTree::Node,
216
+ range_location: YARP::Location,
217
+ selection_range_location: YARP::Location,
211
218
  ).returns(Interface::DocumentSymbol)
212
219
  end
213
- def create_document_symbol(name:, kind:, range_node:, selection_range_node:)
220
+ def create_document_symbol(name:, kind:, range_location:, selection_range_location:)
214
221
  symbol = Interface::DocumentSymbol.new(
215
222
  name: name,
216
223
  kind: kind,
217
- range: range_from_syntax_tree_node(range_node),
218
- selection_range: range_from_syntax_tree_node(selection_range_node),
224
+ range: range_from_location(range_location),
225
+ selection_range: range_from_location(selection_range_location),
219
226
  children: [],
220
227
  )
221
228