neovim 0.3.0 → 0.3.1

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.
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
@@ -1,4 +1,4 @@
1
- require "neovim/logging"
1
+ require "neovim"
2
2
  require "neovim/host/loader"
3
3
 
4
4
  module Neovim
@@ -8,14 +8,16 @@ module Neovim
8
8
 
9
9
  attr_reader :handlers, :specs
10
10
 
11
- # Initialize and populate a +Host+ from a list of plugin paths.
12
- def self.load_from_files(rplugin_paths, options={})
11
+ # Start a plugin host. This is called by the +nvim-ruby-host+ executable,
12
+ # which is spawned by +nvim+ to discover and run Ruby plugins, and acts as
13
+ # the bridge between +nvim+ and the plugin.
14
+ def self.run(rplugin_paths, options={})
13
15
  session = options.fetch(:session) { Session.stdio }
14
16
  client = options.fetch(:client) { Client.new(session) }
15
17
 
16
18
  new(session, client).tap do |host|
17
19
  Loader.new(host).load(rplugin_paths)
18
- end
20
+ end.run
19
21
  end
20
22
 
21
23
  def initialize(session, client)
@@ -1,3 +1,5 @@
1
+ require "neovim/plugin"
2
+
1
3
  module Neovim
2
4
  class Host
3
5
  # @api private
@@ -55,7 +55,7 @@ module Neovim
55
55
  LineRange.new(
56
56
  @buffer,
57
57
  abs_line(pos),
58
- abs_line(pos + len -1)
58
+ abs_line(pos + len - 1)
59
59
  )
60
60
  else
61
61
  @buffer.get_line(abs_line(pos))
@@ -2,6 +2,7 @@ require "logger"
2
2
 
3
3
  module Neovim
4
4
  # Mixed into classes for unified logging helper methods.
5
+ #
5
6
  # @api private
6
7
  module Logging
7
8
  class << self
@@ -9,22 +10,22 @@ module Neovim
9
10
  end
10
11
 
11
12
  # Return the value of @logger, or construct it from the environment.
12
- # $NVIM_RUBY_LOG_FILE specifies a file to log to (default +STDOUT+), while
13
+ # $NVIM_RUBY_LOG_FILE specifies a file to log to (default +STDERR+), while
13
14
  # NVIM_RUBY_LOG_LEVEL specifies the level (default +WARN+)
14
- def self.logger
15
+ def self.logger(env=ENV)
15
16
  return @logger if instance_variable_defined?(:@logger)
16
17
 
17
- if env_file = ENV["NVIM_RUBY_LOG_FILE"]
18
+ if env_file = env["NVIM_RUBY_LOG_FILE"]
18
19
  @logger = Logger.new(env_file)
19
20
  else
20
21
  @logger = Logger.new(STDERR)
21
22
  end
22
23
 
23
- if env_level = ENV["NVIM_RUBY_LOG_LEVEL"]
24
- if Logger.const_defined?(env_level.upcase)
25
- @logger.level = Logger.const_get(env_level.upcase)
26
- else
24
+ if env_level = env["NVIM_RUBY_LOG_LEVEL"]
25
+ begin
27
26
  @logger.level = Integer(env_level)
27
+ rescue ArgumentError
28
+ @logger.level = Logger.const_get(env_level.upcase)
28
29
  end
29
30
  else
30
31
  @logger.level = Logger::WARN
@@ -42,7 +42,7 @@ module Neovim
42
42
  # @param options [Hash] Function options.
43
43
  # @param &block [Proc, nil] The body of the function.
44
44
  #
45
- # @option options [String, Boolean] :range The range argument.
45
+ # @option options [String, Boolean] :range The range argument.
46
46
  # See +:h command-range+.
47
47
  # @option options [String] :eval An +nvim+ expression. Gets evaluated and
48
48
  # passed as an argument to the block.
@@ -9,6 +9,8 @@ module Neovim
9
9
  #
10
10
  # @api private
11
11
  module RubyProvider
12
+ @__buffer_cache = {}
13
+
12
14
  def self.__define_plugin!
13
15
  Thread.abort_on_exception = true
14
16
 
@@ -19,7 +21,7 @@ module Neovim
19
21
  end
20
22
  end
21
23
 
22
- # Evaluate the provided Ruby code, exposing the +VIM+ constant for
24
+ # Evaluate the provided Ruby code, exposing the +Vim+ constant for
23
25
  # interactions with the editor.
24
26
  #
25
27
  # This is used by the +:ruby+ command.
@@ -32,7 +34,7 @@ module Neovim
32
34
  end
33
35
  private_class_method :__define_ruby_execute
34
36
 
35
- # Evaluate the provided Ruby file, exposing the +VIM+ constant for
37
+ # Evaluate the provided Ruby file, exposing the +Vim+ constant for
36
38
  # interactions with the editor.
37
39
  #
38
40
  # This is used by the +:rubyfile+ command.
@@ -82,25 +84,20 @@ module Neovim
82
84
  private_class_method :__wrap_client
83
85
 
84
86
  def self.__with_globals(client)
85
- @__buffer_cache ||= {}
86
- @__window_cache ||= {}
87
-
88
- bufnr, winnr = client.evaluate("[bufnr('%'), winnr()]")
87
+ bufnr = client.evaluate("bufnr('%')")
89
88
 
90
89
  $curbuf = @__buffer_cache.fetch(bufnr) do
91
90
  @__buffer_cache[bufnr] = client.get_current_buffer
92
91
  end
93
92
 
94
- $curwin = @__window_cache.fetch(winnr) do
95
- @__window_cache[winnr] = client.get_current_window
96
- end
93
+ $curwin = client.get_current_window
97
94
 
98
95
  yield
99
96
  end
100
97
  private_class_method :__with_globals
101
98
 
102
99
  def self.__with_vim_constant(client)
103
- ::VIM.__client = client
100
+ ::Vim.__client = client
104
101
  yield
105
102
  end
106
103
  private_class_method :__with_vim_constant
@@ -3,15 +3,15 @@ require "neovim/ruby_provider/vim"
3
3
  module Neovim
4
4
  class Buffer
5
5
  def self.current
6
- ::VIM.get_current_buffer
6
+ ::Vim.get_current_buffer
7
7
  end
8
8
 
9
9
  def self.count
10
- ::VIM.get_buffers.size
10
+ ::Vim.get_buffers.size
11
11
  end
12
12
 
13
13
  def self.[](index)
14
- ::VIM.get_buffers[index]
14
+ ::Vim.get_buffers[index]
15
15
  end
16
16
  end
17
17
  end
@@ -1,7 +1,9 @@
1
1
  require "neovim/buffer"
2
2
  require "neovim/window"
3
3
 
4
- module VIM
4
+ # The VIM module provides backwards compatibility for the legacy +:ruby+,
5
+ # +:rubyfile+, and +:rubydo+ +vim+ functions.
6
+ module Vim
5
7
  Buffer = ::Neovim::Buffer
6
8
  Window = ::Neovim::Window
7
9
 
@@ -9,7 +11,10 @@ module VIM
9
11
  @__client = client
10
12
  end
11
13
 
14
+ # Delegate all method calls to the underlying +Neovim::Client+ object.
12
15
  def self.method_missing(method, *args, &block)
13
16
  @__client.public_send(method, *args, &block)
14
17
  end
15
18
  end
19
+
20
+ VIM = Vim
@@ -3,15 +3,15 @@ require "neovim/ruby_provider/vim"
3
3
  module Neovim
4
4
  class Window
5
5
  def self.current
6
- ::VIM.get_current_window
6
+ ::Vim.get_current_window
7
7
  end
8
8
 
9
9
  def self.count
10
- ::VIM.get_windows.size
10
+ ::Vim.get_current_tabpage.get_windows.size
11
11
  end
12
12
 
13
13
  def self.[](index)
14
- ::VIM.get_windows[index]
14
+ ::Vim.get_current_tabpage.get_windows[index]
15
15
  end
16
16
  end
17
17
  end
@@ -66,8 +66,8 @@ module Neovim
66
66
  def run
67
67
  @running = true
68
68
 
69
- while message = @pending_messages.shift
70
- Fiber.new { yield message if block_given? }.resume
69
+ while pending = @pending_messages.shift
70
+ Fiber.new { yield pending if block_given? }.resume
71
71
  end
72
72
 
73
73
  return unless @running
@@ -45,7 +45,13 @@ module Neovim
45
45
  "#<#{self.class}:0x%x @types={...} @functions={...}>" % (object_id << 1)
46
46
  end
47
47
 
48
- class Function < Struct.new(:name, :async)
48
+ class Function
49
+ attr_reader :name, :async
50
+
51
+ def initialize(name, async)
52
+ @name, @async = name, async
53
+ end
54
+
49
55
  # Apply this function to a running RPC session. Sends either a request if
50
56
  # +async+ is +false+ or a notification if +async+ is +true+.
51
57
  def call(session, *args)
@@ -9,8 +9,6 @@ module Neovim
9
9
  class EventLoop
10
10
  include Logging
11
11
 
12
- private_class_method :new
13
-
14
12
  # Connect to a TCP socket.
15
13
  def self.tcp(host, port)
16
14
  socket = TCPSocket.new(host, port)
@@ -24,8 +22,10 @@ module Neovim
24
22
  end
25
23
 
26
24
  # Spawn and connect to a child +nvim+ process.
27
- def self.child(argv)
28
- io = IO.popen(argv | ["--embed"], "rb+").tap do |_io|
25
+ def self.child(_argv)
26
+ argv = _argv.include?("--embed") ? _argv : _argv + ["--embed"]
27
+
28
+ io = IO.popen(argv, "rb+").tap do |_io|
29
29
  Process.detach(_io.pid)
30
30
  end
31
31
 
@@ -93,14 +93,6 @@ module Neovim
93
93
  io.close
94
94
  rescue IOError
95
95
  end
96
-
97
- begin
98
- if pid = io.pid
99
- Process.kill(:TERM, pid)
100
- Process.waitpid(pid)
101
- end
102
- rescue IOError, Errno::ESRCH, Errno::ECHILD
103
- end
104
96
  end
105
97
  end
106
98
  end
@@ -10,9 +10,9 @@ module Neovim
10
10
  class Serializer
11
11
  include Logging
12
12
 
13
- def initialize(event_loop)
13
+ def initialize(event_loop, unpacker=nil)
14
14
  @event_loop = event_loop
15
- @unpacker = MessagePack::Unpacker.new
15
+ @unpacker = unpacker || MessagePack::Unpacker.new
16
16
  end
17
17
 
18
18
  # Serialize an RPC message to and write it to the event loop.
@@ -6,25 +6,31 @@ module Neovim
6
6
  # The following methods are dynamically generated.
7
7
  =begin
8
8
  @method get_windows
9
+ Send the +tabpage_get_windows+ RPC to +nvim+
9
10
  @return [Array<Window>]
10
11
 
11
12
  @method get_var(name)
13
+ Send the +tabpage_get_var+ RPC to +nvim+
12
14
  @param [String] name
13
15
  @return [Object]
14
16
 
15
17
  @method set_var(name, value)
18
+ Send the +tabpage_set_var+ RPC to +nvim+
16
19
  @param [String] name
17
20
  @param [Object] value
18
21
  @return [Object]
19
22
 
20
23
  @method del_var(name)
24
+ Send the +tabpage_del_var+ RPC to +nvim+
21
25
  @param [String] name
22
26
  @return [Object]
23
27
 
24
28
  @method get_window
29
+ Send the +tabpage_get_window+ RPC to +nvim+
25
30
  @return [Window]
26
31
 
27
32
  @method is_valid
33
+ Send the +tabpage_is_valid+ RPC to +nvim+
28
34
  @return [Boolean]
29
35
 
30
36
  =end
@@ -1,3 +1,3 @@
1
1
  module Neovim
2
- VERSION = Gem::Version.new("0.3.0")
2
+ VERSION = Gem::Version.new("0.3.1")
3
3
  end
@@ -53,64 +53,82 @@ module Neovim
53
53
  # @param coords [Array(Fixnum, Fixnum)]
54
54
  # @return [Array(Fixnum, Fixnum)]
55
55
  def cursor=(coords)
56
- set_cursor(coords)
56
+ _x, _y = coords
57
+ x = [_x, 1].max
58
+ y = [_y, 0].max + 1
59
+ @session.request(:vim_eval, "cursor(#{x}, #{y})")
57
60
  end
58
61
 
59
62
  # The following methods are dynamically generated.
60
63
  =begin
61
64
  @method get_buffer
65
+ Send the +window_get_buffer+ RPC to +nvim+
62
66
  @return [Buffer]
63
67
 
64
68
  @method get_cursor
69
+ Send the +window_get_cursor+ RPC to +nvim+
65
70
  @return [Array<Fixnum>]
66
71
 
67
72
  @method set_cursor(pos)
73
+ Send the +window_set_cursor+ RPC to +nvim+
68
74
  @param [Array<Fixnum>] pos
69
75
  @return [void]
70
76
 
71
77
  @method get_height
78
+ Send the +window_get_height+ RPC to +nvim+
72
79
  @return [Fixnum]
73
80
 
74
81
  @method set_height(height)
82
+ Send the +window_set_height+ RPC to +nvim+
75
83
  @param [Fixnum] height
76
84
  @return [void]
77
85
 
78
86
  @method get_width
87
+ Send the +window_get_width+ RPC to +nvim+
79
88
  @return [Fixnum]
80
89
 
81
90
  @method set_width(width)
91
+ Send the +window_set_width+ RPC to +nvim+
82
92
  @param [Fixnum] width
83
93
  @return [void]
84
94
 
85
95
  @method get_var(name)
96
+ Send the +window_get_var+ RPC to +nvim+
86
97
  @param [String] name
87
98
  @return [Object]
88
99
 
89
100
  @method set_var(name, value)
101
+ Send the +window_set_var+ RPC to +nvim+
90
102
  @param [String] name
91
103
  @param [Object] value
92
104
  @return [Object]
93
105
 
94
106
  @method del_var(name)
107
+ Send the +window_del_var+ RPC to +nvim+
95
108
  @param [String] name
96
109
  @return [Object]
97
110
 
98
111
  @method get_option(name)
112
+ Send the +window_get_option+ RPC to +nvim+
99
113
  @param [String] name
100
114
  @return [Object]
101
115
 
102
116
  @method set_option(name, value)
117
+ Send the +window_set_option+ RPC to +nvim+
103
118
  @param [String] name
104
119
  @param [Object] value
105
120
  @return [void]
106
121
 
107
122
  @method get_position
123
+ Send the +window_get_position+ RPC to +nvim+
108
124
  @return [Array<Fixnum>]
109
125
 
110
126
  @method get_tabpage
127
+ Send the +window_get_tabpage+ RPC to +nvim+
111
128
  @return [Tabpage]
112
129
 
113
130
  @method is_valid
131
+ Send the +window_is_valid+ RPC to +nvim+
114
132
  @return [Boolean]
115
133
 
116
134
  =end
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path("../../lib", __FILE__)
4
+
5
+ require "neovim"
6
+ require "pathname"
7
+
8
+ vim_docs = []
9
+ buffer_docs = []
10
+ window_docs = []
11
+ tabpage_docs = []
12
+ session = Neovim::Session.child(%w(nvim -u NONE -n))
13
+ vim_defs = Neovim::Client.instance_methods(false)
14
+ buffer_defs = Neovim::Buffer.instance_methods(false)
15
+ tabpage_defs = Neovim::Tabpage.instance_methods(false)
16
+ window_defs = Neovim::Window.instance_methods(false)
17
+
18
+ session.request(:vim_get_api_info)[1]["functions"].each do |func|
19
+ prefix, method_name = func["name"].split("_", 2)
20
+
21
+ case prefix
22
+ when "vim"
23
+ next if vim_defs.include?(method_name.to_sym)
24
+ when "buffer"
25
+ next if buffer_defs.include?(method_name.to_sym)
26
+ when "tabpage"
27
+ next if tabpage_defs.include?(method_name.to_sym)
28
+ when "window"
29
+ next if window_defs.include?(method_name.to_sym)
30
+ end
31
+
32
+ return_type = func["return_type"]
33
+ params = func["parameters"]
34
+ params.shift unless prefix == "vim"
35
+ param_names = params.map(&:last)
36
+ param_str = params.empty? ? "" : "(#{param_names.join(", ")})"
37
+ method_decl = "@method #{method_name}#{param_str}"
38
+ method_desc = " Send the +#{prefix}_#{method_name}+ RPC to +nvim+"
39
+ param_docs = params.map do |type, name|
40
+ " @param [#{type}] #{name}"
41
+ end
42
+ return_doc = " @return [#{return_type}]\n"
43
+ method_doc = [method_decl, method_desc, *param_docs, return_doc].join("\n")
44
+ method_doc.gsub!(/ArrayOf\((\w+)[^)]*\)/, 'Array<\1>')
45
+ method_doc.gsub!(/Integer/, "Fixnum")
46
+
47
+ case prefix
48
+ when "vim"
49
+ vim_docs << method_doc
50
+ when "buffer"
51
+ buffer_docs << method_doc
52
+ when "tabpage"
53
+ tabpage_docs << method_doc
54
+ when "window"
55
+ window_docs << method_doc
56
+ end
57
+ end
58
+
59
+ lib_dir = Pathname.new(File.expand_path("../../lib/neovim", __FILE__))
60
+ {
61
+ "client.rb" => vim_docs,
62
+ "buffer.rb" => buffer_docs,
63
+ "tabpage.rb" => tabpage_docs,
64
+ "window.rb" => window_docs,
65
+ }.each do |filename, docs|
66
+ path = lib_dir.join(filename)
67
+ contents = File.read(path)
68
+ doc_str = ["=begin", *docs, "=end"].join("\n")
69
+
70
+ File.write(path, contents.sub(/=begin.+=end/m, doc_str))
71
+ end