neovim 0.0.3 → 0.0.4

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.
@@ -4,7 +4,7 @@ require "tempfile"
4
4
  module Neovim
5
5
  RSpec.describe Host do
6
6
  describe ".load_from_files" do
7
- it "loads the defined plugins" do
7
+ it "loads the defined plugins into a manifest" do
8
8
  plug1 = Tempfile.open("plug1") do |f|
9
9
  f.write("Neovim.plugin")
10
10
  f.path
@@ -15,8 +15,11 @@ module Neovim
15
15
  f.path
16
16
  end
17
17
 
18
- host = Host.load_from_files([plug1, plug2])
19
- expect(host.plugins.size).to eq(3)
18
+ manifest = Manifest.new
19
+
20
+ expect(manifest).to receive(:register).exactly(3).times
21
+ host = Host.load_from_files([plug1, plug2], manifest)
22
+ expect(host.manifest).to eq(manifest)
20
23
  end
21
24
 
22
25
  it "doesn't load plugin code into the global namespace" do
@@ -31,49 +34,7 @@ module Neovim
31
34
  end
32
35
 
33
36
  describe "#run" do
34
- it "runs an async client with the plugins as callbacks" do
35
- sync_cb = lambda { |nvim, x, y| [nvim, x, y] }
36
- async_cb = lambda { |nvim, x, y| [nvim, x, y] }
37
-
38
- plugin = Plugin.from_config_block do |plug|
39
- plug.command(:Sync, :nargs => 2, :sync => true, &sync_cb)
40
- plug.command(:Async, :nargs => 2, &async_cb)
41
- end
42
-
43
- mock_async_session = double(:async_session, :request => nil)
44
- expect(AsyncSession).to receive(:new) { mock_async_session }
45
-
46
- mock_client = double(:client)
47
- expect(Client).to receive(:new) { mock_client }
48
-
49
- expect(EventLoop).to receive(:stdio) { double(:event_loop) }
50
- expect(MsgpackStream).to receive(:new) { double(:msgpack_stream) }
51
- expect(Session).to receive(:new) { double(:session) }
52
-
53
- expect(mock_async_session).to receive(:run) do |req_cb, not_cb|
54
- mock_request = double(
55
- :request,
56
- :method_name => :Sync,
57
- :arguments => [1, 2]
58
- )
59
-
60
- mock_notification = double(
61
- :notification,
62
- :method_name => :Async,
63
- :arguments => [3, 4]
64
- )
65
-
66
- expect(sync_cb).to receive(:call).with(mock_client, 1, 2).and_call_original
67
- expect(mock_request).to receive(:respond).with([mock_client, 1, 2])
68
- req_cb.call(mock_request)
69
-
70
- expect(async_cb).to receive(:call).with(mock_client, 3, 4).and_call_original
71
- not_cb.call(mock_notification)
72
- end
73
-
74
- host = Host.new([plugin])
75
- host.run
76
- end
37
+ # TODO: Find a way to test this without excessive mocking
77
38
  end
78
39
  end
79
40
  end
@@ -0,0 +1,68 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ RSpec.describe LineRange do
5
+ let(:client) { Neovim.attach_child(["--headless", "-n", "-u", "NONE"]) }
6
+ let(:buffer) { client.current.buffer }
7
+ let(:line_range) { LineRange.new(buffer, 0, -1) }
8
+
9
+ before do
10
+ client.command("normal i1")
11
+ client.command("normal o2")
12
+ client.command("normal o3")
13
+ end
14
+
15
+ it "is enumerable" do
16
+ expect(line_range).to be_an(Enumerable)
17
+ expect(line_range).to respond_to(:each)
18
+ end
19
+
20
+ describe "#to_a" do
21
+ it "returns lines as an array" do
22
+ expect(line_range.to_a).to eq(["1", "2", "3"])
23
+ end
24
+ end
25
+
26
+ describe "#[]" do
27
+ it "accepts a single index" do
28
+ expect(line_range[1]).to eq("2")
29
+ end
30
+
31
+ it "accepts an index and length" do
32
+ expect(line_range[0, 2].to_a).to eq(["1", "2"])
33
+ end
34
+
35
+ it "accepts a range" do
36
+ expect(line_range[0..1].to_a).to eq(["1", "2"])
37
+ expect(line_range[0...1].to_a).to eq(["1"])
38
+ end
39
+ end
40
+
41
+ describe "#[]=" do
42
+ it "accepts a single index" do
43
+ line_range[0] = "foo"
44
+ expect(line_range.to_a).to eq(["foo", "2", "3"])
45
+ end
46
+
47
+ it "accepts an index and length" do
48
+ line_range[0, 2] = ["foo"]
49
+ expect(line_range.to_a).to eq(["foo", "3"])
50
+ end
51
+
52
+ it "accepts a range" do
53
+ line_range[0..1] = ["foo"]
54
+ expect(line_range.to_a).to eq(["foo", "3"])
55
+
56
+ line_range[0...1] = ["bar"]
57
+ expect(line_range.to_a).to eq(["bar", "3"])
58
+ end
59
+ end
60
+
61
+ describe "#replace" do
62
+ it "replaces all lines" do
63
+ line_range.replace(["5", "6"])
64
+ expect(line_range.to_a).to eq(["5", "6"])
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,113 @@
1
+ require "helper"
2
+ require "neovim/manifest"
3
+ require "neovim/plugin"
4
+
5
+ module Neovim
6
+ RSpec.describe Manifest do
7
+ it "has a default poll handler" do
8
+ manifest = Manifest.new
9
+ expect(manifest.handlers["poll"]).to respond_to(:call)
10
+ end
11
+
12
+ it "has default specs" do
13
+ manifest = Manifest.new
14
+ expect(manifest.specs).to eq({})
15
+ end
16
+
17
+ describe "#register" do
18
+ it "adds specs" do
19
+ manifest = Manifest.new
20
+
21
+ plugin = Plugin.from_config_block("source") do |plug|
22
+ plug.command(:Foo)
23
+ end
24
+
25
+ expect {
26
+ manifest.register(plugin)
27
+ }.to change { manifest.specs }.from({}).to("source" => plugin.specs)
28
+ end
29
+
30
+ it "adds plugin handlers" do
31
+ manifest = Manifest.new
32
+
33
+ plugin = Plugin.from_config_block("source") do |plug|
34
+ plug.command(:Foo)
35
+ end
36
+
37
+ expect {
38
+ manifest.register(plugin)
39
+ }.to change {
40
+ manifest.handlers["source:command:Foo"]
41
+ }.from(nil).to(kind_of(Proc))
42
+ end
43
+ end
44
+
45
+ describe "#handle" do
46
+ it "calls the poll handler" do
47
+ manifest = Manifest.new
48
+ message = double(:message, :method_name => "poll", :sync? => true)
49
+ client = double(:client)
50
+
51
+ expect(message).to receive(:respond).with("ok")
52
+ manifest.handle(message, client)
53
+ end
54
+
55
+ it "calls the specs handler" do
56
+ manifest = Manifest.new
57
+ plugin = Plugin.from_config_block("source") do |plug|
58
+ plug.command(:Foo)
59
+ end
60
+ manifest.register(plugin)
61
+
62
+ message = double(:message, :method_name => "specs", :sync? => true, :arguments => ["source"])
63
+
64
+ expect(message).to receive(:respond).with(plugin.specs)
65
+ manifest.handle(message, double(:client))
66
+ end
67
+
68
+ it "calls a plugin sync handler" do
69
+ manifest = Manifest.new
70
+ plugin = Plugin.from_config_block("source") do |plug|
71
+ plug.command(:Foo, :sync => true) { |client, arg| [client, arg] }
72
+ end
73
+ manifest.register(plugin)
74
+
75
+ message = double(:message, :method_name => "source:command:Foo", :sync? => true, :arguments => [:arg])
76
+ client = double(:client)
77
+
78
+ expect(message).to receive(:respond).with([client, :arg])
79
+ manifest.handle(message, client)
80
+ end
81
+
82
+ it "calls a plugin async handler" do
83
+ manifest = Manifest.new
84
+ async_proc = Proc.new {}
85
+ plugin = Plugin.from_config_block("source") do |plug|
86
+ plug.command(:Foo, &async_proc)
87
+ end
88
+ manifest.register(plugin)
89
+
90
+ message = double(:message, :method_name => "source:command:Foo", :sync? => false, :arguments => [:arg])
91
+ client = double(:client)
92
+
93
+ expect(async_proc).to receive(:call).with(client, :arg)
94
+ manifest.handle(message, client)
95
+ end
96
+
97
+ it "calls a default sync handler" do
98
+ manifest = Manifest.new
99
+ message = double(:message, :method_name => "foobar", :sync? => true)
100
+
101
+ expect(message).to receive(:error).with("Unknown request foobar")
102
+ manifest.handle(message, double(:client))
103
+ end
104
+
105
+ it "calls a default async handler" do
106
+ manifest = Manifest.new
107
+ message = double(:message, :method_name => "foobar", :sync? => false)
108
+
109
+ manifest.handle(message, double(:client))
110
+ end
111
+ end
112
+ end
113
+ end
@@ -11,13 +11,15 @@ module Neovim
11
11
  srv_thr = Thread.new do
12
12
  client = server.accept
13
13
  messages << client.readpartial(1024)
14
+
14
15
  client.write(MessagePack.pack([2]))
16
+ client.close
17
+ server.close
15
18
  end
16
19
 
17
20
  fiber = Fiber.new do
18
- stream.send([1]).run do |msg|
19
- Fiber.yield(msg)
20
- end
21
+ msg_cb = Proc.new { |msg| Fiber.yield(msg) }
22
+ stream.send([1]).run(msg_cb)
21
23
  end
22
24
 
23
25
  expect(fiber.resume).to eq([2])
@@ -6,60 +6,60 @@ module Neovim
6
6
  it "registers a command" do
7
7
  cmd_block = Proc.new {}
8
8
 
9
- plugin = Plugin.from_config_block do |plug|
9
+ plugin = Plugin.from_config_block("source") do |plug|
10
10
  plug.command("Foo", :range => true, :nargs => 1, &cmd_block)
11
11
  end
12
12
 
13
- expect(plugin.specs).to eq(
14
- [
15
- {
16
- :type => :command,
17
- :name => :Foo,
18
- :sync => false,
19
- :opts => {:range => "", :nargs => 1},
20
- :proc => cmd_block
21
- }
22
- ]
13
+ expect(plugin.handlers.size).to be(1)
14
+ handler = plugin.handlers.first
15
+
16
+ expect(handler.block).to eq(cmd_block)
17
+ expect(handler.qualified_name).to eq("source:command:Foo")
18
+ expect(handler.to_spec).to eq(
19
+ :type => :command,
20
+ :name => "Foo",
21
+ :sync => false,
22
+ :opts => {:range => "", :nargs => 1},
23
23
  )
24
24
  end
25
25
 
26
26
  it "registers an autocmd" do
27
27
  au_block = Proc.new {}
28
28
 
29
- plugin = Plugin.from_config_block do |plug|
29
+ plugin = Plugin.from_config_block("source") do |plug|
30
30
  plug.autocmd("BufEnter", :pattern => "*.rb", &au_block)
31
31
  end
32
32
 
33
- expect(plugin.specs).to eq(
34
- [
35
- {
36
- :type => :autocmd,
37
- :name => :BufEnter,
38
- :sync => false,
39
- :opts => {:pattern => "*.rb"},
40
- :proc => au_block
41
- }
42
- ]
33
+ expect(plugin.handlers.size).to be(1)
34
+ handler = plugin.handlers.first
35
+
36
+ expect(handler.block).to eq(au_block)
37
+ expect(handler.qualified_name).to eq("source:autocmd:BufEnter:*.rb")
38
+ expect(handler.to_spec).to eq(
39
+ :type => :autocmd,
40
+ :name => "BufEnter",
41
+ :sync => false,
42
+ :opts => {:pattern => "*.rb"},
43
43
  )
44
44
  end
45
45
 
46
46
  it "registers a function" do
47
47
  fun_block = Proc.new {}
48
48
 
49
- plugin = Plugin.from_config_block do |plug|
49
+ plugin = Plugin.from_config_block("source") do |plug|
50
50
  plug.function("Foo", :range => true, :nargs => 1, &fun_block)
51
51
  end
52
52
 
53
- expect(plugin.specs).to eq(
54
- [
55
- {
56
- :type => :function,
57
- :name => :Foo,
58
- :sync => false,
59
- :opts => {:range => "", :nargs => 1},
60
- :proc => fun_block
61
- }
62
- ]
53
+ expect(plugin.handlers.size).to be(1)
54
+ handler = plugin.handlers.first
55
+
56
+ expect(handler.block).to eq(fun_block)
57
+ expect(handler.qualified_name).to eq("source:function:Foo")
58
+ expect(handler.to_spec).to eq(
59
+ :type => :function,
60
+ :name => "Foo",
61
+ :sync => false,
62
+ :opts => {:range => "", :nargs => 1},
63
63
  )
64
64
  end
65
65
  end
@@ -1,33 +1,112 @@
1
1
  require "helper"
2
+ require "securerandom"
3
+ require "fileutils"
2
4
 
3
5
  module Neovim
4
6
  RSpec.describe Session do
5
- let(:session) do
6
- event_loop = EventLoop.child(["-n", "-u", "NONE"])
7
- stream = MsgpackStream.new(event_loop)
8
- async = AsyncSession.new(stream)
9
- Session.new(async)
10
- end
7
+ shared_context "session behavior" do
8
+ it "supports functions with async=false" do
9
+ expect(session.request(:vim_strwidth, "foobar")).to be(6)
10
+ end
11
+
12
+ it "supports functions with async=true" do
13
+ expect(session.request(:vim_input, "jk")).to be(2)
14
+ end
15
+
16
+ it "raises an exception when there are errors" do
17
+ expect {
18
+ session.request(:vim_strwidth, "too", "many")
19
+ }.to raise_error(/wrong number of arguments/i)
20
+ end
11
21
 
12
- it "supports functions with async=false" do
13
- expect(session.request(:vim_strwidth, "foobar")).to be(6)
22
+ it "handles large data" do
23
+ large_str = Array.new(1024 * 16) { SecureRandom.hex(1) }.join
24
+ session.request(:vim_set_current_line, large_str)
25
+ expect(session.request(:vim_get_current_line)).to eq(large_str)
26
+ end
27
+
28
+ describe "#api_methods_for_prefix" do
29
+ it "returns relevant functions without a prefix" do
30
+ methods = session.api_methods_for_prefix("vim_")
31
+ expect(methods).to include(:strwidth)
32
+ end
33
+ end
14
34
  end
15
35
 
16
- it "supports functions with async=true" do
17
- expect(session.request(:vim_input, "jk")).to be(2)
36
+ context "tcp" do
37
+ let!(:nvim_port) do
38
+ server = TCPServer.new("0.0.0.0", 0)
39
+ server.addr[1].tap { server.close }
40
+ end
41
+
42
+ let!(:nvim_pid) do
43
+ Process.spawn(
44
+ {"NVIM_LISTEN_ADDRESS" => "0.0.0.0:#{nvim_port}"},
45
+ "#{ENV.fetch("NVIM_EXECUTABLE")} --headless -n -u NONE",
46
+ [:out, :err] => "/dev/null"
47
+ ).tap do
48
+ begin
49
+ TCPSocket.open("0.0.0.0", nvim_port).close
50
+ rescue Errno::ECONNREFUSED
51
+ retry
52
+ end
53
+ end
54
+ end
55
+
56
+ after do
57
+ Process.kill(:TERM, nvim_pid)
58
+ Process.waitpid(nvim_pid)
59
+ end
60
+
61
+ let(:session) do
62
+ event_loop = EventLoop.tcp("0.0.0.0", nvim_port)
63
+ stream = MsgpackStream.new(event_loop)
64
+ async = AsyncSession.new(stream)
65
+ Session.new(async)
66
+ end
67
+
68
+ include_context "session behavior"
18
69
  end
19
70
 
20
- it "raises an exception when there are errors" do
21
- expect {
22
- session.request(:vim_strwidth, "too", "many")
23
- }.to raise_error(/wrong number of arguments/i)
71
+ context "unix" do
72
+ let!(:nvim_pid) do
73
+ FileUtils.rm_f("/tmp/nvim-#$$.sock")
74
+ Process.spawn(
75
+ {"NVIM_LISTEN_ADDRESS" => "/tmp/nvim-#$$.sock"},
76
+ "#{ENV.fetch("NVIM_EXECUTABLE")} --headless -n -u NONE",
77
+ [:out, :err] => "/dev/null"
78
+ ).tap do
79
+ loop do
80
+ break if File.exists?("/tmp/nvim-#$$.sock")
81
+ end
82
+ end
83
+ end
84
+
85
+ after do
86
+ Process.kill(:TERM, nvim_pid)
87
+ Process.waitpid(nvim_pid)
88
+ FileUtils.rm_f("/tmp/nvim-#$$.sock")
89
+ end
90
+
91
+ let(:session) do
92
+ event_loop = EventLoop.unix("/tmp/nvim-#$$.sock")
93
+ stream = MsgpackStream.new(event_loop)
94
+ async = AsyncSession.new(stream)
95
+ Session.new(async)
96
+ end
97
+
98
+ include_context "session behavior"
24
99
  end
25
100
 
26
- describe "#api_methods_for_prefix" do
27
- it "returns relevant functions without a prefix" do
28
- methods = session.api_methods_for_prefix("vim_")
29
- expect(methods).to include(:strwidth)
101
+ context "child" do
102
+ let(:session) do
103
+ event_loop = EventLoop.child(["-n", "-u", "NONE"])
104
+ stream = MsgpackStream.new(event_loop)
105
+ async = AsyncSession.new(stream)
106
+ Session.new(async)
30
107
  end
108
+
109
+ include_context "session behavior"
31
110
  end
32
111
  end
33
112
  end