neovim 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,44 @@
1
+ require "msgpack"
2
+
3
+ module Neovim
4
+ class MsgpackStream
5
+ def initialize(event_loop)
6
+ @event_loop = event_loop
7
+ @unpacker = MessagePack::Unpacker.new
8
+ end
9
+
10
+ def register_session(session)
11
+ session.api_info.types.each do |type, info|
12
+ klass = Neovim.const_get(type)
13
+ id = info.fetch("id")
14
+
15
+ @unpacker.register_type(id) do |data|
16
+ klass.new(MessagePack.unpack(data), session)
17
+ end
18
+ end
19
+ end
20
+
21
+ def send(msg)
22
+ @event_loop.send(MessagePack.pack(msg))
23
+ self
24
+ end
25
+
26
+ def run(&message_cb)
27
+ @event_loop.run do |data|
28
+ @unpacker.feed_each(data) do |msg|
29
+ message_cb.call(msg)
30
+ end
31
+ end
32
+ end
33
+
34
+ def stop
35
+ @event_loop.stop
36
+ self
37
+ end
38
+
39
+ def shutdown
40
+ @event_loop.shutdown
41
+ self
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ module Neovim
2
+ class Object
3
+ attr_reader :index
4
+
5
+ def initialize(index, session)
6
+ @index = index
7
+ @session = session
8
+ end
9
+
10
+ def respond_to?(method_name)
11
+ super || methods.include?(method_name.to_sym)
12
+ end
13
+
14
+ def method_missing(method_name, *args)
15
+ if methods.include?(method_name)
16
+ @session.request(qualify(method_name), @index, *args)
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ def to_msgpack(packer)
23
+ packer.pack(@index)
24
+ end
25
+
26
+ def methods
27
+ super | @session.api_methods_for_prefix(function_prefix)
28
+ end
29
+
30
+ private
31
+
32
+ def function_prefix
33
+ "#{self.class.to_s.split("::").last.downcase}_"
34
+ end
35
+
36
+ def qualify(method_name)
37
+ :"#{function_prefix}#{method_name}"
38
+ end
39
+ end
40
+
41
+ Buffer = Class.new(Object)
42
+ Tabpage = Class.new(Object)
43
+ Window = Class.new(Object)
44
+ end
@@ -0,0 +1,35 @@
1
+ require "neovim/api_info"
2
+
3
+ module Neovim
4
+ class Session
5
+ attr_reader :api_info
6
+
7
+ def initialize(async_session)
8
+ @async_session = async_session
9
+
10
+ @api_info = APIInfo.new(request(:vim_get_api_info))
11
+ @async_session.register_session(self)
12
+ end
13
+
14
+ def request(method, *args)
15
+ err = res = nil
16
+
17
+ @async_session.request(method, *args) do |error, response|
18
+ err, res = error, response
19
+ @async_session.stop
20
+ end.run
21
+
22
+ err ? raise(ArgumentError, err) : res
23
+ end
24
+
25
+ def api_methods_for_prefix(prefix)
26
+ @api_info.functions.inject([]) do |acc, function|
27
+ if function["name"] =~ /\A#{prefix}/
28
+ acc + [function["name"].sub(/\A#{prefix}/, "").to_sym]
29
+ else
30
+ acc
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ module Neovim
2
+ VERSION = Gem::Version.new("0.0.1")
3
+ end
data/neovim.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "neovim/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "neovim"
8
+ spec.version = Neovim::VERSION
9
+ spec.authors = ["Alex Genco"]
10
+ spec.email = ["alexgenco@gmail.com"]
11
+ spec.summary = %q{A Ruby client for Neovim}
12
+ spec.homepage = "https://github.com/alexgenco/neovim-ruby"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^spec/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "msgpack", "0.7.0dev1"
21
+ spec.add_dependency "eventmachine", "~> 1.0"
22
+
23
+ spec.add_development_dependency "bundler"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ spec.add_development_dependency "coveralls", "~> 0.7.2"
27
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,26 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require "neovim"
4
+ require "timeout"
5
+
6
+ if ENV["REPORT_COVERAGE"]
7
+ require "coveralls"
8
+ Coveralls.wear!
9
+ end
10
+
11
+ ENV["NVIM_EXECUTABLE"] = File.expand_path("../../vendor/neovim/build/bin/nvim", __FILE__)
12
+
13
+ RSpec.configure do |config|
14
+ config.expect_with :rspec do |exp|
15
+ exp.syntax = :expect
16
+ end
17
+
18
+ config.disable_monkey_patching!
19
+ config.order = :random
20
+
21
+ Kernel.srand config.seed
22
+
23
+ config.around do |spec|
24
+ Timeout.timeout(1) { spec.run }
25
+ end
26
+ end
@@ -0,0 +1,96 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ RSpec.describe AsyncSession do
5
+ it "receives requests" do
6
+ server = TCPServer.new("0.0.0.0", 0)
7
+ event_loop = EventLoop.tcp("0.0.0.0", server.addr[1])
8
+ stream = MsgpackStream.new(event_loop)
9
+ async = AsyncSession.new(stream)
10
+ messages = []
11
+
12
+ srv_thr = Thread.new do
13
+ client = server.accept
14
+ client.write(MessagePack.pack(
15
+ [0, 123, "func", [1, 2, 3]]
16
+ ))
17
+
18
+ client.close
19
+ server.close
20
+ end
21
+
22
+ req_cb = Proc.new do |*payload|
23
+ messages << payload
24
+ async.shutdown
25
+ end
26
+
27
+ async.run(req_cb)
28
+ srv_thr.join
29
+
30
+ expect(messages.first.size).to eq(3)
31
+ expect(messages.first[0..1]).to eq(["func", [1, 2, 3]])
32
+ expect(messages.first[2]).to be_a(AsyncSession::Responder)
33
+ end
34
+
35
+ it "receives notifications" do
36
+ server = TCPServer.new("0.0.0.0", 0)
37
+ event_loop = EventLoop.tcp("0.0.0.0", server.addr[1])
38
+ stream = MsgpackStream.new(event_loop)
39
+ async = AsyncSession.new(stream)
40
+ messages = []
41
+
42
+ srv_thr = Thread.new do
43
+ client = server.accept
44
+ client.write(MessagePack.pack(
45
+ [2, "func", [1, 2, 3]]
46
+ ))
47
+
48
+ client.close
49
+ server.close
50
+ end
51
+
52
+ not_cb = Proc.new do |*payload|
53
+ messages << payload
54
+ async.shutdown
55
+ end
56
+
57
+ async.run(nil, not_cb)
58
+ srv_thr.join
59
+
60
+ expect(messages).to eq([["func", [1, 2, 3]]])
61
+ end
62
+
63
+ it "receives responses to requests" do
64
+ server = TCPServer.new("0.0.0.0", 0)
65
+ event_loop = EventLoop.tcp("0.0.0.0", server.addr[1])
66
+ stream = MsgpackStream.new(event_loop)
67
+ async = AsyncSession.new(stream)
68
+ messages = []
69
+
70
+ srv_thr = Thread.new do
71
+ client = server.accept
72
+ messages << client.read_nonblock(1024)
73
+
74
+ client.write(MessagePack.pack(
75
+ [1, 0, [0, "error"], "result"]
76
+ ))
77
+
78
+ client.close
79
+ server.close
80
+ end
81
+
82
+ async.request("func", 1, 2, 3) do |error, result|
83
+ expect(error).to eq("error")
84
+ expect(result).to eq("result")
85
+ async.shutdown
86
+ end
87
+
88
+ async.run
89
+ srv_thr.join
90
+
91
+ expect(messages).to eq(
92
+ [MessagePack.pack([0, 0, "func", [1, 2, 3]])]
93
+ )
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,37 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ RSpec.describe Buffer do
5
+ let(:buffer) { Neovim.attach_child(["-n", "-u", "NONE"]).current.buffer }
6
+
7
+ describe "#respond_to?" do
8
+ it "returns true for Buffer functions" do
9
+ expect(buffer).to respond_to(:line_count)
10
+ end
11
+
12
+ it "returns true for Ruby functions" do
13
+ expect(buffer).to respond_to(:inspect)
14
+ end
15
+
16
+ it "returns false otherwise" do
17
+ expect(buffer).not_to respond_to(:foobar)
18
+ end
19
+ end
20
+
21
+ describe "#method_missing" do
22
+ it "enables buffer_* function calls" do
23
+ expect(buffer.line_count).to be(1)
24
+ end
25
+ end
26
+
27
+ describe "#methods" do
28
+ it "returns builtin methods" do
29
+ expect(buffer.methods).to include(:inspect)
30
+ end
31
+
32
+ it "returns api methods" do
33
+ expect(buffer.methods).to include(:get_mark)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,57 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ RSpec.describe Client do
5
+ let(:client) { Neovim.attach_child(["-n", "-u", "NONE"]) }
6
+
7
+ describe "#respond_to?" do
8
+ it "returns true for vim functions" do
9
+ expect(client).to respond_to(:strwidth)
10
+ end
11
+
12
+ it "returns true for Ruby functions" do
13
+ expect(client).to respond_to(:inspect)
14
+ end
15
+
16
+ it "returns false otherwise" do
17
+ expect(client).not_to respond_to(:foobar)
18
+ end
19
+ end
20
+
21
+ describe "#method_missing" do
22
+ it "enables vim_* function calls" do
23
+ expect(client.strwidth("hi")).to eq(2)
24
+ end
25
+
26
+ it "raises exceptions for unknown methods" do
27
+ expect {
28
+ client.foobar
29
+ }.to raise_error(NoMethodError)
30
+ end
31
+
32
+ it "raises exceptions for incorrect usage" do
33
+ expect {
34
+ client.strwidth("too", "many")
35
+ }.to raise_error("Wrong number of arguments: expecting 1 but got 2")
36
+ end
37
+ end
38
+
39
+ describe "#methods" do
40
+ it "includes builtin methods" do
41
+ expect(client.methods).to include(:inspect)
42
+ end
43
+
44
+ it "includes api methods" do
45
+ expect(client.methods).to include(:strwidth)
46
+ end
47
+ end
48
+
49
+ describe "#current" do
50
+ it "returns the target" do
51
+ expect(client.current.buffer).to be_a(Buffer)
52
+ expect(client.current.window).to be_a(Window)
53
+ expect(client.current.tabpage).to be_a(Tabpage)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,78 @@
1
+ require "helper"
2
+
3
+ module Neovim
4
+ RSpec.describe Current do
5
+ let(:client) { Neovim.attach_child(["-n", "-u", "NONE"]) }
6
+ let(:current) { client.current }
7
+
8
+ describe "#line" do
9
+ it "returns an empty string if the current line is empty" do
10
+ expect(current.line).to eq("")
11
+ end
12
+
13
+ it "returns the contents of the line" do
14
+ current.line = "New content"
15
+ expect(current.line).to eq("New content")
16
+ end
17
+ end
18
+
19
+ describe "#line=" do
20
+ it "sets the content of the current line" do
21
+ current.line = "New content"
22
+ expect(current.line).to eq("New content")
23
+ end
24
+ end
25
+
26
+ describe "#buffer" do
27
+ it "returns the current buffer" do
28
+ expect(current.buffer).to be_a(Buffer)
29
+ end
30
+ end
31
+
32
+ describe "#buffer=" do
33
+ it "sets the current buffer" do
34
+ initial_index = current.buffer.index
35
+ client.command("vnew")
36
+
37
+ expect {
38
+ current.buffer = initial_index
39
+ }.to change { current.buffer.index }
40
+ end
41
+ end
42
+
43
+ describe "#window" do
44
+ it "returns the current window" do
45
+ expect(current.window).to be_a(Window)
46
+ end
47
+ end
48
+
49
+ describe "#window=" do
50
+ it "sets the current window" do
51
+ client.command("vsp")
52
+ expect(current.window.index).not_to eq(1)
53
+
54
+ expect {
55
+ current.window = 1
56
+ }.to change { current.window.index }.to(1)
57
+ end
58
+ end
59
+
60
+ describe "#tabpage" do
61
+ it "returns the current tabpage" do
62
+ expect(current.tabpage).to be_a(Tabpage)
63
+ end
64
+ end
65
+
66
+ describe "#tabpage=" do
67
+ it "sets the current tabpage" do
68
+ initial_index = current.tabpage.index
69
+ client.command("tabnew")
70
+ expect(current.tabpage.index).not_to eq(initial_index)
71
+
72
+ expect {
73
+ current.tabpage = initial_index
74
+ }.to change { current.tabpage.index }.to(initial_index)
75
+ end
76
+ end
77
+ end
78
+ end