ruby-lsp 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) 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 +35 -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 +39 -16
  9. data/lib/ruby_indexer/test/configuration_test.rb +2 -0
  10. data/lib/ruby_indexer/test/constant_test.rb +213 -11
  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 +53 -10
  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/setup_bundler.rb +22 -11
  47. data/lib/ruby_lsp/utils.rb +2 -12
  48. 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,29 +92,65 @@ 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
+ )
101
+
102
+ emitter.register(self, :on_def, :on_class, :on_module, :on_constant_write, :on_constant_path_write)
103
+ end
104
+
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
88
124
 
89
- emitter.register(self, :on_comment)
125
+ sig { params(node: YARP::ConstantPathWriteNode).void }
126
+ def on_constant_path_write(node)
127
+ extract_document_link(node)
90
128
  end
91
129
 
92
- sig { params(node: SyntaxTree::Comment).void }
93
- def on_comment(node)
94
- match = node.value.match(%r{source://.*#\d+$})
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)
98
- gem_version = T.must(resolve_version(uri))
141
+ gem_version = resolve_version(uri)
142
+ return if gem_version.nil?
143
+
99
144
  file_path = self.class.gem_paths.dig(uri.gem_name, gem_version, CGI.unescape(uri.path))
100
145
  return if file_path.nil?
101
146
 
102
147
  @_response << Interface::DocumentLink.new(
103
- range: range_from_syntax_tree_node(node),
148
+ range: range_from_location(comment.location),
104
149
  target: "file://#{file_path}##{uri.line_number}",
105
150
  tooltip: "Jump to #{file_path}##{uri.line_number}",
106
151
  )
107
152
  end
108
153
 
109
- private
110
-
111
154
  # Try to figure out the gem version for a source:// link. The order of precedence is:
112
155
  # 1. The version in the URI
113
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