class Neovim::Session

Wraps an event loop in a synchronous API using +Fiber+s.

@api private

Attributes

request_id[W]

Public Class Methods

new(event_loop) click to toggle source
# File lib/neovim/session.rb, line 21
def initialize(event_loop)
  @event_loop = event_loop
  @main_thread = Thread.current
  @main_fiber = Fiber.current
  @response_handlers = Hash.new(-> {})
  @pending_messages = []
  @request_id = 0
end

Public Instance Methods

next() click to toggle source
# File lib/neovim/session.rb, line 40
def next
  return @pending_messages.shift if @pending_messages.any?

  run { |msg| stop; msg }
end
notify(method, *args) click to toggle source
# File lib/neovim/session.rb, line 83
def notify(method, *args)
  @event_loop.notify(method, *args)
end
request(method, *args) click to toggle source

Make an RPC request and return its response.

If this method is called inside a callback, we are already inside a Fiber handler. In that case, we write to the stream and yield the Fiber. Once the response is received, resume the Fiber and return the result.

If this method is called outside a callback, write to the stream and run the event loop until a response is received. Messages received in the meantime are enqueued to be handled later.

# File lib/neovim/session.rb, line 56
def request(method, *args)
  main_thread_only do
    @request_id += 1
    blocking = Fiber.current == @main_fiber

    log(:debug) do
      {
        method_name: method,
        request_id: @request_id,
        blocking: blocking,
        arguments: args
      }
    end

    @event_loop.request(@request_id, method, *args)
    response = blocking ? blocking_response : yielding_response

    raise(Disconnected) if response.nil?
    raise(response.error) if response.error
    response.value
  end
end
respond(request_id, value, error=nil) click to toggle source
# File lib/neovim/session.rb, line 79
def respond(request_id, value, error=nil)
  @event_loop.respond(request_id, value, error)
end
run(&block) click to toggle source
# File lib/neovim/session.rb, line 30
def run(&block)
  block ||= ->(msg) { @pending_messages << msg }

  @running = true

  @event_loop.run do |message|
    Fiber.new { message.received(@response_handlers, &block) }.resume
  end
end
shutdown() click to toggle source
# File lib/neovim/session.rb, line 87
def shutdown
  @running = false
  @event_loop.shutdown
end
stop() click to toggle source
# File lib/neovim/session.rb, line 92
def stop
  @running = false
  @event_loop.stop
end

Private Instance Methods

blocking_response() click to toggle source
# File lib/neovim/session.rb, line 99
def blocking_response
  @response_handlers[@request_id] = ->(res) { stop; res }
  run
end
main_thread_only() { || ... } click to toggle source
# File lib/neovim/session.rb, line 110
def main_thread_only
  if Thread.current == @main_thread
    yield if block_given?
  else
    raise(
      "A Ruby plugin attempted to call neovim outside of the main thread, " \
      "which is not yet supported by the neovim gem."
    )
  end
end
yielding_response() click to toggle source
# File lib/neovim/session.rb, line 104
def yielding_response
  fiber = Fiber.current
  @response_handlers[@request_id] = ->(response) { fiber.resume(response) }
  Fiber.yield
end