neovim 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -1
  3. data/CHANGELOG.md +9 -3
  4. data/CODE_OF_CONDUCT.md +46 -0
  5. data/README.md +2 -2
  6. data/Rakefile +6 -6
  7. data/lib/neovim.rb +8 -7
  8. data/lib/neovim/api.rb +87 -0
  9. data/lib/neovim/buffer.rb +7 -1
  10. data/lib/neovim/client.rb +32 -6
  11. data/lib/neovim/event_loop.rb +114 -0
  12. data/lib/neovim/event_loop/connection.rb +78 -0
  13. data/lib/neovim/event_loop/message_builder.rb +127 -0
  14. data/lib/neovim/event_loop/serializer.rb +37 -0
  15. data/lib/neovim/host.rb +28 -28
  16. data/lib/neovim/logging.rb +41 -19
  17. data/lib/neovim/plugin/dsl.rb +6 -6
  18. data/lib/neovim/remote_object.rb +2 -2
  19. data/lib/neovim/ruby_provider.rb +8 -6
  20. data/lib/neovim/ruby_provider/vim.rb +2 -2
  21. data/lib/neovim/session.rb +42 -79
  22. data/lib/neovim/tabpage.rb +1 -1
  23. data/lib/neovim/version.rb +1 -1
  24. data/lib/neovim/window.rb +1 -1
  25. data/script/dump_api +4 -2
  26. data/script/generate_docs +2 -1
  27. data/spec/{integration → acceptance}/rplugin_autocmd_spec.vim +1 -1
  28. data/spec/{integration → acceptance}/rplugin_command_spec.vim +6 -2
  29. data/spec/{integration → acceptance}/rplugin_function_spec.vim +5 -2
  30. data/spec/{integration → acceptance}/ruby_spec.vim +18 -0
  31. data/spec/{integration → acceptance}/rubydo_spec.vim +0 -0
  32. data/spec/{integration → acceptance}/rubyfile/call_foo.rb +0 -0
  33. data/spec/{integration → acceptance}/rubyfile/curbuf_ivar_get.rb +0 -0
  34. data/spec/{integration → acceptance}/rubyfile/curbuf_ivar_set.rb +0 -0
  35. data/spec/{integration → acceptance}/rubyfile/define_foo.rb +0 -0
  36. data/spec/acceptance/rubyfile/nested.rb +1 -0
  37. data/spec/acceptance/rubyfile/nested_inner.rb +1 -0
  38. data/spec/{integration → acceptance}/rubyfile/raise_standard_error.rb +0 -0
  39. data/spec/{integration → acceptance}/rubyfile/raise_syntax_error.rb +0 -0
  40. data/spec/acceptance/rubyfile/ruby_interface.rb +8 -0
  41. data/spec/{integration → acceptance}/rubyfile/set_pwd_after.rb +0 -0
  42. data/spec/{integration → acceptance}/rubyfile/set_pwd_before.rb +0 -0
  43. data/spec/{integration → acceptance}/rubyfile_spec.vim +9 -0
  44. data/spec/acceptance/runtime/init.vim +8 -0
  45. data/spec/acceptance/runtime/rplugin.vim +37 -0
  46. data/spec/{integration → acceptance}/runtime/rplugin/ruby/autocmds.rb +1 -1
  47. data/spec/{integration → acceptance}/runtime/rplugin/ruby/commands.rb +9 -1
  48. data/spec/{integration → acceptance}/runtime/rplugin/ruby/functions.rb +9 -1
  49. data/spec/{integration → acceptance}/runtime/vader.vim/autoload/vader.vim +0 -0
  50. data/spec/{integration → acceptance}/runtime/vader.vim/autoload/vader/assert.vim +0 -0
  51. data/spec/{integration → acceptance}/runtime/vader.vim/autoload/vader/helper.vim +0 -0
  52. data/spec/{integration → acceptance}/runtime/vader.vim/autoload/vader/parser.vim +0 -0
  53. data/spec/{integration → acceptance}/runtime/vader.vim/autoload/vader/syntax.vim +0 -0
  54. data/spec/{integration → acceptance}/runtime/vader.vim/autoload/vader/window.vim +0 -0
  55. data/spec/{integration → acceptance}/runtime/vader.vim/plugin/vader.vim +0 -0
  56. data/spec/acceptance_spec.rb +74 -0
  57. data/spec/helper.rb +2 -32
  58. data/spec/neovim/api_spec.rb +59 -0
  59. data/spec/neovim/buffer_spec.rb +161 -2
  60. data/spec/neovim/client_spec.rb +18 -4
  61. data/spec/neovim/event_loop/connection_spec.rb +63 -0
  62. data/spec/neovim/event_loop/message_builder_spec.rb +105 -0
  63. data/spec/neovim/event_loop/serializer_spec.rb +63 -0
  64. data/spec/neovim/event_loop_spec.rb +81 -0
  65. data/spec/neovim/host/loader_spec.rb +0 -1
  66. data/spec/neovim/host_spec.rb +130 -161
  67. data/spec/neovim/logging_spec.rb +77 -5
  68. data/spec/neovim/session_spec.rb +54 -127
  69. data/spec/neovim/window_spec.rb +46 -0
  70. metadata +81 -81
  71. data/lib/neovim/session/api.rb +0 -95
  72. data/lib/neovim/session/event_loop.rb +0 -100
  73. data/lib/neovim/session/notification.rb +0 -19
  74. data/lib/neovim/session/request.rb +0 -31
  75. data/lib/neovim/session/rpc.rb +0 -95
  76. data/lib/neovim/session/serializer.rb +0 -62
  77. data/spec/integration/ruby_buffer_spec.rb +0 -151
  78. data/spec/integration/ruby_vim_spec.rb +0 -27
  79. data/spec/integration/ruby_window_spec.rb +0 -56
  80. data/spec/integration/runtime/init.vim +0 -9
  81. data/spec/integration_spec.rb +0 -119
  82. data/spec/neovim/session/api_spec.rb +0 -70
  83. data/spec/neovim/session/event_loop_spec.rb +0 -152
  84. data/spec/neovim/session/notification_spec.rb +0 -20
  85. data/spec/neovim/session/request_spec.rb +0 -36
  86. data/spec/neovim/session/rpc_spec.rb +0 -120
  87. data/spec/neovim/session/serializer_spec.rb +0 -62
@@ -5,10 +5,24 @@ module Neovim
5
5
  let(:client) { Neovim.attach_child(Support.child_argv) }
6
6
  after { client.shutdown }
7
7
 
8
- specify do
9
- client.strwidth("foo")
10
- client.strwidth("bar")
11
- client.command("echom 'hi'")
8
+ describe "#set_option" do
9
+ it "sets an option from two arguments" do
10
+ expect {
11
+ client.set_option("makeprg", "rake")
12
+ }.to change { client.evaluate("&makeprg") }.to("rake")
13
+ end
14
+
15
+ it "sets an option from a string" do
16
+ expect {
17
+ client.set_option("timeoutlen=0")
18
+ }.to change { client.evaluate("&timeoutlen") }.to(0)
19
+ end
20
+
21
+ it "sets a boolean option" do
22
+ expect {
23
+ client.set_option("expandtab")
24
+ }.to change { client.evaluate("&expandtab") }.to(1)
25
+ end
12
26
  end
13
27
 
14
28
  describe "#respond_to?" do
@@ -0,0 +1,63 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ class EventLoop
5
+ RSpec.describe Connection do
6
+ describe "#write" do
7
+ it "writes to the underlying file descriptor" do
8
+ rd, wr = IO.pipe
9
+ connection = Connection.new(nil, wr)
10
+ connection.write("some data")
11
+ wr.close
12
+
13
+ expect(rd.read).to eq("some data")
14
+ end
15
+
16
+ it "writes large amounts of data" do
17
+ File.open(Support.file_path("io"), "w+") do |io|
18
+ connection = Connection.new(nil, io)
19
+ big_data = Array.new(1024 * 16) { SecureRandom.hex(4) }.join
20
+
21
+ connection = Connection.new(nil, io)
22
+ connection.write(big_data)
23
+
24
+ expect(File.read(io.path)).to eq(big_data)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe "#read" do
30
+ it "yields data from the underlying file descriptor" do
31
+ rd, wr = IO.pipe
32
+ wr.write("some data")
33
+ wr.close
34
+
35
+ connection = Connection.new(rd, nil)
36
+
37
+ expect do |y|
38
+ connection.read(&y)
39
+ end.to yield_with_args("some data")
40
+ end
41
+ end
42
+
43
+ describe "#close" do
44
+ it "closes IO handles" do
45
+ rd, wr = ::IO.pipe
46
+ Connection.new(rd, wr).close
47
+
48
+ expect(rd).to be_closed
49
+ expect(wr).to be_closed
50
+ end
51
+
52
+ it "kills spawned processes" do
53
+ io = ::IO.popen("cat", "rb+")
54
+ pid = io.pid
55
+ expect(pid).to respond_to(:to_int)
56
+
57
+ Connection.new(io).close
58
+ expect { Process.kill(0, pid) }.to raise_error(Errno::ESRCH)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,105 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ class EventLoop
5
+ RSpec.describe MessageBuilder do
6
+ let(:message_builder) { MessageBuilder.new }
7
+
8
+ describe "#write" do
9
+ context "requests" do
10
+ it "yields a valid request message" do
11
+ expect do |y|
12
+ message_builder.write(:request, :method, [1, 2], Proc.new {}, &y)
13
+ end.to yield_with_args([0, 1, :method, [1, 2]])
14
+ end
15
+
16
+ it "increments the request id" do
17
+ expect do |y|
18
+ message_builder.write(:request, :method, [], Proc.new {}, &y)
19
+ message_builder.write(:request, :method, [], Proc.new {}, &y)
20
+ end.to yield_successive_args(
21
+ [0, 1, :method, []],
22
+ [0, 2, :method, []]
23
+ )
24
+ end
25
+ end
26
+
27
+ context "responses" do
28
+ it "yields a valid response message" do
29
+ expect do |y|
30
+ message_builder.write(:response, 2, :value, "error msg", &y)
31
+ end.to yield_with_args([1, 2, "error msg", :value])
32
+ end
33
+ end
34
+
35
+ context "notifications" do
36
+ it "yields a valid notification message" do
37
+ expect do |y|
38
+ message_builder.write(:notification, :method, [1, 2], &y)
39
+ end.to yield_with_args([2, :method, [1, 2]])
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "#read" do
45
+ context "requests" do
46
+ it "yields a request object" do
47
+ request = nil
48
+ message_builder.read([0, 1, :method, [1, 2]]) do |req|
49
+ request = req
50
+ end
51
+
52
+ expect(request.sync?).to eq(true)
53
+ expect(request.id).to eq(1)
54
+ expect(request.method_name).to eq(:method)
55
+ expect(request.arguments).to eq([1, 2])
56
+ end
57
+ end
58
+
59
+ context "responses" do
60
+ it "calls the registered handler with a success response" do
61
+ response = nil
62
+ handler = Proc.new { |res| response = res }
63
+
64
+ message_builder.write(:request, :method, [1, 2], handler) {}
65
+ message_builder.read([1, 1, [nil, nil], :result])
66
+
67
+ expect(response.request_id).to eq(1)
68
+ expect(response.value).to eq(:result)
69
+ expect(response.value!).to eq(:result)
70
+ expect(response.error).to eq(nil)
71
+ end
72
+
73
+ it "calls the registered handler with an error response" do
74
+ response = nil
75
+
76
+ handler = Proc.new do |res|
77
+ response = res
78
+ end
79
+
80
+ message_builder.write(:request, :method, [1, 2], handler) {}
81
+ message_builder.read([1, 1, [:some_err, "BOOM"], nil])
82
+
83
+ expect(response.request_id).to eq(1)
84
+ expect(response.error).to eq("BOOM")
85
+ expect(response.value).to eq(nil)
86
+ expect { response.value! }.to raise_error("BOOM")
87
+ end
88
+ end
89
+
90
+ context "notifications" do
91
+ it "yields a notification object" do
92
+ notification = nil
93
+ message_builder.read([2, :method, [1, 2]]) do |ntf|
94
+ notification = ntf
95
+ end
96
+
97
+ expect(notification.sync?).to eq(false)
98
+ expect(notification.method_name).to eq(:method)
99
+ expect(notification.arguments).to eq([1, 2])
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,63 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ class EventLoop
5
+ RSpec.describe Serializer do
6
+ let(:serializer) { Serializer.new }
7
+
8
+ describe "write" do
9
+ it "yields msgpack" do
10
+ expect do |y|
11
+ serializer.write([1, :foo], &y)
12
+ end.to yield_with_args(MessagePack.pack([1, :foo]))
13
+ end
14
+ end
15
+
16
+ describe "read" do
17
+ it "yields an unpacked object" do
18
+ expect do |y|
19
+ serializer.read(MessagePack.pack([1, :foo]), &y)
20
+ end.to yield_with_args([1, "foo"])
21
+ end
22
+
23
+ it "accumulates chunks of data and yields a single object" do
24
+ object = Array.new(16) { SecureRandom.hex(4) }
25
+ msgpack = MessagePack.pack(object)
26
+
27
+ expect do |y|
28
+ msgpack.chars.each_slice(10) do |chunk|
29
+ serializer.read(chunk.join, &y)
30
+ end
31
+ end.to yield_with_args(object)
32
+ end
33
+ end
34
+
35
+ describe "#register_type" do
36
+ it "registers a msgpack ext type" do
37
+ ext_class = Struct.new(:id) do
38
+ def self.from_msgpack_ext(data)
39
+ new(data.unpack('N')[0])
40
+ end
41
+
42
+ def to_msgpack_ext
43
+ [self.id].pack('C')
44
+ end
45
+ end
46
+
47
+ serializer.register_type(42) do |id|
48
+ ext_class.new(id)
49
+ end
50
+
51
+ factory = MessagePack::Factory.new
52
+ factory.register_type(42, ext_class)
53
+ obj = ext_class.new(1)
54
+ msgpack = factory.packer.write(obj).flush.to_str
55
+
56
+ expect do |y|
57
+ serializer.read(msgpack, &y)
58
+ end.to yield_with_args(obj)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,81 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ RSpec.describe EventLoop do
5
+ let!(:push_pipe) { IO.pipe }
6
+ let!(:pull_pipe) { IO.pipe }
7
+
8
+ let(:client_rd) { push_pipe[0] }
9
+ let(:client_wr) { pull_pipe[1] }
10
+ let(:server_rd) { pull_pipe[0] }
11
+ let(:server_wr) { push_pipe[1] }
12
+
13
+ let(:connection) { EventLoop::Connection.new(client_rd, client_wr) }
14
+ let(:event_loop) { EventLoop.new(connection) }
15
+
16
+ describe "#run" do
17
+ it "reads requests" do
18
+ server_wr.write(MessagePack.pack([0, 1, :foo_method, []]))
19
+ server_wr.flush
20
+
21
+ request = nil
22
+ event_loop.run do |req|
23
+ request = req
24
+ event_loop.stop
25
+ end
26
+ expect(request.method_name).to eq("foo_method")
27
+ end
28
+
29
+ it "writes requests" do
30
+ response = nil
31
+
32
+ event_loop.request(:foo_method) do |res|
33
+ response = res
34
+ event_loop.stop
35
+ end
36
+
37
+ server_wr.write(MessagePack.pack([1, 1, nil, :value]))
38
+ server_wr.flush
39
+
40
+ event_loop.run
41
+ expect(response.value!).to eq("value")
42
+ end
43
+
44
+ it "writes responses" do
45
+ event_loop.respond(1, :foo_response, nil)
46
+
47
+ server_wr.write(MessagePack.pack([2, :noop, []]))
48
+ server_wr.flush
49
+
50
+ event_loop.run { event_loop.stop }
51
+ expect(server_rd.readpartial(1024)).to eq(
52
+ MessagePack.pack([1, 1, nil, :foo_response])
53
+ )
54
+ end
55
+
56
+ it "reads notifications" do
57
+ server_wr.write(MessagePack.pack([2, :foo_notification, []]))
58
+ server_wr.flush
59
+
60
+ notification = nil
61
+ event_loop.run do |ntf|
62
+ notification = ntf
63
+ event_loop.stop
64
+ end
65
+ expect(notification.method_name).to eq("foo_notification")
66
+ end
67
+
68
+ it "writes notifications" do
69
+ event_loop.notify(:foo_notification)
70
+
71
+ server_wr.write(MessagePack.pack([2, :noop, []]))
72
+ server_wr.flush
73
+
74
+ event_loop.run { event_loop.stop }
75
+ expect(server_rd.readpartial(1024)).to eq(
76
+ MessagePack.pack([2, :foo_notification, []])
77
+ )
78
+ end
79
+ end
80
+ end
81
+ end
@@ -1,6 +1,5 @@
1
1
  require "helper"
2
2
  require "neovim/host"
3
- require "neovim/host/loader"
4
3
 
5
4
  module Neovim
6
5
  class Host
@@ -3,175 +3,144 @@ require "neovim/host"
3
3
 
4
4
  module Neovim
5
5
  RSpec.describe Host do
6
- let(:session) { instance_double(Session) }
7
- let(:client) { instance_double(Client) }
8
- let(:host) { Host.new(session, client) }
9
-
10
6
  describe ".run" do
11
- it "loads plugins and runs the host event loop" do
12
- paths = ["/foo", "/bar"]
13
-
14
- expect(Host).to receive(:new).and_return(host)
15
- expect(host).to receive(:run)
16
-
17
- loader = instance_double(Host::Loader)
18
-
19
- expect(loader).to receive(:load).with(paths)
20
- expect(Host::Loader).to receive(:new).
21
- with(host).
22
- and_return(loader)
23
-
24
- Host.run(paths, :session => session, :client => client)
25
- end
26
- end
27
-
28
- describe "#run" do
29
- it "runs the session event loop and handles messages" do
30
- message = double(:message)
31
- expect(session).to receive(:run).and_yield(message)
32
- expect(host).to receive(:handle).with(message)
33
-
34
- host.run
35
- end
36
-
37
- it "rescues session exceptions", :silence_warnings do
38
- expect(session).to receive(:run).and_raise("BOOM")
39
- expect { host.run }.not_to raise_error
40
- end
41
- end
42
-
43
- describe "#handlers" do
44
- it "has a default poll handler" do
45
- expect(host.handlers["poll"]).to respond_to(:call)
46
- end
47
- end
48
-
49
- describe "#specs" do
50
- it "has default specs" do
51
- expect(host.specs).to eq({})
52
- end
53
- end
54
-
55
- describe "#register" do
56
- it "adds specs" do
57
- plugin = Plugin.from_config_block("source") do |plug|
58
- plug.command(:Foo)
7
+ let!(:push_pipe) { IO.pipe }
8
+ let!(:pull_pipe) { IO.pipe }
9
+
10
+ let(:host_rd) { push_pipe[0] }
11
+ let(:host_wr) { pull_pipe[1] }
12
+ let(:nvim_rd) { pull_pipe[0] }
13
+ let(:nvim_wr) { push_pipe[1] }
14
+
15
+ let(:plugin_path) do
16
+ Support.file_path("my_plugin").tap do |path|
17
+ File.write(path, <<-PLUGIN)
18
+ Neovim.plugin do |plug|
19
+ plug.command(:StrWidth, :nargs => 1, :sync => true) do |client, arg|
20
+ arg.bytesize
21
+ end
22
+
23
+ plug.command(:Boom, :sync => true) do |client|
24
+ raise "BOOM"
25
+ end
26
+
27
+ plug.command(:BoomAsync) do |client|
28
+ raise "BOOM ASYNC"
29
+ end
30
+ end
31
+ PLUGIN
59
32
  end
60
-
61
- expect {
62
- host.register(plugin)
63
- }.to change { host.specs }.from({}).to("source" => plugin.specs)
64
33
  end
65
34
 
66
- it "adds plugin handlers" do
67
- plugin = Plugin.from_config_block("source") do |plug|
68
- plug.command(:Foo)
69
- end
35
+ let!(:host_thread) do
36
+ connection = EventLoop::Connection.new(host_rd, host_wr)
37
+ event_loop = EventLoop.new(connection)
70
38
 
71
- expect {
72
- host.register(plugin)
73
- }.to change {
74
- host.handlers["source:command:Foo"]
75
- }.from(nil).to(kind_of(Proc))
76
- end
77
-
78
- it "yields a client to the plugin setup blocks" do
79
- yielded = []
80
-
81
- plugin = Plugin.from_config_block("source") do |plug|
82
- plug.__send__(:setup) do |client|
83
- yielded << client
84
- end
85
-
86
- plug.__send__(:setup) do |_|
87
- yielded << :other
88
- end
39
+ Thread.new do
40
+ Host.run([plugin_path], event_loop)
89
41
  end
90
-
91
- expect {
92
- host.register(plugin)
93
- }.to change { yielded }.from([]).to([client, :other])
94
42
  end
95
43
 
96
- it "doesn't add top-level RPCs to specs" do
97
- plugin = Plugin.from_config_block("source") do |plug|
98
- plug.__send__(:rpc, :Foo)
99
- end
100
-
101
- expect {
102
- host.register(plugin)
103
- }.to change { host.specs }.from({}).to("source" => [])
104
- end
105
- end
106
-
107
- describe "#handle" do
108
- it "calls the poll handler" do
109
- message = double(:message, :method_name => "poll", :sync? => true)
110
-
111
- expect(message).to receive(:respond).with("ok")
112
- host.handle(message)
113
- end
114
-
115
- it "calls the specs handler" do
116
- plugin = Plugin.from_config_block("source") do |plug|
117
- plug.command(:Foo)
118
- end
119
- host.register(plugin)
120
-
121
- message = double(:message, :method_name => "specs", :sync? => true, :arguments => ["source"])
122
-
123
- expect(message).to receive(:respond).with(plugin.specs)
124
- host.handle(message)
125
- end
126
-
127
- it "calls a plugin sync handler" do
128
- plugin = Plugin.from_config_block("source") do |plug|
129
- plug.command(:Foo, :sync => true) { |client, arg| [client, arg] }
130
- end
131
- host.register(plugin)
132
-
133
- message = double(:message, :method_name => "source:command:Foo", :sync? => true, :arguments => [:arg])
134
-
135
- expect(message).to receive(:respond).with([client, :arg])
136
- host.handle(message)
137
- end
138
-
139
- it "rescues plugin sync handler exceptions", :silence_warnings do
140
- plugin = Plugin.from_config_block("source") do |plug|
141
- plug.command(:Foo, :sync => true) { raise "BOOM" }
142
- end
143
- host.register(plugin)
144
-
145
- message = double(:message, :method_name => "source:command:Foo", :sync? => true, :arguments => [])
146
-
147
- expect(message).to receive(:error).with("BOOM")
148
- host.handle(message)
149
- end
150
-
151
- it "calls a plugin async handler" do
152
- async_proc = Proc.new {}
153
- plugin = Plugin.from_config_block("source") do |plug|
154
- plug.command(:Foo, &async_proc)
155
- end
156
- host.register(plugin)
157
-
158
- message = double(:message, :method_name => "source:command:Foo", :sync? => false, :arguments => [:arg])
159
-
160
- expect(async_proc).to receive(:call).with(client, :arg)
161
- host.handle(message)
162
- end
163
-
164
- it "calls a default sync handler" do
165
- message = double(:message, :method_name => "foobar", :sync? => true)
166
-
167
- expect(message).to receive(:error).with("Unknown request foobar")
168
- host.handle(message)
169
- end
170
-
171
- it "calls a default async handler" do
172
- message = double(:message, :method_name => "foobar", :sync? => false)
173
-
174
- host.handle(message)
44
+ before do
45
+ _, reqid, method = MessagePack.unpack(nvim_rd.readpartial(1024))
46
+ expect(method).to eq("nvim_get_api_info")
47
+
48
+ session = Session.new(EventLoop.child(Support.child_argv))
49
+ api_info = session.request(:nvim_get_api_info)
50
+ session.shutdown
51
+
52
+ nvim_wr.write(MessagePack.pack([1, reqid, nil, api_info]))
53
+ nvim_wr.flush
54
+ end
55
+
56
+ after do
57
+ host_thread.kill
58
+ host_thread.join
59
+ end
60
+
61
+ it "responds 'ok' to the 'poll' request" do
62
+ message = MessagePack.pack([0, 0, :poll, []])
63
+ nvim_wr.write(message)
64
+ nvim_wr.flush
65
+
66
+ response = MessagePack.unpack(nvim_rd.readpartial(1024))
67
+ expect(response).to eq([1, 0, nil, "ok"])
68
+ end
69
+
70
+ it "responds with specs to the 'specs' request" do
71
+ message = MessagePack.pack([0, 0, :specs, [plugin_path]])
72
+ nvim_wr.write(message)
73
+ nvim_wr.flush
74
+
75
+ response = MessagePack.unpack(nvim_rd.readpartial(1024))
76
+ expect(response).to eq(
77
+ [
78
+ 1,
79
+ 0,
80
+ nil,
81
+ [
82
+ {
83
+ "type" => "command",
84
+ "name" => "StrWidth",
85
+ "sync" => true,
86
+ "opts" => {"nargs" => 1},
87
+ },
88
+ {
89
+ "type" => "command",
90
+ "name" => "Boom",
91
+ "sync" => true,
92
+ "opts" => {},
93
+ },
94
+ {
95
+ "type" => "command",
96
+ "name" => "BoomAsync",
97
+ "sync" => false,
98
+ "opts" => {},
99
+ },
100
+ ],
101
+ ],
102
+ )
103
+ end
104
+
105
+ it "delegates to plugin handlers" do
106
+ message = MessagePack.pack([0, 0, "#{plugin_path}:command:StrWidth", ["hi"]])
107
+ nvim_wr.write(message)
108
+ nvim_wr.flush
109
+
110
+ response = MessagePack.unpack(nvim_rd.readpartial(1024))
111
+ expect(response).to eq([1, 0, nil, 2])
112
+ end
113
+
114
+ it "handles exceptions in sync plugin handlers" do
115
+ message = MessagePack.pack([0, 0, "#{plugin_path}:command:Boom", ["hi"]])
116
+ nvim_wr.write(message)
117
+ nvim_wr.flush
118
+
119
+ response = MessagePack.unpack(nvim_rd.readpartial(1024))
120
+ expect(response).to eq([1, 0, "BOOM", nil])
121
+ end
122
+
123
+ it "handles exceptions in async plugin handlers" do
124
+ message = MessagePack.pack([2, "#{plugin_path}:command:BoomAsync", ["hi"]])
125
+ nvim_wr.write(message)
126
+ nvim_wr.flush
127
+
128
+ message = MessagePack.unpack(nvim_rd.readpartial(1024))
129
+ expect(message).to match_array(
130
+ [
131
+ 0, duck_type(:to_int), "nvim_err_writeln",
132
+ [/my_plugin:command:BoomAsync: \(RuntimeError\) BOOM ASYNC/]
133
+ ]
134
+ )
135
+ end
136
+
137
+ it "handles unknown requests" do
138
+ message = MessagePack.pack([0, 0, "foobar", []])
139
+ nvim_wr.write(message)
140
+ nvim_wr.flush
141
+
142
+ response = MessagePack.unpack(nvim_rd.readpartial(1024))
143
+ expect(response).to eq([1, 0, "Unknown request foobar", nil])
175
144
  end
176
145
  end
177
146
  end