neovim 0.0.6 → 0.1.0

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -19
  3. data/CHANGELOG.md +9 -0
  4. data/README.md +2 -2
  5. data/Rakefile +1 -25
  6. data/bin/j2mp +1 -1
  7. data/bin/mp2j +1 -1
  8. data/bin/neovim-ruby-host +9 -0
  9. data/lib/neovim.rb +5 -7
  10. data/lib/neovim/async_session.rb +2 -1
  11. data/lib/neovim/buffer.rb +112 -0
  12. data/lib/neovim/client.rb +4 -2
  13. data/lib/neovim/current.rb +9 -1
  14. data/lib/neovim/event_loop.rb +8 -4
  15. data/lib/neovim/host.rb +3 -1
  16. data/lib/neovim/line_range.rb +34 -10
  17. data/lib/neovim/logging.rb +29 -20
  18. data/lib/neovim/manifest.rb +9 -3
  19. data/lib/neovim/plugin.rb +3 -1
  20. data/lib/neovim/plugin/dsl.rb +14 -0
  21. data/lib/neovim/plugin/handler.rb +24 -5
  22. data/lib/neovim/ruby_provider.rb +138 -0
  23. data/lib/neovim/session.rb +14 -5
  24. data/lib/neovim/version.rb +1 -1
  25. data/lib/neovim/window.rb +52 -59
  26. data/spec/acceptance/neovim-ruby-host_spec.rb +6 -1
  27. data/spec/acceptance/ruby_provider_spec.rb +76 -0
  28. data/spec/helper.rb +13 -19
  29. data/spec/neovim/async_session_spec.rb +19 -15
  30. data/spec/neovim/buffer_spec.rb +127 -1
  31. data/spec/neovim/client_spec.rb +1 -1
  32. data/spec/neovim/current_spec.rb +9 -1
  33. data/spec/neovim/event_loop_spec.rb +20 -21
  34. data/spec/neovim/host_spec.rb +1 -1
  35. data/spec/neovim/line_range_spec.rb +73 -9
  36. data/spec/neovim/manifest_spec.rb +26 -0
  37. data/spec/neovim/msgpack_stream_spec.rb +8 -8
  38. data/spec/neovim/plugin_spec.rb +41 -0
  39. data/spec/neovim/remote_object_spec.rb +3 -3
  40. data/spec/neovim/session_spec.rb +68 -29
  41. data/spec/neovim/window_spec.rb +47 -24
  42. data/spec/neovim_spec.rb +3 -5
  43. data/spec/support.rb +1 -2
  44. metadata +5 -3
  45. data/.gitmodules +0 -4
@@ -1,5 +1,4 @@
1
1
  require "logger"
2
- require "stringio"
3
2
 
4
3
  module Neovim
5
4
  # Mixed into classes for unified logging helper methods.
@@ -14,14 +13,18 @@ module Neovim
14
13
  def self.logger
15
14
  return @logger if instance_variable_defined?(:@logger)
16
15
 
17
- if ENV["NVIM_RUBY_LOG_FILE"]
18
- @logger = Logger.new(ENV["NVIM_RUBY_LOG_FILE"])
16
+ if env_file = ENV["NVIM_RUBY_LOG_FILE"]
17
+ @logger = Logger.new(env_file)
19
18
  else
20
19
  @logger = Logger.new(STDERR)
21
20
  end
22
21
 
23
- if ENV["NVIM_RUBY_LOG_LEVEL"]
24
- @logger.level = Integer(ENV["NVIM_RUBY_LOG_LEVEL"])
22
+ if env_level = ENV["NVIM_RUBY_LOG_LEVEL"]
23
+ if Logger.const_defined?(env_level.upcase)
24
+ @logger.level = Logger.const_get(env_level.upcase)
25
+ else
26
+ @logger.level = Integer(env_level)
27
+ end
25
28
  else
26
29
  @logger.level = Logger::WARN
27
30
  end
@@ -29,26 +32,32 @@ module Neovim
29
32
  @logger
30
33
  end
31
34
 
32
- private
33
-
34
- def fatal(msg)
35
- logger.fatal(self.class) { msg }
35
+ def self.included(base)
36
+ base.send(:include, Helpers)
36
37
  end
37
38
 
38
- def warn(msg)
39
- logger.warn(self.class) { msg }
40
- end
39
+ module Helpers
40
+ private
41
41
 
42
- def info(msg)
43
- logger.info(self.class) { msg }
44
- end
42
+ def fatal(msg)
43
+ logger.fatal(self.class) { msg }
44
+ end
45
45
 
46
- def debug(msg)
47
- logger.debug(self.class) { msg }
48
- end
46
+ def warn(msg)
47
+ logger.warn(self.class) { msg }
48
+ end
49
49
 
50
- def logger
51
- Logging.logger
50
+ def info(msg)
51
+ logger.info(self.class) { msg }
52
+ end
53
+
54
+ def debug(msg)
55
+ logger.debug(self.class) { msg }
56
+ end
57
+
58
+ def logger
59
+ Logging.logger
60
+ end
52
61
  end
53
62
  end
54
63
  end
@@ -68,15 +68,21 @@ module Neovim
68
68
 
69
69
  def wrap_sync(handler)
70
70
  Proc.new do |client, request|
71
- debug("received #{request.inspect}")
72
- request.respond(handler.call(client, *request.arguments[0]))
71
+ begin
72
+ debug("received #{request.inspect}")
73
+ args = request.arguments.flatten(1)
74
+ request.respond(handler.call(client, *args))
75
+ rescue => e
76
+ request.error(e.message)
77
+ end
73
78
  end
74
79
  end
75
80
 
76
81
  def wrap_async(handler)
77
82
  Proc.new do |client, notification|
78
83
  debug("received #{notification.inspect}")
79
- handler.call(client, *notification.arguments[0])
84
+ args = notification.arguments.flatten(1)
85
+ handler.call(client, *args)
80
86
  end
81
87
  end
82
88
  end
@@ -22,7 +22,9 @@ module Neovim
22
22
 
23
23
  # @return [Array] Handler specs used by +nvim+ to register plugins.
24
24
  def specs
25
- @handlers.map(&:to_spec)
25
+ @handlers.inject([]) do |acc, handler|
26
+ handler.qualified? ? acc + [handler.to_spec] : acc
27
+ end
26
28
  end
27
29
  end
28
30
  end
@@ -52,6 +52,20 @@ module Neovim
52
52
  register_handler(:autocmd, event, options, block)
53
53
  end
54
54
 
55
+ # Register a top-level remote procedure call (RPC).
56
+ #
57
+ # This can be used to directly expose an RPC call without a namespace.
58
+ # This is used primarily for exposing legacy ruby provider calls.
59
+ #
60
+ # @option options [Boolean] :sync (false)
61
+ def rpc(name, options={}, &block)
62
+ sync = options.delete(:sync)
63
+
64
+ @plugin.handlers.push(
65
+ Handler.unqualified(name, sync, options, block)
66
+ )
67
+ end
68
+
55
69
  private
56
70
 
57
71
  def register_handler(type, name, _options, block)
@@ -4,16 +4,39 @@ module Neovim
4
4
  class Handler
5
5
  attr_reader :block
6
6
 
7
+ def self.unqualified(name, sync, options, block)
8
+ new(
9
+ nil,
10
+ nil,
11
+ name,
12
+ sync,
13
+ options.merge(:qualified => false),
14
+ block
15
+ )
16
+ end
17
+
7
18
  def initialize(source, type, name, sync, options, block)
8
19
  @source = source
9
- @type = type.to_sym
20
+ @type = type.to_sym if type.respond_to?(:to_sym)
10
21
  @name = name.to_s
11
22
  @sync = !!sync
12
23
  @options = options
13
24
  @block = block || Proc.new {}
25
+ @qualified =
26
+ options.key?(:qualified) ? options.delete(:qualified) : true
27
+ end
28
+
29
+ def sync?
30
+ @sync
31
+ end
32
+
33
+ def qualified?
34
+ @qualified
14
35
  end
15
36
 
16
37
  def qualified_name
38
+ return @name unless qualified?
39
+
17
40
  if @type == :autocmd
18
41
  pattern = @options.fetch(:pattern, "*")
19
42
  "#{@source}:#{@type}:#{@name}:#{pattern}"
@@ -22,10 +45,6 @@ module Neovim
22
45
  end
23
46
  end
24
47
 
25
- def sync?
26
- @sync
27
- end
28
-
29
48
  def to_spec
30
49
  {
31
50
  :type => @type,
@@ -0,0 +1,138 @@
1
+ class VIM < BasicObject
2
+ class << self
3
+ attr_accessor :__client
4
+ end
5
+
6
+ Buffer = ::Neovim::Buffer
7
+ Window = ::Neovim::Window
8
+
9
+ def self.method_missing(method, *args, &block)
10
+ @__client.public_send(method, *args, &block)
11
+ end
12
+ end
13
+
14
+ module Neovim
15
+ # Make +VIM::Buffer.current+ return the current buffer.
16
+ class Buffer
17
+ def self.current
18
+ ::VIM.current.buffer
19
+ end
20
+ end
21
+
22
+ # Make +VIM::Window.current+ return the current buffer.
23
+ class Window
24
+ def self.current
25
+ ::VIM.current.window
26
+ end
27
+ end
28
+
29
+ module RubyProvider
30
+ def self.define_plugin!
31
+ Neovim.plugin do |plug|
32
+ define_ruby_execute(plug)
33
+ define_ruby_execute_file(plug)
34
+ define_ruby_do_range(plug)
35
+ end
36
+ end
37
+
38
+ def self.define_ruby_execute(plug)
39
+ plug.rpc(:ruby_execute, sync: true) do |nvim, ruby|
40
+ wrap_client(nvim) do
41
+ eval(ruby, binding, __FILE__, __LINE__)
42
+ end
43
+ end
44
+ end
45
+ private_class_method :define_ruby_execute
46
+
47
+ def self.define_ruby_execute_file(plug)
48
+ plug.rpc(:ruby_execute_file, sync: true) do |nvim, path|
49
+ wrap_client(nvim) do
50
+ eval(File.read(path), binding, __FILE__, __LINE__)
51
+ end
52
+ end
53
+ end
54
+ private_class_method :define_ruby_execute_file
55
+
56
+ def self.define_ruby_do_range(plug)
57
+ plug.rpc(:ruby_do_range, sync: true) do |nvim, *args|
58
+ begin
59
+ start, stop, ruby = args
60
+ buffer = nvim.current.buffer
61
+
62
+ (start..stop).each_slice(5000) do |linenos|
63
+ _start, _stop = linenos[0]-1, linenos[-1]
64
+ lines = buffer.get_lines(_start, _stop, true)
65
+
66
+ lines.map! do |line|
67
+ $_ = line
68
+ eval(ruby, binding, __FILE__, __LINE__)
69
+ String($_)
70
+ end
71
+
72
+ buffer.set_lines(_start, _stop, true, lines)
73
+ end
74
+ ensure
75
+ $_ = nil
76
+ end
77
+ end
78
+ end
79
+ private_class_method :define_ruby_do_range
80
+
81
+ def self.wrap_client(client)
82
+ with_globals(client) do
83
+ with_vim_constant(client) do
84
+ with_redirect_streams(client) do
85
+ yield
86
+ end
87
+ end
88
+ end
89
+ end
90
+ private_class_method :wrap_client
91
+
92
+ def self.with_globals(client)
93
+ $curwin = client.current.window
94
+ $curbuf = client.current.buffer
95
+
96
+ begin
97
+ yield
98
+ ensure
99
+ $curwin = $curbuf = nil
100
+ end
101
+ end
102
+ private_class_method :with_globals
103
+
104
+ def self.with_vim_constant(client)
105
+ ::VIM.__client = client
106
+
107
+ begin
108
+ yield
109
+ ensure
110
+ ::VIM.__client = nil
111
+ end
112
+ end
113
+ private_class_method :with_vim_constant
114
+
115
+ def self.with_redirect_streams(client)
116
+ old_out_write = $stdout.method(:write)
117
+ old_err_write = $stderr.method(:write)
118
+
119
+ $stdout.define_singleton_method(:write) do |string|
120
+ client.out_write(string)
121
+ end
122
+
123
+ $stderr.define_singleton_method(:write) do |string|
124
+ client.err_write(string)
125
+ end
126
+
127
+ begin
128
+ yield
129
+ ensure
130
+ $stdout.define_singleton_method(:write, &old_out_write)
131
+ $stderr.define_singleton_method(:write, &old_err_write)
132
+ end
133
+ end
134
+ private_class_method :with_redirect_streams
135
+ end
136
+ end
137
+
138
+ Neovim::RubyProvider.define_plugin!
@@ -1,4 +1,7 @@
1
1
  require "neovim/api"
2
+ require "neovim/async_session"
3
+ require "neovim/event_loop"
4
+ require "neovim/msgpack_stream"
2
5
  require "fiber"
3
6
 
4
7
  module Neovim
@@ -66,11 +69,10 @@ module Neovim
66
69
 
67
70
  # Discover the +nvim+ API as described in the +vim_get_api_info+ call.
68
71
  #
69
- # @return [self]
72
+ # @return [API]
70
73
  # @see API
71
74
  def discover_api
72
75
  @api = API.new(request(:vim_get_api_info))
73
- self
74
76
  end
75
77
 
76
78
  # Run the event loop, handling messages in a +Fiber+.
@@ -121,7 +123,7 @@ module Neovim
121
123
  err ? raise(ArgumentError, err) : res
122
124
  end
123
125
 
124
- # Make an RPC notification
126
+ # Make an RPC notification.
125
127
  #
126
128
  # @param method [String, Symbol] The RPC method name
127
129
  # @param *args [Array] The RPC method arguments
@@ -131,7 +133,7 @@ module Neovim
131
133
  nil
132
134
  end
133
135
 
134
- # Stop the event loop
136
+ # Stop the event loop.
135
137
  #
136
138
  # @return [void]
137
139
  # @see EventLoop#stop
@@ -140,7 +142,7 @@ module Neovim
140
142
  @async_session.stop
141
143
  end
142
144
 
143
- # Shut down the event loop
145
+ # Shut down the event loop.
144
146
  #
145
147
  # @return [void]
146
148
  # @see EventLoop#shutdown
@@ -149,6 +151,13 @@ module Neovim
149
151
  @async_session.shutdown
150
152
  end
151
153
 
154
+ # Return the channel ID if registered via +vim_get_api_info+.
155
+ #
156
+ # @return [Fixnum, nil]
157
+ def channel_id
158
+ api.channel_id
159
+ end
160
+
152
161
  private
153
162
 
154
163
  def in_handler_fiber(&block)
@@ -1,3 +1,3 @@
1
1
  module Neovim
2
- VERSION = Gem::Version.new("0.0.6")
2
+ VERSION = Gem::Version.new("0.1.0")
3
3
  end
@@ -10,65 +10,58 @@ module Neovim
10
10
  @cursor ||= Cursor.new(self)
11
11
  end
12
12
 
13
- class Cursor
14
- def initialize(window)
15
- @window = window
16
- end
17
-
18
- # Get the current coordinates of the cursor.
19
- #
20
- # @return [Array<Fixnum>]
21
- # @note coordinates are 1-indexed
22
- def coordinates
23
- @window.get_cursor
24
- end
25
-
26
- # Set the coordinates of the cursor.
27
- #
28
- # @param coords [Array<Fixnum>] The coordinates as a pair of integers
29
- # @return [Array<Fixnum>]
30
- # @note coordinates are 1-indexed
31
- # @example Move the cursor to line 1, column 2
32
- # window.cursor.coordinates = [1, 2]
33
- def coordinates=(coords)
34
- @window.set_cursor(coords)
35
- end
36
-
37
- # Get the cursor's line number.
38
- #
39
- # @return [Fixnum]
40
- # @note Line numbers are 1-indexed
41
- def line
42
- coordinates[0]
43
- end
44
-
45
- # Set the cursor's line number.
46
- #
47
- # @param n [Fixnum]
48
- # @return [Fixnum]
49
- # @note Line numbers are 1-indexed
50
- def line=(n)
51
- self.coordinates = [n, column]
52
- n
53
- end
54
-
55
- # Get the cursor's column number.
56
- #
57
- # @return [Fixnum]
58
- # @note Column numbers are 1-indexed
59
- def column
60
- coordinates[1]
61
- end
62
-
63
- # Set the cursor's column number.
64
- #
65
- # @param n [Fixnum]
66
- # @return [Fixnum]
67
- # @note Column numbers are 1-indexed
68
- def column=(n)
69
- self.coordinates = [line, n]
70
- n
71
- end
13
+ # Get the buffer displayed in the window
14
+ #
15
+ # @return [Buffer]
16
+ def buffer
17
+ get_buffer
18
+ end
19
+
20
+ # Get the height of the window
21
+ #
22
+ # @return [Fixnum]
23
+ def height
24
+ get_height
25
+ end
26
+
27
+ # Set the height of the window
28
+ #
29
+ # @param height [Fixnum]
30
+ # @return [Fixnum]
31
+ def height=(height)
32
+ set_height(height)
33
+ height
34
+ end
35
+
36
+ # Get the width of the window
37
+ #
38
+ # @return [Fixnum]
39
+ def width
40
+ get_width
41
+ end
42
+
43
+ # Set the width of the window
44
+ #
45
+ # @param width [Fixnum]
46
+ # @return [Fixnum]
47
+ def width=(width)
48
+ set_width(width)
49
+ width
50
+ end
51
+
52
+ # Get the cursor coordinates
53
+ #
54
+ # @return [Array(Fixnum, Fixnum)]
55
+ def cursor
56
+ get_cursor
57
+ end
58
+
59
+ # Set the cursor coodinates
60
+ #
61
+ # @param coords [Array(Fixnum, Fixnum)]
62
+ # @return [Array(Fixnum, Fixnum)]
63
+ def cursor=(coords)
64
+ set_cursor(coords)
72
65
  end
73
66
 
74
67
  # The following methods are dynamically generated.