nvim 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,142 @@
1
+ #
2
+ # neovim/output.rb -- Output to Neovim
3
+ #
4
+
5
+
6
+ module Neovim
7
+
8
+ class Write
9
+ class <<self
10
+ def open *args, **kwargs
11
+ i = new *args, **kwargs
12
+ yield i
13
+ ensure
14
+ i.finish
15
+ end
16
+ end
17
+ def initialize client, *rest
18
+ @client = client
19
+ end
20
+ def << arg
21
+ write arg.to_s
22
+ self
23
+ end
24
+ def print *args
25
+ args.each { |a| write a.to_s }
26
+ nil
27
+ end
28
+ def puts *args
29
+ if args.empty? then
30
+ write $/
31
+ else
32
+ args.each { |a|
33
+ case a
34
+ when Array then
35
+ a.each { |e|
36
+ puts e
37
+ }
38
+ else
39
+ a = a.to_s
40
+ write a
41
+ write $/ unless a.end_with? $/
42
+ end
43
+ }
44
+ end
45
+ nil
46
+ end
47
+ def flush
48
+ end
49
+ end
50
+
51
+ class WriteStd < Write
52
+ class <<self
53
+ def redirect *args, **kwargs
54
+ open *args, **kwargs do |i|
55
+ old, $stdout = $stdout, i
56
+ yield
57
+ ensure
58
+ $stdout = old
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ class WriteOut < WriteStd
65
+ def write *args
66
+ args.each { |a|
67
+ a = a.to_s
68
+ a.notempty? or next
69
+ @client.out_write a
70
+ @line_open = !(a.end_with? $/)
71
+ }
72
+ nil
73
+ end
74
+ def finish
75
+ if @line_open then
76
+ @client.out_write $/
77
+ @line_open = nil
78
+ end
79
+ end
80
+ end
81
+
82
+ class WriteErr < Write
83
+ class <<self
84
+ def redirect *args, **kwargs
85
+ open *args, **kwargs do |i|
86
+ old, $stderr = $stderr, i
87
+ yield
88
+ ensure
89
+ $stderr = old
90
+ end
91
+ end
92
+ end
93
+ def write *args
94
+ args.each { |a|
95
+ @rest ||= ""
96
+ @rest << a.to_s
97
+ while @rest =~ /#$// do
98
+ @client.err_writeln $`
99
+ @rest = $'
100
+ end
101
+ }
102
+ nil
103
+ end
104
+ def finish
105
+ if @rest.notempty? then
106
+ @client.err_writeln @rest
107
+ @rest = nil
108
+ end
109
+ end
110
+ end
111
+
112
+ class WriteBuf < WriteStd
113
+ def initialize *args, whole: nil, top: nil
114
+ super
115
+ @lines, @last = [], ""
116
+ @whole, @top = whole, top
117
+ end
118
+ def write *args
119
+ args.each { |a| @last << a.to_s }
120
+ loop do
121
+ n, r = @last.split $/, 2
122
+ r or break
123
+ @lines.push n
124
+ @last = r
125
+ end
126
+ nil
127
+ end
128
+ def finish
129
+ if @last.notempty? then
130
+ @lines.push @last
131
+ @last = nil
132
+ end
133
+ if @whole then
134
+ @client.buf_set_lines 0, 0, -1, true, @lines
135
+ else
136
+ @client.put @lines, "l", true, !@top
137
+ end
138
+ end
139
+ end
140
+
141
+ end
142
+
data/lib/neovim/remote.rb CHANGED
@@ -1,53 +1,276 @@
1
1
  #
2
- # neovim/remote.rb -- Host for Neovim
2
+ # neovim/remote.rb -- Remote access for Neovim
3
3
  #
4
4
 
5
- require "neovim/session"
6
- require "neovim/handler"
5
+ require "neovim/foreign/supplement"
6
+
7
+ require "neovim/logging"
8
+ require "neovim/connection"
7
9
 
8
10
 
9
11
  module Neovim
10
12
 
11
- class Remote < Session
13
+ class Remote
14
+
15
+ class Message
16
+
17
+ @subs, @subh = [], {}
18
+
19
+ class <<self
20
+
21
+ def from_array ary
22
+ kind, *payload = *ary
23
+ klass = find kind
24
+ klass or raise "No message type for id #{kind.inspect}"
25
+ klass[ *payload]
26
+ end
27
+
28
+ def inherited cls ; @subs.push cls ; end
29
+ def find id
30
+ @subh[ id] ||= @subs.find { |c| c::ID == id }
31
+ end
32
+
33
+ alias [] new
34
+
35
+ end
36
+
37
+ def initialize *args
38
+ z = self.class::KEYS.zip args
39
+ @cont = z.inject Hash.new do |c,(h,k)| c[h] = k ; c end
40
+ end
41
+
42
+ def inspect
43
+ "#<#{self.class.plain_name} #@cont>"
44
+ end
45
+
46
+ def to_s
47
+ j = @cont.map { |k,v| "#{k}:#{v}" if v }.compact.join ","
48
+ "#{self.class.plain_name}(#{j})"
49
+ end
50
+
51
+ def method_missing sym, *args
52
+ if @cont.key? sym then @cont[ sym] else super end
53
+ end
54
+
55
+ def respond_to_missing? sym, priv = nil
56
+ @cont.key? sym.to_sym
57
+ end
58
+
59
+ def methods *args
60
+ super.concat @cont.keys
61
+ end
62
+
63
+ def to_h ; @cont ; end
64
+
65
+ def fields ; @cont.fetch_values *self.class::KEYS ; end
66
+
67
+ def to_a
68
+ [self.class::ID, *fields]
69
+ end
70
+
71
+ class Request < Message
72
+ ID = 0
73
+ KEYS = %i(request_id method_name arguments)
74
+ end
75
+
76
+ class Response < Message
77
+ ID = 1
78
+ KEYS = %i(request_id error value)
79
+ def initialize *args
80
+ super
81
+ e = @cont[ :error]
82
+ if e and not Array === e then
83
+ @cont[ :error] = [0, e]
84
+ end
85
+ end
86
+ end
87
+
88
+ class Notification < Message
89
+ ID = 2
90
+ KEYS = %i(method_name arguments)
91
+ end
92
+
93
+ end
94
+
95
+ class ResponseError < StandardError ; end
96
+
97
+ class Disconnected < RuntimeError ; end
98
+
99
+
100
+ include Logging
12
101
 
13
102
  class <<self
14
103
 
104
+ include Logging
105
+
106
+ private :new
107
+
108
+ def open_conn conntype, *args, **kwargs
109
+ conntype.open_files *args, **kwargs do |conn|
110
+ yield conn
111
+ end
112
+ end
113
+
114
+ public
115
+
116
+ def open conntype, *args, **kwargs
117
+ open_conn conntype, *args, **kwargs do |conn|
118
+ i = new nil, conn
119
+ yield i
120
+ end
121
+ end
122
+
123
+ def start plugins, *args
124
+ open_logfile do
125
+ log :info, "Starting", args: $*
126
+ open_conn *args do |conn|
127
+ i = new plugins, conn
128
+ yield i
129
+ end
130
+ ensure
131
+ log :info, "Leaving"
132
+ end
133
+ end
134
+
15
135
  def start_client *args
16
- start *args do |i|
136
+ start nil, *args do |i|
17
137
  yield i.start
18
138
  end
19
139
  end
20
140
 
21
141
  end
22
142
 
23
- def initialize conn
24
- super
143
+ def initialize plugins, conn
144
+ @conn = conn
145
+ @request_id = 0
146
+ @responses = {}
25
147
  @plugins = {}
148
+ @plugins.update plugins if plugins
26
149
  end
27
150
 
151
+ def client_name
152
+ l = @plugins.values.select { |p| p.type }
153
+ if l.notempty? then
154
+ l.map! { |p| p.type }
155
+ l.uniq!
156
+ name = l.join "-"
157
+ log :info, "Client Name", name: name
158
+ "ruby-#{name}-host"
159
+ else
160
+ "ruby-client"
161
+ end
162
+ end
163
+
164
+ def client_type ; self.class.plain_name.downcase ; end
165
+
166
+ def client_methods
167
+ l = @plugins.values.reject { |p| p.type }
168
+ if l.notempty? then
169
+ r = {}
170
+ l.each { |p| p.options { |name,opts| r[ name] = opts } }
171
+ r
172
+ end
173
+ end
174
+
175
+
28
176
  def start
29
- @conn.start @comm, client_name, self.class.name.downcase.to_sym, client_methods
177
+ @conn.start self
30
178
  @conn.client
31
179
  end
32
180
 
33
- def client_name ; "ruby-client" ; end
34
- def client_methods ; end
181
+ def run until_id = nil
182
+ loop do
183
+ if @deferred and @conn.client then
184
+ d, @deferred = @deferred, nil
185
+ d.each { |p| p.call }
186
+ end
187
+ message = get
188
+ case message
189
+ when Message::Response then
190
+ if @responses.key? message.request_id then
191
+ @responses[ message.request_id] = message
192
+ else
193
+ log :warning, "Dropped response", message.request_id
194
+ end
195
+ when Message::Request, Message::Notification then
196
+ h = find_handler message.method_name
197
+ if h then
198
+ p = proc do
199
+ begin
200
+ log :debug1, "Calling handler", name: message.method_name, args: message.arguments
201
+ r = h.execute @conn.client, *message.arguments
202
+ log :debug1, "Handler result", result: r
203
+ rescue
204
+ e = [ 0, $!.to_s]
205
+ log_exception :error
206
+ end
207
+ put Message::Response[ message.request_id, e, r] if message.respond_to? :request_id
208
+ end
209
+ if @conn.client or not h.needs_client? then
210
+ p.call
211
+ else
212
+ log :info, "Deferred handler for", name: message.method_name
213
+ @deferred ||= []
214
+ @deferred.push p
215
+ end
216
+ else
217
+ if message.respond_to? :request_id then
218
+ put Message::Response[ message.request_id, [0, "No handler #{message.method_name}."], nil]
219
+ end
220
+ end
221
+ end
222
+ break if until_id and @responses[ until_id]
223
+ end
224
+ end
225
+
226
+ def request method, *args
227
+ rid = @request_id = @request_id.succ
228
+ put Message::Request[ rid, method, args]
229
+ @responses[ rid] = nil
230
+ run rid
231
+ r = @responses.delete rid
232
+ if r.error then
233
+ t, e = *r.error
234
+ t = @conn.error t
235
+ raise ResponseError, "#{t}: #{e}"
236
+ end
237
+ r.value
238
+ end
35
239
 
240
+ def notify method, *args
241
+ put Message::Notification[ method, args]
242
+ end
243
+
244
+ private
245
+
246
+ def put msg
247
+ log :debug2, "Sending Message", data: msg
248
+ @conn.put msg.to_a
249
+ self
250
+ rescue Errno::EPIPE
251
+ raise Disconnected, "Broken pipe on write"
252
+ end
36
253
 
37
- def add_plugins source, plugins
38
- @plugins[ source] = plugins
254
+ def get
255
+ IO.select [@conn.input], nil, nil
256
+ raise Disconnected, "EOF on wait" if @conn.eof?
257
+ msg = Message.from_array @conn.get
258
+ log :debug2, "Received Message", data: msg
259
+ msg
260
+ rescue EOFError
261
+ raise Disconnected, "EOF on read"
39
262
  end
40
263
 
41
- def execute_handler name, args
264
+ def find_handler name
42
265
  @plugins.each_value do |plugin|
43
- handler = plugin.get_handler name
44
- if handler then
266
+ h = plugin.get_handler name
267
+ if h then
45
268
  log :info, "Found handler", name: name
46
- log :debug1, "Calling with", args: args
47
- return handler.execute @conn.client, *args
269
+ return h
48
270
  end
49
271
  end
50
- super
272
+ log :error, "No handler found for #{name}."
273
+ nil
51
274
  end
52
275
 
53
276
  end
@@ -55,7 +55,7 @@ module Neovim
55
55
  end
56
56
 
57
57
  def type
58
- @type ||= (name.sub /.*::/, "").to_sym
58
+ @type ||= plain_name.to_sym
59
59
  end
60
60
 
61
61
  end
@@ -231,7 +231,7 @@ module Neovim
231
231
  def line_indices pos, len
232
232
  if Range === pos then
233
233
  r = pos
234
- pos, lst = r.begin, r.end
234
+ pos, lst = r.begin||1, r.end||-1
235
235
  lst += 1 unless r.exclude_end?
236
236
  elsif pos.nil? then
237
237
  pos, lst = 1, 0
@@ -241,7 +241,7 @@ module Neovim
241
241
  if len then
242
242
  lst = pos + (len >= 0 ? len : 0)
243
243
  end
244
- lst = 0 if pos < 0 and lst >= 0
244
+ lst = 0 if pos < 0 and lst > 0
245
245
  yield pos-1, lst-1
246
246
  end
247
247
 
@@ -249,11 +249,11 @@ module Neovim
249
249
  line_indices pos, len do |*fl|
250
250
  c = nil
251
251
  fl.map! { |y|
252
- if y >= 0 then
253
- y
254
- else
255
- y + 1 + (c ||= count)
252
+ unless y >= 0 then
253
+ c ||= count
254
+ y += 1 + c
256
255
  end
256
+ y
257
257
  }
258
258
  yield *fl
259
259
  end
@@ -4,6 +4,7 @@
4
4
 
5
5
  require "neovim/handler"
6
6
  require "neovim/remote_object"
7
+ require "neovim/output"
7
8
 
8
9
 
9
10
  class Object
@@ -51,118 +52,14 @@ end
51
52
 
52
53
  module Neovim
53
54
 
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
55
  class DslProvider < DslBase
163
56
 
164
57
  TYPE = :script
165
58
 
59
+ def initialize source
60
+ super *[]
61
+ end
62
+
166
63
  def setup &block
167
64
  add_setup_block &block
168
65
  end
@@ -220,58 +117,26 @@ module Neovim
220
117
  run_dsl DslProvider, &block
221
118
  end
222
119
 
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
120
  end
271
121
 
272
122
  plugin_provider do |dsl|
273
123
 
274
124
  dsl.setup do |client|
125
+ r = client.get_var "ruby_require" rescue nil
126
+ case r
127
+ when Array then r = r.notempty?
128
+ when nil then nil
129
+ else r = [r]
130
+ end
131
+ if r then
132
+ WriteOut.redirect client do # Protect the RPC interface against erroneous output.
133
+ r.each do |l|
134
+ require l
135
+ rescue LoadError
136
+ client.out_write "Warning: #$!"
137
+ end
138
+ end
139
+ end
275
140
  $curbuf = client.get_current_buf
276
141
  $curwin = client.get_current_win
277
142
  end
@@ -301,19 +166,29 @@ module Neovim
301
166
  if !code.notempty? or code == "|" then # Workaround because Neovim doesn't allow empty code (the ultimate Quine)
302
167
  set_global_client client do
303
168
  client.command "#{lst}"
304
- code = (get_lines client, fst..lst).join "\n"
169
+ code = (get_lines client, fst..lst).join $/
305
170
  WriteBuf.redirect client do
306
171
  r = script_binding.eval code, "ruby_run"
307
- r.nil? or puts "#=> #{r.inspect}"
172
+ unless r.nil? then
173
+ script_binding.local_variable_set :_, r
174
+ puts "#=> #{r.inspect}"
175
+ end
308
176
  end
309
177
  end
310
178
  elsif code == "+" then
311
179
  client.command "#{lst}"
312
180
  set_globals client, fst..lst do |lines|
313
181
  WriteBuf.redirect client do
314
- s = build_sum lines
315
- puts "-"*(s.length + 4)
316
- puts s
182
+ require "neovim/tools/calculator"
183
+ @calc ||= Calculator.new
184
+ @calc.reset!
185
+ w = 0
186
+ lines.each { |l|
187
+ l.length.tap { |g| w = g if g > w }
188
+ @calc.add l
189
+ }
190
+ puts "-"*w
191
+ puts @calc.result
317
192
  rescue
318
193
  puts "Error: #$! (#{$!.class})"
319
194
  end