neovim 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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