Skip to content

Commit 00caa31

Browse files
committed
test
1 parent 89967af commit 00caa31

File tree

3 files changed

+152
-0
lines changed

3 files changed

+152
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
require "json"
5+
require "open3"
6+
7+
# NOTE: We should avoid printing to stderr since it causes problems. We never read the standard error pipe
8+
# from the client, so it will become full and eventually hang or crash.
9+
# Instead, return a response with an `error` key.
10+
11+
module RubyLsp
12+
module Rails
13+
class RunnerClient
14+
extend T::Sig
15+
16+
sig { void }
17+
def initialize
18+
stdin, stdout, stderr, wait_thread = Open3.popen3(
19+
"bin/rails",
20+
"runner",
21+
"#{__dir__}/server_start.rb",
22+
)
23+
@stdin = T.let(stdin, IO)
24+
@stdout = T.let(stdout, IO)
25+
@stderr = T.let(stderr, IO)
26+
@wait_thread = T.let(wait_thread, Process::Waiter)
27+
@stdin.binmode # for Windows compatibility
28+
@stdout.binmode # for Windows compatibility
29+
end
30+
31+
sig { params(name: String).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
32+
def model(name)
33+
make_request("model", name: name)
34+
end
35+
36+
sig { void }
37+
def shutdown
38+
send_notification("shutdown")
39+
sleep(0.01) while @wait_thread.alive?
40+
[@stdin, @stdout, @stderr].each(&:close)
41+
end
42+
43+
private
44+
45+
sig { params(request: T.untyped, params: T.untyped).returns(T.untyped) }
46+
def make_request(request, params = nil)
47+
send_message(request, params)
48+
read_response
49+
end
50+
51+
sig { params(request: T.untyped, params: T.untyped).void }
52+
def send_message(request, params = nil)
53+
json = { method: request, params: params }.compact.to_json
54+
55+
@stdin.write("Content-Length: #{json.length}\r\n\r\n", json)
56+
end
57+
58+
alias_method :send_notification, :send_message
59+
60+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
61+
def read_response
62+
headers = @stdout.gets("\r\n\r\n")
63+
raw_response = @stdout.read(T.must(headers)[/Content-Length: (\d+)/i, 1].to_i)
64+
response = JSON.parse(T.must(raw_response), symbolize_names: true)
65+
66+
# TODO: handle exception if JSON parse fails?
67+
68+
if response[:error]
69+
warn("Ruby LSP Rails error: " + response[:error])
70+
return
71+
end
72+
73+
response.fetch(:result)
74+
end
75+
end
76+
end
77+
end

lib/ruby_lsp/ruby_lsp_rails/server.rb

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
require "sorbet-runtime"
5+
require "json"
6+
7+
module RubyLsp
8+
module Rails
9+
class Server
10+
VOID = Object.new
11+
12+
extend T::Sig
13+
14+
sig { params(model_name: String).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
15+
def resolve_database_info_from_model(model_name)
16+
const = ActiveSupport::Inflector.safe_constantize(model_name)
17+
unless const && const < ActiveRecord::Base && !const.abstract_class?
18+
return {
19+
result: nil,
20+
}
21+
end
22+
23+
schema_file = ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(const.connection.pool.db_config)
24+
25+
{
26+
result: {
27+
columns: const.columns.map { |column| [column.name, column.type] },
28+
schema_file: ::Rails.root + schema_file,
29+
},
30+
}
31+
rescue => e
32+
{
33+
error: e.message,
34+
}
35+
end
36+
37+
sig { void }
38+
def start
39+
$stdin.sync = true
40+
$stdout.sync = true
41+
42+
running = T.let(true, T::Boolean)
43+
44+
while running
45+
headers = $stdin.gets("\r\n\r\n")
46+
request = $stdin.read(headers[/Content-Length: (\d+)/i, 1].to_i)
47+
48+
json = JSON.parse(request, symbolize_names: true)
49+
request_method = json.fetch(:method)
50+
params = json[:params]
51+
52+
response = case request_method
53+
when "shutdown"
54+
running = false
55+
VOID
56+
when "model"
57+
resolve_database_info_from_model(params.fetch(:name))
58+
else
59+
VOID
60+
end
61+
62+
next if response == VOID
63+
64+
json_response = response.to_json
65+
$stdout.write("Content-Length: #{json_response.length}\r\n\r\n#{json_response}")
66+
end
67+
end
68+
end
69+
end
70+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
require_relative "server"
5+
RubyLsp::Rails::Server.new.start

0 commit comments

Comments
 (0)