ruby-lsp 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -86
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp +10 -1
  5. data/lib/ruby_lsp/check_docs.rb +112 -0
  6. data/lib/ruby_lsp/document.rb +13 -2
  7. data/lib/ruby_lsp/event_emitter.rb +86 -18
  8. data/lib/ruby_lsp/executor.rb +146 -45
  9. data/lib/ruby_lsp/extension.rb +104 -0
  10. data/lib/ruby_lsp/internal.rb +2 -0
  11. data/lib/ruby_lsp/listener.rb +14 -11
  12. data/lib/ruby_lsp/requests/base_request.rb +0 -5
  13. data/lib/ruby_lsp/requests/code_action_resolve.rb +1 -1
  14. data/lib/ruby_lsp/requests/code_actions.rb +1 -1
  15. data/lib/ruby_lsp/requests/code_lens.rb +82 -66
  16. data/lib/ruby_lsp/requests/diagnostics.rb +2 -2
  17. data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
  18. data/lib/ruby_lsp/requests/document_link.rb +17 -15
  19. data/lib/ruby_lsp/requests/document_symbol.rb +51 -31
  20. data/lib/ruby_lsp/requests/folding_ranges.rb +1 -1
  21. data/lib/ruby_lsp/requests/formatting.rb +10 -11
  22. data/lib/ruby_lsp/requests/hover.rb +34 -19
  23. data/lib/ruby_lsp/requests/inlay_hints.rb +1 -1
  24. data/lib/ruby_lsp/requests/on_type_formatting.rb +5 -1
  25. data/lib/ruby_lsp/requests/path_completion.rb +21 -57
  26. data/lib/ruby_lsp/requests/selection_ranges.rb +1 -1
  27. data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
  28. data/lib/ruby_lsp/requests/support/common.rb +36 -0
  29. data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +0 -1
  30. data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +0 -1
  31. data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +5 -2
  32. data/lib/ruby_lsp/requests.rb +15 -15
  33. data/lib/ruby_lsp/server.rb +44 -11
  34. data/lib/ruby_lsp/store.rb +1 -1
  35. data/lib/ruby_lsp/utils.rb +9 -8
  36. metadata +5 -3
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![Code lens demo](../../misc/code_lens.gif)
6
+ # ![Code lens demo](../../code_lens.gif)
7
7
  #
8
8
  # This feature is currently experimental. Clients will need to pass `experimentalFeaturesEnabled`
9
9
  # in the initialization options to enable it.
@@ -19,41 +19,41 @@ module RubyLsp
19
19
  # class Test < Minitest::Test
20
20
  # end
21
21
  # ```
22
+ class CodeLens < Listener
23
+ extend T::Sig
24
+ extend T::Generic
25
+
26
+ ResponseType = type_member { { fixed: T::Array[Interface::CodeLens] } }
22
27
 
23
- class CodeLens < BaseRequest
24
28
  BASE_COMMAND = T.let((File.exist?("Gemfile.lock") ? "bundle exec ruby" : "ruby") + " -Itest ", String)
25
29
  ACCESS_MODIFIERS = T.let(["public", "private", "protected"], T::Array[String])
26
30
 
27
- sig do
28
- params(
29
- document: Document,
30
- ).void
31
- end
32
- def initialize(document)
33
- super(document)
34
- @results = T.let([], T::Array[Interface::CodeLens])
35
- @path = T.let(document.uri.delete_prefix("file://"), String)
36
- @modifier = T.let("public", String)
37
- end
31
+ sig { override.returns(ResponseType) }
32
+ attr_reader :response
33
+
34
+ sig { params(uri: String, emitter: EventEmitter, message_queue: Thread::Queue).void }
35
+ def initialize(uri, emitter, message_queue)
36
+ super(emitter, message_queue)
37
+
38
+ @response = T.let([], ResponseType)
39
+ @path = T.let(T.must(URI(uri).path), String)
40
+ @visibility = T.let("public", String)
41
+ @prev_visibility = T.let("public", String)
38
42
 
39
- sig { override.returns(T.all(T::Array[Interface::CodeLens], Object)) }
40
- def run
41
- visit(@document.tree) if @document.parsed?
42
- @results
43
+ emitter.register(self, :on_class, :on_def, :on_command, :after_command, :on_call, :after_call, :on_vcall)
43
44
  end
44
45
 
45
- sig { override.params(node: SyntaxTree::ClassDeclaration).void }
46
- def visit_class(node)
46
+ sig { params(node: SyntaxTree::ClassDeclaration).void }
47
+ def on_class(node)
47
48
  class_name = node.constant.constant.value
48
49
  if class_name.end_with?("Test")
49
50
  add_code_lens(node, name: class_name, command: BASE_COMMAND + @path)
50
51
  end
51
- visit(node.bodystmt)
52
52
  end
53
53
 
54
- sig { override.params(node: SyntaxTree::DefNode).void }
55
- def visit_def(node)
56
- if @modifier == "public"
54
+ sig { params(node: SyntaxTree::DefNode).void }
55
+ def on_def(node)
56
+ if @visibility == "public"
57
57
  method_name = node.name.value
58
58
  if method_name.start_with?("test_")
59
59
  add_code_lens(
@@ -65,69 +65,85 @@ module RubyLsp
65
65
  end
66
66
  end
67
67
 
68
- sig { override.params(node: SyntaxTree::Command).void }
69
- def visit_command(node)
70
- if node.message.value == "public"
71
- with_visiblity("public", node)
68
+ sig { params(node: SyntaxTree::Command).void }
69
+ def on_command(node)
70
+ if ACCESS_MODIFIERS.include?(node.message.value) && node.arguments.parts.any?
71
+ @prev_visibility = @visibility
72
+ @visibility = node.message.value
72
73
  end
73
74
  end
74
75
 
75
- sig { override.params(node: SyntaxTree::CallNode).void }
76
- def visit_call(node)
76
+ sig { params(node: SyntaxTree::Command).void }
77
+ def after_command(node)
78
+ @visibility = @prev_visibility
79
+ end
80
+
81
+ sig { params(node: SyntaxTree::CallNode).void }
82
+ def on_call(node)
77
83
  ident = node.message if node.message.is_a?(SyntaxTree::Ident)
78
84
 
79
85
  if ident
80
- if T.cast(ident, SyntaxTree::Ident).value == "public"
81
- with_visiblity("public", node)
86
+ ident_value = T.cast(ident, SyntaxTree::Ident).value
87
+ if ACCESS_MODIFIERS.include?(ident_value)
88
+ @prev_visibility = @visibility
89
+ @visibility = ident_value
82
90
  end
83
91
  end
84
92
  end
85
93
 
86
- sig { override.params(node: SyntaxTree::VCall).void }
87
- def visit_vcall(node)
94
+ sig { params(node: SyntaxTree::CallNode).void }
95
+ def after_call(node)
96
+ @visibility = @prev_visibility
97
+ end
98
+
99
+ sig { params(node: SyntaxTree::VCall).void }
100
+ def on_vcall(node)
88
101
  vcall_value = node.value.value
89
102
 
90
103
  if ACCESS_MODIFIERS.include?(vcall_value)
91
- @modifier = vcall_value
104
+ @prev_visibility = vcall_value
105
+ @visibility = vcall_value
92
106
  end
93
107
  end
94
108
 
95
- private
96
-
97
- sig do
98
- params(
99
- visibility: String,
100
- node: T.any(SyntaxTree::CallNode, SyntaxTree::Command),
101
- ).void
102
- end
103
- def with_visiblity(visibility, node)
104
- current_visibility = @modifier
105
- @modifier = visibility
106
- visit(node.arguments)
107
- ensure
108
- @modifier = T.must(current_visibility)
109
+ sig { params(other: Listener[ResponseType]).returns(T.self_type) }
110
+ def merge_response!(other)
111
+ @response.concat(other.response)
112
+ self
109
113
  end
110
114
 
115
+ private
116
+
111
117
  sig { params(node: SyntaxTree::Node, name: String, command: String).void }
112
118
  def add_code_lens(node, name:, command:)
113
- @results << Interface::CodeLens.new(
114
- range: range_from_syntax_tree_node(node),
115
- command: Interface::Command.new(
116
- title: "Run",
117
- command: "rubyLsp.runTest",
118
- arguments: [
119
- @path,
120
- name,
121
- command,
122
- {
123
- start_line: node.location.start_line - 1,
124
- start_column: node.location.start_column,
125
- end_line: node.location.end_line - 1,
126
- end_column: node.location.end_column,
127
- },
128
- ],
129
- ),
130
- data: { type: "test" },
119
+ @response << create_code_lens(
120
+ node,
121
+ title: "Run",
122
+ command_name: "rubyLsp.runTest",
123
+ path: @path,
124
+ name: name,
125
+ test_command: command,
126
+ type: "test",
127
+ )
128
+
129
+ @response << create_code_lens(
130
+ node,
131
+ title: "Run In Terminal",
132
+ command_name: "rubyLsp.runTestInTerminal",
133
+ path: @path,
134
+ name: name,
135
+ test_command: command,
136
+ type: "test_in_terminal",
137
+ )
138
+
139
+ @response << create_code_lens(
140
+ node,
141
+ title: "Debug",
142
+ command_name: "rubyLsp.debugTest",
143
+ path: @path,
144
+ name: name,
145
+ test_command: command,
146
+ type: "debug",
131
147
  )
132
148
  end
133
149
  end
@@ -5,7 +5,7 @@ require "ruby_lsp/requests/support/rubocop_diagnostics_runner"
5
5
 
6
6
  module RubyLsp
7
7
  module Requests
8
- # ![Diagnostics demo](../../misc/diagnostics.gif)
8
+ # ![Diagnostics demo](../../diagnostics.gif)
9
9
  #
10
10
  # The
11
11
  # [diagnostics](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics)
@@ -34,7 +34,7 @@ module RubyLsp
34
34
  return unless defined?(Support::RuboCopDiagnosticsRunner)
35
35
 
36
36
  # Don't try to run RuboCop diagnostics for files outside the current working directory
37
- return unless @uri.start_with?(WORKSPACE_URI)
37
+ return unless URI(@uri).path&.start_with?(T.must(WORKSPACE_URI.path))
38
38
 
39
39
  Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document)
40
40
  end
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![Document highlight demo](../../misc/document_highlight.gif)
6
+ # ![Document highlight demo](../../document_highlight.gif)
7
7
  #
8
8
  # The [document highlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight)
9
9
  # informs the editor all relevant elements of the currently pointed item for highlighting. For example, when
@@ -5,7 +5,7 @@ require "ruby_lsp/requests/support/source_uri"
5
5
 
6
6
  module RubyLsp
7
7
  module Requests
8
- # ![Document link demo](../../misc/document_link.gif)
8
+ # ![Document link demo](../../document_link.gif)
9
9
  #
10
10
  # The [document link](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentLink)
11
11
  # makes `# source://PATH_TO_FILE#line` comments in a Ruby/RBI file clickable if the file exists.
@@ -18,8 +18,11 @@ module RubyLsp
18
18
  # def format(source, maxwidth = T.unsafe(nil))
19
19
  # end
20
20
  # ```
21
- class DocumentLink < BaseRequest
21
+ class DocumentLink < Listener
22
22
  extend T::Sig
23
+ extend T::Generic
24
+
25
+ ResponseType = type_member { { fixed: T::Array[Interface::DocumentLink] } }
23
26
 
24
27
  GEM_TO_VERSION_MAP = T.let(
25
28
  [*::Gem::Specification.default_stubs, *::Gem::Specification.stubs].map! do |s|
@@ -69,25 +72,24 @@ module RubyLsp
69
72
  end
70
73
  end
71
74
 
72
- sig { params(document: Document).void }
73
- def initialize(document)
74
- super(document)
75
+ sig { override.returns(ResponseType) }
76
+ attr_reader :response
77
+
78
+ sig { params(uri: String, emitter: EventEmitter, message_queue: Thread::Queue).void }
79
+ def initialize(uri, emitter, message_queue)
80
+ super(emitter, message_queue)
75
81
 
76
82
  # Match the version based on the version in the RBI file name. Notice that the `@` symbol is sanitized to `%40`
77
83
  # in the URI
78
- version_match = /(?<=%40)[\d.]+(?=\.rbi$)/.match(document.uri)
84
+ version_match = /(?<=%40)[\d.]+(?=\.rbi$)/.match(uri)
79
85
  @gem_version = T.let(version_match && version_match[0], T.nilable(String))
80
- @links = T.let([], T::Array[Interface::DocumentLink])
81
- end
86
+ @response = T.let([], T::Array[Interface::DocumentLink])
82
87
 
83
- sig { override.returns(T.all(T::Array[Interface::DocumentLink], Object)) }
84
- def run
85
- visit(@document.tree) if @document.parsed?
86
- @links
88
+ emitter.register(self, :on_comment)
87
89
  end
88
90
 
89
- sig { override.params(node: SyntaxTree::Comment).void }
90
- def visit_comment(node)
91
+ sig { params(node: SyntaxTree::Comment).void }
92
+ def on_comment(node)
91
93
  match = node.value.match(%r{source://.*#\d+$})
92
94
  return unless match
93
95
 
@@ -96,7 +98,7 @@ module RubyLsp
96
98
  file_path = self.class.gem_paths.dig(uri.gem_name, gem_version, uri.path)
97
99
  return if file_path.nil?
98
100
 
99
- @links << Interface::DocumentLink.new(
101
+ @response << Interface::DocumentLink.new(
100
102
  range: range_from_syntax_tree_node(node),
101
103
  target: "file://#{file_path}##{uri.line_number}",
102
104
  tooltip: "Jump to #{file_path}##{uri.line_number}",
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![Document symbol demo](../../misc/document_symbol.gif)
6
+ # ![Document symbol demo](../../document_symbol.gif)
7
7
  #
8
8
  # The [document
9
9
  # symbol](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) request
@@ -26,8 +26,11 @@ module RubyLsp
26
26
  # end
27
27
  # end
28
28
  # ```
29
- class DocumentSymbol < BaseRequest
29
+ class DocumentSymbol < Listener
30
30
  extend T::Sig
31
+ extend T::Generic
32
+
33
+ ResponseType = type_member { { fixed: T::Array[Interface::DocumentSymbol] } }
31
34
 
32
35
  SYMBOL_KIND = T.let(
33
36
  {
@@ -75,40 +78,53 @@ module RubyLsp
75
78
  end
76
79
  end
77
80
 
78
- sig { params(document: Document).void }
79
- def initialize(document)
81
+ sig { override.returns(T::Array[Interface::DocumentSymbol]) }
82
+ attr_reader :response
83
+
84
+ sig { params(emitter: EventEmitter, message_queue: Thread::Queue).void }
85
+ def initialize(emitter, message_queue)
80
86
  super
81
87
 
82
88
  @root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
89
+ @response = T.let(@root.children, T::Array[Interface::DocumentSymbol])
83
90
  @stack = T.let(
84
91
  [@root],
85
92
  T::Array[T.any(SymbolHierarchyRoot, Interface::DocumentSymbol)],
86
93
  )
87
- end
88
94
 
89
- sig { override.returns(T.all(T::Array[Interface::DocumentSymbol], Object)) }
90
- def run
91
- visit(@document.tree) if @document.parsed?
92
- @root.children
95
+ emitter.register(
96
+ self,
97
+ :on_class,
98
+ :after_class,
99
+ :on_command,
100
+ :on_const_path_field,
101
+ :on_def,
102
+ :after_def,
103
+ :on_module,
104
+ :after_module,
105
+ :on_top_const_field,
106
+ :on_var_field,
107
+ )
93
108
  end
94
109
 
95
- sig { override.params(node: SyntaxTree::ClassDeclaration).void }
96
- def visit_class(node)
97
- symbol = create_document_symbol(
110
+ sig { params(node: SyntaxTree::ClassDeclaration).void }
111
+ def on_class(node)
112
+ @stack << create_document_symbol(
98
113
  name: full_constant_name(node.constant),
99
114
  kind: :class,
100
115
  range_node: node,
101
116
  selection_range_node: node.constant,
102
117
  )
118
+ end
103
119
 
104
- @stack << symbol
105
- visit(node.bodystmt)
120
+ sig { params(node: SyntaxTree::ClassDeclaration).void }
121
+ def after_class(node)
106
122
  @stack.pop
107
123
  end
108
124
 
109
- sig { override.params(node: SyntaxTree::Command).void }
110
- def visit_command(node)
111
- return visit(node.arguments) unless ATTR_ACCESSORS.include?(node.message.value)
125
+ sig { params(node: SyntaxTree::Command).void }
126
+ def on_command(node)
127
+ return unless ATTR_ACCESSORS.include?(node.message.value)
112
128
 
113
129
  node.arguments.parts.each do |argument|
114
130
  next unless argument.is_a?(SyntaxTree::SymbolLiteral)
@@ -122,8 +138,8 @@ module RubyLsp
122
138
  end
123
139
  end
124
140
 
125
- sig { override.params(node: SyntaxTree::ConstPathField).void }
126
- def visit_const_path_field(node)
141
+ sig { params(node: SyntaxTree::ConstPathField).void }
142
+ def on_const_path_field(node)
127
143
  create_document_symbol(
128
144
  name: node.constant.value,
129
145
  kind: :constant,
@@ -132,8 +148,8 @@ module RubyLsp
132
148
  )
133
149
  end
134
150
 
135
- sig { override.params(node: SyntaxTree::DefNode).void }
136
- def visit_def(node)
151
+ sig { params(node: SyntaxTree::DefNode).void }
152
+ def on_def(node)
137
153
  target = node.target
138
154
 
139
155
  if target.is_a?(SyntaxTree::VarRef) && target.value.is_a?(SyntaxTree::Kw) && target.value.value == "self"
@@ -152,26 +168,30 @@ module RubyLsp
152
168
  )
153
169
 
154
170
  @stack << symbol
155
- visit(node.bodystmt)
171
+ end
172
+
173
+ sig { params(node: SyntaxTree::DefNode).void }
174
+ def after_def(node)
156
175
  @stack.pop
157
176
  end
158
177
 
159
- sig { override.params(node: SyntaxTree::ModuleDeclaration).void }
160
- def visit_module(node)
161
- symbol = create_document_symbol(
178
+ sig { params(node: SyntaxTree::ModuleDeclaration).void }
179
+ def on_module(node)
180
+ @stack << create_document_symbol(
162
181
  name: full_constant_name(node.constant),
163
182
  kind: :module,
164
183
  range_node: node,
165
184
  selection_range_node: node.constant,
166
185
  )
186
+ end
167
187
 
168
- @stack << symbol
169
- visit(node.bodystmt)
188
+ sig { params(node: SyntaxTree::ModuleDeclaration).void }
189
+ def after_module(node)
170
190
  @stack.pop
171
191
  end
172
192
 
173
- sig { override.params(node: SyntaxTree::TopConstField).void }
174
- def visit_top_const_field(node)
193
+ sig { params(node: SyntaxTree::TopConstField).void }
194
+ def on_top_const_field(node)
175
195
  create_document_symbol(
176
196
  name: node.constant.value,
177
197
  kind: :constant,
@@ -180,8 +200,8 @@ module RubyLsp
180
200
  )
181
201
  end
182
202
 
183
- sig { override.params(node: SyntaxTree::VarField).void }
184
- def visit_var_field(node)
203
+ sig { params(node: SyntaxTree::VarField).void }
204
+ def on_var_field(node)
185
205
  value = node.value
186
206
  kind = case value
187
207
  when SyntaxTree::Const
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![Folding ranges demo](../../misc/folding_ranges.gif)
6
+ # ![Folding ranges demo](../../folding_ranges.gif)
7
7
  #
8
8
  # The [folding ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange)
9
9
  # request informs the editor of the ranges where and how code can be folded.
@@ -6,13 +6,17 @@ require "ruby_lsp/requests/support/syntax_tree_formatting_runner"
6
6
 
7
7
  module RubyLsp
8
8
  module Requests
9
- # ![Formatting symbol demo](../../misc/formatting.gif)
9
+ # ![Formatting symbol demo](../../formatting.gif)
10
10
  #
11
11
  # The [formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting)
12
12
  # request uses RuboCop to fix auto-correctable offenses in the document. This requires enabling format on save and
13
13
  # registering the ruby-lsp as the Ruby formatter.
14
14
  #
15
- # If RuboCop is not available, the request will fall back to SyntaxTree.
15
+ # The `rubyLsp.formatter` setting specifies which formatter to use.
16
+ # If set to `auto`` then it behaves as follows:
17
+ # * It will use RuboCop if it is part of the bundle.
18
+ # * If RuboCop is not available, and `syntax_tree` is a direct dependency, it will use that.
19
+ # * Otherwise, no formatting will be applied.
16
20
  #
17
21
  # # Example
18
22
  #
@@ -32,14 +36,7 @@ module RubyLsp
32
36
  super(document)
33
37
 
34
38
  @uri = T.let(document.uri, String)
35
- @formatter = T.let(
36
- if formatter == "auto"
37
- defined?(Support::RuboCopFormattingRunner) ? "rubocop" : "syntax_tree"
38
- else
39
- formatter
40
- end,
41
- String,
42
- )
39
+ @formatter = formatter
43
40
  end
44
41
 
45
42
  sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
@@ -72,7 +69,9 @@ module RubyLsp
72
69
  def formatted_file
73
70
  case @formatter
74
71
  when "rubocop"
75
- Support::RuboCopFormattingRunner.instance.run(@uri, @document)
72
+ if defined?(Support::RuboCopFormattingRunner)
73
+ Support::RuboCopFormattingRunner.instance.run(@uri, @document)
74
+ end
76
75
  when "syntax_tree"
77
76
  Support::SyntaxTreeFormattingRunner.instance.run(@uri, @document)
78
77
  else
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![Hover demo](../../misc/rails_document_link_hover.gif)
6
+ # ![Hover demo](../../rails_document_link_hover.gif)
7
7
  #
8
8
  # The [hover request](https://microsoft.github.io/language-server-protocol/specification#textDocument_hover)
9
9
  # renders a clickable link to the code's official documentation.
@@ -35,31 +35,46 @@ module RubyLsp
35
35
  sig { override.returns(ResponseType) }
36
36
  attr_reader :response
37
37
 
38
- sig { void }
39
- def initialize
38
+ sig { params(emitter: EventEmitter, message_queue: Thread::Queue).void }
39
+ def initialize(emitter, message_queue)
40
+ super
41
+
40
42
  @response = T.let(nil, ResponseType)
41
- super()
43
+ emitter.register(self, :on_command, :on_const_path_ref, :on_call)
42
44
  end
43
45
 
44
- listener_events do
45
- sig { params(node: SyntaxTree::Command).void }
46
- def on_command(node)
47
- message = node.message
48
- @response = generate_rails_document_link_hover(message.value, message)
49
- end
46
+ # Merges responses from other hover listeners
47
+ sig { params(other: Listener[ResponseType]).returns(T.self_type) }
48
+ def merge_response!(other)
49
+ other_response = other.response
50
+ return self unless other_response
50
51
 
51
- sig { params(node: SyntaxTree::ConstPathRef).void }
52
- def on_const_path_ref(node)
53
- @response = generate_rails_document_link_hover(full_constant_name(node), node)
52
+ if @response.nil?
53
+ @response = other.response
54
+ else
55
+ @response.contents.value << other_response.contents.value << "\n\n"
54
56
  end
55
57
 
56
- sig { params(node: SyntaxTree::CallNode).void }
57
- def on_call(node)
58
- message = node.message
59
- return if message.is_a?(Symbol)
58
+ self
59
+ end
60
60
 
61
- @response = generate_rails_document_link_hover(message.value, message)
62
- end
61
+ sig { params(node: SyntaxTree::Command).void }
62
+ def on_command(node)
63
+ message = node.message
64
+ @response = generate_rails_document_link_hover(message.value, message)
65
+ end
66
+
67
+ sig { params(node: SyntaxTree::ConstPathRef).void }
68
+ def on_const_path_ref(node)
69
+ @response = generate_rails_document_link_hover(full_constant_name(node), node)
70
+ end
71
+
72
+ sig { params(node: SyntaxTree::CallNode).void }
73
+ def on_call(node)
74
+ message = node.message
75
+ return if message.is_a?(Symbol)
76
+
77
+ @response = generate_rails_document_link_hover(message.value, message)
63
78
  end
64
79
 
65
80
  private
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![Inlay hint demo](../../misc/inlay_hint.gif)
6
+ # ![Inlay hint demo](../../inlay_hint.gif)
7
7
  #
8
8
  # [Inlay hints](https://microsoft.github.io/language-server-protocol/specification#textDocument_inlayHint)
9
9
  # are labels added directly in the code that explicitly show the user something that might
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![On type formatting demo](../../misc/on_type_formatting.gif)
6
+ # ![On type formatting demo](../../on_type_formatting.gif)
7
7
  #
8
8
  # The [on type formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_onTypeFormatting)
9
9
  # request formats code as the user is typing. For example, automatically adding `end` to class definitions.
@@ -80,6 +80,10 @@ module RubyLsp
80
80
 
81
81
  sig { void }
82
82
  def handle_statement_end
83
+ # If a keyword occurs in a line which appears be a comment or a string, we will not try to format it, since
84
+ # it could be a coincidental match. This approach is not perfect, but it should cover most cases.
85
+ return if @previous_line.start_with?(/["'#]/)
86
+
83
87
  return unless END_REGEXES.any? { |regex| regex.match?(@previous_line) }
84
88
 
85
89
  indents = " " * @indentation