diff --git a/lib/ruby_lsp/ruby_lsp_rails/addon.rb b/lib/ruby_lsp/ruby_lsp_rails/addon.rb index bc869440..738ef0ab 100644 --- a/lib/ruby_lsp/ruby_lsp_rails/addon.rb +++ b/lib/ruby_lsp/ruby_lsp_rails/addon.rb @@ -6,6 +6,7 @@ require_relative "rails_client" require_relative "hover" require_relative "code_lens" +require "open3" module RubyLsp module Rails @@ -20,10 +21,50 @@ def client sig { override.params(message_queue: Thread::Queue).void } def activate(message_queue) client.check_if_server_is_running! + @stdin, @stdout, @stderr, @wait_thread = Open3.popen3("bin/rails", "runner", "#{__dir__}/server.rb") + + @stdin.binmode + @stdout.binmode end sig { override.void } - def deactivate; end + def deactivate + send_request("shutdown") + + @stdin.close + @stdout.close + @stderr.close + end + + def make_request(request, params = nil) + send_request(request, params) + read_response(request) + end + + def send_request(request, params = nil) + hash = { + method: request, + } + + hash[:params] = params if params + json = hash.to_json + @stdin.write("Content-Length: #{json.length}\r\n\r\n", json) + end + + def read_response(request) + Timeout.timeout(5) do + # Read headers until line breaks + headers = @stdout.gets("\r\n\r\n") + + # Read the response content based on the length received in the headers + raw_response = @stdout.read(headers[/Content-Length: (\d+)/i, 1].to_i) + + json = JSON.parse(raw_response, symbolize_names: true) + warn("*** response ***: #{json}") + end + rescue Timeout::Error + raise "Request #{request} timed out. Is the request returning a response?" + end # Creates a new CodeLens listener. This method is invoked on every CodeLens request sig do diff --git a/lib/ruby_lsp/ruby_lsp_rails/server.rb b/lib/ruby_lsp/ruby_lsp_rails/server.rb new file mode 100644 index 00000000..4ac1a036 --- /dev/null +++ b/lib/ruby_lsp/ruby_lsp_rails/server.rb @@ -0,0 +1,31 @@ +# typed: false +# frozen_string_literal: true + +require "json" + +running = true +while running + # Read headers until line breaks + headers = $stdin.gets("\r\n\r\n") + + # Read the response content based on the length received in the headers + request = $stdin.read(headers[/Content-Length: (\d+)/i, 1].to_i) + + json = JSON.parse(request, symbolize_names: true) + + request_method = json.fetch(:method) + params = json[:params] + + response_json = nil + case request_method + when "schema" + response_json = { result: "ok", columns: User.column_names }.to_json + when "shutdown" + response_json = { result: "ok" }.to_json + + running = false + end + + $stdout.write("Content-Length: #{response_json.length}\r\n\r\n") + $stdout.write(response_json) +end