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.
@@ -0,0 +1,331 @@
1
+ #
2
+ # neovim/remote_object.rb -- Remote Objects: Buffer, Window, Tabpage
3
+ #
4
+
5
+ require "neovim/foreign/mplight"
6
+ require "neovim/foreign/mplight/bufferio"
7
+
8
+
9
+ module Neovim
10
+
11
+ module OptionAccess
12
+
13
+ def get_option name, *args
14
+ vs = [name, *args].map { |a| call_api :get_option_value, a, option_params }
15
+ if args.empty? then
16
+ vs.first
17
+ else
18
+ vs
19
+ end
20
+ end
21
+ alias get_options get_option
22
+
23
+ def set_option *args, **kwargs
24
+ op = option_params
25
+ args.each { |a| call_api :set_option_value, a, true, op }
26
+ kwargs.each { |k,v| call_api :set_option_value, k, v, op }
27
+ nil
28
+ end
29
+ alias set_options set_option
30
+
31
+ def option_params
32
+ r = {}
33
+ n = self.class::OPTION_PARAM
34
+ r[ n] = @index if n
35
+ r
36
+ end
37
+
38
+ end
39
+
40
+
41
+
42
+ class RemoteObject
43
+
44
+ class <<self
45
+
46
+ alias plain_new new
47
+ def new index, client
48
+ @objs ||= []
49
+ i = @objs.find { |s| s.index == index && s.client == client }
50
+ unless i then
51
+ i = plain_new index, client
52
+ @objs.push i
53
+ end
54
+ i
55
+ end
56
+
57
+ def type
58
+ @type ||= (name.sub /.*::/, "").to_sym
59
+ end
60
+
61
+ end
62
+
63
+ attr_reader :index, :client
64
+
65
+ def initialize index, client
66
+ @index, @client = index, client
67
+ end
68
+
69
+ def type
70
+ self.class.type
71
+ end
72
+
73
+ def inspect
74
+ "#<#{self.class}:#{self.object_id} #@index>"
75
+ end
76
+
77
+ # Neovim packs it twice.
78
+ TRANSFER = MPLight::Types.new
79
+ TRANSFER.extend MPLight::Packer, MPLight::Unpacker
80
+ def to_mpdata packer = nil
81
+ b = MPLight::BufferIO.new
82
+ TRANSFER.do_output b do TRANSFER.put @index end
83
+ b.data
84
+ end
85
+ class <<self
86
+ def from_mpdata data, client
87
+ b = MPLight::BufferIO.new data
88
+ index = TRANSFER.do_input b do TRANSFER.get end
89
+ new index, client
90
+ end
91
+ end
92
+
93
+ def == other
94
+ (other.class.equal? self.class) && @index == other.index && @client == other.client
95
+ end
96
+
97
+
98
+ def call_api name, *args, &block
99
+ @client.call_api name, *args, &block
100
+ end
101
+
102
+ def call_obj name, *args, &block
103
+ @client.call_obj self, name, *args, &block
104
+ end
105
+
106
+
107
+ def method_missing sym, *args
108
+ call_obj sym, *args
109
+ rescue UnknownApiObjectFunction
110
+ super
111
+ end
112
+
113
+ def respond_to_missing? sym, priv = nil
114
+ @client.has_obj_function? self, sym
115
+ end
116
+
117
+ def methods regular = true
118
+ s = super
119
+ s |= @client.obj_functions self if regular
120
+ s
121
+ end
122
+
123
+ include OptionAccess
124
+
125
+ end
126
+
127
+
128
+
129
+ class Buffer < RemoteObject
130
+
131
+ # Functions as described in ":h ruby"
132
+
133
+ def name ; call_obj :get_name ; end
134
+ def number ; call_obj :get_number ; end
135
+
136
+ def count ; call_obj :line_count ; end
137
+ alias length count
138
+
139
+ def [] pos = nil, len = nil
140
+ line_indices pos, len do |fst,lst|
141
+ get_lines fst, lst, false
142
+ end
143
+ end
144
+
145
+ def []= pos = nil, len = nil, str
146
+ line_indices pos, len do |fst,lst|
147
+ set_lines fst, lst, false, (str_lines str)
148
+ end
149
+ self
150
+ end
151
+
152
+ def delete pos, len = nil ; self[pos, len] = nil ; end
153
+
154
+ def insert pos = nil, str
155
+ self[ pos||0, 0] = str
156
+ end
157
+
158
+ def append pos = nil, str
159
+ p = (pos||0) + 1
160
+ insert p, str
161
+ end
162
+
163
+
164
+ # Legacy functions
165
+
166
+ def line
167
+ call_api :get_current_line if active?
168
+ end
169
+
170
+ def line= str
171
+ raise "Buffer not active. Use Buffer#[]= instead." unless active?
172
+ call_api :set_current_line, str
173
+ end
174
+
175
+ def line_number
176
+ (call_api :get_current_win).line if active?
177
+ end
178
+
179
+
180
+ def active?
181
+ (call_api :get_current_buf).index == @index
182
+ end
183
+
184
+
185
+ OPTION_PARAM = :buf
186
+
187
+
188
+ # Iterating functions
189
+
190
+ include Enumerable
191
+
192
+ def each pos = nil, len = nil, &block
193
+ iter_chunks pos, len do |fst,nxt|
194
+ (get_lines fst, nxt, true).each &block
195
+ end
196
+ end
197
+
198
+ def map! pos = nil, len = nil, &block
199
+ iter_chunks pos, len do |fst,nxt|
200
+ l = (get_lines fst, nxt, true).map &block
201
+ set_lines fst, nxt, true, l
202
+ end
203
+ end
204
+
205
+ def select! pos = nil, len = nil, &block
206
+ line_indices_positive pos, len do |fst,lst|
207
+ while fst < lst do
208
+ l, = get_lines fst, fst+1, true
209
+ if yield l then
210
+ fst += 1
211
+ else
212
+ set_lines fst, fst+1, true, []
213
+ lst -= 1
214
+ end
215
+ end
216
+ end
217
+ end
218
+
219
+ def reject! pos = nil, len = nil, &block
220
+ select! pos, len do |l| !yield l end
221
+ end
222
+
223
+
224
+ # Don't run into `method_missing`.
225
+ def get_lines fst, lst, strict ; call_obj :get_lines, fst, lst, strict ; end
226
+ def set_lines fst, lst, strict, ary ; call_obj :set_lines, fst, lst, strict, ary ; end
227
+
228
+
229
+ private
230
+
231
+ def line_indices pos, len
232
+ if Range === pos then
233
+ r = pos
234
+ pos, lst = r.begin, r.end
235
+ lst += 1 unless r.exclude_end?
236
+ elsif pos.nil? then
237
+ pos, lst = 1, 0
238
+ else
239
+ lst = pos+1
240
+ end
241
+ if len then
242
+ lst = pos + (len >= 0 ? len : 0)
243
+ end
244
+ lst = 0 if pos < 0 and lst >= 0
245
+ yield pos-1, lst-1
246
+ end
247
+
248
+ def line_indices_positive pos, len
249
+ line_indices pos, len do |*fl|
250
+ c = nil
251
+ fl.map! { |y|
252
+ if y >= 0 then
253
+ y
254
+ else
255
+ y + 1 + (c ||= count)
256
+ end
257
+ }
258
+ yield *fl
259
+ end
260
+ end
261
+
262
+ @chunk = 1024 # Attention! Each chunk is its own undo level.
263
+ class <<self
264
+ attr_accessor :chunk
265
+ end
266
+
267
+ def iter_chunks pos, len
268
+ line_indices_positive pos, len do |fst,lst|
269
+ while lst do
270
+ nxt = fst + self.class.chunk
271
+ if nxt > lst then
272
+ nxt, lst = lst, nil
273
+ end
274
+ yield fst, nxt
275
+ fst = nxt
276
+ end
277
+ end
278
+ end
279
+
280
+ def str_lines str
281
+ if Array === str then
282
+ str
283
+ elsif str.nil? then
284
+ []
285
+ else
286
+ str.lines.each { |l| l.chomp! }
287
+ end
288
+ end
289
+
290
+ end
291
+
292
+
293
+ class Window < RemoteObject
294
+
295
+ def number ; call_obj :get_number ; end
296
+
297
+ def buffer ; call_obj :get_buf ; end
298
+
299
+ def height ; call_obj :get_height ; end
300
+ def height= n ; call_obj :set_height, n ; end
301
+
302
+ def width ; call_obj :get_width ; end
303
+ def width= n ; call_obj :set_width, n ; end
304
+
305
+ def line ; cursor.first ; end
306
+
307
+ def cursor ; call_obj :get_cursor ; end
308
+ def cursor= yx ; call_obj :set_cursor, yx ; end
309
+
310
+ def save_cursor
311
+ c = cursor
312
+ yield
313
+ self.cursor = c
314
+ end
315
+
316
+ OPTION_PARAM = :win
317
+
318
+ end
319
+
320
+
321
+ class Tabpage < RemoteObject
322
+
323
+ def number ; call_obj :get_number ; end
324
+
325
+ # There is currently only one tabpage-local option, 'cmdheight'.
326
+ OPTION_PARAM = :tab # Neovim is missing this.
327
+
328
+ end
329
+
330
+ end
331
+
@@ -0,0 +1,372 @@
1
+ #
2
+ # neovim/ruby_provider.rb -- Plugin for :ruby* commands
3
+ #
4
+
5
+ require "neovim/handler"
6
+ require "neovim/remote_object"
7
+
8
+
9
+ class Object
10
+ # Poor, poor RubyGems is polluting the global namespace.
11
+ # see <https://github.com/rubygems/rubygems/pull/7200>
12
+ def empty_binding
13
+ binding
14
+ end
15
+ end
16
+
17
+
18
+ # The VIM module as documented in ":h ruby".
19
+ module Vim
20
+
21
+ class Buffer < ::Neovim::Buffer
22
+ class <<self
23
+ def current ; $vim.get_current_buf ; end
24
+ def count ; $vim.list_bufs.size ; end
25
+ def [] i ; $vim.list_bufs[ i] ; end
26
+ end
27
+ end
28
+
29
+ class Window < ::Neovim::Window
30
+ class <<self
31
+ def current ; $vim.get_current_win ; end
32
+ def count ; $vim.get_current_tabpage.list_wins.size ; end
33
+ def [] i ; $vim.get_current_tabpage.list_wins[ i] ; end
34
+ end
35
+ end
36
+
37
+ class <<self
38
+ def message str ; $vim.message str ; end
39
+ def set_option *args, **kwargs ; $vim.set_option *args, **kwargs ; end
40
+ alias set_options set_option
41
+ def command arg ; $vim.command arg ; end
42
+ def evaluate expr ; $vim.evaluate expr ; end
43
+ end
44
+
45
+ ::VIM = self
46
+
47
+ end
48
+
49
+
50
+
51
+
52
+ module Neovim
53
+
54
+ class Write
55
+ class <<self
56
+ def open client
57
+ i = new client
58
+ yield i
59
+ ensure
60
+ i.finish
61
+ end
62
+ end
63
+ def initialize client
64
+ @client = client
65
+ end
66
+ def print *args
67
+ args.each { |a| write a.to_s }
68
+ nil
69
+ end
70
+ def puts *args
71
+ args.each { |a|
72
+ a = a.to_s
73
+ write a
74
+ write "\n" unless a.end_with? $/
75
+ }
76
+ nil
77
+ end
78
+ def flush
79
+ end
80
+ end
81
+
82
+ class WriteStd < Write
83
+ class <<self
84
+ def redirect client
85
+ open client do |i|
86
+ old, $stdout = $stdout, i
87
+ yield
88
+ ensure
89
+ $stdout = old
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ class WriteOut < WriteStd
96
+ def write *args
97
+ args.each { |a|
98
+ a.notempty? or next
99
+ @client.out_write a
100
+ @line_open = !(a.end_with? $/)
101
+ }
102
+ nil
103
+ end
104
+ def finish
105
+ if @line_open then
106
+ @client.out_write $/
107
+ @line_open = nil
108
+ end
109
+ end
110
+ end
111
+
112
+ class WriteErr < Write
113
+ class <<self
114
+ def redirect client
115
+ open client do |i|
116
+ old, $stderr = $stderr, i
117
+ yield
118
+ ensure
119
+ $stderr = old
120
+ end
121
+ end
122
+ end
123
+ def write *args
124
+ args.each { |a|
125
+ @rest ||= ""
126
+ @rest << a
127
+ while @rest =~ /#$// do
128
+ @client.err_writeln $`
129
+ @rest = $'
130
+ end
131
+ }
132
+ nil
133
+ end
134
+ def finish
135
+ if @rest.notempty? then
136
+ @client.err_writeln @rest
137
+ @rest = nil
138
+ end
139
+ end
140
+ end
141
+
142
+ class WriteBuf < WriteStd
143
+ def write *args
144
+ s = @rest||""
145
+ args.each { |a|
146
+ s << a
147
+ }
148
+ s = s.split $/, -1
149
+ @rest = s.pop
150
+ @client.put s, "l", true, false
151
+ nil
152
+ end
153
+ def finish
154
+ if @rest.notempty? then
155
+ @client.put [@rest], "l", true, false
156
+ @rest = nil
157
+ end
158
+ end
159
+ end
160
+
161
+
162
+ class DslProvider < DslBase
163
+
164
+ TYPE = :script
165
+
166
+ def setup &block
167
+ add_setup_block &block
168
+ end
169
+
170
+ def setup_autocmd event, fn, *args
171
+ add_setup_block do |client|
172
+ a = [ client.channel_id, "'#{fn}'", *args].join ", "
173
+ client.command "autocmd #{event} * call rpcrequest(#{a})"
174
+ end
175
+ end
176
+
177
+ def updater name, &block
178
+ add_handler nil, name, &block
179
+ end
180
+
181
+ def rpc name
182
+ add_handler nil, name do |client,*args|
183
+ WriteOut.redirect client do
184
+ WriteErr.redirect client do
185
+ yield client, *args
186
+ end
187
+ end
188
+ rescue ScriptError, StandardError
189
+ line = $@.first[ /:(\d+):/, 1]
190
+ client.err_writeln "Ruby #$! (#{$!.class}), line #{line}"
191
+ end
192
+ end
193
+
194
+ end
195
+
196
+ class <<self
197
+
198
+ def set_global_client client
199
+ $vim = client
200
+ yield
201
+ ensure
202
+ $vim = nil
203
+ end
204
+
205
+ def set_globals client, range
206
+ set_global_client client do
207
+ lines = get_lines client, range
208
+ $range, $lines = range, lines
209
+ yield lines
210
+ end
211
+ ensure
212
+ $range, $lines = nil, nil
213
+ end
214
+
215
+ def get_lines client, range
216
+ client.buf_get_lines 0, range.begin-1, range.end, true
217
+ end
218
+
219
+ def plugin_provider &block
220
+ run_dsl DslProvider, &block
221
+ end
222
+
223
+ def build_sum lines
224
+ require "bigdecimal"
225
+ sum = BigDecimal 0
226
+ prev, decs = 0, 0
227
+ sep = "."
228
+ lines.each { |l|
229
+ l.slice! /^.*:/
230
+ l.slice! /#.*/
231
+ l = l.split /(?:\+\s+|\|)/
232
+ l.map! { |m|
233
+ m.strip!
234
+ if m =~ %r/ *%\z/ then
235
+ prev * (BigDecimal $`) / 100
236
+ else
237
+ m = m.split "*"
238
+ m.map! { |n|
239
+ n.sub! /,/ do sep = $& ; "." end
240
+ n.sub! /\.(?:-+|([0-9]+))/ do
241
+ if $1 then
242
+ d = $1.length
243
+ decs = d if decs < d
244
+ ".#$1"
245
+ else
246
+ decs = 2
247
+ nil
248
+ end
249
+ end
250
+ BigDecimal n
251
+ }
252
+ prev = m.inject do |p,e| p*e end
253
+ end
254
+ }
255
+ sum = l.inject sum do |s,e| s+e end
256
+ }
257
+ sum = sum.round decs
258
+ case sum
259
+ when BigDecimal then
260
+ sum = sum.to_s "F"
261
+ sum.sub! /(?:\.([0-9]+))?\z/ do
262
+ sep + ($1.to_s.ljust decs, "0")
263
+ end
264
+ when Integer then
265
+ sum = sum.to_s
266
+ end
267
+ sum
268
+ end
269
+
270
+ end
271
+
272
+ plugin_provider do |dsl|
273
+
274
+ dsl.setup do |client|
275
+ $curbuf = client.get_current_buf
276
+ $curwin = client.get_current_win
277
+ end
278
+
279
+ dsl.setup_autocmd :BufEnter, "ruby_bufenter"
280
+ dsl.updater :ruby_bufenter do |client|
281
+ $curbuf = client.get_current_buf
282
+ end
283
+
284
+ dsl.setup_autocmd :WinEnter, "ruby_winenter"
285
+ dsl.updater :ruby_winenter do |client|
286
+ $curbuf = client.get_current_buf
287
+ $curwin = client.get_current_win
288
+ end
289
+
290
+ dsl.setup_autocmd :DirChanged, "ruby_chdir", "v:event"
291
+ dsl.updater :ruby_chdir do |_,event|
292
+ Dir.chdir event[ "cwd"]
293
+ end
294
+
295
+
296
+ script_binding = TOPLEVEL_BINDING.eval "empty_binding"
297
+
298
+ # This is called by the +:ruby+ command.
299
+ dsl.rpc :ruby_execute do |client,code,fst,lst|
300
+ code.rstrip!
301
+ if !code.notempty? or code == "|" then # Workaround because Neovim doesn't allow empty code (the ultimate Quine)
302
+ set_global_client client do
303
+ client.command "#{lst}"
304
+ code = (get_lines client, fst..lst).join "\n"
305
+ WriteBuf.redirect client do
306
+ r = script_binding.eval code, "ruby_run"
307
+ r.nil? or puts "#=> #{r.inspect}"
308
+ end
309
+ end
310
+ elsif code == "+" then
311
+ client.command "#{lst}"
312
+ set_globals client, fst..lst do |lines|
313
+ WriteBuf.redirect client do
314
+ s = build_sum lines
315
+ puts "-"*(s.length + 4)
316
+ puts s
317
+ rescue
318
+ puts "Error: #$! (#{$!.class})"
319
+ end
320
+ end
321
+ else
322
+ set_globals client, fst..lst do ||
323
+ script_binding.eval code, "ruby_execute"
324
+ end
325
+ end
326
+ nil
327
+ end
328
+
329
+ # This is called by the +:rubyfile+ command.
330
+ dsl.rpc :ruby_execute_file do |client,path,fst,lst|
331
+ set_globals client, fst..lst do ||
332
+ r = File.read path
333
+ script_binding.eval r, "ruby_file #{path}"
334
+ end
335
+ nil
336
+ end
337
+
338
+ # This is called by the +:rubydo+ command.
339
+ dsl.rpc :ruby_do_range do |client,fst,lst,code|
340
+ set_globals client, fst..lst do |lines|
341
+ i = fst
342
+ lines.each do |l|
343
+ h = l.hash
344
+ (script_binding.eval 'proc do |l,i| $_, $. = l, i end').call l, i
345
+ script_binding.eval code, "ruby_do_range"
346
+ m = script_binding.eval '$_'
347
+ if m.hash != h then
348
+ m = m.lines
349
+ m.each { |x| x.chomp! }
350
+ client.buf_set_lines 0, i-1, i, true, m
351
+ i += m.length
352
+ else
353
+ i += 1
354
+ end
355
+ end
356
+ end
357
+ nil
358
+ ensure
359
+ script_binding.eval '$_, $. = nil, 0'
360
+ end
361
+
362
+ # This is called by the +rubyeval()+ function.
363
+ dsl.rpc :ruby_eval do |client,code|
364
+ set_global_client client do
365
+ script_binding.eval code, "ruby_eval"
366
+ end
367
+ end
368
+
369
+ end
370
+
371
+ end
372
+