Skip to content

Commit b2b57fb

Browse files
committed
wip
1 parent 6246305 commit b2b57fb

File tree

2 files changed

+85
-33
lines changed

2 files changed

+85
-33
lines changed

lib/ruby_lsp/ruby_lsp_rails/code_lens.rb

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,62 +7,96 @@ class CodeLens < ::RubyLsp::Listener
77
extend T::Sig
88
extend T::Generic
99

10+
# This feature is currently experimental. Clients will need to pass `experimentalFeaturesEnabled`
11+
# in the initialization options to enable it.
12+
#
13+
# The
14+
# [code lens](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens)
15+
# request informs the editor of runnable commands such as tests
16+
#
17+
# # Example
18+
#
19+
# ```ruby
20+
# # Run
21+
# class Test < Minitest::Test
22+
# end
23+
# ```
24+
1025
ResponseType = type_member { { fixed: T.nilable(T::Array[::RubyLsp::Interface::CodeLens]) } }
26+
BASE_COMMAND = "bin/rails test"
1127

1228
::RubyLsp::Requests::CodeLens.add_listener(self)
1329

1430
sig { override.returns(ResponseType) }
1531
attr_reader :response
1632

17-
sig { params(uri: String, message_queue: Thread::Queue).void }
18-
def initialize(uri, message_queue)
33+
sig { params(uri: String, emitter: EventEmitter, message_queue: Thread::Queue).void }
34+
def initialize(uri, emitter, message_queue)
1935
@response = T.let([], ResponseType)
2036
@visibility = T.let("public", String)
2137
@prev_visibility = T.let("public", String)
2238
@path = T.let(uri.delete_prefix("file://"), String)
23-
super
39+
emitter.register(self, :on_command, :on_class)
40+
41+
super(emitter, message_queue) # can be just super later?
2442
end
2543

26-
listener_events do
27-
sig { params(node: SyntaxTree::Command).void }
28-
def on_command(node)
29-
if @visibility == "public"
30-
message_value = node.message.value
31-
if message_value == "test" && node.arguments.parts.any?
32-
first_argument = node.arguments.parts.first
33-
method_name = first_argument.parts.first.value if first_argument.is_a?(SyntaxTree::StringLiteral)
44+
sig { params(node: SyntaxTree::Command).void }
45+
def on_command(node)
46+
if @visibility == "public"
47+
message_value = node.message.value
48+
if message_value == "test" && node.arguments.parts.any?
49+
first_argument = node.arguments.parts.first
50+
method_name = first_argument.parts.first.value if first_argument.is_a?(SyntaxTree::StringLiteral)
51+
test_file_path = Pathname.new(@path).relative_path_from(RailsClient.instance.root).to_s
52+
line_number = node.location.start_line
53+
command = "#{BASE_COMMAND} #{test_file_path}:#{line_number}"
3454

35-
if method_name
36-
add_code_lens(
37-
node,
38-
name: method_name,
39-
command: RubyLsp::Requests::CodeLens::BASE_COMMAND + @path + " --name " + "test_" + method_name.gsub(
40-
" ", "_"
41-
),
42-
)
43-
end
55+
if method_name
56+
add_code_lens(node, name: method_name, command: command)
4457
end
4558
end
4659
end
60+
end
4761

48-
sig { params(node: SyntaxTree::DefNode).void }
49-
def on_def(node); end
62+
sig { params(node: SyntaxTree::ClassDeclaration).void }
63+
def on_class(node)
64+
class_name = node.constant.constant.value
65+
if class_name.end_with?("Test")
66+
add_code_lens(node, name: class_name, command: "#{BASE_COMMAND} #{@path}")
67+
end
5068
end
5169

5270
private
5371

5472
sig { params(node: SyntaxTree::Node, name: String, command: String).void }
5573
def add_code_lens(node, name:, command:)
56-
@response << ::RubyLsp::Requests::CodeLens.create_code_lens(
74+
@response = T.must(@response)
75+
76+
@response << create_code_lens(
5777
node,
78+
title: "Run",
79+
command_name: "rubyLsp.runTest",
5880
path: @path,
5981
name: name,
6082
test_command: command,
6183
type: "test",
6284
)
6385

64-
@response << ::RubyLsp::Requests::CodeLens.create_code_lens(
86+
@response << create_code_lens(
87+
node,
88+
title: "Run In Terminal",
89+
command_name: "rubyLsp.runTestInTerminal",
90+
path: @path,
91+
name: name,
92+
test_command: command,
93+
type: "test_in_terminal",
94+
)
95+
96+
@response << create_code_lens(
6597
node,
98+
title: "Debug",
99+
command_name: "rubyLsp.debugTest",
66100
path: @path,
67101
name: name,
68102
test_command: command,

test/ruby_lsp_rails/code_lens_test.rb

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,37 @@
66
module RubyLsp
77
module Rails
88
class CodeLensTest < ActiveSupport::TestCase
9-
test "recognizes Rails active support test cases" do
9+
test "recognizes Rails Active Support test cases" do
1010
message_queue = Thread::Queue.new
11-
listener = CodeLens.new("", message_queue)
1211

13-
test_name = "handles test case"
12+
store = RubyLsp::Store.new
13+
store.set(uri: "file:///fake.rb", source: <<~RUBY, version: 1)
14+
class Test < ActiveSupport::TestCase
15+
test "an example" do
16+
# test body
17+
end
18+
end
19+
RUBY
1420

15-
RubyLsp::EventEmitter.new(listener).emit_for_target(Command(
16-
Ident("test"),
17-
Args([StringLiteral([TStringContent(test_name)], "")]),
18-
BodyStmt(SyntaxTree::VoidStmt, "", "", "", ""),
19-
))
21+
response = RubyLsp::Executor.new(store, message_queue).execute({
22+
method: "textDocument/codeLens",
23+
params: { textDocument: { uri: "file:///fake.rb" }, position: { line: 0, character: 0 } },
24+
}).response
2025

21-
assert_equal(test_name, T.must(T.must(listener.response).first).command.arguments[1])
26+
# There are 9 responses in total. The first 3 responses come from ruby-lsp, but are not visible, as they are
27+
# overwritten by those from ruby-lsp-rails.
28+
#
29+
# The next 3 responses are for the test declaration.
30+
# The last 3 are for the test class.
31+
assert_equal(9, response.size)
32+
assert_match("Run", response[3].command.title)
33+
assert_equal("bin/rails test /fake.rb", response[3].command.arguments[2])
34+
assert_match("Run In Terminal", response[4].command.title)
35+
assert_match("Debug", response[5].command.title)
36+
37+
ensure
38+
RubyLsp::Requests::Hover.listeners.clear
39+
T.must(message_queue).close
2240
end
2341
end
2442
end

0 commit comments

Comments
 (0)