ruby-lsp-rails 0.3.26 → 0.3.28

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df7c6791cb1fc007fc4705e034eb60cde1d5905a1771b145c2d4bb6f36224658
4
- data.tar.gz: 1fdd80b7787bf31a237aa9f9f196c3170ee5e612ce8105c2fc20a63fd9027f73
3
+ metadata.gz: 231b488bf88047c642f2556980d6c0ce96edbeafbf2ded65a4104515584a5100
4
+ data.tar.gz: 207b91a283859f74804b4e825d4ca71ee645b0f73ac84e5d7e7348b382bf2745
5
5
  SHA512:
6
- metadata.gz: 8de8df639f440b7bcedb854e03ead56eb56517569dc31938759593cce32ff87d968b07b88598de01939fab8d3e1b8bb73108cf21b85c7f30493093d1f8d2973a
7
- data.tar.gz: 69550bcd5575bf7d8f6f82e7e738e53392fd776534dc88495274ab500e9ea3e11472e1008d05fe27de3ae40beee9a43d039be49866902e569ec7fdd0c91af161
6
+ metadata.gz: 8ef4e5363a31a1821da8d43738c5049239e827d609ffa8c8214f9e8fae148739770614a4f06af082da98a755bfd3522426560936d1ac57f0c14092ace8ced86b
7
+ data.tar.gz: 348fab1dc3ada6a6a2672c4c9b54e0ae0f67f2f056023929af7c76dac5d66583c32c9fbdcc1347fc3913cb59a3e30ae7e495977b762228aad6a52f502254a930
@@ -2,15 +2,3 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "ruby_lsp_rails/version"
5
- require "ruby_lsp_rails/railtie"
6
-
7
- module RubyLsp
8
- # # Supported features
9
- #
10
- # - [Hover](rdoc-ref:RubyLsp::Rails::Hover)
11
- # - [CodeLens](rdoc-ref:RubyLsp::Rails::CodeLens)
12
- # - [DocumentSymbol](rdoc-ref:RubyLsp::Rails::DocumentSymbol)
13
- # - [Definition](rdoc-ref:RubyLsp::Rails::Definition)
14
- module Rails
15
- end
16
- end
@@ -13,6 +13,7 @@ require_relative "hover"
13
13
  require_relative "code_lens"
14
14
  require_relative "document_symbol"
15
15
  require_relative "definition"
16
+ require_relative "completion"
16
17
  require_relative "indexing_enhancement"
17
18
 
18
19
  module RubyLsp
@@ -56,7 +57,6 @@ module RubyLsp
56
57
  @outgoing_queue << Notification.window_log_message("Activating Ruby LSP Rails add-on v#{VERSION}")
57
58
 
58
59
  register_additional_file_watchers(global_state: global_state, outgoing_queue: outgoing_queue)
59
- @global_state.index.register_enhancement(IndexingEnhancement.new(@global_state.index))
60
60
 
61
61
  # Start booting the real client in a background thread. Until this completes, the client will be a NullClient
62
62
  @client_mutex.unlock
@@ -120,6 +120,18 @@ module RubyLsp
120
120
  Definition.new(@rails_runner_client, response_builder, node_context, index, dispatcher)
121
121
  end
122
122
 
123
+ sig do
124
+ override.params(
125
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
126
+ node_context: NodeContext,
127
+ dispatcher: Prism::Dispatcher,
128
+ uri: URI::Generic,
129
+ ).void
130
+ end
131
+ def create_completion_listener(response_builder, node_context, dispatcher, uri)
132
+ Completion.new(@rails_runner_client, response_builder, node_context, dispatcher, uri)
133
+ end
134
+
123
135
  sig { params(changes: T::Array[{ uri: String, type: Integer }]).void }
124
136
  def workspace_did_change_watched_files(changes)
125
137
  if changes.any? { |c| c[:uri].end_with?("db/schema.rb") || c[:uri].end_with?("structure.sql") }
@@ -254,7 +254,7 @@ module RubyLsp
254
254
 
255
255
  @response_builder << create_code_lens(
256
256
  node,
257
- title: "Run",
257
+ title: "Run",
258
258
  command_name: "rubyLsp.runTask",
259
259
  arguments: [command],
260
260
  data: { type: "migrate" },
@@ -283,7 +283,7 @@ module RubyLsp
283
283
 
284
284
  @response_builder << create_code_lens(
285
285
  node,
286
- title: "Run",
286
+ title: "Run",
287
287
  command_name: "rubyLsp.runTest",
288
288
  arguments: arguments,
289
289
  data: { type: "test", **grouping_data },
@@ -291,7 +291,7 @@ module RubyLsp
291
291
 
292
292
  @response_builder << create_code_lens(
293
293
  node,
294
- title: "Run In Terminal",
294
+ title: "Run In Terminal",
295
295
  command_name: "rubyLsp.runTestInTerminal",
296
296
  arguments: arguments,
297
297
  data: { type: "test_in_terminal", **grouping_data },
@@ -0,0 +1,92 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Rails
6
+ class Completion
7
+ extend T::Sig
8
+ include Requests::Support::Common
9
+
10
+ sig do
11
+ override.params(
12
+ client: RunnerClient,
13
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
14
+ node_context: NodeContext,
15
+ dispatcher: Prism::Dispatcher,
16
+ uri: URI::Generic,
17
+ ).void
18
+ end
19
+ def initialize(client, response_builder, node_context, dispatcher, uri)
20
+ @response_builder = response_builder
21
+ @client = client
22
+ @node_context = node_context
23
+ dispatcher.register(
24
+ self,
25
+ :on_call_node_enter,
26
+ )
27
+ end
28
+
29
+ sig { params(node: Prism::CallNode).void }
30
+ def on_call_node_enter(node)
31
+ call_node = @node_context.call_node
32
+ return unless call_node
33
+
34
+ receiver = call_node.receiver
35
+ if call_node.name == :where && receiver.is_a?(Prism::ConstantReadNode)
36
+ handle_active_record_where_completions(node: node, receiver: receiver)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ sig { params(node: Prism::CallNode, receiver: Prism::ConstantReadNode).void }
43
+ def handle_active_record_where_completions(node:, receiver:)
44
+ resolved_class = @client.model(receiver.name.to_s)
45
+ return if resolved_class.nil?
46
+
47
+ arguments = T.must(@node_context.call_node).arguments&.arguments
48
+ indexed_call_node_args = T.let({}, T::Hash[String, Prism::Node])
49
+
50
+ if arguments
51
+ indexed_call_node_args = index_call_node_args(arguments: arguments)
52
+ return if indexed_call_node_args.values.any? { |v| v == node }
53
+ end
54
+
55
+ range = range_from_location(node.location)
56
+
57
+ resolved_class[:columns].each do |column|
58
+ next unless column[0].start_with?(node.name.to_s)
59
+ next if indexed_call_node_args.key?(column[0])
60
+
61
+ @response_builder << Interface::CompletionItem.new(
62
+ label: column[0],
63
+ filter_text: column[0],
64
+ label_details: Interface::CompletionItemLabelDetails.new(
65
+ description: "Filter #{receiver.name} records by #{column[0]}",
66
+ ),
67
+ text_edit: Interface::TextEdit.new(range: range, new_text: "#{column[0]}: "),
68
+ kind: Constant::CompletionItemKind::FIELD,
69
+ )
70
+ end
71
+ end
72
+
73
+ sig { params(arguments: T::Array[Prism::Node]).returns(T::Hash[String, Prism::Node]) }
74
+ def index_call_node_args(arguments:)
75
+ indexed_call_node_args = {}
76
+ arguments.each do |argument|
77
+ next unless argument.is_a?(Prism::KeywordHashNode)
78
+
79
+ argument.elements.each do |e|
80
+ next unless e.is_a?(Prism::AssocNode)
81
+
82
+ key = e.key
83
+ if key.is_a?(Prism::SymbolNode)
84
+ indexed_call_node_args[key.value] = e.value
85
+ end
86
+ end
87
+ end
88
+ indexed_call_node_args
89
+ end
90
+ end
91
+ end
92
+ end
@@ -144,15 +144,9 @@ module RubyLsp
144
144
  return unless methods
145
145
 
146
146
  methods.each do |target_method|
147
- location = target_method.location
148
- file_path = target_method.file_path
149
-
150
147
  @response_builder << Interface::Location.new(
151
- uri: URI::Generic.from_path(path: file_path).to_s,
152
- range: Interface::Range.new(
153
- start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
154
- end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
155
- ),
148
+ uri: target_method.uri.to_s,
149
+ range: range_from_location(target_method.location),
156
150
  )
157
151
  end
158
152
  end
@@ -8,25 +8,32 @@ module RubyLsp
8
8
 
9
9
  sig do
10
10
  override.params(
11
- owner: T.nilable(RubyIndexer::Entry::Namespace),
12
- node: Prism::CallNode,
13
- file_path: String,
14
- code_units_cache: T.any(
15
- T.proc.params(arg0: Integer).returns(Integer),
16
- Prism::CodeUnitsCache,
17
- ),
11
+ call_node: Prism::CallNode,
18
12
  ).void
19
13
  end
20
- def on_call_node_enter(owner, node, file_path, code_units_cache)
14
+ def on_call_node_enter(call_node)
15
+ owner = @listener.current_owner
21
16
  return unless owner
22
17
 
23
- name = node.name
24
-
25
- case name
18
+ case call_node.name
26
19
  when :extend
27
- handle_concern_extend(owner, node)
20
+ handle_concern_extend(owner, call_node)
28
21
  when :has_one, :has_many, :belongs_to, :has_and_belongs_to_many
29
- handle_association(owner, node, file_path, code_units_cache)
22
+ handle_association(owner, call_node)
23
+ # for `class_methods do` blocks within concerns
24
+ when :class_methods
25
+ handle_class_methods(owner, call_node)
26
+ end
27
+ end
28
+
29
+ sig do
30
+ override.params(
31
+ call_node: Prism::CallNode,
32
+ ).void
33
+ end
34
+ def on_call_node_leave(call_node)
35
+ if call_node.name == :class_methods && call_node.block
36
+ @listener.pop_namespace_stack
30
37
  end
31
38
  end
32
39
 
@@ -35,16 +42,11 @@ module RubyLsp
35
42
  sig do
36
43
  params(
37
44
  owner: RubyIndexer::Entry::Namespace,
38
- node: Prism::CallNode,
39
- file_path: String,
40
- code_units_cache: T.any(
41
- T.proc.params(arg0: Integer).returns(Integer),
42
- Prism::CodeUnitsCache,
43
- ),
45
+ call_node: Prism::CallNode,
44
46
  ).void
45
47
  end
46
- def handle_association(owner, node, file_path, code_units_cache)
47
- arguments = node.arguments&.arguments
48
+ def handle_association(owner, call_node)
49
+ arguments = call_node.arguments&.arguments
48
50
  return unless arguments
49
51
 
50
52
  name_arg = arguments.first
@@ -58,41 +60,22 @@ module RubyLsp
58
60
 
59
61
  return unless name
60
62
 
61
- loc = RubyIndexer::Location.from_prism_location(name_arg.location, code_units_cache)
63
+ loc = name_arg.location
62
64
 
63
65
  # Reader
64
- @index.add(RubyIndexer::Entry::Method.new(
65
- name,
66
- file_path,
67
- loc,
68
- loc,
69
- nil,
70
- [RubyIndexer::Entry::Signature.new([])],
71
- RubyIndexer::Entry::Visibility::PUBLIC,
72
- owner,
73
- ))
66
+ reader_signatures = [RubyIndexer::Entry::Signature.new([])]
67
+ @listener.add_method(name, loc, reader_signatures)
74
68
 
75
69
  # Writer
76
- @index.add(RubyIndexer::Entry::Method.new(
77
- "#{name}=",
78
- file_path,
79
- loc,
80
- loc,
81
- nil,
82
- [RubyIndexer::Entry::Signature.new([RubyIndexer::Entry::RequiredParameter.new(name: name.to_sym)])],
83
- RubyIndexer::Entry::Visibility::PUBLIC,
84
- owner,
85
- ))
70
+ writer_signatures = [
71
+ RubyIndexer::Entry::Signature.new([RubyIndexer::Entry::RequiredParameter.new(name: name.to_sym)]),
72
+ ]
73
+ @listener.add_method("#{name}=", loc, writer_signatures)
86
74
  end
87
75
 
88
- sig do
89
- params(
90
- owner: RubyIndexer::Entry::Namespace,
91
- node: Prism::CallNode,
92
- ).void
93
- end
94
- def handle_concern_extend(owner, node)
95
- arguments = node.arguments&.arguments
76
+ sig { params(owner: RubyIndexer::Entry::Namespace, call_node: Prism::CallNode).void }
77
+ def handle_concern_extend(owner, call_node)
78
+ arguments = call_node.arguments&.arguments
96
79
  return unless arguments
97
80
 
98
81
  arguments.each do |node|
@@ -101,7 +84,7 @@ module RubyLsp
101
84
  module_name = node.full_name
102
85
  next unless module_name == "ActiveSupport::Concern"
103
86
 
104
- @index.register_included_hook(owner.name) do |index, base|
87
+ @listener.register_included_hook do |index, base|
105
88
  class_methods_name = "#{owner.name}::ClassMethods"
106
89
 
107
90
  if index.indexed?(class_methods_name)
@@ -114,6 +97,13 @@ module RubyLsp
114
97
  # Do nothing
115
98
  end
116
99
  end
100
+
101
+ sig { params(owner: RubyIndexer::Entry::Namespace, call_node: Prism::CallNode).void }
102
+ def handle_class_methods(owner, call_node)
103
+ return unless call_node.block
104
+
105
+ @listener.add_module("ClassMethods", call_node.location, call_node.location)
106
+ end
117
107
  end
118
108
  end
119
109
  end
@@ -27,7 +27,7 @@ module RubyLsp
27
27
 
28
28
  NullClient.new
29
29
  end
30
- rescue Errno::ENOENT, StandardError => e # rubocop:disable Lint/ShadowedException
30
+ rescue StandardError => e
31
31
  unless outgoing_queue.closed?
32
32
  outgoing_queue << RubyLsp::Notification.window_log_message(
33
33
  <<~MESSAGE.chomp,
@@ -44,7 +44,6 @@ module RubyLsp
44
44
 
45
45
  class InitializationError < StandardError; end
46
46
  class MessageError < StandardError; end
47
- class IncompleteMessageError < MessageError; end
48
47
  class EmptyMessageError < MessageError; end
49
48
 
50
49
  extend T::Sig
@@ -109,7 +108,7 @@ module RubyLsp
109
108
  end,
110
109
  Thread,
111
110
  )
112
- rescue Errno::EPIPE, IncompleteMessageError
111
+ rescue StandardError
113
112
  raise InitializationError, @stderr.read
114
113
  end
115
114
 
@@ -282,7 +281,7 @@ module RubyLsp
282
281
  json = message.to_json
283
282
 
284
283
  @mutex.synchronize do
285
- @stdin.write("Content-Length: #{json.length}\r\n\r\n", json)
284
+ @stdin.write("Content-Length: #{json.bytesize}\r\n\r\n", json)
286
285
  end
287
286
  rescue Errno::EPIPE
288
287
  # The server connection died
@@ -13,13 +13,49 @@ module RubyLsp
13
13
  # Write a message to the client. Can be used for sending notifications to the editor
14
14
  def send_message(message)
15
15
  json_message = message.to_json
16
- @stdout.write("Content-Length: #{json_message.length}\r\n\r\n#{json_message}")
16
+ @stdout.write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
17
17
  end
18
18
 
19
19
  # Log a message to the editor's output panel
20
20
  def log_message(message)
21
21
  $stderr.puts(message)
22
- send_message({ result: nil })
22
+ end
23
+
24
+ # Sends an error result to a request, if the request failed. DO NOT INVOKE THIS METHOD FOR NOTIFICATIONS! Use
25
+ # `log_message` instead, otherwise the client/server communication will go out of sync
26
+ def send_error_response(message)
27
+ send_message({ error: message })
28
+ end
29
+
30
+ # Sends a result back to the client
31
+ def send_result(result)
32
+ send_message({ result: result })
33
+ end
34
+
35
+ # Handle possible errors for a request. This should only be used for requests, which means messages that return a
36
+ # response back to the client. Errors are returned as an error object back to the client
37
+ def with_request_error_handling(request_name, &block)
38
+ block.call
39
+ rescue ActiveRecord::ConnectionNotEstablished
40
+ # Since this is a common problem, we show a specific error message to the user, instead of the full stack trace.
41
+ send_error_response("Request #{request_name} failed because database connection was not established.")
42
+ rescue ActiveRecord::NoDatabaseError
43
+ send_error_response("Request #{request_name} failed because the database does not exist.")
44
+ rescue => e
45
+ send_error_response("Request #{request_name} failed:\n#{e.full_message(highlight: false)}")
46
+ end
47
+
48
+ # Handle possible errors for a notification. This should only be used for notifications, which means messages that
49
+ # do not return a response back to the client. Errors are logged to the editor's output panel
50
+ def with_notification_error_handling(notification_name, &block)
51
+ block.call
52
+ rescue ActiveRecord::ConnectionNotEstablished
53
+ # Since this is a common problem, we show a specific error message to the user, instead of the full stack trace.
54
+ log_message("Request #{notification_name} failed because database connection was not established.")
55
+ rescue ActiveRecord::NoDatabaseError
56
+ log_message("Request #{notification_name} failed because the database does not exist.")
57
+ rescue => e
58
+ log_message("Request #{notification_name} failed:\n#{e.full_message(highlight: false)}")
23
59
  end
24
60
  end
25
61
 
@@ -88,11 +124,8 @@ module RubyLsp
88
124
  end
89
125
 
90
126
  def start
91
- # Load routes if they haven't been loaded yet (see https://github.com/rails/rails/pull/51614).
92
- routes_reloader = ::Rails.application.routes_reloader
93
- routes_reloader.execute_unless_loaded if routes_reloader&.respond_to?(:execute_unless_loaded)
94
-
95
- send_message({ result: { message: "ok", root: ::Rails.root.to_s } })
127
+ load_routes
128
+ send_result({ message: "ok", root: ::Rails.root.to_s })
96
129
 
97
130
  while @running
98
131
  headers = @stdin.gets("\r\n\r\n")
@@ -104,41 +137,50 @@ module RubyLsp
104
137
  end
105
138
 
106
139
  def execute(request, params)
107
- request_name = request
108
- request_name = "#{params[:server_addon_name]}##{params[:request_name]}" if request == "server_addon/delegate"
109
-
110
140
  case request
111
141
  when "shutdown"
112
142
  @running = false
113
143
  when "model"
114
- send_message(resolve_database_info_from_model(params.fetch(:name)))
144
+ with_request_error_handling(request) do
145
+ send_result(resolve_database_info_from_model(params.fetch(:name)))
146
+ end
115
147
  when "association_target_location"
116
- send_message(resolve_association_target(params))
148
+ with_request_error_handling(request) do
149
+ send_result(resolve_association_target(params))
150
+ end
117
151
  when "pending_migrations_message"
118
- send_message({ result: { pending_migrations_message: pending_migrations_message } })
152
+ with_request_error_handling(request) do
153
+ send_result({ pending_migrations_message: pending_migrations_message })
154
+ end
119
155
  when "run_migrations"
120
- send_message({ result: run_migrations })
156
+ with_request_error_handling(request) do
157
+ send_result(run_migrations)
158
+ end
121
159
  when "reload"
122
- ::Rails.application.reloader.reload!
160
+ with_notification_error_handling(request) do
161
+ ::Rails.application.reloader.reload!
162
+ end
123
163
  when "route_location"
124
- send_message(route_location(params.fetch(:name)))
164
+ with_request_error_handling(request) do
165
+ send_result(route_location(params.fetch(:name)))
166
+ end
125
167
  when "route_info"
126
- send_message(resolve_route_info(params))
168
+ with_request_error_handling(request) do
169
+ send_result(resolve_route_info(params))
170
+ end
127
171
  when "server_addon/register"
128
- require params[:server_addon_path]
129
- ServerAddon.finalize_registrations!(@stdout)
172
+ with_notification_error_handling(request) do
173
+ require params[:server_addon_path]
174
+ ServerAddon.finalize_registrations!(@stdout)
175
+ end
130
176
  when "server_addon/delegate"
131
177
  server_addon_name = params[:server_addon_name]
132
178
  request_name = params[:request_name]
179
+
180
+ # Do not wrap this in error handlers. Server add-ons need to have the flexibility to choose if they want to
181
+ # include a response or not as part of error handling, so a blanket approach is not appropriate.
133
182
  ServerAddon.delegate(server_addon_name, request_name, params.except(:request_name, :server_addon_name))
134
183
  end
135
- # Since this is a common problem, we show a specific error message to the user, instead of the full stack trace.
136
- rescue ActiveRecord::ConnectionNotEstablished
137
- log_message("Request #{request_name} failed because database connection was not established.")
138
- rescue ActiveRecord::NoDatabaseError
139
- log_message("Request #{request_name} failed because the database does not exist.")
140
- rescue => e
141
- log_message("Request #{request_name} failed:\n" + e.full_message(highlight: false))
142
184
  end
143
185
 
144
186
  private
@@ -156,19 +198,15 @@ module RubyLsp
156
198
  end
157
199
 
158
200
  source_location = route&.respond_to?(:source_location) && route.source_location
201
+ return unless source_location
159
202
 
160
- if source_location
161
- file, _, line = source_location.rpartition(":")
162
- body = {
163
- source_location: [::Rails.root.join(file).to_s, line],
164
- verb: route.verb,
165
- path: route.path.spec.to_s,
166
- }
203
+ file, _, line = source_location.rpartition(":")
167
204
 
168
- { result: body }
169
- else
170
- { result: nil }
171
- end
205
+ {
206
+ source_location: [::Rails.root.join(file).to_s, line],
207
+ verb: route.verb,
208
+ path: route.path.spec.to_s,
209
+ }
172
210
  end
173
211
 
174
212
  # Older versions of Rails don't support `route_source_locations`.
@@ -182,74 +220,48 @@ module RubyLsp
182
220
  end
183
221
 
184
222
  match_data = name.match(/^(.+)(_path|_url)$/)
185
- return { result: nil } unless match_data
223
+ return unless match_data
186
224
 
187
225
  key = match_data[1]
188
226
 
189
227
  # A token could match the _path or _url pattern, but not be an actual route.
190
228
  route = ::Rails.application.routes.named_routes.get(key)
191
- return { result: nil } unless route&.source_location
192
-
193
- {
194
- result: {
195
- location: ::Rails.root.join(route.source_location).to_s,
196
- },
197
- }
198
- rescue => e
199
- { error: e.full_message(highlight: false) }
229
+ return unless route&.source_location
230
+
231
+ { location: ::Rails.root.join(route.source_location).to_s }
200
232
  end
201
233
  else
202
234
  def route_location(name)
203
- { result: nil }
235
+ nil
204
236
  end
205
237
  end
206
238
 
207
239
  def resolve_database_info_from_model(model_name)
208
240
  const = ActiveSupport::Inflector.safe_constantize(model_name)
209
- unless active_record_model?(const)
210
- return {
211
- result: nil,
212
- }
213
- end
241
+ return unless active_record_model?(const)
214
242
 
215
243
  info = {
216
- result: {
217
- columns: const.columns.map { |column| [column.name, column.type, column.default, column.null] },
218
- primary_keys: Array(const.primary_key),
219
- },
244
+ columns: const.columns.map { |column| [column.name, column.type, column.default, column.null] },
245
+ primary_keys: Array(const.primary_key),
220
246
  }
221
247
 
222
248
  if ActiveRecord::Tasks::DatabaseTasks.respond_to?(:schema_dump_path)
223
- info[:result][:schema_file] =
224
- ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(const.connection.pool.db_config)
225
-
249
+ info[:schema_file] = ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(const.connection.pool.db_config)
226
250
  end
251
+
227
252
  info
228
- rescue => e
229
- { error: e.full_message(highlight: false) }
230
253
  end
231
254
 
232
255
  def resolve_association_target(params)
233
256
  const = ActiveSupport::Inflector.safe_constantize(params[:model_name])
234
- unless active_record_model?(const)
235
- return {
236
- result: nil,
237
- }
238
- end
257
+ return unless active_record_model?(const)
239
258
 
240
259
  association_klass = const.reflect_on_association(params[:association_name].intern).klass
241
-
242
260
  source_location = Object.const_source_location(association_klass.to_s)
243
261
 
244
- {
245
- result: {
246
- location: source_location.first + ":" + source_location.second.to_s,
247
- },
248
- }
262
+ { location: source_location.first + ":" + source_location.second.to_s }
249
263
  rescue NameError
250
- {
251
- result: nil,
252
- }
264
+ nil
253
265
  end
254
266
 
255
267
  def active_record_model?(const)
@@ -282,6 +294,14 @@ module RubyLsp
282
294
 
283
295
  { message: stdout, status: status.exitstatus }
284
296
  end
297
+
298
+ def load_routes
299
+ with_notification_error_handling("initial_load_routes") do
300
+ # Load routes if they haven't been loaded yet (see https://github.com/rails/rails/pull/51614).
301
+ routes_reloader = ::Rails.application.routes_reloader
302
+ routes_reloader.execute_unless_loaded if routes_reloader&.respond_to?(:execute_unless_loaded)
303
+ end
304
+ end
285
305
  end
286
306
  end
287
307
  end
@@ -3,6 +3,6 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Rails
6
- VERSION = "0.3.26"
6
+ VERSION = "0.3.28"
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.26
4
+ version: 0.3.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-11-08 00:00:00.000000000 Z
10
+ date: 2025-01-07 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: ruby-lsp
@@ -16,20 +15,20 @@ dependencies:
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: 0.21.2
18
+ version: 0.23.0
20
19
  - - "<"
21
20
  - !ruby/object:Gem::Version
22
- version: 0.22.0
21
+ version: 0.24.0
23
22
  type: :runtime
24
23
  prerelease: false
25
24
  version_requirements: !ruby/object:Gem::Requirement
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
29
- version: 0.21.2
28
+ version: 0.23.0
30
29
  - - "<"
31
30
  - !ruby/object:Gem::Version
32
- version: 0.22.0
31
+ version: 0.24.0
33
32
  description: A Ruby LSP addon that adds extra editor functionality for Rails applications
34
33
  email:
35
34
  - ruby@shopify.com
@@ -43,6 +42,7 @@ files:
43
42
  - lib/ruby-lsp-rails.rb
44
43
  - lib/ruby_lsp/ruby_lsp_rails/addon.rb
45
44
  - lib/ruby_lsp/ruby_lsp_rails/code_lens.rb
45
+ - lib/ruby_lsp/ruby_lsp_rails/completion.rb
46
46
  - lib/ruby_lsp/ruby_lsp_rails/definition.rb
47
47
  - lib/ruby_lsp/ruby_lsp_rails/document_symbol.rb
48
48
  - lib/ruby_lsp/ruby_lsp_rails/hover.rb
@@ -53,7 +53,6 @@ files:
53
53
  - lib/ruby_lsp/ruby_lsp_rails/support/associations.rb
54
54
  - lib/ruby_lsp/ruby_lsp_rails/support/callbacks.rb
55
55
  - lib/ruby_lsp/ruby_lsp_rails/support/location_builder.rb
56
- - lib/ruby_lsp_rails/railtie.rb
57
56
  - lib/ruby_lsp_rails/version.rb
58
57
  - lib/tasks/ruby_lsp_rails_tasks.rake
59
58
  homepage: https://github.com/Shopify/ruby-lsp-rails
@@ -65,7 +64,6 @@ metadata:
65
64
  source_code_uri: https://github.com/Shopify/ruby-lsp-rails
66
65
  changelog_uri: https://github.com/Shopify/ruby-lsp-rails/releases
67
66
  documentation_uri: https://shopify.github.io/ruby-lsp/rails-add-on.html
68
- post_install_message:
69
67
  rdoc_options: []
70
68
  require_paths:
71
69
  - lib
@@ -80,8 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
78
  - !ruby/object:Gem::Version
81
79
  version: '0'
82
80
  requirements: []
83
- rubygems_version: 3.5.23
84
- signing_key:
81
+ rubygems_version: 3.6.2
85
82
  specification_version: 4
86
83
  summary: A Ruby LSP addon for Rails
87
84
  test_files: []
@@ -1,21 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require "rails"
5
-
6
- module RubyLsp
7
- module Rails
8
- class Railtie < ::Rails::Railtie
9
- config.ruby_lsp_rails = ActiveSupport::OrderedOptions.new
10
-
11
- initializer "ruby_lsp_rails.setup" do |_app|
12
- config.after_initialize do |_app|
13
- unless config.ruby_lsp_rails.server.nil?
14
- ActiveSupport::Deprecation.new.warn("The `ruby_lsp_rails.server` configuration option is no longer " \
15
- "needed and will be removed in a future release.")
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end