ruby-lsp-rails 0.3.27 → 0.3.31

Sign up to get free protection for your applications and to get access to all the features.
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