Class: RubyLsp::Server

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/ruby_lsp/server.rb

Instance Method Summary collapse

Constructor Details

#initializeServer

Returns a new instance of Server.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/ruby_lsp/server.rb', line 13

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)

  Thread.main.priority = 1
end

Instance Method Details

#startObject



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
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ruby_lsp/server.rb', line 29

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.new(@store).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...")

      # 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
      @store.clear

      finalize_request(Result.new(response: nil, notifications: []), 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)

      # Remember a handle to the job, so that we can cancel it
      @mutex.synchronize { @jobs[request[:id]] = job }
      @job_queue << job
    end
  end
end