ruby-lsp-rails 0.3.27 → 0.3.31

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: 2df24f43b3e6666c310cb91e43d3b4311eea8326e27aa7bb4278c9fd03de42d1
4
- data.tar.gz: 116f736d81055adf4a287d3d76a4f9e641cf2ac81f2a39b63ccb9603bfbd351e
3
+ metadata.gz: b1d9f0d516dcad6d833e05e05defd6ba7ea0bbb3fb2b0c48e7edb9709306d854
4
+ data.tar.gz: 41b2f9dec0e1ba1d3d4d92a5eb1b4ad5dfd6b6d8c3e62b69822ac156f3232bfd
5
5
  SHA512:
6
- metadata.gz: c462629b903ebbee663323f52385423fb697bd338bcf7c57574874de21f323230d381c5d6e5eb30602248f33021bc2d0082602fa3b5c0b65d674f9c9c1668ff5
7
- data.tar.gz: e909ea43dc3a8012f1de165e1aa4cbf4ad0873134199273103e329fec5ac141792113adb5eb1eb788f065f63e3c2fba299c0501a837719a816b2698e119e50bf
6
+ metadata.gz: f4421fb81f4cffaa89abe05244ec8bcc2da8ffa0e27b5f7c310c49747d7b2e20a6eec85b58dfe77f5107bd8281ca9d2e61a5f70b2d100c5938f4a2932deedfd0
7
+ data.tar.gz: aa8476c6f72a66782d9d8b3225944c862f708cd9fc60fd17cf871d9f3332885bd0b7060cbf778710e9213686d5e24c1e415327c14a00a738e28f934dfae156c7
@@ -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
@@ -119,6 +120,18 @@ module RubyLsp
119
120
  Definition.new(@rails_runner_client, response_builder, node_context, index, dispatcher)
120
121
  end
121
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
+
122
135
  sig { params(changes: T::Array[{ uri: String, type: Integer }]).void }
123
136
  def workspace_did_change_watched_files(changes)
124
137
  if changes.any? { |c| c[:uri].end_with?("db/schema.rb") || c[:uri].end_with?("structure.sql") }
@@ -210,12 +223,7 @@ module RubyLsp
210
223
  id: "workspace/didChangeWatchedFilesRails",
211
224
  method: "workspace/didChangeWatchedFiles",
212
225
  register_options: Interface::DidChangeWatchedFilesRegistrationOptions.new(
213
- watchers: [
214
- Interface::FileSystemWatcher.new(
215
- glob_pattern: "**/*structure.sql",
216
- kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE,
217
- ),
218
- ],
226
+ watchers: [structure_sql_file_watcher, fixture_file_watcher],
219
227
  ),
220
228
  ),
221
229
  ],
@@ -223,6 +231,22 @@ module RubyLsp
223
231
  )
224
232
  end
225
233
 
234
+ sig { returns(Interface::FileSystemWatcher) }
235
+ def structure_sql_file_watcher
236
+ Interface::FileSystemWatcher.new(
237
+ glob_pattern: "**/*structure.sql",
238
+ kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE,
239
+ )
240
+ end
241
+
242
+ sig { returns(Interface::FileSystemWatcher) }
243
+ def fixture_file_watcher
244
+ Interface::FileSystemWatcher.new(
245
+ glob_pattern: "**/fixtures/**/*.{yml,yaml,yml.erb,yaml.erb}",
246
+ kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE,
247
+ )
248
+ end
249
+
226
250
  sig { void }
227
251
  def offer_to_run_pending_migrations
228
252
  return unless @outgoing_queue
@@ -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
@@ -105,6 +105,8 @@ module RubyLsp
105
105
  while (content = @stderr.gets("\n"))
106
106
  log_message(content, type: RubyLsp::Constant::MessageType::LOG)
107
107
  end
108
+ rescue IOError
109
+ # The server was shutdown and stderr is already closed
108
110
  end,
109
111
  Thread,
110
112
  )
@@ -281,7 +283,7 @@ module RubyLsp
281
283
  json = message.to_json
282
284
 
283
285
  @mutex.synchronize do
284
- @stdin.write("Content-Length: #{json.length}\r\n\r\n", json)
286
+ @stdin.write("Content-Length: #{json.bytesize}\r\n\r\n", json)
285
287
  end
286
288
  rescue Errno::EPIPE
287
289
  # The server connection died
@@ -4,16 +4,13 @@
4
4
  require "json"
5
5
  require "open3"
6
6
 
7
- # NOTE: We should avoid printing to stderr since it causes problems. We never read the standard error pipe from the
8
- # client, so it will become full and eventually hang or crash. Instead, return a response with an `error` key.
9
-
10
7
  module RubyLsp
11
8
  module Rails
12
9
  module Common
13
10
  # Write a message to the client. Can be used for sending notifications to the editor
14
11
  def send_message(message)
15
12
  json_message = message.to_json
16
- @stdout.write("Content-Length: #{json_message.length}\r\n\r\n#{json_message}")
13
+ @stdout.write("Content-Length: #{json_message.bytesize}\r\n\r\n#{json_message}")
17
14
  end
18
15
 
19
16
  # Log a message to the editor's output panel
@@ -125,6 +122,7 @@ module RubyLsp
125
122
 
126
123
  def start
127
124
  load_routes
125
+ clear_file_system_resolver_hooks
128
126
  send_result({ message: "ok", root: ::Rails.root.to_s })
129
127
 
130
128
  while @running
@@ -302,6 +300,18 @@ module RubyLsp
302
300
  routes_reloader.execute_unless_loaded if routes_reloader&.respond_to?(:execute_unless_loaded)
303
301
  end
304
302
  end
303
+
304
+ # File system resolver hooks spawn file watcher threads which introduce unnecessary overhead since the LSP already
305
+ # watches files. Since the Rails application is already booted by the time we reach this script, we can't no-op
306
+ # the file watcher implementation. Instead, we clear the hooks to prevent the registered file watchers from being
307
+ # instantiated
308
+ def clear_file_system_resolver_hooks
309
+ return unless defined?(::ActionView::PathRegistry)
310
+
311
+ with_notification_error_handling("clear_file_system_resolver_hooks") do
312
+ ::ActionView::PathRegistry.file_system_resolver_hooks.clear
313
+ end
314
+ end
305
315
  end
306
316
  end
307
317
  end
@@ -3,6 +3,6 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Rails
6
- VERSION = "0.3.27"
6
+ VERSION = "0.3.31"
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.27
4
+ version: 0.3.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-11-22 00:00:00.000000000 Z
10
+ date: 2025-01-23 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.22.0
18
+ version: 0.23.0
20
19
  - - "<"
21
20
  - !ruby/object:Gem::Version
22
- version: 0.23.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.22.0
28
+ version: 0.23.0
30
29
  - - "<"
31
30
  - !ruby/object:Gem::Version
32
- version: 0.23.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