Skip to content

Commit 379dfc4

Browse files
authored
Merge pull request #157 from Shopify/migrate-to-yarp
Use YARP-based ruby-lsp
2 parents 3f77449 + 8320daa commit 379dfc4

File tree

17 files changed

+15461
-21002
lines changed

17 files changed

+15461
-21002
lines changed

Gemfile.lock

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ PATH
104104
specs:
105105
ruby-lsp-rails (0.2.5)
106106
rails (>= 6.0)
107-
ruby-lsp (>= 0.10.0, < 0.11.0)
107+
ruby-lsp (>= 0.11.0, < 0.12.0)
108108
sorbet-runtime (>= 0.5.9897)
109109

110110
GEM
@@ -221,11 +221,10 @@ GEM
221221
rubocop (~> 1.51)
222222
rubocop-sorbet (0.7.4)
223223
rubocop (>= 0.90.0)
224-
ruby-lsp (0.10.1)
224+
ruby-lsp (0.11.0)
225225
language_server-protocol (~> 3.17.0)
226-
sorbet-runtime
227-
syntax_tree (>= 6.1.1, < 7)
228-
yarp (>= 0.11, < 0.12)
226+
sorbet-runtime (>= 0.5.5685)
227+
yarp (>= 0.12, < 0.13)
229228
ruby-progressbar (1.13.0)
230229
ruby2_keywords (0.0.5)
231230
sorbet (0.5.11054)
@@ -244,7 +243,7 @@ GEM
244243
sqlite3 (1.6.6)
245244
mini_portile2 (~> 2.8.0)
246245
stringio (3.0.8)
247-
syntax_tree (6.1.1)
246+
syntax_tree (6.2.0)
248247
prettier_print (>= 1.2.0)
249248
tapioca (0.11.9)
250249
bundler (>= 2.2.25)
@@ -270,7 +269,7 @@ GEM
270269
yard-sorbet (0.8.1)
271270
sorbet-runtime (>= 0.5)
272271
yard (>= 0.9)
273-
yarp (0.11.0)
272+
yarp (0.12.0)
274273
zeitwerk (2.6.12)
275274

276275
PLATFORMS

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Ruby LSP Rails
22

3-
Ruby LSP Rails is a [Ruby LSP](https://github.com/Shopify/ruby-lsp) extension for extra Rails editor features, such as:
3+
Ruby LSP Rails is a [Ruby LSP](https://github.com/Shopify/ruby-lsp) addon for extra Rails editor features, such as:
44

55
- Displaying an ActiveRecord model's database columns and types when hovering over it
66
- Running tests and debugging tests through the terminal or the editor's UI
@@ -56,7 +56,7 @@ cause the test runner to hang.
5656
This gem consists of two components that enable enhanced Rails functionality in the editor:
5757

5858
1. A Rack app that automatically exposes APIs when Rails server is running
59-
1. A Ruby LSP extension that connects to the exposed APIs to fetch runtime information from the Rails server
59+
1. A Ruby LSP addon that connects to the exposed APIs to fetch runtime information from the Rails server
6060

6161
This is why the Rails server needs to be running for some features to work.
6262

lib/ruby_lsp/ruby_lsp_rails/extension.rb renamed to lib/ruby_lsp/ruby_lsp_rails/addon.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# typed: strict
22
# frozen_string_literal: true
33

4-
require "ruby_lsp/extension"
4+
require "ruby_lsp/addon"
55

66
require_relative "rails_client"
77
require_relative "hover"
88
require_relative "code_lens"
99

1010
module RubyLsp
1111
module Rails
12-
class Extension < ::RubyLsp::Extension
12+
class Addon < ::RubyLsp::Addon
1313
extend T::Sig
1414

1515
sig { returns(RailsClient) }
@@ -39,11 +39,13 @@ def create_code_lens_listener(uri, emitter, message_queue)
3939

4040
sig do
4141
override.params(
42+
nesting: T::Array[String],
43+
index: RubyIndexer::Index,
4244
emitter: EventEmitter,
4345
message_queue: Thread::Queue,
4446
).returns(T.nilable(Listener[T.nilable(Interface::Hover)]))
4547
end
46-
def create_hover_listener(emitter, message_queue)
48+
def create_hover_listener(nesting, index, emitter, message_queue)
4749
Hover.new(client, emitter, message_queue)
4850
end
4951

lib/ruby_lsp/ruby_lsp_rails/code_lens.rb

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,57 +46,55 @@ class CodeLens < ::RubyLsp::Listener
4646
def initialize(uri, emitter, message_queue)
4747
@_response = T.let([], ResponseType)
4848
@path = T.let(uri.to_standardized_path, T.nilable(String))
49-
emitter.register(self, :on_command, :on_class, :on_def)
49+
emitter.register(self, :on_call, :on_class, :on_def)
5050

5151
super(emitter, message_queue)
5252
end
5353

54-
sig { params(node: SyntaxTree::Command).void }
55-
def on_command(node)
56-
message_value = node.message.value
57-
return unless message_value == "test" && node.arguments.parts.any?
54+
sig { params(node: YARP::CallNode).void }
55+
def on_call(node)
56+
message_value = node.message
57+
return unless message_value == "test"
5858

59-
first_argument = node.arguments.parts.first
59+
arguments = node.arguments&.arguments
60+
return unless arguments&.any?
6061

61-
parts = case first_argument
62-
when SyntaxTree::StringConcat
62+
first_argument = arguments.first
63+
64+
content = case first_argument
65+
when YARP::StringConcatNode
66+
left = first_argument.left
67+
right = first_argument.right
6368
# We only support two lines of concatenation on test names
64-
if first_argument.left.is_a?(SyntaxTree::StringLiteral) &&
65-
first_argument.right.is_a?(SyntaxTree::StringLiteral)
66-
[*first_argument.left.parts, *first_argument.right.parts]
69+
if left.is_a?(YARP::StringNode) &&
70+
right.is_a?(YARP::StringNode)
71+
left.content + right.content
6772
end
68-
when SyntaxTree::StringLiteral
69-
first_argument.parts
73+
when YARP::StringNode
74+
first_argument.content
7075
end
7176

72-
# The test name may be a blank string while the code is being typed
73-
return if parts.nil? || parts.empty?
74-
75-
# We can't handle interpolation yet
76-
return unless parts.all? { |part| part.is_a?(SyntaxTree::TStringContent) }
77-
78-
test_name = parts.map(&:value).join
79-
return if test_name.empty?
77+
return unless content && !content.empty?
8078

8179
line_number = node.location.start_line
8280
command = "#{BASE_COMMAND} #{@path}:#{line_number}"
83-
add_test_code_lens(node, name: test_name, command: command, kind: :example)
81+
add_test_code_lens(node, name: content, command: command, kind: :example)
8482
end
8583

8684
# Although uncommon, Rails tests can be written with the classic "def test_name" syntax.
87-
sig { params(node: SyntaxTree::DefNode).void }
85+
sig { params(node: YARP::DefNode).void }
8886
def on_def(node)
89-
method_name = node.name.value
87+
method_name = node.name.to_s
9088
if method_name.start_with?("test_")
9189
line_number = node.location.start_line
9290
command = "#{BASE_COMMAND} #{@path}:#{line_number}"
9391
add_test_code_lens(node, name: method_name, command: command, kind: :example)
9492
end
9593
end
9694

97-
sig { params(node: SyntaxTree::ClassDeclaration).void }
95+
sig { params(node: YARP::ClassNode).void }
9896
def on_class(node)
99-
class_name = node.constant.constant.value
97+
class_name = node.constant_path.slice
10098
if class_name.end_with?("Test")
10199
command = "#{BASE_COMMAND} #{@path}"
102100
add_test_code_lens(node, name: class_name, command: command, kind: :group)
@@ -105,7 +103,7 @@ def on_class(node)
105103

106104
private
107105

108-
sig { params(node: SyntaxTree::Node, name: String, command: String, kind: Symbol).void }
106+
sig { params(node: YARP::Node, name: String, command: String, kind: Symbol).void }
109107
def add_test_code_lens(node, name:, command:, kind:)
110108
return unless @path
111109

lib/ruby_lsp/ruby_lsp_rails/hover.rb

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,17 @@ def initialize(client, emitter, message_queue)
3131

3232
@_response = T.let(nil, ResponseType)
3333
@client = client
34-
emitter.register(self, :on_const, :on_command, :on_const_path_ref, :on_call)
34+
emitter.register(self, :on_constant_path, :on_constant_read, :on_call)
3535
end
3636

37-
sig { params(node: SyntaxTree::Const).void }
38-
def on_const(node)
39-
model = @client.model(node.value)
37+
sig { params(node: YARP::ConstantPathNode).void }
38+
def on_constant_path(node)
39+
@_response = generate_rails_document_link_hover(node.slice, node.location)
40+
end
41+
42+
sig { params(node: YARP::ConstantReadNode).void }
43+
def on_constant_read(node)
44+
model = @client.model(node.name.to_s)
4045
return if model.nil?
4146

4247
schema_file = model[:schema_file]
@@ -46,37 +51,28 @@ def on_const(node)
4651
end
4752
content << model[:columns].map { |name, type| "**#{name}**: #{type}\n" }.join("\n")
4853
contents = RubyLsp::Interface::MarkupContent.new(kind: "markdown", value: content)
49-
@_response = RubyLsp::Interface::Hover.new(range: range_from_syntax_tree_node(node), contents: contents)
50-
end
51-
52-
sig { params(node: SyntaxTree::Command).void }
53-
def on_command(node)
54-
message = node.message
55-
@_response = generate_rails_document_link_hover(message.value, message)
54+
@_response = RubyLsp::Interface::Hover.new(range: range_from_node(node), contents: contents)
5655
end
5756

58-
sig { params(node: SyntaxTree::ConstPathRef).void }
59-
def on_const_path_ref(node)
60-
@_response = generate_rails_document_link_hover(full_constant_name(node), node)
61-
end
62-
63-
sig { params(node: SyntaxTree::CallNode).void }
57+
sig { params(node: YARP::CallNode).void }
6458
def on_call(node)
65-
message = node.message
66-
return if message.is_a?(Symbol)
59+
message_value = node.message
60+
message_loc = node.message_loc
61+
62+
return unless message_value && message_loc
6763

68-
@_response = generate_rails_document_link_hover(message.value, message)
64+
@_response = generate_rails_document_link_hover(message_value, message_loc)
6965
end
7066

7167
private
7268

73-
sig { params(name: String, node: SyntaxTree::Node).returns(T.nilable(Interface::Hover)) }
74-
def generate_rails_document_link_hover(name, node)
69+
sig { params(name: String, location: YARP::Location).returns(T.nilable(Interface::Hover)) }
70+
def generate_rails_document_link_hover(name, location)
7571
urls = Support::RailsDocumentClient.generate_rails_document_urls(name)
7672
return if urls.empty?
7773

7874
contents = RubyLsp::Interface::MarkupContent.new(kind: "markdown", value: urls.join("\n\n"))
79-
RubyLsp::Interface::Hover.new(range: range_from_syntax_tree_node(node), contents: contents)
75+
RubyLsp::Interface::Hover.new(range: range_from_location(location), contents: contents)
8076
end
8177
end
8278
end

lib/ruby_lsp_rails/railtie.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ class Railtie < ::Rails::Railtie
2727
app_uri_path.write(app_uri)
2828

2929
at_exit do
30-
# The app_uri.txt file should only exist when the server is running. The extension uses its presence to
31-
# report if the server is running or not. If the server is not running, some of the extension features
30+
# The app_uri.txt file should only exist when the server is running. The addon uses its presence to
31+
# report if the server is running or not. If the server is not running, some of the addon features
3232
# will not be available.
3333
File.delete(app_uri_path) if File.exist?(app_uri_path)
3434
end

ruby-lsp-rails.gemspec

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
88
spec.authors = ["Shopify"]
99
spec.email = ["[email protected]"]
1010
spec.homepage = "https://github.com/Shopify/ruby-lsp-rails"
11-
spec.summary = "A Ruby LSP extension for Rails"
12-
spec.description = "A Ruby LSP extension that adds extra editor functionality for Rails applications"
11+
spec.summary = "A Ruby LSP addon for Rails"
12+
spec.description = "A Ruby LSP addon that adds extra editor functionality for Rails applications"
1313
spec.license = "MIT"
1414

1515
spec.metadata["allowed_push_host"] = "https://rubygems.org"
@@ -22,6 +22,6 @@ Gem::Specification.new do |spec|
2222
end
2323

2424
spec.add_dependency("rails", ">= 6.0")
25-
spec.add_dependency("ruby-lsp", ">= 0.10.0", "< 0.11.0")
25+
spec.add_dependency("ruby-lsp", ">= 0.11.0", "< 0.12.0")
2626
spec.add_dependency("sorbet-runtime", ">= 0.5.9897")
2727
end

0 commit comments

Comments
 (0)