Skip to content

Commit fa84c70

Browse files
committed
Use window log messages instead of printing to stderr
1 parent f6bade4 commit fa84c70

File tree

6 files changed

+134
-53
lines changed

6 files changed

+134
-53
lines changed

lib/ruby_lsp/addon.rb

+9-4
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,18 @@ def inherited(child_class)
4949
super
5050
end
5151

52-
# Discovers and loads all addons. Returns the list of activated addons
53-
sig { params(global_state: GlobalState, outgoing_queue: Thread::Queue).returns(T::Array[Addon]) }
52+
# Discovers and loads all addons. Returns a list of errors when trying to require addons
53+
sig do
54+
params(global_state: GlobalState, outgoing_queue: Thread::Queue).returns(T::Array[StandardError])
55+
end
5456
def load_addons(global_state, outgoing_queue)
5557
# Require all addons entry points, which should be placed under
5658
# `some_gem/lib/ruby_lsp/your_gem_name/addon.rb`
57-
Gem.find_files("ruby_lsp/**/addon.rb").each do |addon|
59+
errors = Gem.find_files("ruby_lsp/**/addon.rb").filter_map do |addon|
5860
require File.expand_path(addon)
61+
nil
5962
rescue => e
60-
$stderr.puts(e.full_message)
63+
e
6164
end
6265

6366
# Instantiate all discovered addon classes
@@ -71,6 +74,8 @@ def load_addons(global_state, outgoing_queue)
7174
rescue => e
7275
addon.add_error(e)
7376
end
77+
78+
errors
7479
end
7580

7681
# Intended for use by tests for addons

lib/ruby_lsp/base_server.rb

+7-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def start
6565
when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
6666
process_message(message)
6767
when "shutdown"
68-
$stderr.puts("Shutting down Ruby LSP...")
68+
send_log_message("Shutting down Ruby LSP...")
6969

7070
shutdown
7171

@@ -76,7 +76,7 @@ def start
7676
when "exit"
7777
@mutex.synchronize do
7878
status = @incoming_queue.closed? ? 0 : 1
79-
$stderr.puts("Shutdown complete with status #{status}")
79+
send_log_message("Shutdown complete with status #{status}")
8080
exit(status)
8181
end
8282
else
@@ -145,5 +145,10 @@ def send_message(message)
145145
def send_empty_response(id)
146146
send_message(Result.new(id: id, response: nil))
147147
end
148+
149+
sig { params(message: String, type: Integer).void }
150+
def send_log_message(message, type: Constant::MessageType::LOG)
151+
send_message(Notification.window_log_message(message, type: Constant::MessageType::LOG))
152+
end
148153
end
149154
end

lib/ruby_lsp/global_state.rb

+33-13
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,48 @@ def active_linters
5757
@linters.filter_map { |name| @supported_formatters[name] }
5858
end
5959

60-
sig { params(options: T::Hash[Symbol, T.untyped]).void }
60+
# Applies the options provided by the editor and returns an array of notifications to send back to the client
61+
sig { params(options: T::Hash[Symbol, T.untyped]).returns(T::Array[Notification]) }
6162
def apply_options(options)
63+
notifications = []
6264
direct_dependencies = gather_direct_dependencies
6365
all_dependencies = gather_direct_and_indirect_dependencies
6466
workspace_uri = options.dig(:workspaceFolders, 0, :uri)
6567
@workspace_uri = URI(workspace_uri) if workspace_uri
6668

6769
specified_formatter = options.dig(:initializationOptions, :formatter)
68-
@formatter = specified_formatter if specified_formatter
69-
@formatter = detect_formatter(direct_dependencies, all_dependencies) if @formatter == "auto"
70+
71+
if specified_formatter
72+
@formatter = specified_formatter
73+
74+
if specified_formatter != "auto"
75+
notifications << Notification.window_log_message("Using formatter specified by user: #{@formatter}")
76+
end
77+
end
78+
79+
if @formatter == "auto"
80+
@formatter = detect_formatter(direct_dependencies, all_dependencies)
81+
notifications << Notification.window_log_message("Auto detected formatter: #{@formatter}")
82+
end
7083

7184
specified_linters = options.dig(:initializationOptions, :linters)
7285
@linters = specified_linters || detect_linters(direct_dependencies, all_dependencies)
86+
87+
notifications << if specified_linters
88+
Notification.window_log_message("Using linters specified by user: #{@linters.join(", ")}")
89+
else
90+
Notification.window_log_message("Auto detected linters: #{@linters.join(", ")}")
91+
end
92+
7393
@test_library = detect_test_library(direct_dependencies)
94+
notifications << Notification.window_log_message("Detected test library: #{@test_library}")
95+
7496
@has_type_checker = detect_typechecker(direct_dependencies)
97+
if @has_type_checker
98+
notifications << Notification.window_log_message(
99+
"Ruby LSP detected this is a Sorbet project and will defer to the Sorbet LSP for some functionality",
100+
)
101+
end
75102

76103
encodings = options.dig(:capabilities, :general, :positionEncodings)
77104
@encoding = if !encodings || encodings.empty?
@@ -91,6 +118,8 @@ def apply_options(options)
91118

92119
@experimental_features = options.dig(:initializationOptions, :experimentalFeaturesEnabled) || false
93120
@type_inferrer.experimental_features = @experimental_features
121+
122+
notifications
94123
end
95124

96125
sig { returns(String) }
@@ -163,16 +192,7 @@ def detect_test_library(dependencies)
163192
def detect_typechecker(dependencies)
164193
return false if ENV["RUBY_LSP_BYPASS_TYPECHECKER"]
165194

166-
# We can't read the env from within `Bundle.with_original_env` so we need to set it here.
167-
ruby_lsp_env_is_test = (ENV["RUBY_LSP_ENV"] == "test")
168-
Bundler.with_original_env do
169-
sorbet_static_detected = dependencies.any?(/^sorbet-static/)
170-
# Don't show message while running tests, since it's noisy
171-
if sorbet_static_detected && !ruby_lsp_env_is_test
172-
$stderr.puts("Ruby LSP detected this is a Sorbet project so will defer to Sorbet LSP for some functionality")
173-
end
174-
sorbet_static_detected
175-
end
195+
dependencies.any?(/^sorbet-static/)
176196
rescue Bundler::GemfileNotFound
177197
false
178198
end

lib/ruby_lsp/server.rb

+21-6
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ def initialize(test_mode: false)
1919
def process_message(message)
2020
case message[:method]
2121
when "initialize"
22-
$stderr.puts("Initializing Ruby LSP v#{VERSION}...")
22+
send_log_message("Initializing Ruby LSP v#{VERSION}...")
2323
run_initialize(message)
2424
when "initialized"
25-
$stderr.puts("Finished initializing Ruby LSP!") unless @test_mode
25+
send_log_message("Finished initializing Ruby LSP!") unless @test_mode
2626
run_initialized
2727
when "textDocument/didOpen"
2828
text_document_did_open(message)
@@ -121,12 +121,20 @@ def process_message(message)
121121
end
122122
end
123123

124-
$stderr.puts("Error processing #{message[:method]}: #{e.full_message}")
124+
send_log_message("Error processing #{message[:method]}: #{e.full_message}", type: Constant::MessageType::ERROR)
125125
end
126126

127127
sig { void }
128128
def load_addons
129-
Addon.load_addons(@global_state, @outgoing_queue)
129+
errors = Addon.load_addons(@global_state, @outgoing_queue)
130+
131+
if errors.any?
132+
send_log_message(
133+
"Error loading addons:\n\n#{errors.map(&:full_message).join("\n\n")}",
134+
type: Constant::MessageType::WARNING,
135+
)
136+
end
137+
130138
errored_addons = Addon.addons.select(&:error?)
131139

132140
if errored_addons.any?
@@ -140,7 +148,12 @@ def load_addons
140148
),
141149
)
142150

143-
$stderr.puts(errored_addons.map(&:errors_details).join("\n\n")) unless @test_mode
151+
unless @test_mode
152+
send_log_message(
153+
errored_addons.map(&:errors_details).join("\n\n"),
154+
type: Constant::MessageType::WARNING,
155+
)
156+
end
144157
end
145158
end
146159

@@ -149,7 +162,7 @@ def load_addons
149162
sig { params(message: T::Hash[Symbol, T.untyped]).void }
150163
def run_initialize(message)
151164
options = message[:params]
152-
@global_state.apply_options(options)
165+
global_state_notifications = @global_state.apply_options(options)
153166

154167
client_name = options.dig(:clientInfo, :name)
155168
@store.client_name = client_name if client_name
@@ -258,6 +271,8 @@ def run_initialize(message)
258271
process_indexing_configuration(options.dig(:initializationOptions, :indexing))
259272

260273
begin_progress("indexing-progress", "Ruby LSP: indexing files")
274+
275+
global_state_notifications.each { |notification| send_message(notification) }
261276
end
262277

263278
sig { void }

lib/ruby_lsp/utils.rb

+12
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def to_hash; end
5353
class Notification < Message
5454
class << self
5555
extend T::Sig
56+
5657
sig { params(message: String).returns(Notification) }
5758
def window_show_error(message)
5859
new(
@@ -63,6 +64,14 @@ def window_show_error(message)
6364
),
6465
)
6566
end
67+
68+
sig { params(message: String, type: Integer).returns(Notification) }
69+
def window_log_message(message, type: Constant::MessageType::LOG)
70+
new(
71+
method: "window/logMessage",
72+
params: Interface::LogMessageParams.new(type: type, message: message),
73+
)
74+
end
6675
end
6776

6877
extend T::Sig
@@ -122,6 +131,9 @@ class Result
122131
sig { returns(T.untyped) }
123132
attr_reader :response
124133

134+
sig { returns(Integer) }
135+
attr_reader :id
136+
125137
sig { params(id: Integer, response: T.untyped).void }
126138
def initialize(id:, response:)
127139
@id = id

0 commit comments

Comments
 (0)