diff --git a/lib/ruby_lsp/ruby_lsp_rails/server.rb b/lib/ruby_lsp/ruby_lsp_rails/server.rb index a6b20171..f4eb777a 100644 --- a/lib/ruby_lsp/ruby_lsp_rails/server.rb +++ b/lib/ruby_lsp/ruby_lsp_rails/server.rb @@ -158,6 +158,8 @@ def send_notification(message) class ServerAddon include Common + class MissingAddonError < StandardError; end + @server_addon_classes = [] @server_addons = {} @@ -171,7 +173,10 @@ def inherited(child) # Delegate `request` with `params` to the server add-on with the given `name` def delegate(name, request, params) - @server_addons[name]&.execute(request, params) + addon = @server_addons.fetch(name) do + raise ServerAddon::MissingAddonError, "No extension with name #{name}" + end + addon.execute(request, params) end # Instantiate all server addons and store them in a hash for easy access after we have discovered the classes @@ -298,9 +303,13 @@ def execute(request, params) server_addon_name = params[:server_addon_name] request_name = params[:request_name] - # Do not wrap this in error handlers. Server add-ons need to have the flexibility to choose if they want to - # include a response or not as part of error handling, so a blanket approach is not appropriate. - ServerAddon.delegate(server_addon_name, request_name, params.except(:request_name, :server_addon_name)) + # Do not wrap this in additional error handlers. Server add-ons need to have the flexibility to choose if they want to + # include a response or not as part of their own error handling, so a blanket approach is not appropriate. + begin + ServerAddon.delegate(server_addon_name, request_name, params.except(:request_name, :server_addon_name)) + rescue ServerAddon::MissingAddonError => e + send_error_response(e.message) + end end end