File: host.rb

package info (click to toggle)
ruby-neovim 0.10.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 548 kB
  • sloc: ruby: 4,178; sh: 23; makefile: 4
file content (107 lines) | stat: -rw-r--r-- 2,623 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
58
59
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
require "neovim"
require "neovim/client"
require "neovim/client_info"
require "neovim/event_loop"
require "neovim/host/loader"

module Neovim
  # @api private
  class Host
    include Logging

    attr_reader :plugins

    def self.run(rplugin_paths, event_loop=EventLoop.stdio)
      new(event_loop).tap do |host|
        Loader.new(host).load(rplugin_paths)
      end.run
    end

    def initialize(event_loop)
      @event_loop = event_loop
      @session = Session.new(event_loop)
      @handlers = {"poll" => poll_handler, "specs" => specs_handler}
      @plugins = []
      @specs = {}
    end

    def run
      @session.run { |msg| handle(msg) }
    end

    def handle(message)
      log(:debug) { message.to_h }

      @handlers
        .fetch(message.method_name, default_handler)
        .call(@client, message)
    rescue Exception => e
      log_exception(:error, e, __method__)

      if message.sync?
        @session.respond(message.id, nil, e.message)
      else
        @client.err_writeln("Exception handling #{message.method_name}: (#{e.class}) #{e.message}")
      end

      raise unless e.is_a?(StandardError)
    end

    private

    def poll_handler
      @poll_handler ||= lambda do |_, req|
        initialize_client(req.id)
        initialize_plugins

        @session.respond(req.id, "ok")
      end
    end

    def specs_handler
      @specs_handler ||= lambda do |_, req|
        source = req.arguments.fetch(0)

        if @specs.key?(source)
          @session.respond(req.id, @specs.fetch(source))
        else
          @session.respond(req.id, nil, "Unknown plugin #{source}")
        end
      end
    end

    def default_handler
      @default_handler ||= lambda do |_, message|
        next unless message.sync?
        @session.respond(message.id, nil, "Unknown request #{message.method_name}")
      end
    end

    def initialize_client(request_id)
      @session.request_id = request_id
      @session.notify(:nvim_set_client_info, *ClientInfo.for_host(self).to_args)

      @client = Client.from_event_loop(@event_loop, @session)
    end

    def initialize_plugins
      @plugins.each do |plugin|
        plugin.handlers.each do |handler|
          @handlers[handler.qualified_name] = wrap_plugin_handler(handler)
        end

        plugin.setup(@client)
        @specs[plugin.source] = plugin.specs
      end
    end

    def wrap_plugin_handler(handler)
      lambda do |client, message|
        args = message.arguments.flatten(1)
        result = handler.call(client, *args)

        @session.respond(message.id, result) if message.sync?
      end
    end
  end
end