Class: RubyLsp::Server
- Inherits:
-
Object
- Object
- RubyLsp::Server
- Extended by:
- T::Sig
- Defined in:
- lib/ruby_lsp/server.rb
Overview
rubocop:enable RubyLsp/UseLanguageServerAliases
Instance Method Summary collapse
-
#initialize ⇒ Server
constructor
A new instance of Server.
- #start ⇒ Object
Constructor Details
#initialize ⇒ Server
Returns a new instance of Server.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/ruby_lsp/server.rb', line 15 def initialize @writer = T.let(Transport::Stdio::Writer.new, Transport::Stdio::Writer) @reader = T.let(Transport::Stdio::Reader.new, Transport::Stdio::Reader) @store = T.let(Store.new, Store) # The job queue is the actual list of requests we have to process @job_queue = T.let(Thread::Queue.new, Thread::Queue) # The jobs hash is just a way of keeping a handle to jobs based on the request ID, so we can cancel them @jobs = T.let({}, T::Hash[T.any(String, Integer), Job]) @mutex = T.let(Mutex.new, Mutex) @worker = T.let(new_worker, Thread) # The messages queue includes requests and notifications to be sent to the client @message_queue = T.let(Thread::Queue.new, Thread::Queue) # The executor is responsible for executing requests @executor = T.let(Executor.new(@store, @message_queue), Executor) # Create a thread to watch the messages queue and send them to the client @message_dispatcher = T.let( Thread.new do current_request_id = 1 loop do = @message_queue.pop break if .nil? @mutex.synchronize do case when Notification @writer.write(method: ., params: .params) when Request @writer.write(id: current_request_id, method: ., params: .params) current_request_id += 1 end end end end, Thread, ) Thread.main.priority = 1 end |
Instance Method Details
#start ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/ruby_lsp/server.rb', line 60 def start warn("Starting Ruby LSP...") # Requests that have to be executed sequentially or in the main process are implemented here. All other requests # fall under the else branch which just pushes requests to the queue @reader.read do |request| case request[:method] when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange" result = @executor.execute(request) finalize_request(result, request) when "$/cancelRequest" # Cancel the job if it's still in the queue @mutex.synchronize { @jobs[request[:params][:id]]&.cancel } when "shutdown" warn("Shutting down Ruby LSP...") @message_queue.close # Close the queue so that we can no longer receive items @job_queue.close # Clear any remaining jobs so that the thread can terminate @job_queue.clear @jobs.clear # Wait until the thread is finished @worker.join @message_dispatcher.join @store.clear finalize_request(Result.new(response: nil), request) when "exit" # We return zero if shutdown has already been received or one otherwise as per the recommendation in the spec # https://microsoft.github.io/language-server-protocol/specification/#exit status = @store.empty? ? 0 : 1 warn("Shutdown complete with status #{status}") exit(status) else # Default case: push the request to the queue to be executed by the worker job = Job.new(request: request, cancelled: false) @mutex.synchronize do # Remember a handle to the job, so that we can cancel it @jobs[request[:id]] = job # We must parse the document under a mutex lock or else we might switch threads and accept text edits in the # source. Altering the source reference during parsing will put the parser in an invalid internal state, # since it started parsing with one source but then it changed in the middle uri = request.dig(:params, :textDocument, :uri) @store.get(uri).parse if uri end @job_queue << job end end end |