neovim 0.3.0 → 0.3.1

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/Gemfile +1 -0
  4. data/README.md +6 -2
  5. data/Rakefile +4 -72
  6. data/bin/neovim-ruby-host +3 -2
  7. data/lib/neovim.rb +4 -16
  8. data/lib/neovim/buffer.rb +21 -0
  9. data/lib/neovim/client.rb +35 -0
  10. data/lib/neovim/host.rb +6 -4
  11. data/lib/neovim/host/loader.rb +2 -0
  12. data/lib/neovim/line_range.rb +1 -1
  13. data/lib/neovim/logging.rb +8 -7
  14. data/lib/neovim/plugin/dsl.rb +1 -1
  15. data/lib/neovim/ruby_provider.rb +7 -10
  16. data/lib/neovim/ruby_provider/buffer_ext.rb +3 -3
  17. data/lib/neovim/ruby_provider/vim.rb +6 -1
  18. data/lib/neovim/ruby_provider/window_ext.rb +3 -3
  19. data/lib/neovim/session.rb +2 -2
  20. data/lib/neovim/session/api.rb +7 -1
  21. data/lib/neovim/session/event_loop.rb +4 -12
  22. data/lib/neovim/session/serializer.rb +2 -2
  23. data/lib/neovim/tabpage.rb +6 -0
  24. data/lib/neovim/version.rb +1 -1
  25. data/lib/neovim/window.rb +19 -1
  26. data/script/generate_docs +71 -0
  27. data/{bin → script}/j2mp +0 -0
  28. data/{bin → script}/mp2j +0 -0
  29. data/spec/acceptance/neovim-ruby-host_spec.rb +1 -6
  30. data/spec/acceptance/ruby_provider_spec.rb +17 -33
  31. data/spec/helper.rb +42 -37
  32. data/spec/neovim/buffer_spec.rb +1 -1
  33. data/spec/neovim/client_spec.rb +1 -1
  34. data/spec/neovim/current_spec.rb +1 -1
  35. data/spec/neovim/host/loader_spec.rb +2 -0
  36. data/spec/neovim/host_spec.rb +25 -5
  37. data/spec/neovim/line_range_spec.rb +2 -2
  38. data/spec/neovim/logging_spec.rb +56 -0
  39. data/spec/neovim/plugin_spec.rb +9 -0
  40. data/spec/neovim/remote_object_spec.rb +5 -1
  41. data/spec/neovim/ruby_provider/buffer_ext_spec.rb +5 -5
  42. data/spec/neovim/ruby_provider/vim_spec.rb +32 -0
  43. data/spec/neovim/ruby_provider/window_ext_spec.rb +22 -8
  44. data/spec/neovim/session/api_spec.rb +24 -5
  45. data/spec/neovim/session/event_loop_spec.rb +54 -1
  46. data/spec/neovim/session/notification_spec.rb +20 -0
  47. data/spec/neovim/session/request_spec.rb +36 -0
  48. data/spec/neovim/session/rpc_spec.rb +12 -0
  49. data/spec/neovim/session/serializer_spec.rb +14 -0
  50. data/spec/neovim/session_spec.rb +4 -4
  51. data/spec/neovim/window_spec.rb +17 -1
  52. data/spec/neovim_spec.rb +4 -20
  53. metadata +13 -4
@@ -2,7 +2,7 @@ require "helper"
2
2
 
3
3
  module Neovim
4
4
  RSpec.describe RemoteObject do
5
- let(:client) { Neovim.attach_child(["nvim", "-n", "-u", "NONE"]) }
5
+ let(:client) { Neovim.attach_child(Support.child_argv) }
6
6
  after { client.shutdown }
7
7
 
8
8
  context Window do
@@ -26,6 +26,10 @@ module Neovim
26
26
  it "enables window_* function calls" do
27
27
  expect(window.get_cursor).to eq([1, 0])
28
28
  end
29
+
30
+ it "falls back to super" do
31
+ expect { window.foobar }.to raise_error(NoMethodError)
32
+ end
29
33
  end
30
34
 
31
35
  describe "#methods" do
@@ -4,21 +4,21 @@ 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(["nvim", "-u", "NONE", "-n"]).tap do |nvim|
8
- stub_const("::VIM", nvim)
7
+ Neovim.attach_child(Support.child_argv).tap do |nvim|
8
+ stub_const("::Vim", nvim)
9
9
  end
10
10
  end
11
11
 
12
12
  after { nvim.shutdown }
13
13
 
14
14
  describe ".current" do
15
- it "returns the current buffer from the global VIM client" do
15
+ it "returns the current buffer from the global Vim client" do
16
16
  expect(Buffer.current).to eq(nvim.get_current_buffer)
17
17
  end
18
18
  end
19
19
 
20
20
  describe ".count" do
21
- it "returns the current buffer count from the global VIM client" do
21
+ it "returns the current buffer count from the global Vim client" do
22
22
  expect {
23
23
  nvim.command("new")
24
24
  }.to change { Buffer.count }.by(1)
@@ -26,7 +26,7 @@ module Neovim
26
26
  end
27
27
 
28
28
  describe ".[]" do
29
- it "returns the buffer from the global VIM client at the given index" do
29
+ it "returns the buffer from the global Vim client at the given index" do
30
30
  expect(Buffer[0]).to eq(nvim.get_current_buffer)
31
31
  nvim.command("new")
32
32
  expect(Buffer[1]).to eq(nvim.get_current_buffer)
@@ -0,0 +1,32 @@
1
+ require "helper"
2
+ require "neovim/ruby_provider/vim"
3
+
4
+ RSpec.describe Vim do
5
+ describe Vim::Buffer do
6
+ it "refers to Neovim::Buffer" do
7
+ expect(Vim::Buffer).to be(Neovim::Buffer)
8
+ end
9
+ end
10
+
11
+ describe Vim::Window do
12
+ it "refers to Neovim::Window" do
13
+ expect(Vim::Window).to be(Neovim::Window)
14
+ end
15
+ end
16
+
17
+ describe VIM do
18
+ it "is an alias for the Vim module" do
19
+ expect(VIM).to be(Vim)
20
+ end
21
+ end
22
+
23
+ describe "#method_missing" do
24
+ it "delegates method calls to @__client" do
25
+ client = double(:client)
26
+ expect(client).to receive(:foo).with(1, 2)
27
+
28
+ Vim.__client = client
29
+ Vim.foo(1, 2)
30
+ end
31
+ end
32
+ end
@@ -4,32 +4,46 @@ 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(["nvim", "-u", "NONE", "-n"]).tap do |nvim|
8
- stub_const("::VIM", nvim)
7
+ Neovim.attach_child(Support.child_argv).tap do |nvim|
8
+ stub_const("::Vim", nvim)
9
9
  end
10
10
  end
11
11
 
12
12
  after { nvim.shutdown }
13
13
 
14
14
  describe ".current" do
15
- it "returns the current window from the global VIM client" do
15
+ it "returns the current window from the global Vim client" do
16
16
  expect(Window.current).to eq(nvim.get_current_window)
17
17
  end
18
18
  end
19
19
 
20
20
  describe ".count" do
21
- it "returns the current window count from the global VIM client" do
21
+ it "returns the current window count from the global Vim client" do
22
22
  expect {
23
23
  nvim.command("new")
24
24
  }.to change { Window.count }.by(1)
25
25
  end
26
+
27
+ it "only includes windows within a tabpage" do
28
+ expect {
29
+ nvim.command("tabnew")
30
+ }.not_to change { Window.count }.from(1)
31
+ end
26
32
  end
27
33
 
28
34
  describe ".[]" do
29
- it "returns the window from the global VIM client at the given index" do
30
- expect(Window[0]).to eq(nvim.get_current_window)
31
- nvim.command("tabnew")
32
- expect(Window[1]).to eq(nvim.get_current_window)
35
+ it "returns the window at the given index" do
36
+ expect {
37
+ nvim.command("new")
38
+ }.to change { Window[1] }.from(nil).to(kind_of(Window))
39
+ end
40
+
41
+ it "only includes windows within a tabpage" do
42
+ nvim.command("new")
43
+
44
+ expect {
45
+ nvim.command("tabnew")
46
+ }.to change { Window[1] }.from(kind_of(Window)).to(nil)
33
47
  end
34
48
  end
35
49
  end
@@ -13,17 +13,36 @@ module Neovim
13
13
  end
14
14
 
15
15
  describe "#function" do
16
- it "returns a corresponding Function object" do
16
+ it "returns a sync function object" do
17
17
  api = API.new(
18
18
  [nil, {"functions" => [
19
- {"name" => "vim_strwidth", "async" => false}
19
+ {"name" => "vim_sync", "async" => false}
20
20
  ]}]
21
21
  )
22
22
 
23
- function = api.function("vim_strwidth")
24
- expect(function).to be_a(API::Function)
25
- expect(function.name).to eq("vim_strwidth")
23
+ function = api.function("vim_sync")
24
+ expect(function.name).to eq("vim_sync")
26
25
  expect(function.async).to be(false)
26
+
27
+ session = instance_double(Session)
28
+ expect(session).to receive(:request).with("vim_sync", "msg")
29
+ function.call(session, "msg")
30
+ end
31
+
32
+ it "returns an async function object" do
33
+ api = API.new(
34
+ [nil, {"functions" => [
35
+ {"name" => "vim_async", "async" => true}
36
+ ]}]
37
+ )
38
+
39
+ function = api.function("vim_async")
40
+ expect(function.name).to eq("vim_async")
41
+ expect(function.async).to be(true)
42
+
43
+ session = instance_double(Session)
44
+ expect(session).to receive(:notify).with("vim_async", "msg")
45
+ function.call(session, "msg")
27
46
  end
28
47
  end
29
48
 
@@ -82,7 +82,7 @@ module Neovim
82
82
 
83
83
  context "child" do
84
84
  it "sends and receives data" do
85
- event_loop = EventLoop.child(["nvim", "-n", "-u", "NONE"])
85
+ event_loop = EventLoop.child(Support.child_argv)
86
86
  input = MessagePack.pack([0, 0, :vim_strwidth, ["hi"]])
87
87
 
88
88
  response = nil
@@ -94,6 +94,59 @@ module Neovim
94
94
  expect(response).to eq(MessagePack.pack([1, 0, nil, 2]))
95
95
  end
96
96
  end
97
+
98
+ describe "#run" do
99
+ it "handles EOF" do
100
+ rd, wr = IO.pipe
101
+ wr.close
102
+ event_loop = EventLoop.new(rd, wr)
103
+ expect(event_loop).to receive(:info).with(/EOFError/)
104
+
105
+ event_loop.run
106
+ end
107
+
108
+ it "handles other errors" do
109
+ rd, wr = IO.pipe
110
+ rd.close
111
+ event_loop = EventLoop.new(rd, wr)
112
+ expect(event_loop).to receive(:fatal).with(/IOError/)
113
+
114
+ event_loop.run
115
+ end
116
+ end
117
+
118
+ describe "#write" do
119
+ it "retries when writes would block" do
120
+ rd, wr = IO.pipe
121
+ event_loop = EventLoop.new(rd, wr)
122
+ err_class = Class.new(RuntimeError) { include IO::WaitWritable }
123
+
124
+ expect(wr).to receive(:write_nonblock).and_raise(err_class)
125
+ expect(wr).to receive(:write_nonblock).and_call_original
126
+
127
+ event_loop.write("a")
128
+ expect(rd.readpartial(1)).to eq("a")
129
+ end
130
+ end
131
+
132
+ describe "#shutdown" do
133
+ it "closes IO handles" do
134
+ rd, wr = IO.pipe
135
+ EventLoop.new(rd, wr).shutdown
136
+
137
+ expect(rd).to be_closed
138
+ expect(wr).to be_closed
139
+ end
140
+
141
+ it "kills spawned processes" do
142
+ io = IO.popen("cat", "rb+")
143
+ pid = io.pid
144
+ expect(pid).to respond_to(:to_int)
145
+
146
+ EventLoop.new(io).shutdown
147
+ expect { Process.kill(0, pid) }.to raise_error(Errno::ESRCH)
148
+ end
149
+ end
97
150
  end
98
151
  end
99
152
  end
@@ -0,0 +1,20 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ class Session
5
+ RSpec.describe Notification do
6
+ let(:notification) { Notification.new(:method, ["arg"]) }
7
+
8
+ it "has readers" do
9
+ expect(notification.method_name).to eq("method")
10
+ expect(notification.arguments).to eq(["arg"])
11
+ end
12
+
13
+ describe "#sync?" do
14
+ it "is false" do
15
+ expect(notification.sync?).to be(false)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ class Session
5
+ RSpec.describe Request do
6
+ let(:serializer) { double(:serializer) }
7
+ let(:reqid) { 1 }
8
+ let(:request) { Request.new(:method, ["arg"], serializer, reqid) }
9
+
10
+ it "has readers" do
11
+ expect(request.method_name).to eq("method")
12
+ expect(request.arguments).to eq(["arg"])
13
+ end
14
+
15
+ describe "#sync?" do
16
+ it "is true" do
17
+ expect(request.sync?).to be(true)
18
+ end
19
+ end
20
+
21
+ describe "#respond" do
22
+ it "writes an RPC response to serializer" do
23
+ expect(serializer).to receive(:write).with([1, reqid, nil, "val"])
24
+ request.respond("val")
25
+ end
26
+ end
27
+
28
+ describe "#error" do
29
+ it "writes an RPC error response to serializer" do
30
+ expect(serializer).to receive(:write).with([1, reqid, "err", nil])
31
+ request.error("err")
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -103,6 +103,18 @@ module Neovim
103
103
 
104
104
  include_context "rpc behavior"
105
105
  end
106
+
107
+ describe "#run" do
108
+ it "logs exceptions" do
109
+ serializer = instance_double(Serializer)
110
+ rpc = RPC.new(serializer)
111
+
112
+ expect(serializer).to receive(:run).and_raise("BOOM")
113
+ expect(rpc).to receive(:fatal).with(/BOOM/)
114
+
115
+ rpc.run
116
+ end
117
+ end
106
118
  end
107
119
  end
108
120
  end
@@ -43,6 +43,20 @@ module Neovim
43
43
 
44
44
  include_context "serializer behavior"
45
45
  end
46
+
47
+ describe "#run" do
48
+ it "logs exceptions" do
49
+ unpacker = instance_double(MessagePack::Unpacker)
50
+ event_loop = instance_double(EventLoop)
51
+ serializer = Serializer.new(event_loop, unpacker)
52
+
53
+ expect(event_loop).to receive(:run).and_yield("data")
54
+ expect(unpacker).to receive(:feed_each).with("data").and_raise("BOOM")
55
+ expect(serializer).to receive(:fatal).with(/BOOM/)
56
+
57
+ serializer.run
58
+ end
59
+ end
46
60
  end
47
61
  end
48
62
  end
@@ -95,11 +95,11 @@ module Neovim
95
95
  end
96
96
 
97
97
  context "tcp" do
98
- let!(:nvim_port) { Support.port }
98
+ let!(:nvim_port) { Support.tcp_port }
99
99
  let!(:nvim_pid) do
100
100
  pid = Process.spawn(
101
101
  {"NVIM_LISTEN_ADDRESS" => "0.0.0.0:#{nvim_port}"},
102
- "nvim --headless -n -u NONE",
102
+ Support.child_argv.join(" "),
103
103
  [:out, :err] => "/dev/null"
104
104
  )
105
105
 
@@ -126,7 +126,7 @@ module Neovim
126
126
  let!(:nvim_pid) do
127
127
  pid = Process.spawn(
128
128
  {"NVIM_LISTEN_ADDRESS" => socket_path},
129
- "nvim --headless -n -u NONE",
129
+ Support.child_argv.join(" "),
130
130
  [:out, :err] => "/dev/null"
131
131
  )
132
132
 
@@ -149,7 +149,7 @@ module Neovim
149
149
  end
150
150
 
151
151
  context "child" do
152
- let!(:session) { Session.child(["nvim", "-n", "-u", "NONE"]) }
152
+ let!(:session) { Session.child(Support.child_argv) }
153
153
  include_context "session behavior"
154
154
  after { session.shutdown }
155
155
  end
@@ -2,7 +2,7 @@ require "helper"
2
2
 
3
3
  module Neovim
4
4
  RSpec.describe Window do
5
- let(:client) { Neovim.attach_child(["nvim", "-n", "-u", "NONE"]) }
5
+ let(:client) { Neovim.attach_child(Support.child_argv) }
6
6
  let(:window) { client.current.window }
7
7
  after { client.shutdown }
8
8
 
@@ -69,6 +69,22 @@ module Neovim
69
69
  client.command("normal ix")
70
70
  }.to change { client.current.line }.to("oxne")
71
71
  end
72
+
73
+ it "supports out of range indexes" do
74
+ window.buffer.lines = ["x", "xx"]
75
+
76
+ expect {
77
+ window.cursor = [10, 10]
78
+ }.to change { window.cursor }.to([2, 1])
79
+
80
+ expect {
81
+ window.cursor = [0, -1]
82
+ }.to change { window.cursor }.to([1, 0])
83
+ end
84
+
85
+ it "returns the cursor array" do
86
+ expect(window.cursor = [10, 10]).to eq([10, 10])
87
+ end
72
88
  end
73
89
  end
74
90
  end
@@ -1,13 +1,11 @@
1
1
  require "helper"
2
2
 
3
3
  RSpec.describe Neovim do
4
- let(:nvim_argv) { %w(nvim --headless -u NONE -i NONE -n) }
5
-
6
4
  describe ".attach_tcp" do
7
5
  it "attaches to a TCP socket" do
8
- port = Support.port
6
+ port = Support.tcp_port
9
7
  env = {"NVIM_LISTEN_ADDRESS" => "0.0.0.0:#{port}"}
10
- pid = Process.spawn(env, *nvim_argv, [:out, :err] => "/dev/null")
8
+ pid = Process.spawn(env, *Support.child_argv, [:out, :err] => "/dev/null")
11
9
 
12
10
  begin
13
11
  client = Neovim.attach_tcp("0.0.0.0", port)
@@ -28,7 +26,7 @@ RSpec.describe Neovim do
28
26
  it "attaches to a UNIX socket" do
29
27
  socket_path = Support.socket_path
30
28
  env = {"NVIM_LISTEN_ADDRESS" => socket_path}
31
- pid = Process.spawn(env, *nvim_argv, [:out, :err] => "/dev/null")
29
+ pid = Process.spawn(env, *Support.child_argv, [:out, :err] => "/dev/null")
32
30
 
33
31
  begin
34
32
  client = Neovim.attach_unix(socket_path)
@@ -48,25 +46,11 @@ RSpec.describe Neovim do
48
46
  describe ".attach_child" do
49
47
  it "spawns and attaches to a child process" do
50
48
  begin
51
- client = Neovim.attach_child(nvim_argv)
49
+ client = Neovim.attach_child(Support.child_argv)
52
50
  expect(client.strwidth("hi")).to eq(2)
53
51
  ensure
54
52
  client.shutdown
55
53
  end
56
54
  end
57
55
  end
58
-
59
- describe ".start_host" do
60
- it "loads and runs a Host" do
61
- paths = ["/foo", "/bar"]
62
- host = double(:host)
63
-
64
- expect(Neovim::Host).to receive(:load_from_files).
65
- with(paths).
66
- and_return(host)
67
-
68
- expect(host).to receive(:run)
69
- Neovim.start_host(paths)
70
- end
71
- end
72
56
  end