neovim 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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