neovim 0.6.2 → 0.9.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/docs.yml +36 -0
  3. data/.github/workflows/linter.yml +32 -0
  4. data/.github/workflows/tests.yml +62 -0
  5. data/.gitignore +5 -1
  6. data/.rubocop.yml +149 -0
  7. data/CHANGELOG.md +56 -0
  8. data/CODE_OF_CONDUCT.md +3 -3
  9. data/Gemfile +0 -11
  10. data/README.md +22 -23
  11. data/Rakefile +47 -15
  12. data/VimFlavor +1 -0
  13. data/exe/neovim-ruby-host +5 -0
  14. data/lib/neovim.rb +15 -6
  15. data/lib/neovim/api.rb +2 -1
  16. data/lib/neovim/buffer.rb +81 -53
  17. data/lib/neovim/client.rb +226 -41
  18. data/lib/neovim/client_info.rb +46 -0
  19. data/lib/neovim/connection.rb +73 -0
  20. data/lib/neovim/event_loop.rb +41 -37
  21. data/lib/neovim/executable.rb +1 -0
  22. data/lib/neovim/host.rb +50 -51
  23. data/lib/neovim/host/cli.rb +41 -0
  24. data/lib/neovim/host/loader.rb +1 -4
  25. data/lib/neovim/line_range.rb +16 -16
  26. data/lib/neovim/logging.rb +18 -18
  27. data/lib/neovim/message.rb +70 -0
  28. data/lib/neovim/plugin.rb +7 -5
  29. data/lib/neovim/plugin/dsl.rb +10 -4
  30. data/lib/neovim/plugin/handler.rb +8 -8
  31. data/lib/neovim/remote_object.rb +8 -5
  32. data/lib/neovim/ruby_provider.rb +52 -26
  33. data/lib/neovim/ruby_provider/buffer_ext.rb +1 -0
  34. data/lib/neovim/ruby_provider/object_ext.rb +5 -0
  35. data/lib/neovim/ruby_provider/vim.rb +19 -6
  36. data/lib/neovim/ruby_provider/window_ext.rb +1 -0
  37. data/lib/neovim/session.rb +45 -50
  38. data/lib/neovim/tabpage.rb +8 -15
  39. data/lib/neovim/version.rb +1 -1
  40. data/lib/neovim/window.rb +39 -36
  41. data/neovim.gemspec +11 -6
  42. data/script/ci/download_nvim.sh +40 -0
  43. data/script/{dump_api → dump_api.rb} +1 -1
  44. data/script/{generate_docs → generate_docs.rb} +6 -7
  45. data/script/{j2mp → j2mp.rb} +0 -0
  46. data/script/{mp2j → mp2j.rb} +0 -0
  47. data/script/run_acceptance.rb +39 -0
  48. data/spec/acceptance/client_info_spec.vim +42 -0
  49. data/spec/acceptance/rplugin_autocmd_spec.vim +20 -10
  50. data/spec/acceptance/rplugin_command_spec.vim +54 -56
  51. data/spec/acceptance/rplugin_function_spec.vim +28 -22
  52. data/spec/acceptance/ruby_spec.vim +52 -53
  53. data/spec/acceptance/rubydo_spec.vim +49 -52
  54. data/spec/acceptance/rubyeval_spec.vim +22 -0
  55. data/spec/acceptance/rubyfile/curbuf_ivar_get.rb +1 -1
  56. data/spec/acceptance/rubyfile/curbuf_ivar_set.rb +1 -1
  57. data/spec/acceptance/rubyfile/define_foo.rb +1 -1
  58. data/spec/acceptance/rubyfile/nested.rb +1 -1
  59. data/spec/acceptance/rubyfile/nested_inner.rb +1 -1
  60. data/spec/acceptance/rubyfile/set_pwd_after.rb +1 -1
  61. data/spec/acceptance/rubyfile/set_pwd_before.rb +1 -1
  62. data/spec/acceptance/rubyfile_spec.vim +60 -66
  63. data/spec/acceptance/runtime/init.vim +5 -4
  64. data/spec/acceptance/runtime/rplugin/ruby/autocmds.rb +7 -3
  65. data/spec/acceptance/runtime/rplugin/ruby/commands.rb +18 -17
  66. data/spec/acceptance/runtime/rplugin/ruby/functions.rb +9 -9
  67. data/spec/helper.rb +38 -9
  68. data/spec/neovim/api_spec.rb +2 -2
  69. data/spec/neovim/buffer_spec.rb +10 -6
  70. data/spec/neovim/client_info_spec.rb +77 -0
  71. data/spec/neovim/client_spec.rb +19 -12
  72. data/spec/neovim/connection_spec.rb +106 -0
  73. data/spec/neovim/current_spec.rb +13 -14
  74. data/spec/neovim/event_loop_spec.rb +48 -46
  75. data/spec/neovim/executable_spec.rb +2 -2
  76. data/spec/neovim/host/cli_spec.rb +94 -0
  77. data/spec/neovim/host/loader_spec.rb +18 -11
  78. data/spec/neovim/host_spec.rb +84 -92
  79. data/spec/neovim/line_range_spec.rb +17 -19
  80. data/spec/neovim/logging_spec.rb +3 -3
  81. data/spec/neovim/message_spec.rb +119 -0
  82. data/spec/neovim/plugin_spec.rb +34 -34
  83. data/spec/neovim/remote_object_spec.rb +1 -2
  84. data/spec/neovim/ruby_provider/buffer_ext_spec.rb +8 -9
  85. data/spec/neovim/ruby_provider/object_ext_spec.rb +10 -0
  86. data/spec/neovim/ruby_provider/vim_spec.rb +5 -5
  87. data/spec/neovim/ruby_provider/window_ext_spec.rb +12 -15
  88. data/spec/neovim/session_spec.rb +20 -47
  89. data/spec/neovim/window_spec.rb +1 -2
  90. data/spec/neovim_spec.rb +28 -51
  91. data/spec/support.rb +27 -1
  92. metadata +83 -48
  93. data/.coveralls.yml +0 -1
  94. data/.gitmodules +0 -3
  95. data/.rspec +0 -1
  96. data/.travis.yml +0 -23
  97. data/appveyor.yml +0 -21
  98. data/bin/neovim-ruby-host +0 -18
  99. data/lib/neovim/event_loop/connection.rb +0 -78
  100. data/lib/neovim/event_loop/message_builder.rb +0 -127
  101. data/lib/neovim/event_loop/serializer.rb +0 -37
  102. data/spec/acceptance/runtime/rplugin.vim +0 -37
  103. data/spec/acceptance/runtime/vader.vim/autoload/vader.vim +0 -348
  104. data/spec/acceptance/runtime/vader.vim/autoload/vader/assert.vim +0 -116
  105. data/spec/acceptance/runtime/vader.vim/autoload/vader/helper.vim +0 -43
  106. data/spec/acceptance/runtime/vader.vim/autoload/vader/parser.vim +0 -179
  107. data/spec/acceptance/runtime/vader.vim/autoload/vader/syntax.vim +0 -73
  108. data/spec/acceptance/runtime/vader.vim/autoload/vader/window.vim +0 -205
  109. data/spec/acceptance/runtime/vader.vim/plugin/vader.vim +0 -37
  110. data/spec/acceptance_spec.rb +0 -82
  111. data/spec/neovim/event_loop/connection_spec.rb +0 -89
  112. data/spec/neovim/event_loop/message_builder_spec.rb +0 -105
  113. data/spec/neovim/event_loop/serializer_spec.rb +0 -63
@@ -10,71 +10,73 @@ module Neovim
10
10
  let(:server_rd) { pull_pipe[0] }
11
11
  let(:server_wr) { push_pipe[1] }
12
12
 
13
- let(:connection) { EventLoop::Connection.new(client_rd, client_wr) }
13
+ let(:connection) { Connection.new(client_rd, client_wr) }
14
14
  let(:event_loop) { EventLoop.new(connection) }
15
15
 
16
- describe "#run" do
17
- it "reads requests" do
18
- server_wr.write(MessagePack.pack([0, 1, :foo_method, []]))
19
- server_wr.flush
16
+ describe "#request" do
17
+ it "writes a msgpack request" do
18
+ event_loop.request(1, :method, 1, 2)
19
+ connection.flush
20
+ message = server_rd.readpartial(1024)
20
21
 
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")
22
+ expect(message).to eq(MessagePack.pack([0, 1, "method", [1, 2]]))
27
23
  end
24
+ end
28
25
 
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
26
+ describe "#respond" do
27
+ it "writes a msgpack response" do
28
+ event_loop.respond(2, "value", "error")
29
+ connection.flush
30
+ message = server_rd.readpartial(1024)
36
31
 
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")
32
+ expect(message).to eq(MessagePack.pack([1, 2, "error", "value"]))
42
33
  end
34
+ end
43
35
 
44
- it "writes responses" do
45
- event_loop.respond(1, :foo_response, nil)
36
+ describe "#notify" do
37
+ it "writes a msgpack notification" do
38
+ event_loop.notify(:method, 1, 2)
39
+ connection.flush
40
+ message = server_rd.readpartial(1024)
46
41
 
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
- )
42
+ expect(message).to eq(MessagePack.pack([2, "method", [1, 2]]))
54
43
  end
44
+ end
55
45
 
56
- it "reads notifications" do
57
- server_wr.write(MessagePack.pack([2, :foo_notification, []]))
46
+ describe "#run" do
47
+ it "yields received messages to the block" do
48
+ server_wr.write(MessagePack.pack([0, 1, :foo_method, []]))
58
49
  server_wr.flush
59
50
 
60
- notification = nil
61
- event_loop.run do |ntf|
62
- notification = ntf
51
+ message = nil
52
+ event_loop.run do |req|
53
+ message = req
63
54
  event_loop.stop
64
55
  end
65
- expect(notification.method_name).to eq("foo_notification")
66
- end
67
56
 
68
- it "writes notifications" do
69
- event_loop.notify(:foo_notification)
57
+ expect(message.sync?).to eq(true)
58
+ expect(message.method_name).to eq("foo_method")
59
+ end
70
60
 
71
- server_wr.write(MessagePack.pack([2, :noop, []]))
61
+ it "returns the last message received" do
62
+ server_wr.write(MessagePack.pack([0, 1, :foo_method, []]))
72
63
  server_wr.flush
73
64
 
74
- event_loop.run { event_loop.stop }
75
- expect(server_rd.readpartial(1024)).to eq(
76
- MessagePack.pack([2, :foo_notification, []])
77
- )
65
+ message = event_loop.run { |req| event_loop.stop; req }
66
+
67
+ expect(message.sync?).to eq(true)
68
+ expect(message.method_name).to eq("foo_method")
69
+ end
70
+
71
+ it "shuts down after receiving EOFError" do
72
+ run_thread = Thread.new do
73
+ event_loop.run
74
+ end
75
+
76
+ server_wr.close
77
+ run_thread.join
78
+ expect(client_rd).to be_closed
79
+ expect(client_wr).to be_closed
78
80
  end
79
81
  end
80
82
  end
@@ -23,9 +23,9 @@ module Neovim
23
23
  it "raises with an invalid executable path" do
24
24
  executable = Executable.new(File::NULL)
25
25
 
26
- expect {
26
+ expect do
27
27
  executable.version
28
- }.to raise_error(Executable::Error, Regexp.new(File::NULL))
28
+ end.to raise_error(Executable::Error, Regexp.new(File::NULL))
29
29
  end
30
30
  end
31
31
  end
@@ -0,0 +1,94 @@
1
+ require "helper"
2
+ require "neovim/host/cli"
3
+
4
+ begin
5
+ require "pty"
6
+ rescue LoadError
7
+ # Not available on Windows
8
+ end
9
+
10
+ module Neovim
11
+ class Host
12
+ RSpec.describe CLI do
13
+ let(:stdin) { StringIO.new }
14
+ let(:stdout) { StringIO.new }
15
+ let(:stderr) { StringIO.new }
16
+
17
+ specify "-V" do
18
+ expect do
19
+ CLI.run("/exe/nv-rb-host", ["-V"], stdin, stdout, stderr)
20
+ end.to raise_error(SystemExit) { |e| expect(e.status).to eq(0) }
21
+
22
+ expect(stderr.string).to be_empty
23
+ expect(stdout.string).to eq(Neovim::VERSION.to_s + "\n")
24
+ end
25
+
26
+ specify "-h" do
27
+ expect do
28
+ CLI.run("/exe/nv-rb-host", ["-h"], stdin, stdout, stderr)
29
+ end.to raise_error(SystemExit) { |e| expect(e.status).to eq(0) }
30
+
31
+ expect(stderr.string).to be_empty
32
+ expect(stdout.string).to eq("Usage: nv-rb-host [-hV] rplugin_path ...\n")
33
+ end
34
+
35
+ it "fails with invalid arguments" do
36
+ expect do
37
+ CLI.run("/exe/nv-rb-host", ["-x"], stdin, stdout, stderr)
38
+ end.to raise_error(SystemExit) { |e| expect(e.status).to eq(1) }
39
+
40
+ expect(stdout.string).to be_empty
41
+ expect(stderr.string).to eq("invalid option: -x\n")
42
+ end
43
+
44
+ it "fails when run interactively" do
45
+ if !defined?(PTY)
46
+ skip "Skipping without `pty` library."
47
+ end
48
+
49
+ PTY.open do |tty,|
50
+ expect do
51
+ CLI.run("/exe/nv-rb-host", ["plugin.rb"], tty, stdout, stderr)
52
+ end.to raise_error(SystemExit) { |e| expect(e.status).to eq(1) }
53
+
54
+ expect(stdout.string).to be_empty
55
+ expect(stderr.string).to eq("Can't run nv-rb-host interactively.\n")
56
+ end
57
+ end
58
+
59
+ it "starts a stdio host" do
60
+ nvim_r, host_w = IO.pipe
61
+ host_r, nvim_w = IO.pipe
62
+
63
+ nvim_u = MessagePack::Unpacker.new(nvim_r)
64
+ nvim_p = MessagePack::Packer.new(nvim_w)
65
+
66
+ Support.file_path("plugin").tap do |path|
67
+ File.write(path, "Neovim.plugin { |p| p.function('Foo') }")
68
+
69
+ thr = Thread.new do
70
+ CLI.run("/exe/nv-rb-host", [path], host_r, host_w, stderr)
71
+ end
72
+
73
+ begin
74
+ nvim_p.write([0, 1, :poll, []]).flush
75
+
76
+ expect(nvim_u.read[0..1]).to eq([2, "nvim_set_client_info"])
77
+ expect(nvim_u.read[0..2]).to eq([0, 2, "nvim_get_api_info"])
78
+
79
+ nvim_p.write([1, 2, nil, [10, {"functions" => {}, "types" => {}}]]).flush
80
+ expect(nvim_u.read).to eq([1, 1, nil, "ok"])
81
+
82
+ nvim_p.write([0, 3, :specs, [path]]).flush
83
+ *prefix, (payload, *) = nvim_u.read
84
+
85
+ expect(prefix).to eq([1, 3, nil])
86
+ expect(payload["name"]).to eq("Foo")
87
+ ensure
88
+ thr.kill.join
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -6,7 +6,7 @@ module Neovim
6
6
  RSpec.describe Loader do
7
7
  describe "#load" do
8
8
  let(:plugin_path) { Support.file_path("plug.rb") }
9
- let(:host) { instance_double(Host, :register => nil) }
9
+ let(:host) { instance_double(Host, plugins: []) }
10
10
  let(:loader) { Loader.new(host) }
11
11
 
12
12
  before do
@@ -14,33 +14,40 @@ module Neovim
14
14
  end
15
15
 
16
16
  it "registers plugins defined in the provided files" do
17
- expect(host).to receive(:register).with(kind_of(Plugin))
18
- loader.load([plugin_path])
17
+ expect do
18
+ loader.load([plugin_path])
19
+ end.to change { host.plugins.size }.by(1)
19
20
  end
20
21
 
21
22
  it "registers multiple plugins defined in the provided files" do
22
23
  File.write(plugin_path, "Neovim.plugin; Neovim.plugin")
23
- expect(host).to receive(:register).with(kind_of(Plugin)).twice
24
- loader.load([plugin_path])
24
+
25
+ expect do
26
+ loader.load([plugin_path])
27
+ end.to change { host.plugins.size }.by(2)
25
28
  end
26
29
 
27
30
  it "doesn't register plugins when none are defined" do
28
31
  File.write(plugin_path, "class FooClass; end")
29
- expect(host).not_to receive(:register)
30
- loader.load([plugin_path])
32
+
33
+ expect do
34
+ loader.load([plugin_path])
35
+ end.not_to change { host.plugins.size }
31
36
  end
32
37
 
33
38
  it "doesn't leak constants defined in plugins" do
34
39
  File.write(plugin_path, "class FooClass; end")
35
- loader.load([plugin_path])
36
- expect(Kernel.const_defined?(:FooClass)).to be(false)
40
+
41
+ expect do
42
+ loader.load([plugin_path])
43
+ end.not_to change { Kernel.const_defined?(:FooClass) }.from(false)
37
44
  end
38
45
 
39
46
  it "doesn't leak the overidden Neovim.plugin method" do
40
47
  loader.load([plugin_path])
41
- expect {
48
+ expect do
42
49
  Neovim.plugin
43
- }.to raise_error(/outside of a plugin host/)
50
+ end.to raise_error(/outside of a plugin host/)
44
51
  end
45
52
  end
46
53
  end
@@ -9,18 +9,18 @@ module Neovim
9
9
 
10
10
  let(:host_rd) { push_pipe[0] }
11
11
  let(:host_wr) { pull_pipe[1] }
12
- let(:nvim_rd) { pull_pipe[0] }
13
- let(:nvim_wr) { push_pipe[1] }
12
+ let(:nvim_rd) { MessagePack::Unpacker.new(pull_pipe[0]) }
13
+ let(:nvim_wr) { MessagePack::Packer.new(push_pipe[1]) }
14
14
 
15
15
  let(:plugin_path) do
16
16
  Support.file_path("my_plugin").tap do |path|
17
17
  File.write(path, <<-PLUGIN)
18
18
  Neovim.plugin do |plug|
19
- plug.command(:StrWidth, :nargs => 1, :sync => true) do |client, arg|
20
- arg.bytesize
19
+ plug.command(:Echo, nargs: 1, sync: true) do |client, arg|
20
+ arg
21
21
  end
22
22
 
23
- plug.command(:Boom, :sync => true) do |client|
23
+ plug.command(:Boom, sync: true) do |client|
24
24
  raise "BOOM"
25
25
  end
26
26
 
@@ -33,7 +33,7 @@ module Neovim
33
33
  end
34
34
 
35
35
  let!(:host_thread) do
36
- connection = EventLoop::Connection.new(host_rd, host_wr)
36
+ connection = Connection.new(host_rd, host_wr)
37
37
  event_loop = EventLoop.new(connection)
38
38
 
39
39
  Thread.new do
@@ -41,106 +41,98 @@ module Neovim
41
41
  end
42
42
  end
43
43
 
44
- before do
45
- _, reqid, method = MessagePack.unpack(nvim_rd.readpartial(1024))
46
- expect(method).to eq("nvim_get_api_info")
44
+ after { host_thread.kill.join }
47
45
 
48
- session = Session.new(EventLoop.child(Support.child_argv))
49
- api_info = session.request(:nvim_get_api_info)
50
- session.shutdown
46
+ context "poll" do
47
+ it "initializes a client, sets client info, and responds 'ok'" do
48
+ nvim_wr.write([0, 1, :poll, []]).flush
51
49
 
52
- nvim_wr.write(MessagePack.pack([1, reqid, nil, api_info]))
53
- nvim_wr.flush
54
- end
50
+ expect(nvim_rd.read).to match([2, "nvim_set_client_info", duck_type(:to_ary)])
55
51
 
56
- after do
57
- host_thread.kill
58
- host_thread.join
59
- end
52
+ type, reqid, method = nvim_rd.read
53
+ expect([type, reqid, method]).to match([0, duck_type(:to_int), "nvim_get_api_info"])
60
54
 
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
55
+ api_info = [0, {"types" => {}, "functions" => {}}]
56
+ nvim_wr.write([1, reqid, nil, api_info]).flush
65
57
 
66
- response = MessagePack.unpack(nvim_rd.readpartial(1024))
67
- expect(response).to eq([1, 0, nil, "ok"])
58
+ expect(nvim_rd.read).to eq([1, 1, nil, "ok"])
59
+ end
68
60
  end
69
61
 
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
62
+ context "after poll" do
63
+ before do
64
+ nvim_wr.write([0, 1, :poll, []]).flush
104
65
 
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
66
+ expect(nvim_rd.read[1]).to eq("nvim_set_client_info")
109
67
 
110
- response = MessagePack.unpack(nvim_rd.readpartial(1024))
111
- expect(response).to eq([1, 0, nil, 2])
112
- end
68
+ _, reqid, method = nvim_rd.read
113
69
 
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
70
+ expect(method).to eq("nvim_get_api_info")
118
71
 
119
- response = MessagePack.unpack(nvim_rd.readpartial(1024))
120
- expect(response).to eq([1, 0, "BOOM", nil])
121
- end
72
+ api_info = Support.persistent_client.get_api_info
122
73
 
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
74
+ nvim_wr.write([1, reqid, nil, api_info]).flush
75
+
76
+ expect(nvim_rd.read[3]).to eq("ok")
77
+ end
78
+
79
+ it "responds with specs to the 'specs' request" do
80
+ nvim_wr.write([0, 2, :specs, [plugin_path]]).flush
136
81
 
137
- it "handles unknown requests" do
138
- message = MessagePack.pack([0, 0, "foobar", []])
139
- nvim_wr.write(message)
140
- nvim_wr.flush
82
+ expect(nvim_rd.read).to eq(
83
+ [
84
+ 1,
85
+ 2,
86
+ nil,
87
+ [
88
+ {
89
+ "type" => "command",
90
+ "name" => "Echo",
91
+ "sync" => true,
92
+ "opts" => {"nargs" => 1}
93
+ },
94
+ {
95
+ "type" => "command",
96
+ "name" => "Boom",
97
+ "sync" => true,
98
+ "opts" => {}
99
+ },
100
+ {
101
+ "type" => "command",
102
+ "name" => "BoomAsync",
103
+ "sync" => false,
104
+ "opts" => {}
105
+ }
106
+ ]
107
+ ]
108
+ )
109
+ end
110
+
111
+ it "delegates to plugin handlers" do
112
+ nvim_wr.write([0, 0, "#{plugin_path}:command:Echo", ["hi"]]).flush
113
+ expect(nvim_rd.read).to eq([1, 0, nil, "hi"])
114
+ end
115
+
116
+ it "handles exceptions in sync plugin handlers" do
117
+ nvim_wr.write([0, 0, "#{plugin_path}:command:Boom", ["hi"]]).flush
118
+ expect(nvim_rd.read).to eq([1, 0, "BOOM", nil])
119
+ end
141
120
 
142
- response = MessagePack.unpack(nvim_rd.readpartial(1024))
143
- expect(response).to eq([1, 0, "Unknown request foobar", nil])
121
+ it "handles exceptions in async plugin handlers" do
122
+ nvim_wr.write([2, "#{plugin_path}:command:BoomAsync", ["hi"]]).flush
123
+
124
+ expect(nvim_rd.read).to match_array(
125
+ [
126
+ 0, duck_type(:to_int), "nvim_err_writeln",
127
+ [/my_plugin:command:BoomAsync: \(RuntimeError\) BOOM ASYNC/]
128
+ ]
129
+ )
130
+ end
131
+
132
+ it "handles unknown requests" do
133
+ nvim_wr.write([0, 0, "foobar", []]).flush
134
+ expect(nvim_rd.read).to eq([1, 0, "Unknown request foobar", nil])
135
+ end
144
136
  end
145
137
  end
146
138
  end