nvim 1.0.0

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