neovim 0.2.2 → 0.2.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: af56f57f1cf54f8adc5229739e6bc59970b993c2
4
- data.tar.gz: d9c97e2f4086a239d18cad60b0e0143df4a5b476
3
+ metadata.gz: f815ff4bec0348ba8b77aa4f9b04197e8a521655
4
+ data.tar.gz: 149067ce655eb2b13102f9d68b0ef635668a3578
5
5
  SHA512:
6
- metadata.gz: a209db461c6fd40c4b43cf2dc71b0a156e2dd563d6ca3644b383cfd3a625ab6e8302de6f60e1bab216a9efd93db9ad22479687764f41346f806526356034d390
7
- data.tar.gz: ea4a5ff5be12e6d6e9bf57c454d5cc8fe7d198bcb80329d2a62cad7a2202987a25575c542f51dbe3e501e5cc6a74ea9dcc5719678de4669d193262ad0a0c8b9a
6
+ metadata.gz: a0b76436db1b7523be49ecfb8be84785f3420a0eeeea294b38f6173b94136a5d60cd02f8c9dd3ff6d209bf728dc1e042c1faf1c5b0a24239a199a3099a5b141b
7
+ data.tar.gz: e7048d7300227a7effc924d3248798b0669471dfa56820eac798a0300f3cc3545bad333d14d37c682b61b67d3cbf185f9d40c356c17491ff8288706551a2da46
@@ -15,4 +15,4 @@ before_install:
15
15
  - eval "$(curl -Ss https://raw.githubusercontent.com/neovim/bot-ci/master/scripts/travis-setup.sh) nightly-x64"
16
16
 
17
17
  env: REPORT_COVERAGE=1
18
- script: bundle exec rake --trace spec
18
+ script: travis_retry bundle exec rake --trace spec
@@ -1,3 +1,8 @@
1
+ # 0.2.3
2
+ - Detach child processes in `Neovim::EventLoop.child`
3
+ - Improve performance/compatibility of `Buffer#append`
4
+ - Various improvements around `Host` loading
5
+
1
6
  # 0.2.2
2
7
  - Make `VIM` constant a module instead of a class
3
8
  - Make `Client#set_option` accept a single string argument
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  Ruby bindings for [Neovim](https://github.com/neovim/neovim).
9
9
 
10
- *Warning*: This project is currently incomplete and unstable.
10
+ *Warning*: This project follows [Semantic Versioning](http://semver.org/), thus its API should be considered unstable until it reaches v1.0.0 ([spec](http://semver.org/#spec-item-4)).
11
11
 
12
12
  ## Installation
13
13
 
@@ -25,20 +25,20 @@ Or install it yourself as:
25
25
 
26
26
  ## Usage
27
27
 
28
- You can control a running `nvim` process by connecting to `$NVIM_LISTEN_ADDRESS`. Start it up like this:
28
+ You can control a running `nvim` process by connecting to `$NVIM_LISTEN_ADDRESS`. For example, to connect to `nvim` over a UNIX domain socket, start it up like this:
29
29
 
30
30
  ```shell
31
31
  $ NVIM_LISTEN_ADDRESS=/tmp/nvim.sock nvim
32
32
  ```
33
33
 
34
- You can then connect to that socket to get a `Neovim::Client`:
34
+ You can then connect to that socket path to get a `Neovim::Client`:
35
35
 
36
36
  ```ruby
37
37
  require "neovim"
38
38
  client = Neovim.attach_unix("/tmp/nvim.sock")
39
39
  ```
40
40
 
41
- The client's interface is generated at runtime from the `vim_get_api_info` RPC call. Refer to the [docs](http://www.rubydoc.info/github/alexgenco/neovim-ruby/master/Neovim/Client) for details.
41
+ Refer to the [`Neovim` docs](http://www.rubydoc.info/github/alexgenco/neovim-ruby/master/Neovim) for other ways to connect to `nvim`, and the [`Neovim::Client` docs](http://www.rubydoc.info/github/alexgenco/neovim-ruby/master/Neovim/Client) for a summary of the client interface.
42
42
 
43
43
  ### Plugins
44
44
 
@@ -68,9 +68,7 @@ Neovim.plugin do |plug|
68
68
  end
69
69
  ```
70
70
 
71
- After a call to `:UpdateRemotePlugins`, plugins will be auto-loaded from the `$VIMRUNTIME/rplugin/ruby` directory.
72
-
73
- Neovim also supports the legacy Vim commands `:ruby`, `:rubyfile`, and `:rubydo`. A detailed description of their usage can be found with `:help ruby`.
71
+ Ruby plugins go in the `$VIMRUNTIME/rplugin/ruby` directory, and are auto-loaded after calling `:UpdateRemotePlugins`. Refer to the [`Neovim::Plugin::DSL` docs](http://www.rubydoc.info/github/alexgenco/neovim-ruby/master/Neovim/Plugin/DSL) for a more complete overview.
74
72
 
75
73
  ## Links
76
74
 
data/Rakefile CHANGED
@@ -14,9 +14,25 @@ namespace :neovim do
14
14
  window_docs = []
15
15
  tabpage_docs = []
16
16
  session = Neovim::Session.child(%w(nvim -u NONE -n))
17
+ vim_defs = Neovim::Client.instance_methods(false)
18
+ buffer_defs = Neovim::Buffer.instance_methods(false)
19
+ tabpage_defs = Neovim::Tabpage.instance_methods(false)
20
+ window_defs = Neovim::Window.instance_methods(false)
17
21
 
18
22
  session.request(:vim_get_api_info)[1]["functions"].each do |func|
19
23
  prefix, method_name = func["name"].split("_", 2)
24
+
25
+ case prefix
26
+ when "vim"
27
+ next if vim_defs.include?(method_name.to_sym)
28
+ when "buffer"
29
+ next if buffer_defs.include?(method_name.to_sym)
30
+ when "tabpage"
31
+ next if tabpage_defs.include?(method_name.to_sym)
32
+ when "window"
33
+ next if window_defs.include?(method_name.to_sym)
34
+ end
35
+
20
36
  return_type = func["return_type"]
21
37
  params = func["parameters"]
22
38
  params.shift unless prefix == "vim"
@@ -54,16 +54,6 @@ require "neovim/version"
54
54
  # @see Client
55
55
  # @see Plugin::DSL
56
56
  module Neovim
57
- class << self
58
- # @api private
59
- # @return [Manifest, nil]
60
- attr_accessor :__configured_plugin_manifest
61
-
62
- # @api private
63
- # @return [String, nil]
64
- attr_accessor :__configured_plugin_path
65
- end
66
-
67
57
  # Connect to a running +nvim+ instance over TCP.
68
58
  #
69
59
  # @param host [String] The hostname or IP address
@@ -92,19 +82,6 @@ module Neovim
92
82
  Client.new Session.child(argv)
93
83
  end
94
84
 
95
- # Define an +nvim+ remote plugin using the plugin DSL.
96
- #
97
- # @yield [Plugin::DSL]
98
- # @return [Plugin]
99
- # @see Plugin::DSL
100
- def self.plugin(&block)
101
- Plugin.from_config_block(__configured_plugin_path, &block).tap do |plugin|
102
- if __configured_plugin_manifest.respond_to?(:register)
103
- __configured_plugin_manifest.register(plugin)
104
- end
105
- end
106
- end
107
-
108
85
  # Start a plugin host. This is called by the +nvim-ruby-host+ executable,
109
86
  # which is spawned by +nvim+ to discover and run Ruby plugins, and acts as
110
87
  # the bridge between +nvim+ and the plugin.
@@ -116,6 +93,15 @@ module Neovim
116
93
  Host.load_from_files(rplugin_paths).run
117
94
  end
118
95
 
96
+ # Placeholder method for exposing the remote plugin DSL. This gets
97
+ # temporarily overwritten in +Host#load_files+.
98
+ #
99
+ # @see Host#load_files
100
+ # @see Plugin::DSL
101
+ def self.plugin
102
+ raise "Can't call Neovim.plugin outside of a plugin host."
103
+ end
104
+
119
105
  # Set the Neovim global logger.
120
106
  #
121
107
  # @param logger [Logger] The target logger
@@ -1,4 +1,5 @@
1
1
  module Neovim
2
+ # @api private
2
3
  class API
3
4
  # Represents an unknown API. Used as a stand-in when the API hasn't been
4
5
  # discovered yet via the +vim_get_api_info+ RPC call.
@@ -6,6 +6,8 @@ module Neovim
6
6
  # Handles formatting RPC requests and writing them to the
7
7
  # +MsgpackStream+. This exposes an asynchronous API, in which responses
8
8
  # are handled in callbacks.
9
+ #
10
+ # @api private
9
11
  class AsyncSession
10
12
  include Logging
11
13
 
@@ -72,7 +74,7 @@ module Neovim
72
74
  end
73
75
  end
74
76
  rescue => e
75
- fatal("got unexpected error #{e}")
77
+ fatal("got unexpected error #{e.inspect}")
76
78
  debug(e.backtrace.join("\n"))
77
79
  end
78
80
 
@@ -97,7 +97,11 @@ module Neovim
97
97
  # @param str [String]
98
98
  # @return [String]
99
99
  def append(index, str)
100
- lines[index-1, 1] = [lines[index-1], str]
100
+ if index < 0
101
+ raise ArgumentError, "Index out of bounds"
102
+ else
103
+ lines.insert(index, str)
104
+ end
101
105
  str
102
106
  end
103
107
 
@@ -88,6 +88,10 @@ module Neovim
88
88
  end
89
89
  end
90
90
 
91
+ def shutdown
92
+ @session.shutdown
93
+ end
94
+
91
95
  private
92
96
 
93
97
  def rpc_methods
@@ -176,11 +180,6 @@ module Neovim
176
180
  @param [String] name
177
181
  @return [Object]
178
182
 
179
- @method set_option(name, value)
180
- @param [String] name
181
- @param [Object] value
182
- @return [void]
183
-
184
183
  @method out_write(str)
185
184
  @param [String] str
186
185
  @return [void]
@@ -4,7 +4,9 @@ require "neovim/window"
4
4
 
5
5
  module Neovim
6
6
  # Support for +client.current+ chaining.
7
+ #
7
8
  # @see Client#current
9
+ # @api private
8
10
  class Current
9
11
  def initialize(session)
10
12
  @session = session
@@ -3,6 +3,8 @@ require "socket"
3
3
 
4
4
  module Neovim
5
5
  # The lowest level interface to reading from and writing to +nvim+.
6
+ #
7
+ # @api private
6
8
  class EventLoop
7
9
  include Logging
8
10
 
@@ -32,7 +34,10 @@ module Neovim
32
34
  # @param argv [Array] The arguments to pass to the spawned process
33
35
  # @return [EventLoop]
34
36
  def self.child(argv)
35
- io = IO.popen(argv | ["--embed"], "rb+")
37
+ io = IO.popen(argv | ["--embed"], "rb+").tap do |_io|
38
+ Process.detach(_io.pid)
39
+ end
40
+
36
41
  new(io)
37
42
  end
38
43
 
@@ -87,7 +92,7 @@ module Neovim
87
92
  rescue EOFError
88
93
  info("got EOFError")
89
94
  rescue => e
90
- fatal("got unexpected error #{e}")
95
+ fatal("got unexpected error #{e.inspect}")
91
96
  debug(e.backtrace.join("\n"))
92
97
  end
93
98
 
@@ -109,6 +114,14 @@ module Neovim
109
114
  io.close
110
115
  rescue IOError
111
116
  end
117
+
118
+ begin
119
+ if pid = io.pid
120
+ Process.kill(:TERM, pid)
121
+ Process.waitpid(pid)
122
+ end
123
+ rescue IOError, Errno::ESRCH, Errno::ECHILD
124
+ end
112
125
  end
113
126
  end
114
127
  end
@@ -1,69 +1,113 @@
1
1
  require "neovim/logging"
2
- require "neovim/manifest"
2
+ require "neovim/host/loader"
3
3
 
4
4
  module Neovim
5
+ # @api private
5
6
  class Host
6
7
  include Logging
7
8
 
8
- attr_reader :manifest
9
+ attr_reader :handlers, :specs
9
10
 
10
- # Load plugin definitions and instantiate a new +Host+. This temporarily
11
- # mutates global state on the +Neovim+ module so that +Neovim.plugin+ calls
12
- # will be registered correctly with the provided +Manifest+.
13
- #
14
- # @overload load_from_files(rplugin_paths)
15
- # @param rplugin_paths [Array<String>] The remote plugin paths.
16
- #
17
- # @overload load_from_files(rplugin_paths, target_manifest)
18
- # @param rplugin_paths [Array<String>] The remote plugin paths.
19
- # @param target_manifest [Manifest] The plugin manifest.
11
+ # Initialize and populate a +Host+ from a list of plugin paths.
20
12
  #
13
+ # @param rplugin_paths [Array<String>]
21
14
  # @return [Host]
22
- # @see Neovim.start_host
23
- # @see Neovim.plugin
24
- def self.load_from_files(rplugin_paths, target_manifest=Manifest.new)
25
- old_manifest = Neovim.__configured_plugin_manifest
26
- old_path = Neovim.__configured_plugin_path
27
-
28
- begin
29
- Neovim.__configured_plugin_manifest = target_manifest
30
-
31
- rplugin_paths.each do |rplugin_path|
32
- Neovim.__configured_plugin_path = rplugin_path
33
- Kernel.load(rplugin_path, true)
34
- end
15
+ # @see Loader#load
16
+ def self.load_from_files(rplugin_paths, options={})
17
+ session = options.fetch(:session) { Session.stdio }
18
+ client = options.fetch(:client) { Client.new(session) }
35
19
 
36
- new(target_manifest)
37
- ensure
38
- Neovim.__configured_plugin_manifest = old_manifest
39
- Neovim.__configured_plugin_path = old_path
20
+ new(session, client).tap do |host|
21
+ Loader.new(host).load(rplugin_paths)
40
22
  end
41
23
  end
42
24
 
43
- def initialize(manifest, session=nil)
44
- @session = session || Session.stdio
45
- @manifest = manifest
25
+ def initialize(session, client)
26
+ @session = session
27
+ @client = client
28
+ @handlers = {"poll" => poll_handler, "specs" => specs_handler}
29
+ @specs = {}
30
+ end
31
+
32
+ # Register a +Plugin+ to receive +Host+ messages.
33
+ #
34
+ # @param plugin [Plugin]
35
+ def register(plugin)
36
+ plugin.handlers.each do |handler|
37
+ @handlers[handler.qualified_name] = wrap_plugin_handler(handler)
38
+ end
39
+
40
+ @specs[plugin.source] = plugin.specs
46
41
  end
47
42
 
48
- # Run the event loop, passing received messages to the manifest.
43
+ # Run the event loop, passing received messages to the appropriate handler.
49
44
  #
50
45
  # @return [void]
51
46
  def run
52
- @session.discover_api
47
+ @session.run { |msg| handle(msg) }
48
+ rescue => e
49
+ fatal("got unexpected error #{e.inspect}")
50
+ debug(e.backtrace.join("\n"))
51
+ end
53
52
 
54
- @session.run do |msg|
55
- debug("received #{msg.inspect}")
56
- @manifest.handle(msg, client)
57
- end
53
+ # Handle messages received from the host. Sends a +Neovim::Client+ along
54
+ # with the message to be used in plugin callbacks.
55
+ #
56
+ # @param message [Neovim::Request, Neovim::Notification]
57
+ # @param client [Neovim::Client]
58
+ def handle(message)
59
+ debug("received #{message.inspect}")
60
+
61
+ @handlers.
62
+ fetch(message.method_name, default_handler).
63
+ call(@client, message)
58
64
  rescue => e
59
- fatal("got unexpected error #{e}")
65
+ fatal("got unexpected error #{e.inspect}")
60
66
  debug(e.backtrace.join("\n"))
61
67
  end
62
68
 
63
69
  private
64
70
 
65
- def client
66
- @client ||= Client.new(@session)
71
+ def poll_handler
72
+ @poll_handler ||= Proc.new do |_, req|
73
+ debug("received 'poll' request #{req.inspect}")
74
+ req.respond("ok")
75
+ end
76
+ end
77
+
78
+ def specs_handler
79
+ @specs_handler ||= Proc.new do |_, req|
80
+ debug("received 'specs' request #{req.inspect}")
81
+ source = req.arguments.fetch(0)
82
+
83
+ if @specs.key?(source)
84
+ req.respond(@specs.fetch(source))
85
+ else
86
+ req.error("Unknown plugin #{source}")
87
+ end
88
+ end
89
+ end
90
+
91
+ def default_handler
92
+ @default_handler ||= Proc.new do |_, message|
93
+ if message.sync?
94
+ message.error("Unknown request #{message.method_name}")
95
+ end
96
+ end
97
+ end
98
+
99
+ def wrap_plugin_handler(handler)
100
+ Proc.new do |client, message|
101
+ begin
102
+ debug("received #{message.inspect}")
103
+ args = message.arguments.flatten(1)
104
+ result = handler.call(client, *args)
105
+ message.respond(result) if message.sync?
106
+ rescue => e
107
+ warn("got unexpected error #{e.inspect}")
108
+ message.error(e.message) if message.sync?
109
+ end
110
+ end
67
111
  end
68
112
  end
69
113
  end
@@ -0,0 +1,39 @@
1
+ module Neovim
2
+ class Host
3
+ # @api private
4
+ class Loader
5
+ def initialize(host)
6
+ @host = host
7
+ end
8
+
9
+ # Load the provided Ruby files while temporarily overriding
10
+ # +Neovim.plugin+ to expose the remote plugin DSL and register the result
11
+ # to the host.
12
+ #
13
+ # @param paths [Array<String>]
14
+ def load(paths)
15
+ paths.each do |path|
16
+ override_plugin_method(path) do
17
+ Kernel.load(path, true)
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def override_plugin_method(path)
25
+ old_plugin_def = Neovim.method(:plugin)
26
+ at_host = @host
27
+
28
+ Neovim.define_singleton_method(:plugin) do |&block|
29
+ plugin = Plugin.from_config_block(path, &block)
30
+ at_host.register(plugin)
31
+ end
32
+
33
+ yield
34
+ ensure
35
+ Neovim.define_singleton_method(:plugin, &old_plugin_def)
36
+ end
37
+ end
38
+ end
39
+ end