neovim 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -1
- data/.travis.yml +2 -3
- data/CHANGELOG.md +29 -0
- data/Gemfile +0 -11
- data/README.md +3 -3
- data/Rakefile +1 -1
- data/appveyor.yml +9 -1
- data/lib/neovim.rb +3 -3
- data/lib/neovim/client.rb +2 -3
- data/lib/neovim/connection.rb +69 -0
- data/lib/neovim/event_loop.rb +34 -34
- data/lib/neovim/host.rb +47 -51
- data/lib/neovim/host/loader.rb +1 -4
- data/lib/neovim/logging.rb +8 -8
- data/lib/neovim/message.rb +70 -0
- data/lib/neovim/plugin.rb +0 -3
- data/lib/neovim/plugin/handler.rb +6 -6
- data/lib/neovim/remote_object.rb +1 -1
- data/lib/neovim/ruby_provider.rb +25 -14
- data/lib/neovim/session.rb +36 -43
- data/lib/neovim/version.rb +1 -1
- data/neovim.gemspec +4 -0
- data/spec/acceptance/runtime/rplugin/ruby/autocmds.rb +3 -3
- data/spec/acceptance/runtime/rplugin/ruby/commands.rb +15 -15
- data/spec/acceptance/runtime/rplugin/ruby/functions.rb +5 -5
- data/spec/acceptance_spec.rb +19 -16
- data/spec/helper.rb +15 -0
- data/spec/neovim/connection_spec.rb +79 -0
- data/spec/neovim/event_loop_spec.rb +36 -50
- data/spec/neovim/host/loader_spec.rb +16 -9
- data/spec/neovim/host_spec.rb +82 -92
- data/spec/neovim/logging_spec.rb +6 -6
- data/spec/neovim/message_spec.rb +119 -0
- data/spec/neovim/plugin_spec.rb +31 -31
- data/spec/neovim/session_spec.rb +1 -1
- metadata +38 -15
- data/lib/neovim/event_loop/connection.rb +0 -78
- data/lib/neovim/event_loop/message_builder.rb +0 -127
- data/lib/neovim/event_loop/serializer.rb +0 -37
- data/spec/acceptance/runtime/rplugin.vim +0 -37
- data/spec/neovim/event_loop/connection_spec.rb +0 -89
- data/spec/neovim/event_loop/message_builder_spec.rb +0 -105
- data/spec/neovim/event_loop/serializer_spec.rb +0 -63
data/spec/neovim/host_spec.rb
CHANGED
@@ -9,18 +9,18 @@ module Neovim
|
|
9
9
|
|
10
10
|
let(:host_rd) { push_pipe[0] }
|
11
11
|
let(:host_wr) { pull_pipe[1] }
|
12
|
-
let(:nvim_rd) { pull_pipe[0] }
|
13
|
-
let(:nvim_wr) { push_pipe[1] }
|
12
|
+
let(:nvim_rd) { MessagePack::Unpacker.new(pull_pipe[0]) }
|
13
|
+
let(:nvim_wr) { MessagePack::Packer.new(push_pipe[1]) }
|
14
14
|
|
15
15
|
let(:plugin_path) do
|
16
16
|
Support.file_path("my_plugin").tap do |path|
|
17
17
|
File.write(path, <<-PLUGIN)
|
18
18
|
Neovim.plugin do |plug|
|
19
|
-
plug.command(:
|
20
|
-
arg
|
19
|
+
plug.command(:Echo, nargs: 1, sync: true) do |client, arg|
|
20
|
+
arg
|
21
21
|
end
|
22
22
|
|
23
|
-
plug.command(:Boom, :
|
23
|
+
plug.command(:Boom, sync: true) do |client|
|
24
24
|
raise "BOOM"
|
25
25
|
end
|
26
26
|
|
@@ -33,7 +33,7 @@ module Neovim
|
|
33
33
|
end
|
34
34
|
|
35
35
|
let!(:host_thread) do
|
36
|
-
connection =
|
36
|
+
connection = Connection.new(host_rd, host_wr)
|
37
37
|
event_loop = EventLoop.new(connection)
|
38
38
|
|
39
39
|
Thread.new do
|
@@ -41,106 +41,96 @@ module Neovim
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
before do
|
45
|
-
_, reqid, method = MessagePack.unpack(nvim_rd.readpartial(1024))
|
46
|
-
expect(method).to eq("nvim_get_api_info")
|
47
|
-
|
48
|
-
session = Session.new(EventLoop.child(Support.child_argv))
|
49
|
-
api_info = session.request(:nvim_get_api_info)
|
50
|
-
session.shutdown
|
51
|
-
|
52
|
-
nvim_wr.write(MessagePack.pack([1, reqid, nil, api_info]))
|
53
|
-
nvim_wr.flush
|
54
|
-
end
|
55
|
-
|
56
44
|
after do
|
57
|
-
host_thread.kill
|
45
|
+
host_thread.kill while host_thread.alive?
|
58
46
|
host_thread.join
|
59
47
|
end
|
60
48
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
49
|
+
context "poll" do
|
50
|
+
it "initializes a client and responds 'ok'" do
|
51
|
+
nvim_wr.write([0, 1, :poll, []]).flush
|
52
|
+
type, reqid, method = nvim_rd.read
|
65
53
|
|
66
|
-
|
67
|
-
|
68
|
-
|
54
|
+
expect(type).to eq(0)
|
55
|
+
expect(reqid).to eq(2)
|
56
|
+
expect(method).to eq("nvim_get_api_info")
|
69
57
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
response = MessagePack.unpack(nvim_rd.readpartial(1024))
|
76
|
-
expect(response).to eq(
|
77
|
-
[
|
78
|
-
1,
|
79
|
-
0,
|
80
|
-
nil,
|
81
|
-
[
|
82
|
-
{
|
83
|
-
"type" => "command",
|
84
|
-
"name" => "StrWidth",
|
85
|
-
"sync" => true,
|
86
|
-
"opts" => {"nargs" => 1},
|
87
|
-
},
|
88
|
-
{
|
89
|
-
"type" => "command",
|
90
|
-
"name" => "Boom",
|
91
|
-
"sync" => true,
|
92
|
-
"opts" => {},
|
93
|
-
},
|
94
|
-
{
|
95
|
-
"type" => "command",
|
96
|
-
"name" => "BoomAsync",
|
97
|
-
"sync" => false,
|
98
|
-
"opts" => {},
|
99
|
-
},
|
100
|
-
],
|
101
|
-
],
|
102
|
-
)
|
58
|
+
api_info = [0, {"types" => {}, "functions" => {}}]
|
59
|
+
nvim_wr.write([1, reqid, nil, api_info]).flush
|
60
|
+
expect(nvim_rd.read).to eq([1, 1, nil, "ok"])
|
61
|
+
end
|
103
62
|
end
|
104
63
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
64
|
+
context "after poll" do
|
65
|
+
before do
|
66
|
+
nvim_wr.write([0, 1, :poll, []]).flush
|
67
|
+
_, reqid, _ = nvim_rd.read
|
109
68
|
|
110
|
-
|
111
|
-
|
112
|
-
|
69
|
+
session = Session.new(EventLoop.child(Support.child_argv))
|
70
|
+
api_info = session.request(:nvim_get_api_info)
|
71
|
+
session.shutdown
|
113
72
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
nvim_wr.flush
|
73
|
+
nvim_wr.write([1, reqid, nil, api_info]).flush
|
74
|
+
nvim_rd.read
|
75
|
+
end
|
118
76
|
|
119
|
-
|
120
|
-
|
121
|
-
end
|
77
|
+
it "responds with specs to the 'specs' request" do
|
78
|
+
nvim_wr.write([0, 2, :specs, [plugin_path]]).flush
|
122
79
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
80
|
+
expect(nvim_rd.read).to eq(
|
81
|
+
[
|
82
|
+
1,
|
83
|
+
2,
|
84
|
+
nil,
|
85
|
+
[
|
86
|
+
{
|
87
|
+
"type" => "command",
|
88
|
+
"name" => "Echo",
|
89
|
+
"sync" => true,
|
90
|
+
"opts" => {"nargs" => 1},
|
91
|
+
},
|
92
|
+
{
|
93
|
+
"type" => "command",
|
94
|
+
"name" => "Boom",
|
95
|
+
"sync" => true,
|
96
|
+
"opts" => {},
|
97
|
+
},
|
98
|
+
{
|
99
|
+
"type" => "command",
|
100
|
+
"name" => "BoomAsync",
|
101
|
+
"sync" => false,
|
102
|
+
"opts" => {},
|
103
|
+
},
|
104
|
+
],
|
105
|
+
],
|
106
|
+
)
|
107
|
+
end
|
136
108
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
109
|
+
it "delegates to plugin handlers" do
|
110
|
+
nvim_wr.write([0, 0, "#{plugin_path}:command:Echo", ["hi"]]).flush
|
111
|
+
expect(nvim_rd.read).to eq([1, 0, nil, "hi"])
|
112
|
+
end
|
113
|
+
|
114
|
+
it "handles exceptions in sync plugin handlers" do
|
115
|
+
nvim_wr.write([0, 0, "#{plugin_path}:command:Boom", ["hi"]]).flush
|
116
|
+
expect(nvim_rd.read).to eq([1, 0, "BOOM", nil])
|
117
|
+
end
|
141
118
|
|
142
|
-
|
143
|
-
|
119
|
+
it "handles exceptions in async plugin handlers" do
|
120
|
+
nvim_wr.write([2, "#{plugin_path}:command:BoomAsync", ["hi"]]).flush
|
121
|
+
|
122
|
+
expect(nvim_rd.read).to match_array(
|
123
|
+
[
|
124
|
+
0, duck_type(:to_int), "nvim_err_writeln",
|
125
|
+
[/my_plugin:command:BoomAsync: \(RuntimeError\) BOOM ASYNC/]
|
126
|
+
]
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "handles unknown requests" do
|
131
|
+
nvim_wr.write([0, 0, "foobar", []]).flush
|
132
|
+
expect(nvim_rd.read).to eq([1, 0, "Unknown request foobar", nil])
|
133
|
+
end
|
144
134
|
end
|
145
135
|
end
|
146
136
|
end
|
data/spec/neovim/logging_spec.rb
CHANGED
@@ -16,21 +16,21 @@ module Neovim
|
|
16
16
|
|
17
17
|
describe ".logger" do
|
18
18
|
it "fetches the output from $NVIM_RUBY_LOG_FILE" do
|
19
|
-
logger = instance_double(Logger,
|
19
|
+
logger = instance_double(Logger, "level=": nil, "formatter=": nil)
|
20
20
|
expect(Logger).to receive(:new).with("/tmp/nvim.log").and_return(logger)
|
21
21
|
Logging.logger("NVIM_RUBY_LOG_FILE" => "/tmp/nvim.log")
|
22
22
|
expect(Logging.logger).to be(logger)
|
23
23
|
end
|
24
24
|
|
25
25
|
it "defaults the output to STDERR" do
|
26
|
-
logger = instance_double(Logger,
|
26
|
+
logger = instance_double(Logger, "level=": nil, "formatter=": nil)
|
27
27
|
expect(Logger).to receive(:new).with(STDERR).and_return(logger)
|
28
28
|
Logging.logger({})
|
29
29
|
expect(Logging.logger).to be(logger)
|
30
30
|
end
|
31
31
|
|
32
32
|
it "fetches the level from $NVIM_RUBY_LOG_LEVEL as a string" do
|
33
|
-
logger = instance_double(Logger,
|
33
|
+
logger = instance_double(Logger, "formatter=": nil)
|
34
34
|
expect(Logger).to receive(:new).and_return(logger)
|
35
35
|
expect(logger).to receive(:level=).with(Logger::DEBUG)
|
36
36
|
Logging.logger("NVIM_RUBY_LOG_LEVEL" => "DEBUG")
|
@@ -38,7 +38,7 @@ module Neovim
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it "fetches the level from $NVIM_RUBY_LOG_LEVEL as an integer" do
|
41
|
-
logger = instance_double(Logger,
|
41
|
+
logger = instance_double(Logger, "formatter=": nil)
|
42
42
|
expect(Logger).to receive(:new).and_return(logger)
|
43
43
|
expect(logger).to receive(:level=).with(0)
|
44
44
|
Logging.logger("NVIM_RUBY_LOG_LEVEL" => "0")
|
@@ -46,7 +46,7 @@ module Neovim
|
|
46
46
|
end
|
47
47
|
|
48
48
|
it "defaults the level to WARN" do
|
49
|
-
logger = instance_double(Logger,
|
49
|
+
logger = instance_double(Logger, "formatter=": nil)
|
50
50
|
expect(Logger).to receive(:new).and_return(logger)
|
51
51
|
expect(logger).to receive(:level=).with(Logger::WARN)
|
52
52
|
Logging.logger({})
|
@@ -81,7 +81,7 @@ module Neovim
|
|
81
81
|
|
82
82
|
describe "#log" do
|
83
83
|
it "logs JSON at the specified level" do
|
84
|
-
obj.public_log(:info, :
|
84
|
+
obj.public_log(:info, foo: "bar")
|
85
85
|
logged = MultiJson.decode(log.string)
|
86
86
|
|
87
87
|
expect(logged).to match(
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
module Neovim
|
4
|
+
RSpec.describe Message do
|
5
|
+
describe ".request" do
|
6
|
+
it "builds a request" do
|
7
|
+
request = Message.request(1, :method, [1, 2])
|
8
|
+
|
9
|
+
expect(request).to be_a(Message::Request)
|
10
|
+
expect(request.sync?).to eq(true)
|
11
|
+
expect(request.id).to eq(1)
|
12
|
+
expect(request.method_name).to eq(:method)
|
13
|
+
expect(request.arguments).to eq([1, 2])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe ".response" do
|
18
|
+
it "builds a response" do
|
19
|
+
response = Message.response(1, "error", "value")
|
20
|
+
|
21
|
+
expect(response).to be_a(Message::Response)
|
22
|
+
expect(response.request_id).to eq(1)
|
23
|
+
expect(response.error).to eq("error")
|
24
|
+
expect(response.value).to eq("value")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".notification" do
|
29
|
+
it "builds a notification" do
|
30
|
+
notification = Message.notification(:method, [1, 2])
|
31
|
+
|
32
|
+
expect(notification).to be_a(Message::Notification)
|
33
|
+
expect(notification.sync?).to eq(false)
|
34
|
+
expect(notification.method_name).to eq(:method)
|
35
|
+
expect(notification.arguments).to eq([1, 2])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe ".from_array" do
|
40
|
+
it "returns a request" do
|
41
|
+
request = Message.from_array([0, 1, :method, [1, 2]])
|
42
|
+
|
43
|
+
expect(request).to be_a(Message::Request)
|
44
|
+
expect(request.id).to eq(1)
|
45
|
+
expect(request.method_name).to eq(:method)
|
46
|
+
expect(request.arguments).to eq([1, 2])
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns a response" do
|
50
|
+
response = Message.from_array([1, 1, [1, "error"], "value"])
|
51
|
+
|
52
|
+
expect(response).to be_a(Message::Response)
|
53
|
+
expect(response.request_id).to eq(1)
|
54
|
+
expect(response.error).to eq("error")
|
55
|
+
expect(response.value).to eq("value")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns a notification" do
|
59
|
+
notification = Message.from_array([2, :method, [1, 2]])
|
60
|
+
|
61
|
+
expect(notification).to be_a(Message::Notification)
|
62
|
+
expect(notification.method_name).to eq(:method)
|
63
|
+
expect(notification.arguments).to eq([1, 2])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe Message::Request do
|
68
|
+
subject { described_class.new(1, :method, [1, 2]) }
|
69
|
+
|
70
|
+
specify "#to_a" do
|
71
|
+
expect(subject.to_a).to eq([0, 1, :method, [1, 2]])
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#received" do
|
75
|
+
it "yields itself to the block" do
|
76
|
+
request = Message::Request.new(1, :method, [1, 2])
|
77
|
+
|
78
|
+
expect do |block|
|
79
|
+
request.received({}, &block)
|
80
|
+
end.to yield_with_args(request)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe Message::Response do
|
86
|
+
subject { described_class.new(2, "error", "result") }
|
87
|
+
|
88
|
+
specify "#to_a" do
|
89
|
+
expect(subject.to_a).to eq([1, 2, "error", "result"])
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#received" do
|
93
|
+
it "yields itself to the response handler" do
|
94
|
+
response = Message::Response.new(1, nil, "value")
|
95
|
+
|
96
|
+
expect do |block|
|
97
|
+
response.received(1 => block.to_proc)
|
98
|
+
end.to yield_with_args(response)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe Message::Notification do
|
104
|
+
subject { described_class.new(:method, [1, 2]) }
|
105
|
+
|
106
|
+
specify "#to_a" do
|
107
|
+
expect(subject.to_a).to eq([2, :method, [1, 2]])
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#received" do
|
111
|
+
it "yields itself to the block" do
|
112
|
+
expect do |block|
|
113
|
+
subject.received({}, &block)
|
114
|
+
end.to yield_with_args(subject)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/spec/neovim/plugin_spec.rb
CHANGED
@@ -5,15 +5,15 @@ module Neovim
|
|
5
5
|
RSpec.describe Plugin do
|
6
6
|
describe ".from_config_block" do
|
7
7
|
it "registers a command" do
|
8
|
-
cmd_block =
|
8
|
+
cmd_block = -> {}
|
9
9
|
|
10
10
|
plugin = Plugin.from_config_block("source") do |plug|
|
11
11
|
plug.command(
|
12
12
|
"Foo",
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
13
|
+
nargs: 1,
|
14
|
+
range: true,
|
15
|
+
bang: true,
|
16
|
+
register: true,
|
17
17
|
&cmd_block
|
18
18
|
)
|
19
19
|
end
|
@@ -26,23 +26,23 @@ module Neovim
|
|
26
26
|
expect(handler.block).to eq(cmd_block)
|
27
27
|
expect(handler.qualified_name).to eq("source:command:Foo")
|
28
28
|
expect(handler.to_spec).to eq(
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
29
|
+
type: :command,
|
30
|
+
name: "Foo",
|
31
|
+
sync: false,
|
32
|
+
opts: {
|
33
|
+
nargs: 1,
|
34
|
+
range: "",
|
35
|
+
bang: "",
|
36
|
+
register: "",
|
37
37
|
},
|
38
38
|
)
|
39
39
|
end
|
40
40
|
|
41
41
|
it "registers an autocmd" do
|
42
|
-
au_block =
|
42
|
+
au_block = -> {}
|
43
43
|
|
44
44
|
plugin = Plugin.from_config_block("source") do |plug|
|
45
|
-
plug.autocmd("BufEnter", :
|
45
|
+
plug.autocmd("BufEnter", pattern: "*.rb", &au_block)
|
46
46
|
end
|
47
47
|
|
48
48
|
expect(plugin.handlers.size).to be(1)
|
@@ -53,18 +53,18 @@ module Neovim
|
|
53
53
|
expect(handler.block).to eq(au_block)
|
54
54
|
expect(handler.qualified_name).to eq("source:autocmd:BufEnter:*.rb")
|
55
55
|
expect(handler.to_spec).to eq(
|
56
|
-
:
|
57
|
-
:
|
58
|
-
:
|
59
|
-
:
|
56
|
+
type: :autocmd,
|
57
|
+
name: "BufEnter",
|
58
|
+
sync: false,
|
59
|
+
opts: {pattern: "*.rb"},
|
60
60
|
)
|
61
61
|
end
|
62
62
|
|
63
63
|
it "registers a function" do
|
64
|
-
fun_block =
|
64
|
+
fun_block = -> {}
|
65
65
|
|
66
66
|
plugin = Plugin.from_config_block("source") do |plug|
|
67
|
-
plug.function("Foo", :
|
67
|
+
plug.function("Foo", range: true, nargs: 1, &fun_block)
|
68
68
|
end
|
69
69
|
|
70
70
|
expect(plugin.handlers.size).to be(1)
|
@@ -75,10 +75,10 @@ module Neovim
|
|
75
75
|
expect(handler.block).to eq(fun_block)
|
76
76
|
expect(handler.qualified_name).to eq("source:function:Foo")
|
77
77
|
expect(handler.to_spec).to eq(
|
78
|
-
:
|
79
|
-
:
|
80
|
-
:
|
81
|
-
:
|
78
|
+
type: :function,
|
79
|
+
name: "Foo",
|
80
|
+
sync: false,
|
81
|
+
opts: {range: "", nargs: 1},
|
82
82
|
)
|
83
83
|
end
|
84
84
|
|
@@ -101,7 +101,7 @@ module Neovim
|
|
101
101
|
end
|
102
102
|
|
103
103
|
it "registers a top level RPC" do
|
104
|
-
cmd_block =
|
104
|
+
cmd_block = -> {}
|
105
105
|
|
106
106
|
plugin = Plugin.from_config_block("source") do |plug|
|
107
107
|
plug.__send__(:rpc, "Foo", &cmd_block)
|
@@ -120,16 +120,16 @@ module Neovim
|
|
120
120
|
describe "#specs" do
|
121
121
|
it "returns specs for plugin handlers" do
|
122
122
|
plugin = Plugin.from_config_block("source") do |plug|
|
123
|
-
plug.command("Foo", :
|
123
|
+
plug.command("Foo", sync: true, nargs: 2)
|
124
124
|
end
|
125
125
|
|
126
126
|
expect(plugin.specs).to eq(
|
127
127
|
[
|
128
128
|
{
|
129
|
-
:
|
130
|
-
:
|
131
|
-
:
|
132
|
-
:
|
129
|
+
type: :command,
|
130
|
+
name: "Foo",
|
131
|
+
sync: true,
|
132
|
+
opts: {nargs: 2}
|
133
133
|
}
|
134
134
|
]
|
135
135
|
)
|