@@ -10,20 +10,34 @@ class RunnerClient
10
10
class << self
11
11
extend T ::Sig
12
12
13
- sig { returns ( RunnerClient ) }
14
- def create_client
13
+ sig { params ( outgoing_queue : Thread :: Queue ) . returns ( RunnerClient ) }
14
+ def create_client ( outgoing_queue )
15
15
if File . exist? ( "bin/rails" )
16
- new
16
+ new ( outgoing_queue )
17
17
else
18
- $stderr. puts ( <<~MSG )
19
- Ruby LSP Rails failed to locate bin/rails in the current directory: #{ Dir . pwd } "
20
- MSG
21
- $stderr. puts ( "Server dependent features will not be available" )
18
+ unless outgoing_queue . closed?
19
+ outgoing_queue << RubyLsp ::Notification . window_log_message (
20
+ <<~MESSAGE . chomp ,
21
+ Ruby LSP Rails failed to locate bin/rails in the current directory: #{ Dir . pwd }
22
+ Server dependent features will not be available
23
+ MESSAGE
24
+ type : RubyLsp ::Constant ::MessageType ::WARNING ,
25
+ )
26
+ end
27
+
22
28
NullClient . new
23
29
end
24
30
rescue Errno ::ENOENT , StandardError => e # rubocop:disable Lint/ShadowedException
25
- $stderr. puts ( "Ruby LSP Rails failed to initialize server: #{ e . message } \n #{ e . backtrace &.join ( "\n " ) } " )
26
- $stderr. puts ( "Server dependent features will not be available" )
31
+ unless outgoing_queue . closed?
32
+ outgoing_queue << RubyLsp ::Notification . window_log_message (
33
+ <<~MESSAGE . chomp ,
34
+ Ruby LSP Rails failed to initialize server: #{ e . full_message }
35
+ Server dependent features will not be available
36
+ MESSAGE
37
+ type : Constant ::MessageType ::ERROR ,
38
+ )
39
+ end
40
+
27
41
NullClient . new
28
42
end
29
43
end
@@ -39,8 +53,9 @@ class EmptyMessageError < StandardError; end
39
53
sig { returns ( String ) }
40
54
attr_reader :rails_root
41
55
42
- sig { void }
43
- def initialize
56
+ sig { params ( outgoing_queue : Thread ::Queue ) . void }
57
+ def initialize ( outgoing_queue )
58
+ @outgoing_queue = T . let ( outgoing_queue , Thread ::Queue )
44
59
@mutex = T . let ( Mutex . new , Mutex )
45
60
# Spring needs a Process session ID. It uses this ID to "attach" itself to the parent process, so that when the
46
61
# parent ends, the spring process ends as well. If this is not set, Spring will throw an error while trying to
@@ -69,24 +84,23 @@ def initialize
69
84
@stdout . binmode
70
85
@stderr . binmode
71
86
72
- $stderr . puts ( "Ruby LSP Rails booting server" )
87
+ log_message ( "Ruby LSP Rails booting server" )
73
88
count = 0
74
89
75
90
begin
76
91
count += 1
77
92
initialize_response = T . must ( read_response )
78
93
@rails_root = T . let ( initialize_response [ :root ] , String )
79
94
rescue EmptyMessageError
80
- $stderr . puts ( "Ruby LSP Rails is retrying initialize (#{ count } )" )
95
+ log_message ( "Ruby LSP Rails is retrying initialize (#{ count } )" )
81
96
retry if count < MAX_RETRIES
82
97
end
83
98
84
- $stderr . puts ( "Finished booting Ruby LSP Rails server" )
99
+ log_message ( "Finished booting Ruby LSP Rails server" )
85
100
86
101
unless ENV [ "RAILS_ENV" ] == "test"
87
102
at_exit do
88
103
if @wait_thread . alive?
89
- $stderr. puts ( "Ruby LSP Rails is force killing the server" )
90
104
sleep ( 0.5 ) # give the server a bit of time if we already issued a shutdown notification
91
105
force_kill
92
106
end
@@ -100,15 +114,21 @@ def initialize
100
114
def register_server_addon ( server_addon_path )
101
115
send_notification ( "server_addon/register" , server_addon_path : server_addon_path )
102
116
rescue IncompleteMessageError
103
- $stderr. puts ( "Ruby LSP Rails failed to register server addon #{ server_addon_path } " )
117
+ log_message (
118
+ "Ruby LSP Rails failed to register server addon #{ server_addon_path } " ,
119
+ type : RubyLsp ::Constant ::MessageType ::ERROR ,
120
+ )
104
121
nil
105
122
end
106
123
107
124
sig { params ( name : String ) . returns ( T . nilable ( T ::Hash [ Symbol , T . untyped ] ) ) }
108
125
def model ( name )
109
126
make_request ( "model" , name : name )
110
127
rescue IncompleteMessageError
111
- $stderr. puts ( "Ruby LSP Rails failed to get model information: #{ @stderr . read } " )
128
+ log_message (
129
+ "Ruby LSP Rails failed to get model information: #{ @stderr . read } " ,
130
+ type : RubyLsp ::Constant ::MessageType ::ERROR ,
131
+ )
112
132
nil
113
133
end
114
134
@@ -125,37 +145,50 @@ def association_target_location(model_name:, association_name:)
125
145
association_name : association_name ,
126
146
)
127
147
rescue => e
128
- $stderr. puts ( "Ruby LSP Rails failed with #{ e . message } : #{ @stderr . read } " )
148
+ log_message (
149
+ "Ruby LSP Rails failed with #{ e . message } : #{ @stderr . read } " ,
150
+ type : RubyLsp ::Constant ::MessageType ::ERROR ,
151
+ )
152
+ nil
129
153
end
130
154
131
155
sig { params ( name : String ) . returns ( T . nilable ( T ::Hash [ Symbol , T . untyped ] ) ) }
132
156
def route_location ( name )
133
157
make_request ( "route_location" , name : name )
134
158
rescue IncompleteMessageError
135
- $stderr. puts ( "Ruby LSP Rails failed to get route location: #{ @stderr . read } " )
159
+ log_message (
160
+ "Ruby LSP Rails failed to get route location: #{ @stderr . read } " ,
161
+ type : RubyLsp ::Constant ::MessageType ::ERROR ,
162
+ )
136
163
nil
137
164
end
138
165
139
166
sig { params ( controller : String , action : String ) . returns ( T . nilable ( T ::Hash [ Symbol , T . untyped ] ) ) }
140
167
def route ( controller :, action :)
141
168
make_request ( "route_info" , controller : controller , action : action )
142
169
rescue IncompleteMessageError
143
- $stderr. puts ( "Ruby LSP Rails failed to get route information: #{ @stderr . read } " )
170
+ log_message (
171
+ "Ruby LSP Rails failed to get route information: #{ @stderr . read } " ,
172
+ type : RubyLsp ::Constant ::MessageType ::ERROR ,
173
+ )
144
174
nil
145
175
end
146
176
147
177
sig { void }
148
178
def trigger_reload
149
- $stderr . puts ( "Reloading Rails application" )
179
+ log_message ( "Reloading Rails application" )
150
180
send_notification ( "reload" )
151
181
rescue IncompleteMessageError
152
- $stderr. puts ( "Ruby LSP Rails failed to trigger reload" )
182
+ log_message (
183
+ "Ruby LSP Rails failed to trigger reload" ,
184
+ type : RubyLsp ::Constant ::MessageType ::ERROR ,
185
+ )
153
186
nil
154
187
end
155
188
156
189
sig { void }
157
190
def shutdown
158
- $stderr . puts ( "Ruby LSP Rails shutting down server" )
191
+ log_message ( "Ruby LSP Rails shutting down server" )
159
192
send_message ( "shutdown" )
160
193
sleep ( 0.5 ) # give the server a bit of time to shutdown
161
194
[ @stdin , @stdout , @stderr ] . each ( &:close )
@@ -214,7 +247,10 @@ def read_response
214
247
response = JSON . parse ( T . must ( raw_response ) , symbolize_names : true )
215
248
216
249
if response [ :error ]
217
- $stderr. puts ( "Ruby LSP Rails error: " + response [ :error ] )
250
+ log_message (
251
+ "Ruby LSP Rails error: #{ response [ :error ] } " ,
252
+ type : RubyLsp ::Constant ::MessageType ::ERROR ,
253
+ )
218
254
return
219
255
end
220
256
@@ -229,6 +265,13 @@ def force_kill
229
265
# Windows does not support the `TERM` signal, so we're forced to use `KILL` here
230
266
Process . kill ( T . must ( Signal . list [ "KILL" ] ) , @wait_thread . pid )
231
267
end
268
+
269
+ sig { params ( message : ::String , type : ::Integer ) . void }
270
+ def log_message ( message , type : RubyLsp ::Constant ::MessageType ::LOG )
271
+ return if @outgoing_queue . closed?
272
+
273
+ @outgoing_queue << RubyLsp ::Notification . window_log_message ( message , type : type )
274
+ end
232
275
end
233
276
234
277
class NullClient < RunnerClient
@@ -255,6 +298,11 @@ def rails_root
255
298
256
299
private
257
300
301
+ sig { params ( message : ::String , type : ::Integer ) . void }
302
+ def log_message ( message , type : RubyLsp ::Constant ::MessageType ::LOG )
303
+ # no-op
304
+ end
305
+
258
306
sig { override . params ( request : String , params : T . nilable ( T ::Hash [ Symbol , T . untyped ] ) ) . void }
259
307
def send_message ( request , params = nil )
260
308
# no-op
0 commit comments