neovim 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/docs.yml +39 -0
  3. data/.github/workflows/tests.yml +64 -0
  4. data/.gitignore +2 -0
  5. data/CHANGELOG.md +22 -0
  6. data/CODE_OF_CONDUCT.md +3 -3
  7. data/README.md +19 -20
  8. data/Rakefile +21 -11
  9. data/exe/neovim-ruby-host +5 -0
  10. data/lib/neovim/buffer.rb +120 -41
  11. data/lib/neovim/client.rb +304 -39
  12. data/lib/neovim/client_info.rb +46 -0
  13. data/lib/neovim/connection.rb +7 -2
  14. data/lib/neovim/event_loop.rb +8 -4
  15. data/lib/neovim/host/cli.rb +41 -0
  16. data/lib/neovim/host.rb +3 -0
  17. data/lib/neovim/logging.rb +1 -1
  18. data/lib/neovim/message.rb +1 -1
  19. data/lib/neovim/plugin/dsl.rb +6 -0
  20. data/lib/neovim/plugin.rb +7 -2
  21. data/lib/neovim/remote_object.rb +5 -2
  22. data/lib/neovim/ruby_provider/object_ext.rb +5 -0
  23. data/lib/neovim/ruby_provider/vim.rb +6 -5
  24. data/lib/neovim/ruby_provider.rb +29 -10
  25. data/lib/neovim/session.rb +21 -16
  26. data/lib/neovim/tabpage.rb +8 -15
  27. data/lib/neovim/version.rb +1 -1
  28. data/lib/neovim/window.rb +45 -33
  29. data/lib/neovim.rb +12 -3
  30. data/neovim.gemspec +4 -5
  31. data/script/ci/download_nvim.sh +40 -0
  32. data/script/dump_api.rb +1 -1
  33. data/script/generate_docs.rb +6 -7
  34. data/script/run_acceptance.rb +15 -11
  35. data/spec/acceptance/client_info_spec.vim +42 -0
  36. data/spec/acceptance/rplugin_command_spec.vim +2 -2
  37. data/spec/acceptance/ruby_spec.vim +18 -11
  38. data/spec/acceptance/rubydo_spec.vim +9 -0
  39. data/spec/acceptance/rubyeval_spec.vim +22 -0
  40. data/spec/acceptance/rubyfile/curbuf_ivar_get.rb +1 -1
  41. data/spec/acceptance/rubyfile/curbuf_ivar_set.rb +1 -1
  42. data/spec/acceptance/rubyfile/define_foo.rb +1 -1
  43. data/spec/acceptance/rubyfile/nested_inner.rb +1 -1
  44. data/spec/acceptance/rubyfile/set_pwd_after.rb +1 -1
  45. data/spec/acceptance/rubyfile/set_pwd_before.rb +1 -1
  46. data/spec/acceptance/rubyfile_spec.vim +19 -19
  47. data/spec/acceptance/runtime/init.vim +2 -2
  48. data/spec/acceptance/runtime/rplugin/ruby/commands.rb +2 -2
  49. data/spec/helper.rb +25 -7
  50. data/spec/neovim/api_spec.rb +1 -1
  51. data/spec/neovim/buffer_spec.rb +10 -6
  52. data/spec/neovim/client_info_spec.rb +77 -0
  53. data/spec/neovim/client_spec.rb +9 -2
  54. data/spec/neovim/connection_spec.rb +32 -4
  55. data/spec/neovim/current_spec.rb +1 -2
  56. data/spec/neovim/event_loop_spec.rb +16 -0
  57. data/spec/neovim/host/cli_spec.rb +94 -0
  58. data/spec/neovim/host_spec.rb +16 -14
  59. data/spec/neovim/line_range_spec.rb +1 -3
  60. data/spec/neovim/remote_object_spec.rb +1 -2
  61. data/spec/neovim/ruby_provider/buffer_ext_spec.rb +6 -7
  62. data/spec/neovim/ruby_provider/object_ext_spec.rb +10 -0
  63. data/spec/neovim/ruby_provider/vim_spec.rb +1 -1
  64. data/spec/neovim/ruby_provider/window_ext_spec.rb +7 -10
  65. data/spec/neovim/session_spec.rb +13 -40
  66. data/spec/neovim/window_spec.rb +1 -1
  67. data/spec/neovim_spec.rb +28 -51
  68. data/spec/support.rb +27 -1
  69. metadata +26 -44
  70. data/.coveralls.yml +0 -1
  71. data/.rubocop.yml +0 -118
  72. data/.travis.yml +0 -22
  73. data/appveyor.yml +0 -31
  74. data/bin/neovim-ruby-host +0 -18
  75. data/script/validate_docs.rb +0 -29
@@ -7,11 +7,31 @@ module Neovim
7
7
  describe "#write" do
8
8
  it "writes msgpack to the underlying file descriptor" do
9
9
  rd, wr = IO.pipe
10
- connection = Connection.new(nil_io, wr)
11
- connection.write("some data")
10
+ Connection.new(nil_io, wr).write("some data").flush
11
+ data = rd.readpartial(1024)
12
+
13
+ expect(MessagePack.unpack(data)).to eq("some data")
14
+ end
15
+ end
16
+
17
+ describe "#flush" do
18
+ it "flushes writes to the underlying file descriptor" do
19
+ rd, wr = IO.pipe
20
+ connection = Connection.new(nil_io, wr).write("some data")
21
+
22
+ expect { rd.read_nonblock(16) }.to raise_error(IO::WaitReadable)
23
+
24
+ connection.flush
25
+
26
+ expect(rd.read_nonblock(16)).to eq(MessagePack.pack("some data"))
27
+ end
28
+
29
+ it "throws an exception when the file is closed" do
30
+ _, wr = IO.pipe
31
+ connection = Connection.new(nil_io, wr).write("some data")
12
32
  wr.close
13
33
 
14
- expect(MessagePack.unpack(rd.read)).to eq("some data")
34
+ expect { connection.flush }.to raise_error(IOError)
15
35
  end
16
36
  end
17
37
 
@@ -19,11 +39,19 @@ module Neovim
19
39
  it "reads msgpack from the underlying file descriptor" do
20
40
  rd, wr = IO.pipe
21
41
  wr.write(MessagePack.pack("some data"))
22
- wr.close
42
+ wr.flush
23
43
 
24
44
  connection = Connection.new(rd, nil_io)
25
45
  expect(connection.read).to eq("some data")
26
46
  end
47
+
48
+ it "throws an exception when the file is closed" do
49
+ rd, wr = IO.pipe
50
+ wr.close
51
+
52
+ connection = Connection.new(rd, nil_io)
53
+ expect { connection.read }.to raise_error(EOFError)
54
+ end
27
55
  end
28
56
 
29
57
  describe "#register_type" do
@@ -2,9 +2,8 @@ require "helper"
2
2
 
3
3
  module Neovim
4
4
  RSpec.describe Current do
5
- let(:client) { Neovim.attach_child(Support.child_argv) }
5
+ let(:client) { Support.persistent_client }
6
6
  let(:current) { client.current }
7
- after { client.shutdown }
8
7
 
9
8
  describe "#line" do
10
9
  it "returns an empty string if the current line is empty" do
@@ -16,7 +16,9 @@ module Neovim
16
16
  describe "#request" do
17
17
  it "writes a msgpack request" do
18
18
  event_loop.request(1, :method, 1, 2)
19
+ connection.flush
19
20
  message = server_rd.readpartial(1024)
21
+
20
22
  expect(message).to eq(MessagePack.pack([0, 1, "method", [1, 2]]))
21
23
  end
22
24
  end
@@ -24,7 +26,9 @@ module Neovim
24
26
  describe "#respond" do
25
27
  it "writes a msgpack response" do
26
28
  event_loop.respond(2, "value", "error")
29
+ connection.flush
27
30
  message = server_rd.readpartial(1024)
31
+
28
32
  expect(message).to eq(MessagePack.pack([1, 2, "error", "value"]))
29
33
  end
30
34
  end
@@ -32,7 +36,9 @@ module Neovim
32
36
  describe "#notify" do
33
37
  it "writes a msgpack notification" do
34
38
  event_loop.notify(:method, 1, 2)
39
+ connection.flush
35
40
  message = server_rd.readpartial(1024)
41
+
36
42
  expect(message).to eq(MessagePack.pack([2, "method", [1, 2]]))
37
43
  end
38
44
  end
@@ -52,6 +58,16 @@ module Neovim
52
58
  expect(message.method_name).to eq("foo_method")
53
59
  end
54
60
 
61
+ it "returns the last message received" do
62
+ server_wr.write(MessagePack.pack([0, 1, :foo_method, []]))
63
+ server_wr.flush
64
+
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
+
55
71
  it "shuts down after receiving EOFError" do
56
72
  run_thread = Thread.new do
57
73
  event_loop.run
@@ -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
@@ -41,22 +41,20 @@ module Neovim
41
41
  end
42
42
  end
43
43
 
44
- after do
45
- host_thread.kill while host_thread.alive?
46
- host_thread.join
47
- end
44
+ after { host_thread.kill.join }
48
45
 
49
46
  context "poll" do
50
- it "initializes a client and responds 'ok'" do
47
+ it "initializes a client, sets client info, and responds 'ok'" do
51
48
  nvim_wr.write([0, 1, :poll, []]).flush
52
- type, reqid, method = nvim_rd.read
53
49
 
54
- expect(type).to eq(0)
55
- expect(reqid).to eq(2)
56
- expect(method).to eq("nvim_get_api_info")
50
+ expect(nvim_rd.read).to match([2, "nvim_set_client_info", duck_type(:to_ary)])
51
+
52
+ type, reqid, method = nvim_rd.read
53
+ expect([type, reqid, method]).to match([0, duck_type(:to_int), "nvim_get_api_info"])
57
54
 
58
55
  api_info = [0, {"types" => {}, "functions" => {}}]
59
56
  nvim_wr.write([1, reqid, nil, api_info]).flush
57
+
60
58
  expect(nvim_rd.read).to eq([1, 1, nil, "ok"])
61
59
  end
62
60
  end
@@ -64,14 +62,18 @@ module Neovim
64
62
  context "after poll" do
65
63
  before do
66
64
  nvim_wr.write([0, 1, :poll, []]).flush
67
- _, reqid, = nvim_rd.read
68
65
 
69
- session = Session.new(EventLoop.child(Support.child_argv))
70
- api_info = session.request(:nvim_get_api_info)
71
- session.shutdown
66
+ expect(nvim_rd.read[1]).to eq("nvim_set_client_info")
67
+
68
+ _, reqid, method = nvim_rd.read
69
+
70
+ expect(method).to eq("nvim_get_api_info")
71
+
72
+ api_info = Support.persistent_client.get_api_info
72
73
 
73
74
  nvim_wr.write([1, reqid, nil, api_info]).flush
74
- nvim_rd.read
75
+
76
+ expect(nvim_rd.read[3]).to eq("ok")
75
77
  end
76
78
 
77
79
  it "responds with specs to the 'specs' request" do
@@ -2,7 +2,7 @@ require "helper"
2
2
 
3
3
  module Neovim
4
4
  RSpec.describe LineRange do
5
- let(:client) { Neovim.attach_child(Support.child_argv) }
5
+ let(:client) { Support.persistent_client }
6
6
  let(:buffer) { client.current.buffer }
7
7
  let(:line_range) { LineRange.new(buffer) }
8
8
 
@@ -10,8 +10,6 @@ module Neovim
10
10
  buffer.set_lines(0, -1, true, ["1", "2", "3", "4"])
11
11
  end
12
12
 
13
- after { client.shutdown }
14
-
15
13
  describe "#each" do
16
14
  it "yields each line" do
17
15
  yielded = []
@@ -2,8 +2,7 @@ require "helper"
2
2
 
3
3
  module Neovim
4
4
  RSpec.describe RemoteObject do
5
- let(:client) { Neovim.attach_child(Support.child_argv) }
6
- after { client.shutdown }
5
+ let(:client) { Support.persistent_client }
7
6
 
8
7
  context Window do
9
8
  let(:window) { client.current.window }
@@ -4,13 +4,11 @@ require "neovim/ruby_provider/buffer_ext"
4
4
  module Neovim
5
5
  RSpec.describe Buffer do
6
6
  let!(:nvim) do
7
- Neovim.attach_child(Support.child_argv).tap do |nvim|
8
- stub_const("::Vim", nvim)
7
+ Support.persistent_client.tap do |client|
8
+ stub_const("::Vim", client)
9
9
  end
10
10
  end
11
11
 
12
- after { nvim.shutdown }
13
-
14
12
  describe ".current" do
15
13
  it "returns the current buffer from the global Vim client" do
16
14
  expect(Buffer.current).to eq(nvim.get_current_buf)
@@ -27,9 +25,10 @@ module Neovim
27
25
 
28
26
  describe ".[]" do
29
27
  it "returns the buffer from the global Vim client at the given index" do
30
- expect(Buffer[0]).to eq(nvim.get_current_buf)
31
- nvim.command("new")
32
- expect(Buffer[1]).to eq(nvim.get_current_buf)
28
+ buffer = Buffer[0]
29
+
30
+ expect(buffer).to be_a(Buffer)
31
+ expect(buffer).to eq(nvim.list_bufs[0])
33
32
  end
34
33
  end
35
34
  end
@@ -0,0 +1,10 @@
1
+ require "helper"
2
+ require "neovim/ruby_provider/object_ext"
3
+
4
+ RSpec.describe Object do
5
+ describe "#to_msgpack" do
6
+ it "converts classes to strings" do
7
+ expect(MessagePack.pack(String)).to eq(MessagePack.pack("String"))
8
+ end
9
+ end
10
+ end
@@ -52,7 +52,7 @@ RSpec.describe Vim do
52
52
  end
53
53
 
54
54
  it "refreshes global variables" do
55
- client = Neovim.attach_child(Support.child_argv)
55
+ client = Support.persistent_client
56
56
  client.command("vs foo")
57
57
 
58
58
  Vim.__client = client
@@ -4,13 +4,11 @@ require "neovim/ruby_provider/window_ext"
4
4
  module Neovim
5
5
  RSpec.describe Window do
6
6
  let!(:nvim) do
7
- Neovim.attach_child(Support.child_argv).tap do |nvim|
8
- stub_const("::Vim", nvim)
7
+ Support.persistent_client.tap do |client|
8
+ stub_const("::Vim", client)
9
9
  end
10
10
  end
11
11
 
12
- after { nvim.shutdown }
13
-
14
12
  describe ".current" do
15
13
  it "returns the current window from the global Vim client" do
16
14
  expect(Window.current).to eq(nvim.get_current_win)
@@ -33,17 +31,16 @@ module Neovim
33
31
 
34
32
  describe ".[]" do
35
33
  it "returns the window at the given index" do
36
- expect do
37
- nvim.command("new")
38
- end.to change { Window[1] }.from(nil).to(kind_of(Window))
34
+ window = Window[0]
35
+
36
+ expect(window).to be_a(Window)
37
+ expect(window).to eq(nvim.list_wins[0])
39
38
  end
40
39
 
41
40
  it "only includes windows within a tabpage" do
42
- nvim.command("new")
43
-
44
41
  expect do
45
42
  nvim.command("tabnew")
46
- end.to change { Window[1] }.from(kind_of(Window)).to(nil)
43
+ end.to change { Window[0] }
47
44
  end
48
45
  end
49
46
  end
@@ -2,10 +2,8 @@ require "helper"
2
2
 
3
3
  module Neovim
4
4
  RSpec.describe Session do
5
- let(:event_loop) { EventLoop.child(Support.child_argv) }
6
- let!(:session) { Session.new(event_loop) }
7
-
8
- after { session.shutdown }
5
+ let(:client) { Support.persistent_client }
6
+ let(:session) { client.session }
9
7
 
10
8
  describe "#request" do
11
9
  it "synchronously returns a result" do
@@ -18,12 +16,6 @@ module Neovim
18
16
  end.to raise_error(/wrong number of arguments/i)
19
17
  end
20
18
 
21
- it "handles large data" do
22
- large_str = Array.new(1024 * 17) { SecureRandom.hex(1) }.join
23
- session.request(:nvim_set_current_line, large_str)
24
- expect(session.request(:nvim_get_current_line)).to eq(large_str)
25
- end
26
-
27
19
  it "fails outside of the main thread", :silence_thread_exceptions do
28
20
  expect do
29
21
  Thread.new { session.request(:nvim_strwidth, "foo") }.join
@@ -32,18 +24,6 @@ module Neovim
32
24
  end
33
25
 
34
26
  describe "#notify" do
35
- it "doesn't raise exceptions" do
36
- expect do
37
- session.notify(:nvim_strwidth, "too", "many")
38
- end.not_to raise_error
39
- end
40
-
41
- it "handles large data" do
42
- large_str = Array.new(1024 * 17) { SecureRandom.hex(1) }.join
43
- session.notify(:nvim_set_current_line, large_str)
44
- expect(session.request(:nvim_get_current_line)).to eq(large_str)
45
- end
46
-
47
27
  it "succeeds outside of the main thread" do
48
28
  expect do
49
29
  Thread.new { session.notify(:nvim_set_current_line, "foo") }.join
@@ -51,33 +31,26 @@ module Neovim
51
31
  end
52
32
  end
53
33
 
54
- describe "#run" do
55
- it "enqueues messages received during blocking requests" do
56
- session.request(:nvim_subscribe, "my_event")
57
- session.request(:nvim_command, "call rpcnotify(0, 'my_event', 'foo')")
34
+ describe "#next" do
35
+ it "returns the next message from the event loop" do
36
+ cid, = session.request(:nvim_get_api_info)
37
+ session.request(:nvim_command, "call rpcnotify(#{cid}, 'my_event', 'foo')")
58
38
 
59
- message = nil
60
- session.run do |msg|
61
- message = msg
62
- session.shutdown
63
- end
39
+ message = session.next
64
40
 
65
41
  expect(message.sync?).to eq(false)
66
42
  expect(message.method_name).to eq("my_event")
67
43
  expect(message.arguments).to eq(["foo"])
68
44
  end
69
45
 
70
- it "supports requests within callbacks" do
71
- session.request(:nvim_subscribe, "my_event")
72
- session.request(:nvim_command, "call rpcnotify(0, 'my_event', 'foo')")
46
+ it "returns asynchronous notification errors", nvim_version: ">= 0.4.pre.dev" do
47
+ session.notify(:nvim_set_current_line, "too", "many", "args")
73
48
 
74
- result = nil
75
- session.run do |msg|
76
- result = session.request(:nvim_strwidth, msg.arguments.first)
77
- session.shutdown
78
- end
49
+ message = session.next
79
50
 
80
- expect(result).to be(3)
51
+ expect(message.sync?).to eq(false)
52
+ expect(message.method_name).to eq("nvim_error_event")
53
+ expect(message.arguments).to eq([0, "Wrong number of arguments: expecting 1 but got 3"])
81
54
  end
82
55
  end
83
56
  end