nvim 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d8207d1ea220ae3a18b71de6377beaac8f117b7b8fb2c816f773a36dc2852043
4
+ data.tar.gz: eb0c7bf8c52bc66a26952c5985edc3a0ffca154b0ba51560f9802428e51594b2
5
+ SHA512:
6
+ metadata.gz: 17c4b731220d2da8b667da00bfba85b63f27664d0d6119f4d021b92e66c24ecabd279abc090b8cba6b5ff84baeb2561d6ce3410c7fabb1c91a94857c82d2f82e
7
+ data.tar.gz: 3197fe71bdd9506350206fff209e2b0c9fb93bfa926f204e4bebcbacfee849a566b42f9f576efdeb86ee751fbc7b8197a07329fe6e2e9191b735ad86ac3c9604
data/INFO.yaml ADDED
@@ -0,0 +1,18 @@
1
+ #
2
+ # INFO.yaml -- Version number etc.
3
+ #
4
+
5
+ nvim:
6
+ version: 1.0.0
7
+ license: BSD-2-Clause+
8
+ authors:
9
+ - Bertram Scharpf
10
+ email: software@bertram-scharpf.de
11
+
12
+ summary: Yet another Ruby client for Neovim
13
+ description: |-
14
+ A simple Ruby client for Neovim.
15
+ Clean code, minimal dependecies, no frills, no wokeness.
16
+
17
+ homepage: http://bertram-scharpf.de
18
+
data/LICENSE ADDED
@@ -0,0 +1,52 @@
1
+ # BSD-2-clause license, extended by language use conditions
2
+
3
+ Copyright (C) 2024, Bertram Scharpf <software@bertram-scharpf.de>.
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are
8
+ met:
9
+
10
+ * Redistributions of source code must retain the above copyright
11
+ notice, this list of conditions and the following disclaimer.
12
+
13
+ * Redistributions in binary form must reproduce the above copyright
14
+ notice, this list of conditions and the following disclaimer in
15
+ the documentation and/or other materials provided with the
16
+ distribution.
17
+
18
+ * Redistributions must not contain any clauses about anticipated
19
+ harassment or discrimination, nor must they be held in a so-called
20
+ "inclusive language". As far as German language is used, the
21
+ conditions mentioned below additionally apply.
22
+
23
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
26
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
27
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+
35
+
36
+ ## Use of the German Language
37
+
38
+ Beim Gebrauch deutscher Sprache sind Weiterentwicklungen und
39
+ -verbreitungen nur gestattet unter Einhaltung folgender
40
+ zusätzlicher Bedingungen:
41
+
42
+ * Keine Verwendung von sogenannter „geschlechtergerechter Sprache“,
43
+ also Anfügen von weiblichen Endungen mit Binnen-I, Sternchen,
44
+ Doppelpunkt, Unterstrich oder ähnlichem, oder Konstruktionen, die
45
+ den Sachverhalt falsch wiedergeben („Radfahrende“, „Studierende“).
46
+
47
+ * Keine Verwendung der „reformierten Rechtschreibung“ von 1996,
48
+ insbesondere Doppel-S am Silbenende, „plazieren“ mit T, sowie
49
+ Großschreibung von Wendungen wie „des weiteren“.
50
+
51
+
52
+ <!-- vim:set ft=markdown : -->
data/README.md ADDED
@@ -0,0 +1,264 @@
1
+ # Ruby-Nvim
2
+
3
+ Ruby support for [Neovim](https://github.com/neovim/neovim).
4
+
5
+ Clean code, minimal dependecies, no frills, no wokeness.
6
+
7
+ *I would have written a shorter letter, but I did not have the time.* --
8
+ Blaise Pascal
9
+
10
+
11
+ ## Installation
12
+
13
+ ```shell
14
+ sudo gem uninstall neovim || true
15
+ sudo gem install nvim
16
+ ```
17
+
18
+ You may prefer to also install the dependencies. Yet, this is not
19
+ neccessary, as they are small and Ruby-Nvim includes a copy of them.
20
+
21
+ ```shell
22
+ sudo gem install supplement mplight
23
+ ```
24
+
25
+
26
+ ## Usage
27
+
28
+
29
+ ### Command, Function and Autoload Plugins
30
+
31
+ Put this into a new buffer:
32
+
33
+ ```ruby
34
+ Neovim.plugin do |dsl|
35
+ dsl.command :SetLine, nargs: 1 do |client,(str)|
36
+ client.set_current_line str
37
+ end
38
+ dsl.function :Sum, nargs: 2, sync: true do |client,(x,y)|
39
+ x + y
40
+ end
41
+ dsl.autocmd :BufEnter, pattern: "*.rb" do |client|
42
+ client.command "echom 'Hello, Ruby!'"
43
+ end
44
+ end
45
+ ```
46
+
47
+ Then run these Vim commands:
48
+
49
+ ```vim
50
+ w ++p ~/.config/nvim/rplugin/ruby/demo.rb
51
+ UpdateRemotePlugins
52
+
53
+ " Check the generated manifest file
54
+ split ~/.local/share/nvim/rplugin.vim
55
+ help remote-plugin-manifest
56
+ ```
57
+
58
+ Open a new Neovim and see what happens:
59
+
60
+ ```vim
61
+ e dummy.rb
62
+ SetLine some text
63
+ echo Sum(13,7)
64
+ ```
65
+
66
+
67
+ ### Calling the :ruby... Interface
68
+
69
+ The `:ruby...` commands and the `rubyeval()` function behave as descibed
70
+ in `:h ruby`.
71
+
72
+ Additionally you can directly execute the buffers contents:
73
+
74
+ ```vim
75
+ set number
76
+ ```
77
+
78
+ ```
79
+ 1 class C
80
+ 2 def f
81
+ 3 :F
82
+ 4 end
83
+ 5 end
84
+ 6 c = C.new
85
+ ~
86
+ ~
87
+ ~
88
+ :1,6ruby |
89
+ ```
90
+
91
+ The last value, if it is not `nil`, will be added through `#inspect` as
92
+ a comment.
93
+
94
+ ```
95
+ 1 class C
96
+ 2 def f
97
+ 3 :F
98
+ 4 end
99
+ 5 end
100
+ 6 c = C.new
101
+ 7 #=> #<C:0x000001b347456478>
102
+ ~
103
+ ~
104
+ :
105
+ ```
106
+
107
+ The classes and variables will be preserved and are available during the
108
+ next call.
109
+
110
+ ```
111
+ 5 end
112
+ 6 c = C.new
113
+ 7 #=> #<C:0x00001fd2fd1f89d0>
114
+ 8 [ c.f, C]
115
+ ~
116
+ ~
117
+ ~
118
+ :8ruby |
119
+ ```
120
+
121
+ This results in:
122
+
123
+ ```
124
+ 7 #=> #<C:0x00001fd2fd1f89d0>
125
+ 8 [ c.f, C]
126
+ 9 #=> [:F, C]
127
+ ~
128
+ ~
129
+ :
130
+ ```
131
+
132
+ Output will be added to the buffer, too.
133
+
134
+ ```
135
+ 1 puts "ba" + "na"*2
136
+ 2 print "hell"
137
+ 3 puts "o"
138
+ ~
139
+ ~
140
+ :%ruby |
141
+ ```
142
+
143
+ Further, a simple number/cash summing tool is included.
144
+
145
+ ```
146
+ Apples : 3.99
147
+ Bananas : 5 * 0.40 # multiplication
148
+ Oranges : 3.59 | -10% # percentage added (here subtracted)
149
+ Kiwi : 0,40 # comma is allowed
150
+ Coconut : 5,- # empty decimal places
151
+ ~
152
+ ~
153
+ :%ruby +
154
+ ```
155
+
156
+
157
+ ### Modern rpcrequest() Calls
158
+
159
+ Put this into a new buffer:
160
+
161
+ ```ruby
162
+ require "neovim"
163
+ counter = 0
164
+ Neovim.start_remote do |dsl|
165
+ dsl.register_handler "rb_add" do |client,n|
166
+ counter += n
167
+ client.command "echo 'Counter value now is: '..#{counter}..'.'"
168
+ end
169
+ dsl.register_handler "rb_raise" do |client|
170
+ raise "Ouch!"
171
+ end
172
+ end
173
+ ```
174
+
175
+ Then enter these Vim commands:
176
+
177
+ ```vim
178
+ w demo_remote.rb
179
+ let chan = jobstart(['ruby','demo_remote.rb'], { 'rpc': v:true })
180
+ call rpcrequest(chan, 'rb_add', 7)
181
+ call rpcrequest(chan, 'rb_raise')
182
+ call jobstop(chan)
183
+ ```
184
+
185
+ If you prefer, you can also use a shebang line.
186
+
187
+ ```ruby
188
+ #!/usr/bin/env ruby
189
+ require "neovim"
190
+ Neovim.start_remote do |dsl|
191
+ # ... (as above)
192
+ end
193
+ ```
194
+
195
+ Then enter these Vim commands:
196
+
197
+ ```vim
198
+ w demo_remote.rb
199
+ !chmod +x %
200
+ let chan = jobstart('./demo_remote.rb', { 'rpc': v:true })
201
+ " proceed as above
202
+ ```
203
+
204
+
205
+ ### Logging and Debugging
206
+
207
+ Logging is a easy as this:
208
+
209
+ ```shell
210
+ export NVIM_RUBY_LOG_LEVEL=all NVIM_RUBY_LOG_FILE=nvim.log
211
+ nvim +'ruby puts "hi"*10'
212
+ ```
213
+
214
+ To show the log levels, simply run in Neovim:
215
+
216
+ ```vim
217
+ ruby puts Neovim::Logging::LEVELS.keys
218
+ ```
219
+
220
+ If you are inside a [Tmux](https://tmux.github.io), you might prefer to trace the colored log in a split window.
221
+
222
+ ```shell
223
+ tmux split-window -fhd 'echo -e "\e[33m==== $$ ==== `tty` ====\e[m" ; ln -sf `tty` /tmp/tmux-`id -u`/debug ; exec cat >/dev/null 2>&1'
224
+ export NVIM_RUBY_LOG_LEVEL=all NVIM_RUBY_LOG_FILE=/tmp/tmux-`id -u`/debug
225
+
226
+ examples/demo_attach
227
+
228
+ nvim +'ruby puts "hi"*10'
229
+ ```
230
+
231
+ You may start an interactive session and control a running Neovim through it.
232
+ Open Neovim specifying the `--listen` option
233
+
234
+ ```shell
235
+ nvim --listen /path/to/some.sock
236
+ ```
237
+
238
+ or ask the running Neovim for its server name.
239
+
240
+ ```vim
241
+ echo v:servername
242
+ ```
243
+
244
+ Then connect to it. This requires the [Intar](https://github.com/BertramScharpf/ruby-intar) gem.
245
+
246
+ ```
247
+ $ intar -r neovim/remote
248
+ main:0:001> include Neovim
249
+ => Object
250
+ main:0:002> Remote.start_client ConnectionUnix, "/path/to/some.sock" do |c|&
251
+ main:1:001> c.command "e /etc/passwd"
252
+ main:1:002> b = c.get_current_buf
253
+ => #<Neovim::Buffer:400 1>
254
+ main:1:003> b[1]
255
+ => ["root:*:0:0:Charlie &:/root:/bin/sh"]
256
+ main:1:004> \q!!
257
+ ```
258
+
259
+
260
+ ## Copyright
261
+
262
+ * (C) 2024 Bertram Scharpf <software@bertram-scharpf.de>
263
+ * License: [BSD-2-Clause+](./LICENSE)
264
+
data/Rakefile ADDED
@@ -0,0 +1,68 @@
1
+ #
2
+ # Rakefile -- Generate files
3
+ #
4
+
5
+
6
+ INFOFILE = "lib/neovim/info.rb"
7
+
8
+
9
+ GENERATED = [ INFOFILE]
10
+
11
+ task :default => GENERATED
12
+ task :infofile => INFOFILE
13
+
14
+
15
+ file INFOFILE => "INFO.yaml" do |f|
16
+ create_info f.name, f.source
17
+ end
18
+
19
+
20
+ task :clean do
21
+ rm *GENERATED
22
+ end
23
+
24
+
25
+ def commit
26
+ c = `git rev-parse --short HEAD`
27
+ c.chomp!
28
+ c
29
+ end
30
+
31
+ def create_info dst, src
32
+ File.open dst, "w" do |vf|
33
+ require "yaml"
34
+ m = YAML.load File.read src
35
+ name = m.keys.first
36
+ args = m[ name]
37
+ args[ :commit] = commit
38
+ unless args[ :authors] then
39
+ u = args.delete :author
40
+ args[ :authors] = [ u] if u
41
+ end
42
+ vf.puts 'require "neovim/meta.rb"'
43
+ vf.print "Neovim::INFO = Neovim::Meta.new #{name.inspect}"
44
+ args.each { |k,v|
45
+ vf.puts ","
46
+ vf.print " #{k.to_sym}: #{v.inspect}"
47
+ }
48
+ vf.puts
49
+ end
50
+ end
51
+
52
+
53
+ task :diffdeps do
54
+ %w(mplight).each { |gem|
55
+ c = `gem contents #{gem}`
56
+ unless $?.success? then
57
+ puts "Gem #{gem} not installed. Cannot compare."
58
+ next
59
+ end
60
+ (c.split $/).each { |file|
61
+ if file =~ %r[/gems/#{gem}-.*/lib/(.*\.rb)$] then
62
+ ours = "lib/neovim/foreign/#$1"
63
+ sh *%W(nvim -d #{ours} #{file}) if File.exist? ours
64
+ end
65
+ }
66
+ }
67
+ end
68
+
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # bin/neovim-ruby-host -- Child started by Neovim
5
+ #
6
+
7
+ require "neovim/host"
8
+
9
+
10
+ module Neovim
11
+
12
+ class <<self
13
+
14
+ def plugin &block
15
+ require "neovim/vimscript_provider"
16
+ run_dsl DslVimscript, &block
17
+ end
18
+
19
+ private
20
+
21
+ def run_dsl dsl
22
+ @host or raise "Can't add plugins outside of a running session."
23
+ dsl.open @path, @host do |dsl|
24
+ yield dsl
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ if $*.delete "--version" then
31
+ puts [ Neovim::INFO.name, Neovim::INFO.version].join " "
32
+ exit
33
+ end
34
+
35
+ r = Host.run do |h|
36
+ begin
37
+ @host = h
38
+ $*.each do |p|
39
+ @path = p
40
+ Kernel.load @path, true
41
+ ensure
42
+ @path = nil
43
+ end
44
+ ensure
45
+ @host = nil
46
+ end
47
+ end
48
+ exit r.to_i
49
+
50
+ end
51
+
@@ -0,0 +1,108 @@
1
+ #
2
+ # neovim/client.rb -- Clients
3
+ #
4
+
5
+ require "neovim/foreign/supplement"
6
+
7
+ require "neovim/remote_object"
8
+
9
+
10
+ module Neovim
11
+
12
+ class Client
13
+
14
+ @strict = true
15
+ class <<self
16
+ attr_accessor :strict
17
+ end
18
+
19
+ class UnknownApiFunction < RuntimeError ; end
20
+ class UnknownApiObjectFunction < RuntimeError ; end
21
+
22
+
23
+ attr_reader :channel_id
24
+
25
+ def initialize comm, channel_id
26
+ @comm, @channel_id = comm, channel_id
27
+ @functions = {}
28
+ @objfuncs = Hash.new do |h,k| h[k] = {} end
29
+ end
30
+
31
+ def inspect
32
+ "#<#{self.class} #@channel_id>"
33
+ end
34
+
35
+ def add_functions list, prefixes
36
+ list.each { |fn|
37
+ next if fn[ "deprecated_since"] && self.class.strict
38
+ n = fn[ "name"]
39
+ next unless n =~ /\Anvim_/
40
+ @functions[ $'.to_sym] = n
41
+ t, = prefixes.find { |t,p| n =~ p }
42
+ @objfuncs[ t][ $'.to_sym] = n if t
43
+ }
44
+ end
45
+
46
+
47
+ def call_api name, *args
48
+ f = @functions[ name.to_sym]
49
+ f or raise UnknownApiFunction, "Function: #{name}"
50
+ @comm.request f, *args
51
+ end
52
+
53
+ def call_obj obj, name, *args
54
+ n = obj.type
55
+ f = @objfuncs[ n.to_sym][ name.to_sym]
56
+ f or raise UnknownApiObjectFunction, "Object: #{n}, Function: #{name}"
57
+ @comm.request f, obj.index, *args
58
+ end
59
+
60
+
61
+
62
+ def method_missing sym, *args
63
+ call_api sym, *args
64
+ rescue UnknownApiFunction
65
+ super
66
+ end
67
+
68
+ def respond_to_missing? sym, priv = nil
69
+ # Be aware that calling a proc (our handlers) with a single argument
70
+ # asks whether that argument is an array. In case it is a Client object,
71
+ # we end up here with +sym = to_ary+.
72
+ @functions[ sym.to_sym].to_bool
73
+ end
74
+
75
+ def methods regular = true
76
+ s = super
77
+ s |= @functions.keys if regular
78
+ s
79
+ end
80
+
81
+
82
+ def has_obj_function? obj, name
83
+ @objfuncs[ obj.type][ name.to_sym].to_bool
84
+ end
85
+
86
+ def obj_functions obj
87
+ @objfuncs[ obj.type].keys
88
+ end
89
+
90
+
91
+
92
+ def message str
93
+ call_api :out_write, str
94
+ str.end_with? $/ or call_api :out_write, $/
95
+ end
96
+
97
+
98
+ include OptionAccess
99
+ OPTION_PARAM = nil
100
+
101
+ def command arg ; call_api :command, arg ; end
102
+
103
+ def evaluate expr ; call_api :eval, expr ; end
104
+
105
+ end
106
+
107
+ end
108
+
@@ -0,0 +1,129 @@
1
+ #
2
+ # neovim/connection.rb -- Connections
3
+ #
4
+
5
+ require "neovim/logging"
6
+ require "neovim/client"
7
+ require "neovim/info"
8
+
9
+
10
+ module Neovim
11
+
12
+ class Connection < MPLight::Types
13
+
14
+ include Logging
15
+
16
+ include MPLight::Packer, MPLight::Unpacker
17
+
18
+ attr_reader :client
19
+
20
+ def initialize rd, wr
21
+ super
22
+ default_to_string!
23
+ init_input rd
24
+ init_output wr
25
+ @errors = {}
26
+ end
27
+
28
+ def additional_data ; [ *super, @client] ; end
29
+
30
+
31
+ def error id
32
+ @errors[ id] || "Error #{id}"
33
+ end
34
+
35
+
36
+ def start comm, client_name, client_type, client_methods = nil
37
+ comm.notify :nvim_set_client_info, client_name, Neovim::INFO.version_h, client_type, client_methods||{}, Neovim::INFO.attributes
38
+ channel_id, api_info = *(comm.request :nvim_get_api_info)
39
+ @client = Client.new comm, channel_id
40
+ prefixes = {}
41
+ api_info[ "types"].each do |type,info|
42
+ type = type.to_sym
43
+ prefixes[ type] = /\A#{info[ "prefix"]}/
44
+ register_type type, info[ "id"]
45
+ end
46
+ @client.add_functions api_info[ "functions"], prefixes
47
+ api_info[ "error_types"].each { |type,info|
48
+ register_error type, info[ "id"]
49
+ }
50
+ nil
51
+ end
52
+
53
+ private
54
+
55
+ def register_type type, id
56
+ klass = Neovim.const_get type
57
+ klass or raise "Class #{type} is not defined."
58
+ klass < RemoteObject or raise "Class #{klass} is not a descendant of RemoteObject."
59
+ log :debug2, "Registering type", type: type, id: id
60
+ register id, klass
61
+ end
62
+
63
+ def register_error id, type
64
+ @errors[ id] = type
65
+ end
66
+
67
+ end
68
+
69
+
70
+ class ConnectionTcp < Connection
71
+ class <<self
72
+ def open_files host, port
73
+ require "socket"
74
+ TCPSocket.open host, port do |socket|
75
+ yield (new socket, socket)
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ class ConnectionUnix < Connection
82
+ class <<self
83
+ def open_files path
84
+ require "socket"
85
+ UNIXSocket.open path do |socket|
86
+ yield (new socket, socket)
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ class ConnectionChild < Connection
93
+
94
+ class <<self
95
+
96
+ def open_files *argv
97
+ eb = "--embed"
98
+ argv.unshift eb unless argv.include? eb
99
+ argv.unshift path
100
+ IO.popen argv, "r+" do |io|
101
+ Process.detach io.pid
102
+ yield (new io, io)
103
+ end
104
+ end
105
+
106
+ def path
107
+ ENV[ "NVIM_EXECUTABLE"].notempty? || "nvim"
108
+ end
109
+
110
+ def version
111
+ IO.popen [ path, "--version"] do |io|
112
+ io.gets[ /\ANVIM +v?(.+)/, 1]
113
+ end
114
+ end
115
+
116
+ end
117
+
118
+ end
119
+
120
+ class ConnectionStdio < Connection
121
+ class <<self
122
+ def open_files *argv
123
+ yield (new $stdin, $stdout)
124
+ end
125
+ end
126
+ end
127
+
128
+ end
129
+