neovim 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,7 @@
1
1
  module Neovim
2
2
  # Provide an enumerable interface for dealing with ranges of lines.
3
+ #
4
+ # @api private
3
5
  class LineRange
4
6
  include Enumerable
5
7
 
@@ -111,6 +113,12 @@ module Neovim
111
113
  self
112
114
  end
113
115
 
116
+ # @param index [Fixnum]
117
+ # @param line [String]
118
+ def insert(index, lines)
119
+ @buffer.insert(index, Array(lines))
120
+ end
121
+
114
122
  # @param index [Fixnum]
115
123
  def delete(index)
116
124
  @buffer.del_line(abs_line(index))
@@ -2,6 +2,7 @@ require "logger"
2
2
 
3
3
  module Neovim
4
4
  # Mixed into classes for unified logging helper methods.
5
+ # @api private
5
6
  module Logging
6
7
  class << self
7
8
  attr_writer :logger
@@ -3,7 +3,9 @@ require "msgpack"
3
3
 
4
4
  module Neovim
5
5
  # Handles serializing RPC messages to MessagePack and passing them to
6
- # the event loop
6
+ # the event loop.
7
+ #
8
+ # @api private
7
9
  class MsgpackStream
8
10
  include Logging
9
11
 
@@ -40,7 +42,7 @@ module Neovim
40
42
  end
41
43
  end
42
44
  rescue => e
43
- fatal("got unexpected error #{e}")
45
+ fatal("got unexpected error #{e.inspect}")
44
46
  debug(e.backtrace.join("\n"))
45
47
  end
46
48
 
@@ -1,5 +1,6 @@
1
1
  module Neovim
2
2
  # An asynchronous message from +nvim+.
3
+ #
3
4
  # @api private
4
5
  class Notification
5
6
  attr_reader :method_name, :arguments
@@ -1,6 +1,7 @@
1
1
  require "neovim/plugin/dsl"
2
2
 
3
3
  module Neovim
4
+ # @api private
4
5
  class Plugin
5
6
  attr_accessor :handlers
6
7
  attr_reader :source
@@ -1,5 +1,6 @@
1
1
  module Neovim
2
2
  # A synchronous message from +nvim+.
3
+ #
3
4
  # @api private
4
5
  class Request
5
6
  attr_reader :method_name, :arguments
@@ -6,6 +6,8 @@ module Neovim
6
6
  # This class is used to define a +Neovim::Plugin+ to act as a backend for the
7
7
  # legacy +:ruby+, +:rubyfile+, and +:rubydo+ Vim commands. It is autoloaded
8
8
  # from +nvim+ and not intended to be loaded directly.
9
+ #
10
+ # @api private
9
11
  module RubyProvider
10
12
  def self.__define_plugin!
11
13
  Thread.abort_on_exception = true
@@ -7,6 +7,8 @@ require "fiber"
7
7
 
8
8
  module Neovim
9
9
  # Wraps an +AsyncSession+ in a synchronous API using +Fiber+s.
10
+ #
11
+ # @api private
10
12
  class Session
11
13
  include Logging
12
14
 
@@ -99,7 +101,7 @@ module Neovim
99
101
  Fiber.new { yield message if block_given? }.resume
100
102
  end
101
103
  ensure
102
- stop
104
+ shutdown
103
105
  end
104
106
 
105
107
  # Make an RPC request and return its response.
@@ -1,3 +1,3 @@
1
1
  module Neovim
2
- VERSION = Gem::Version.new("0.2.2")
2
+ VERSION = Gem::Version.new("0.2.3")
3
3
  end
@@ -38,4 +38,5 @@ RSpec.configure do |config|
38
38
  Kernel.srand config.seed
39
39
  end
40
40
 
41
+ Neovim.logger.level = Logger::FATAL
41
42
  Thread.abort_on_exception = true
@@ -4,6 +4,7 @@ module Neovim
4
4
  RSpec.describe Buffer do
5
5
  let(:client) { Neovim.attach_child(["nvim", "-n", "-u", "NONE"]) }
6
6
  let(:buffer) { client.current.buffer }
7
+ after { client.shutdown }
7
8
 
8
9
  describe "#lines" do
9
10
  it "returns a LineRange" do
@@ -108,6 +109,25 @@ module Neovim
108
109
  }.to change { buffer.lines.to_a }.to(["one", "two"])
109
110
  end
110
111
 
112
+ it "unshifts buffer lines using index 0" do
113
+ buffer.lines = []
114
+
115
+ expect {
116
+ buffer.append(0, "two")
117
+ buffer.append(0, "one")
118
+ }.to change { buffer.lines.to_a }.to(["one", "two", ""])
119
+ end
120
+
121
+ it "raises for out of bounds indexes" do
122
+ expect {
123
+ buffer.append(-1, "err")
124
+ }.to raise_error(/out of bounds/i)
125
+
126
+ expect {
127
+ buffer.append(10, "err")
128
+ }.to raise_error(/out of bounds/i)
129
+ end
130
+
111
131
  it "returns the appended line" do
112
132
  expect(buffer.append(0, "two")).to eq("two")
113
133
  end
@@ -3,6 +3,7 @@ require "helper"
3
3
  module Neovim
4
4
  RSpec.describe Client do
5
5
  let(:client) { Neovim.attach_child(["nvim", "-n", "-u", "NONE"]) }
6
+ after { client.shutdown }
6
7
 
7
8
  describe "#respond_to?" do
8
9
  it "returns true for vim functions" do
@@ -4,6 +4,7 @@ module Neovim
4
4
  RSpec.describe Current do
5
5
  let(:client) { Neovim.attach_child(["nvim", "-n", "-u", "NONE"]) }
6
6
  let(:current) { client.current }
7
+ after { client.shutdown }
7
8
 
8
9
  describe "#line" do
9
10
  it "returns an empty string if the current line is empty" do
@@ -0,0 +1,47 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ class Host
5
+ RSpec.describe Loader do
6
+ describe "#load" do
7
+ let(:plugin_path) { Support.file_path("plug.rb") }
8
+ let(:host) { instance_double(Host, :register => nil) }
9
+ let(:loader) { Loader.new(host) }
10
+
11
+ before do
12
+ File.write(plugin_path, "Neovim.plugin")
13
+ end
14
+
15
+ it "registers plugins defined in the provided files" do
16
+ expect(host).to receive(:register).with(kind_of(Plugin))
17
+ loader.load([plugin_path])
18
+ end
19
+
20
+ it "registers multiple plugins defined in the provided files" do
21
+ File.write(plugin_path, "Neovim.plugin; Neovim.plugin")
22
+ expect(host).to receive(:register).with(kind_of(Plugin)).twice
23
+ loader.load([plugin_path])
24
+ end
25
+
26
+ it "doesn't register plugins when none are defined" do
27
+ File.write(plugin_path, "class FooClass; end")
28
+ expect(host).not_to receive(:register)
29
+ loader.load([plugin_path])
30
+ end
31
+
32
+ it "doesn't leak constants defined in plugins" do
33
+ File.write(plugin_path, "class FooClass; end")
34
+ loader.load([plugin_path])
35
+ expect(Kernel.const_defined?(:FooClass)).to be(false)
36
+ end
37
+
38
+ it "doesn't leak the overidden Neovim.plugin method" do
39
+ loader.load([plugin_path])
40
+ expect {
41
+ Neovim.plugin
42
+ }.to raise_error(/outside of a plugin host/)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -2,50 +2,138 @@ require "helper"
2
2
 
3
3
  module Neovim
4
4
  RSpec.describe Host do
5
+ let(:session) { instance_double(Session) }
6
+ let(:client) { instance_double(Client) }
7
+ let(:host) { Host.new(session, client) }
8
+
5
9
  describe ".load_from_files" do
6
- it "loads the defined plugins into a manifest" do
7
- plug1 = Support.file_path("plug1.rb")
8
- plug2 = Support.file_path("plug2.rb")
10
+ it "instantiates with a session and loads plugins" do
11
+ paths = ["/foo", "/bar"]
12
+ loader = instance_double(Host::Loader)
9
13
 
10
- File.write(plug1, "Neovim.plugin")
11
- File.write(plug2, "Neovim.plugin; Neovim.plugin")
14
+ expect(Host::Loader).to receive(:new).
15
+ with(kind_of(Host)).
16
+ and_return(loader)
17
+ expect(loader).to receive(:load).with(paths)
12
18
 
13
- manifest = Manifest.new
19
+ Host.load_from_files(paths, :session => session, :client => client)
20
+ end
21
+ end
22
+
23
+ describe "#handlers" do
24
+ it "has a default poll handler" do
25
+ expect(host.handlers["poll"]).to respond_to(:call)
26
+ end
27
+ end
14
28
 
15
- expect(manifest).to receive(:register).exactly(3).times
16
- host = Host.load_from_files([plug1, plug2], manifest)
17
- expect(host.manifest).to eq(manifest)
29
+ describe "#specs" do
30
+ it "has default specs" do
31
+ expect(host.specs).to eq({})
18
32
  end
33
+ end
19
34
 
20
- it "doesn't load plugin code into the global namespace" do
21
- plug = Support.file_path("plug.rb")
22
- File.write(plug, "class FooClass; end")
35
+ describe "#register" do
36
+ it "adds specs" do
37
+ plugin = Plugin.from_config_block("source") do |plug|
38
+ plug.command(:Foo)
39
+ end
23
40
 
24
- host = Host.load_from_files([plug])
25
- expect(Kernel.const_defined?("FooClass")).to be(false)
41
+ expect {
42
+ host.register(plugin)
43
+ }.to change { host.specs }.from({}).to("source" => plugin.specs)
44
+ end
45
+
46
+ it "adds plugin handlers" do
47
+ plugin = Plugin.from_config_block("source") do |plug|
48
+ plug.command(:Foo)
49
+ end
50
+
51
+ expect {
52
+ host.register(plugin)
53
+ }.to change {
54
+ host.handlers["source:command:Foo"]
55
+ }.from(nil).to(kind_of(Proc))
56
+ end
57
+
58
+ it "doesn't add top-level RPCs to specs" do
59
+ plugin = Plugin.from_config_block("source") do |plug|
60
+ plug.rpc(:Foo)
61
+ end
62
+
63
+ expect {
64
+ host.register(plugin)
65
+ }.to change { host.specs }.from({}).to("source" => [])
26
66
  end
27
67
  end
28
68
 
29
- describe "#run" do
30
- it "delegates messages to the manifest" do
31
- messages = []
32
- manifest = instance_double(Manifest)
33
- session = Session.child(["nvim", "-n", "-u", "NONE"])
69
+ describe "#handle" do
70
+ it "calls the poll handler" do
71
+ message = double(:message, :method_name => "poll", :sync? => true)
72
+
73
+ expect(message).to receive(:respond).with("ok")
74
+ host.handle(message)
75
+ end
34
76
 
35
- host = Host.new(manifest, session)
77
+ it "calls the specs handler" do
78
+ plugin = Plugin.from_config_block("source") do |plug|
79
+ plug.command(:Foo)
80
+ end
81
+ host.register(plugin)
36
82
 
37
- expect(manifest).to receive(:handle) do |msg, client|
38
- expect(msg.method_name).to eq("my_event")
39
- expect(msg.arguments).to eq(["arg"])
40
- expect(client).to be_a(Client)
83
+ message = double(:message, :method_name => "specs", :sync? => true, :arguments => ["source"])
41
84
 
42
- session.stop
85
+ expect(message).to receive(:respond).with(plugin.specs)
86
+ host.handle(message)
87
+ end
88
+
89
+ it "calls a plugin sync handler" do
90
+ plugin = Plugin.from_config_block("source") do |plug|
91
+ plug.command(:Foo, :sync => true) { |client, arg| [client, arg] }
92
+ end
93
+ host.register(plugin)
94
+
95
+ message = double(:message, :method_name => "source:command:Foo", :sync? => true, :arguments => [:arg])
96
+
97
+ expect(message).to receive(:respond).with([client, :arg])
98
+ host.handle(message)
99
+ end
100
+
101
+ it "rescues plugin sync handler exceptions" do
102
+ plugin = Plugin.from_config_block("source") do |plug|
103
+ plug.command(:Foo, :sync => true) { raise "BOOM" }
104
+ end
105
+ host.register(plugin)
106
+
107
+ message = double(:message, :method_name => "source:command:Foo", :sync? => true, :arguments => [])
108
+
109
+ expect(message).to receive(:error).with("BOOM")
110
+ host.handle(message)
111
+ end
112
+
113
+ it "calls a plugin async handler" do
114
+ async_proc = Proc.new {}
115
+ plugin = Plugin.from_config_block("source") do |plug|
116
+ plug.command(:Foo, &async_proc)
43
117
  end
118
+ host.register(plugin)
119
+
120
+ message = double(:message, :method_name => "source:command:Foo", :sync? => false, :arguments => [:arg])
121
+
122
+ expect(async_proc).to receive(:call).with(client, :arg)
123
+ host.handle(message)
124
+ end
125
+
126
+ it "calls a default sync handler" do
127
+ message = double(:message, :method_name => "foobar", :sync? => true)
128
+
129
+ expect(message).to receive(:error).with("Unknown request foobar")
130
+ host.handle(message)
131
+ end
44
132
 
45
- session.request(:vim_subscribe, "my_event")
46
- session.request(:vim_command, "call rpcnotify(0, 'my_event', 'arg')")
133
+ it "calls a default async handler" do
134
+ message = double(:message, :method_name => "foobar", :sync? => false)
47
135
 
48
- host.run
136
+ host.handle(message)
49
137
  end
50
138
  end
51
139
  end
@@ -4,7 +4,7 @@ module Neovim
4
4
  RSpec.describe LineRange do
5
5
  let(:client) { Neovim.attach_child(["nvim", "-n", "-u", "NONE"]) }
6
6
  let(:buffer) { client.current.buffer }
7
- let(:line_range) { LineRange.new(buffer, 0, 3) }
7
+ let(:line_range) { LineRange.new(buffer, 0, -1) }
8
8
  let(:sub_range) { LineRange.new(buffer, 1, 2) }
9
9
 
10
10
  before do
@@ -14,6 +14,8 @@ module Neovim
14
14
  client.command("normal o4")
15
15
  end
16
16
 
17
+ after { client.shutdown }
18
+
17
19
  it "is enumerable" do
18
20
  expect(line_range).to be_an(Enumerable)
19
21
  expect(line_range).to respond_to(:each)
@@ -115,6 +117,46 @@ module Neovim
115
117
  end
116
118
  end
117
119
 
120
+ describe "#insert" do
121
+ before { line_range.replace(["1", "2"]) }
122
+
123
+ it "inserts lines at the beginning" do
124
+ expect {
125
+ line_range.insert(0, "z")
126
+ }.to change { line_range.to_a }.to(["z", "1", "2"])
127
+
128
+ expect {
129
+ line_range.insert(0, ["x", "y"])
130
+ }.to change { line_range.to_a }.to(["x", "y", "z", "1", "2"])
131
+ end
132
+
133
+ it "inserts lines in the middle" do
134
+ expect {
135
+ line_range.insert(1, "z")
136
+ }.to change { line_range.to_a }.to(["1", "z", "2"])
137
+
138
+ expect {
139
+ line_range.insert(1, ["x", "y"])
140
+ }.to change { line_range.to_a }.to(["1", "x", "y", "z", "2"])
141
+ end
142
+
143
+ it "inserts lines at the end" do
144
+ expect {
145
+ line_range.insert(-1, "x")
146
+ }.to change { line_range.to_a }.to(["1", "2", "x"])
147
+
148
+ expect {
149
+ line_range.insert(-1, ["y", "z"])
150
+ }.to change { line_range.to_a }.to(["1", "2", "x", "y", "z"])
151
+ end
152
+
153
+ it "raises on out of bounds indexes" do
154
+ expect {
155
+ line_range.insert(10, "x")
156
+ }.to raise_error(/out of bounds/i)
157
+ end
158
+ end
159
+
118
160
  describe "#delete" do
119
161
  it "deletes the line at the given index" do
120
162
  expect {
@@ -2,8 +2,11 @@ require "helper"
2
2
 
3
3
  module Neovim
4
4
  RSpec.describe RemoteObject do
5
+ let(:client) { Neovim.attach_child(["nvim", "-n", "-u", "NONE"]) }
6
+ after { client.shutdown }
7
+
5
8
  context Window do
6
- let(:window) { Neovim.attach_child(["nvim", "-n", "-u", "NONE"]).current.window }
9
+ let(:window) { client.current.window }
7
10
 
8
11
  describe "#respond_to?" do
9
12
  it "returns true for Window functions" do
@@ -37,7 +40,7 @@ module Neovim
37
40
  end
38
41
 
39
42
  context Tabpage do
40
- let(:tabpage) { Neovim.attach_child(["nvim", "-n", "-u", "NONE"]).current.tabpage }
43
+ let(:tabpage) { client.current.tabpage }
41
44
 
42
45
  describe "#respond_to?" do
43
46
  it "returns true for Tabpage functions" do
@@ -71,7 +74,7 @@ module Neovim
71
74
  end
72
75
 
73
76
  context Buffer do
74
- let(:buffer) { Neovim.attach_child(["nvim", "-n", "-u", "NONE"]).current.buffer }
77
+ let(:buffer) { client.current.buffer }
75
78
 
76
79
  describe "#respond_to?" do
77
80
  it "returns true for Buffer functions" do