irb 1.8.2 → 1.9.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 +4 -4
- data/Gemfile +7 -0
- data/README.md +101 -0
- data/Rakefile +2 -2
- data/lib/irb/cmd/irb_info.rb +1 -0
- data/lib/irb/completion.rb +43 -22
- data/lib/irb/context.rb +39 -2
- data/lib/irb/easter-egg.rb +16 -6
- data/lib/irb/init.rb +41 -0
- data/lib/irb/input-method.rb +29 -8
- data/lib/irb/lc/help-message +3 -0
- data/lib/irb/lc/ja/help-message +3 -0
- data/lib/irb/ruby_logo.aa +43 -0
- data/lib/irb/type_completion/completor.rb +235 -0
- data/lib/irb/type_completion/methods.rb +13 -0
- data/lib/irb/type_completion/scope.rb +412 -0
- data/lib/irb/type_completion/type_analyzer.rb +1169 -0
- data/lib/irb/type_completion/types.rb +426 -0
- data/lib/irb/version.rb +2 -2
- data/lib/irb.rb +83 -127
- data/man/irb.1 +7 -0
- metadata +8 -3
@@ -0,0 +1,426 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'methods'
|
4
|
+
|
5
|
+
module IRB
|
6
|
+
module TypeCompletion
|
7
|
+
module Types
|
8
|
+
OBJECT_TO_TYPE_SAMPLE_SIZE = 50
|
9
|
+
|
10
|
+
singleton_class.attr_reader :rbs_builder, :rbs_load_error
|
11
|
+
|
12
|
+
def self.preload_in_thread
|
13
|
+
return if @preload_started
|
14
|
+
|
15
|
+
@preload_started = true
|
16
|
+
Thread.new do
|
17
|
+
load_rbs_builder
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.load_rbs_builder
|
22
|
+
require 'rbs'
|
23
|
+
require 'rbs/cli'
|
24
|
+
loader = RBS::CLI::LibraryOptions.new.loader
|
25
|
+
loader.add path: Pathname('sig')
|
26
|
+
@rbs_builder = RBS::DefinitionBuilder.new env: RBS::Environment.from_loader(loader).resolve_type_names
|
27
|
+
rescue LoadError, StandardError => e
|
28
|
+
@rbs_load_error = e
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.class_name_of(klass)
|
33
|
+
klass = klass.superclass if klass.singleton_class?
|
34
|
+
Methods::MODULE_NAME_METHOD.bind_call klass
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.rbs_search_method(klass, method_name, singleton)
|
38
|
+
klass.ancestors.each do |ancestor|
|
39
|
+
name = class_name_of ancestor
|
40
|
+
next unless name && rbs_builder
|
41
|
+
type_name = RBS::TypeName(name).absolute!
|
42
|
+
definition = (singleton ? rbs_builder.build_singleton(type_name) : rbs_builder.build_instance(type_name)) rescue nil
|
43
|
+
method = definition.methods[method_name] if definition
|
44
|
+
return method if method
|
45
|
+
end
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.method_return_type(type, method_name)
|
50
|
+
receivers = type.types.map do |t|
|
51
|
+
case t
|
52
|
+
in SingletonType
|
53
|
+
[t, t.module_or_class, true]
|
54
|
+
in InstanceType
|
55
|
+
[t, t.klass, false]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
types = receivers.flat_map do |receiver_type, klass, singleton|
|
59
|
+
method = rbs_search_method klass, method_name, singleton
|
60
|
+
next [] unless method
|
61
|
+
method.method_types.map do |method|
|
62
|
+
from_rbs_type(method.type.return_type, receiver_type, {})
|
63
|
+
end
|
64
|
+
end
|
65
|
+
UnionType[*types]
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.rbs_methods(type, method_name, args_types, kwargs_type, has_block)
|
69
|
+
return [] unless rbs_builder
|
70
|
+
|
71
|
+
receivers = type.types.map do |t|
|
72
|
+
case t
|
73
|
+
in SingletonType
|
74
|
+
[t, t.module_or_class, true]
|
75
|
+
in InstanceType
|
76
|
+
[t, t.klass, false]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
has_splat = args_types.include?(nil)
|
80
|
+
methods_with_score = receivers.flat_map do |receiver_type, klass, singleton|
|
81
|
+
method = rbs_search_method klass, method_name, singleton
|
82
|
+
next [] unless method
|
83
|
+
method.method_types.map do |method_type|
|
84
|
+
score = 0
|
85
|
+
score += 2 if !!method_type.block == has_block
|
86
|
+
reqs = method_type.type.required_positionals
|
87
|
+
opts = method_type.type.optional_positionals
|
88
|
+
rest = method_type.type.rest_positionals
|
89
|
+
trailings = method_type.type.trailing_positionals
|
90
|
+
keyreqs = method_type.type.required_keywords
|
91
|
+
keyopts = method_type.type.optional_keywords
|
92
|
+
keyrest = method_type.type.rest_keywords
|
93
|
+
args = args_types
|
94
|
+
if kwargs_type&.any? && keyreqs.empty? && keyopts.empty? && keyrest.nil?
|
95
|
+
kw_value_type = UnionType[*kwargs_type.values]
|
96
|
+
args += [InstanceType.new(Hash, K: SYMBOL, V: kw_value_type)]
|
97
|
+
end
|
98
|
+
if has_splat
|
99
|
+
score += 1 if args.count(&:itself) <= reqs.size + opts.size + trailings.size
|
100
|
+
elsif reqs.size + trailings.size <= args.size && (rest || args.size <= reqs.size + opts.size + trailings.size)
|
101
|
+
score += 2
|
102
|
+
centers = args[reqs.size...-trailings.size]
|
103
|
+
given = args.first(reqs.size) + centers.take(opts.size) + args.last(trailings.size)
|
104
|
+
expected = (reqs + opts.take(centers.size) + trailings).map(&:type)
|
105
|
+
if rest
|
106
|
+
given << UnionType[*centers.drop(opts.size)]
|
107
|
+
expected << rest.type
|
108
|
+
end
|
109
|
+
if given.any?
|
110
|
+
score += given.zip(expected).count do |t, e|
|
111
|
+
e = from_rbs_type e, receiver_type
|
112
|
+
intersect?(t, e) || (intersect?(STRING, e) && t.methods.include?(:to_str)) || (intersect?(INTEGER, e) && t.methods.include?(:to_int)) || (intersect?(ARRAY, e) && t.methods.include?(:to_ary))
|
113
|
+
end.fdiv(given.size)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
[[method_type, given || [], expected || []], score]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
max_score = methods_with_score.map(&:last).max
|
120
|
+
methods_with_score.select { _2 == max_score }.map(&:first)
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.intersect?(a, b)
|
124
|
+
atypes = a.types.group_by(&:class)
|
125
|
+
btypes = b.types.group_by(&:class)
|
126
|
+
if atypes[SingletonType] && btypes[SingletonType]
|
127
|
+
aa, bb = [atypes, btypes].map {|types| types[SingletonType].map(&:module_or_class) }
|
128
|
+
return true if (aa & bb).any?
|
129
|
+
end
|
130
|
+
|
131
|
+
aa, bb = [atypes, btypes].map {|types| (types[InstanceType] || []).map(&:klass) }
|
132
|
+
(aa.flat_map(&:ancestors) & bb).any?
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.type_from_object(object)
|
136
|
+
case object
|
137
|
+
when Array
|
138
|
+
InstanceType.new Array, { Elem: union_type_from_objects(object) }
|
139
|
+
when Hash
|
140
|
+
InstanceType.new Hash, { K: union_type_from_objects(object.keys), V: union_type_from_objects(object.values) }
|
141
|
+
when Module
|
142
|
+
SingletonType.new object
|
143
|
+
else
|
144
|
+
klass = Methods::OBJECT_SINGLETON_CLASS_METHOD.bind_call(object) rescue Methods::OBJECT_CLASS_METHOD.bind_call(object)
|
145
|
+
InstanceType.new klass
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.union_type_from_objects(objects)
|
150
|
+
values = objects.size <= OBJECT_TO_TYPE_SAMPLE_SIZE ? objects : objects.sample(OBJECT_TO_TYPE_SAMPLE_SIZE)
|
151
|
+
klasses = values.map { Methods::OBJECT_CLASS_METHOD.bind_call(_1) }
|
152
|
+
UnionType[*klasses.uniq.map { InstanceType.new _1 }]
|
153
|
+
end
|
154
|
+
|
155
|
+
class SingletonType
|
156
|
+
attr_reader :module_or_class
|
157
|
+
def initialize(module_or_class)
|
158
|
+
@module_or_class = module_or_class
|
159
|
+
end
|
160
|
+
def transform() = yield(self)
|
161
|
+
def methods() = @module_or_class.methods
|
162
|
+
def all_methods() = methods | Kernel.methods
|
163
|
+
def constants() = @module_or_class.constants
|
164
|
+
def types() = [self]
|
165
|
+
def nillable?() = false
|
166
|
+
def nonnillable() = self
|
167
|
+
def inspect
|
168
|
+
"#{module_or_class}.itself"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
class InstanceType
|
173
|
+
attr_reader :klass, :params
|
174
|
+
def initialize(klass, params = {})
|
175
|
+
@klass = klass
|
176
|
+
@params = params
|
177
|
+
end
|
178
|
+
def transform() = yield(self)
|
179
|
+
def methods() = rbs_methods.select { _2.public? }.keys | @klass.instance_methods
|
180
|
+
def all_methods() = rbs_methods.keys | @klass.instance_methods | @klass.private_instance_methods
|
181
|
+
def constants() = []
|
182
|
+
def types() = [self]
|
183
|
+
def nillable?() = (@klass == NilClass)
|
184
|
+
def nonnillable() = self
|
185
|
+
def rbs_methods
|
186
|
+
name = Types.class_name_of(@klass)
|
187
|
+
return {} unless name && Types.rbs_builder
|
188
|
+
|
189
|
+
type_name = RBS::TypeName(name).absolute!
|
190
|
+
Types.rbs_builder.build_instance(type_name).methods rescue {}
|
191
|
+
end
|
192
|
+
def inspect
|
193
|
+
if params.empty?
|
194
|
+
inspect_without_params
|
195
|
+
else
|
196
|
+
params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]"
|
197
|
+
"#{inspect_without_params}#{params_string}"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
def inspect_without_params
|
201
|
+
if klass == NilClass
|
202
|
+
'nil'
|
203
|
+
elsif klass == TrueClass
|
204
|
+
'true'
|
205
|
+
elsif klass == FalseClass
|
206
|
+
'false'
|
207
|
+
else
|
208
|
+
klass.singleton_class? ? klass.superclass.to_s : klass.to_s
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
NIL = InstanceType.new NilClass
|
214
|
+
OBJECT = InstanceType.new Object
|
215
|
+
TRUE = InstanceType.new TrueClass
|
216
|
+
FALSE = InstanceType.new FalseClass
|
217
|
+
SYMBOL = InstanceType.new Symbol
|
218
|
+
STRING = InstanceType.new String
|
219
|
+
INTEGER = InstanceType.new Integer
|
220
|
+
RANGE = InstanceType.new Range
|
221
|
+
REGEXP = InstanceType.new Regexp
|
222
|
+
FLOAT = InstanceType.new Float
|
223
|
+
RATIONAL = InstanceType.new Rational
|
224
|
+
COMPLEX = InstanceType.new Complex
|
225
|
+
ARRAY = InstanceType.new Array
|
226
|
+
HASH = InstanceType.new Hash
|
227
|
+
CLASS = InstanceType.new Class
|
228
|
+
MODULE = InstanceType.new Module
|
229
|
+
PROC = InstanceType.new Proc
|
230
|
+
|
231
|
+
class UnionType
|
232
|
+
attr_reader :types
|
233
|
+
|
234
|
+
def initialize(*types)
|
235
|
+
@types = []
|
236
|
+
singletons = []
|
237
|
+
instances = {}
|
238
|
+
collect = -> type do
|
239
|
+
case type
|
240
|
+
in UnionType
|
241
|
+
type.types.each(&collect)
|
242
|
+
in InstanceType
|
243
|
+
params = (instances[type.klass] ||= {})
|
244
|
+
type.params.each do |k, v|
|
245
|
+
(params[k] ||= []) << v
|
246
|
+
end
|
247
|
+
in SingletonType
|
248
|
+
singletons << type
|
249
|
+
end
|
250
|
+
end
|
251
|
+
types.each(&collect)
|
252
|
+
@types = singletons.uniq + instances.map do |klass, params|
|
253
|
+
InstanceType.new(klass, params.transform_values { |v| UnionType[*v] })
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def transform(&block)
|
258
|
+
UnionType[*types.map(&block)]
|
259
|
+
end
|
260
|
+
|
261
|
+
def nillable?
|
262
|
+
types.any?(&:nillable?)
|
263
|
+
end
|
264
|
+
|
265
|
+
def nonnillable
|
266
|
+
UnionType[*types.reject { _1.is_a?(InstanceType) && _1.klass == NilClass }]
|
267
|
+
end
|
268
|
+
|
269
|
+
def self.[](*types)
|
270
|
+
type = new(*types)
|
271
|
+
if type.types.empty?
|
272
|
+
OBJECT
|
273
|
+
elsif type.types.size == 1
|
274
|
+
type.types.first
|
275
|
+
else
|
276
|
+
type
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def methods() = @types.flat_map(&:methods).uniq
|
281
|
+
def all_methods() = @types.flat_map(&:all_methods).uniq
|
282
|
+
def constants() = @types.flat_map(&:constants).uniq
|
283
|
+
def inspect() = @types.map(&:inspect).join(' | ')
|
284
|
+
end
|
285
|
+
|
286
|
+
BOOLEAN = UnionType[TRUE, FALSE]
|
287
|
+
|
288
|
+
def self.array_of(*types)
|
289
|
+
type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
|
290
|
+
InstanceType.new Array, Elem: type
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.from_rbs_type(return_type, self_type, extra_vars = {})
|
294
|
+
case return_type
|
295
|
+
when RBS::Types::Bases::Self
|
296
|
+
self_type
|
297
|
+
when RBS::Types::Bases::Bottom, RBS::Types::Bases::Nil
|
298
|
+
NIL
|
299
|
+
when RBS::Types::Bases::Any, RBS::Types::Bases::Void
|
300
|
+
OBJECT
|
301
|
+
when RBS::Types::Bases::Class
|
302
|
+
self_type.transform do |type|
|
303
|
+
case type
|
304
|
+
in SingletonType
|
305
|
+
InstanceType.new(self_type.module_or_class.is_a?(Class) ? Class : Module)
|
306
|
+
in InstanceType
|
307
|
+
SingletonType.new type.klass
|
308
|
+
end
|
309
|
+
end
|
310
|
+
UnionType[*types]
|
311
|
+
when RBS::Types::Bases::Bool
|
312
|
+
BOOLEAN
|
313
|
+
when RBS::Types::Bases::Instance
|
314
|
+
self_type.transform do |type|
|
315
|
+
if type.is_a?(SingletonType) && type.module_or_class.is_a?(Class)
|
316
|
+
InstanceType.new type.module_or_class
|
317
|
+
else
|
318
|
+
OBJECT
|
319
|
+
end
|
320
|
+
end
|
321
|
+
when RBS::Types::Union
|
322
|
+
UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
|
323
|
+
when RBS::Types::Proc
|
324
|
+
PROC
|
325
|
+
when RBS::Types::Tuple
|
326
|
+
elem = UnionType[*return_type.types.map { from_rbs_type _1, self_type, extra_vars }]
|
327
|
+
InstanceType.new Array, Elem: elem
|
328
|
+
when RBS::Types::Record
|
329
|
+
InstanceType.new Hash, K: SYMBOL, V: OBJECT
|
330
|
+
when RBS::Types::Literal
|
331
|
+
InstanceType.new return_type.literal.class
|
332
|
+
when RBS::Types::Variable
|
333
|
+
if extra_vars.key? return_type.name
|
334
|
+
extra_vars[return_type.name]
|
335
|
+
elsif self_type.is_a? InstanceType
|
336
|
+
self_type.params[return_type.name] || OBJECT
|
337
|
+
elsif self_type.is_a? UnionType
|
338
|
+
types = self_type.types.filter_map do |t|
|
339
|
+
t.params[return_type.name] if t.is_a? InstanceType
|
340
|
+
end
|
341
|
+
UnionType[*types]
|
342
|
+
else
|
343
|
+
OBJECT
|
344
|
+
end
|
345
|
+
when RBS::Types::Optional
|
346
|
+
UnionType[from_rbs_type(return_type.type, self_type, extra_vars), NIL]
|
347
|
+
when RBS::Types::Alias
|
348
|
+
case return_type.name.name
|
349
|
+
when :int
|
350
|
+
INTEGER
|
351
|
+
when :boolish
|
352
|
+
BOOLEAN
|
353
|
+
when :string
|
354
|
+
STRING
|
355
|
+
else
|
356
|
+
# TODO: ???
|
357
|
+
OBJECT
|
358
|
+
end
|
359
|
+
when RBS::Types::Interface
|
360
|
+
# unimplemented
|
361
|
+
OBJECT
|
362
|
+
when RBS::Types::ClassInstance
|
363
|
+
klass = return_type.name.to_namespace.path.reduce(Object) { _1.const_get _2 }
|
364
|
+
if return_type.args
|
365
|
+
args = return_type.args.map { from_rbs_type _1, self_type, extra_vars }
|
366
|
+
names = rbs_builder.build_singleton(return_type.name).type_params
|
367
|
+
params = names.map.with_index { [_1, args[_2] || OBJECT] }.to_h
|
368
|
+
end
|
369
|
+
InstanceType.new klass, params || {}
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def self.method_return_bottom?(method)
|
374
|
+
method.type.return_type.is_a? RBS::Types::Bases::Bottom
|
375
|
+
end
|
376
|
+
|
377
|
+
def self.match_free_variables(vars, types, values)
|
378
|
+
accumulator = {}
|
379
|
+
types.zip values do |t, v|
|
380
|
+
_match_free_variable(vars, t, v, accumulator) if v
|
381
|
+
end
|
382
|
+
accumulator.transform_values { UnionType[*_1] }
|
383
|
+
end
|
384
|
+
|
385
|
+
def self._match_free_variable(vars, rbs_type, value, accumulator)
|
386
|
+
case [rbs_type, value]
|
387
|
+
in [RBS::Types::Variable,]
|
388
|
+
(accumulator[rbs_type.name] ||= []) << value if vars.include? rbs_type.name
|
389
|
+
in [RBS::Types::ClassInstance, InstanceType]
|
390
|
+
names = rbs_builder.build_singleton(rbs_type.name).type_params
|
391
|
+
names.zip(rbs_type.args).each do |name, arg|
|
392
|
+
v = value.params[name]
|
393
|
+
_match_free_variable vars, arg, v, accumulator if v
|
394
|
+
end
|
395
|
+
in [RBS::Types::Tuple, InstanceType] if value.klass == Array
|
396
|
+
v = value.params[:Elem]
|
397
|
+
rbs_type.types.each do |t|
|
398
|
+
_match_free_variable vars, t, v, accumulator
|
399
|
+
end
|
400
|
+
in [RBS::Types::Record, InstanceType] if value.klass == Hash
|
401
|
+
# TODO
|
402
|
+
in [RBS::Types::Interface,]
|
403
|
+
definition = rbs_builder.build_interface rbs_type.name
|
404
|
+
convert = {}
|
405
|
+
definition.type_params.zip(rbs_type.args).each do |from, arg|
|
406
|
+
convert[from] = arg.name if arg.is_a? RBS::Types::Variable
|
407
|
+
end
|
408
|
+
return if convert.empty?
|
409
|
+
ac = {}
|
410
|
+
definition.methods.each do |method_name, method|
|
411
|
+
return_type = method_return_type value, method_name
|
412
|
+
method.defs.each do |method_def|
|
413
|
+
interface_return_type = method_def.type.type.return_type
|
414
|
+
_match_free_variable convert, interface_return_type, return_type, ac
|
415
|
+
end
|
416
|
+
end
|
417
|
+
convert.each do |from, to|
|
418
|
+
values = ac[from]
|
419
|
+
(accumulator[to] ||= []).concat values if values
|
420
|
+
end
|
421
|
+
else
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
data/lib/irb/version.rb
CHANGED
data/lib/irb.rb
CHANGED
@@ -140,6 +140,10 @@ require_relative "irb/debug"
|
|
140
140
|
#
|
141
141
|
# IRB.conf[:USE_AUTOCOMPLETE] = false
|
142
142
|
#
|
143
|
+
# To enable enhanced completion using type information, add the following to your +.irbrc+:
|
144
|
+
#
|
145
|
+
# IRB.conf[:COMPLETOR] = :type
|
146
|
+
#
|
143
147
|
# === History
|
144
148
|
#
|
145
149
|
# By default, irb will store the last 1000 commands you used in
|
@@ -367,24 +371,6 @@ module IRB
|
|
367
371
|
# An exception raised by IRB.irb_abort
|
368
372
|
class Abort < Exception;end
|
369
373
|
|
370
|
-
@CONF = {}
|
371
|
-
# Displays current configuration.
|
372
|
-
#
|
373
|
-
# Modifying the configuration is achieved by sending a message to IRB.conf.
|
374
|
-
#
|
375
|
-
# See IRB@Configuration for more information.
|
376
|
-
def IRB.conf
|
377
|
-
@CONF
|
378
|
-
end
|
379
|
-
|
380
|
-
# Returns the current version of IRB, including release version and last
|
381
|
-
# updated date.
|
382
|
-
def IRB.version
|
383
|
-
if v = @CONF[:VERSION] then return v end
|
384
|
-
|
385
|
-
@CONF[:VERSION] = format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE)
|
386
|
-
end
|
387
|
-
|
388
374
|
# The current IRB::Context of the session, see IRB.conf
|
389
375
|
#
|
390
376
|
# irb
|
@@ -431,6 +417,11 @@ module IRB
|
|
431
417
|
PROMPT_MAIN_TRUNCATE_OMISSION = '...'.freeze
|
432
418
|
CONTROL_CHARACTERS_PATTERN = "\x00-\x1F".freeze
|
433
419
|
|
420
|
+
# Returns the current context of this irb session
|
421
|
+
attr_reader :context
|
422
|
+
# The lexer used by this irb session
|
423
|
+
attr_accessor :scanner
|
424
|
+
|
434
425
|
# Creates a new irb session
|
435
426
|
def initialize(workspace = nil, input_method = nil)
|
436
427
|
@context = Context.new(self, workspace, input_method)
|
@@ -509,41 +500,6 @@ module IRB
|
|
509
500
|
end
|
510
501
|
end
|
511
502
|
|
512
|
-
# Returns the current context of this irb session
|
513
|
-
attr_reader :context
|
514
|
-
# The lexer used by this irb session
|
515
|
-
attr_accessor :scanner
|
516
|
-
|
517
|
-
private def generate_prompt(opens, continue, line_offset)
|
518
|
-
ltype = @scanner.ltype_from_open_tokens(opens)
|
519
|
-
indent = @scanner.calc_indent_level(opens)
|
520
|
-
continue = opens.any? || continue
|
521
|
-
line_no = @line_no + line_offset
|
522
|
-
|
523
|
-
if ltype
|
524
|
-
f = @context.prompt_s
|
525
|
-
elsif continue
|
526
|
-
f = @context.prompt_c
|
527
|
-
else
|
528
|
-
f = @context.prompt_i
|
529
|
-
end
|
530
|
-
f = "" unless f
|
531
|
-
if @context.prompting?
|
532
|
-
p = format_prompt(f, ltype, indent, line_no)
|
533
|
-
else
|
534
|
-
p = ""
|
535
|
-
end
|
536
|
-
if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
|
537
|
-
unless ltype
|
538
|
-
prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
|
539
|
-
ind = format_prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
|
540
|
-
indent * 2 - p.size
|
541
|
-
p += " " * ind if ind > 0
|
542
|
-
end
|
543
|
-
end
|
544
|
-
p
|
545
|
-
end
|
546
|
-
|
547
503
|
# Evaluates input for this session.
|
548
504
|
def eval_input
|
549
505
|
configure_io
|
@@ -835,16 +791,6 @@ module IRB
|
|
835
791
|
end
|
836
792
|
end
|
837
793
|
|
838
|
-
# Evaluates the given block using the given +context+ as the Context.
|
839
|
-
def suspend_context(context)
|
840
|
-
@context, back_context = context, @context
|
841
|
-
begin
|
842
|
-
yield back_context
|
843
|
-
ensure
|
844
|
-
@context = back_context
|
845
|
-
end
|
846
|
-
end
|
847
|
-
|
848
794
|
# Handler for the signal SIGINT, see Kernel#trap for more information.
|
849
795
|
def signal_handle
|
850
796
|
unless @context.ignore_sigint?
|
@@ -880,52 +826,6 @@ module IRB
|
|
880
826
|
end
|
881
827
|
end
|
882
828
|
|
883
|
-
private def truncate_prompt_main(str) # :nodoc:
|
884
|
-
str = str.tr(CONTROL_CHARACTERS_PATTERN, ' ')
|
885
|
-
if str.size <= PROMPT_MAIN_TRUNCATE_LENGTH
|
886
|
-
str
|
887
|
-
else
|
888
|
-
str[0, PROMPT_MAIN_TRUNCATE_LENGTH - PROMPT_MAIN_TRUNCATE_OMISSION.size] + PROMPT_MAIN_TRUNCATE_OMISSION
|
889
|
-
end
|
890
|
-
end
|
891
|
-
|
892
|
-
private def format_prompt(format, ltype, indent, line_no) # :nodoc:
|
893
|
-
format.gsub(/%([0-9]+)?([a-zA-Z])/) do
|
894
|
-
case $2
|
895
|
-
when "N"
|
896
|
-
@context.irb_name
|
897
|
-
when "m"
|
898
|
-
truncate_prompt_main(@context.main.to_s)
|
899
|
-
when "M"
|
900
|
-
truncate_prompt_main(@context.main.inspect)
|
901
|
-
when "l"
|
902
|
-
ltype
|
903
|
-
when "i"
|
904
|
-
if indent < 0
|
905
|
-
if $1
|
906
|
-
"-".rjust($1.to_i)
|
907
|
-
else
|
908
|
-
"-"
|
909
|
-
end
|
910
|
-
else
|
911
|
-
if $1
|
912
|
-
format("%" + $1 + "d", indent)
|
913
|
-
else
|
914
|
-
indent.to_s
|
915
|
-
end
|
916
|
-
end
|
917
|
-
when "n"
|
918
|
-
if $1
|
919
|
-
format("%" + $1 + "d", line_no)
|
920
|
-
else
|
921
|
-
line_no.to_s
|
922
|
-
end
|
923
|
-
when "%"
|
924
|
-
"%"
|
925
|
-
end
|
926
|
-
end
|
927
|
-
end
|
928
|
-
|
929
829
|
def output_value(omit = false) # :nodoc:
|
930
830
|
str = @context.inspect_last_value
|
931
831
|
multiline_p = str.include?("\n")
|
@@ -978,28 +878,84 @@ module IRB
|
|
978
878
|
end
|
979
879
|
format("#<%s: %s>", self.class, ary.join(", "))
|
980
880
|
end
|
981
|
-
end
|
982
881
|
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
882
|
+
private
|
883
|
+
|
884
|
+
def generate_prompt(opens, continue, line_offset)
|
885
|
+
ltype = @scanner.ltype_from_open_tokens(opens)
|
886
|
+
indent = @scanner.calc_indent_level(opens)
|
887
|
+
continue = opens.any? || continue
|
888
|
+
line_no = @line_no + line_offset
|
889
|
+
|
890
|
+
if ltype
|
891
|
+
f = @context.prompt_s
|
892
|
+
elsif continue
|
893
|
+
f = @context.prompt_c
|
894
|
+
else
|
895
|
+
f = @context.prompt_i
|
896
|
+
end
|
897
|
+
f = "" unless f
|
898
|
+
if @context.prompting?
|
899
|
+
p = format_prompt(f, ltype, indent, line_no)
|
900
|
+
else
|
901
|
+
p = ""
|
902
|
+
end
|
903
|
+
if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
|
904
|
+
unless ltype
|
905
|
+
prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
|
906
|
+
ind = format_prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
|
907
|
+
indent * 2 - p.size
|
908
|
+
p += " " * ind if ind > 0
|
909
|
+
end
|
910
|
+
end
|
911
|
+
p
|
912
|
+
end
|
913
|
+
|
914
|
+
def truncate_prompt_main(str) # :nodoc:
|
915
|
+
str = str.tr(CONTROL_CHARACTERS_PATTERN, ' ')
|
916
|
+
if str.size <= PROMPT_MAIN_TRUNCATE_LENGTH
|
917
|
+
str
|
998
918
|
else
|
999
|
-
|
919
|
+
str[0, PROMPT_MAIN_TRUNCATE_LENGTH - PROMPT_MAIN_TRUNCATE_OMISSION.size] + PROMPT_MAIN_TRUNCATE_OMISSION
|
920
|
+
end
|
921
|
+
end
|
922
|
+
|
923
|
+
def format_prompt(format, ltype, indent, line_no) # :nodoc:
|
924
|
+
format.gsub(/%([0-9]+)?([a-zA-Z])/) do
|
925
|
+
case $2
|
926
|
+
when "N"
|
927
|
+
@context.irb_name
|
928
|
+
when "m"
|
929
|
+
truncate_prompt_main(@context.main.to_s)
|
930
|
+
when "M"
|
931
|
+
truncate_prompt_main(@context.main.inspect)
|
932
|
+
when "l"
|
933
|
+
ltype
|
934
|
+
when "i"
|
935
|
+
if indent < 0
|
936
|
+
if $1
|
937
|
+
"-".rjust($1.to_i)
|
938
|
+
else
|
939
|
+
"-"
|
940
|
+
end
|
941
|
+
else
|
942
|
+
if $1
|
943
|
+
format("%" + $1 + "d", indent)
|
944
|
+
else
|
945
|
+
indent.to_s
|
946
|
+
end
|
947
|
+
end
|
948
|
+
when "n"
|
949
|
+
if $1
|
950
|
+
format("%" + $1 + "d", line_no)
|
951
|
+
else
|
952
|
+
line_no.to_s
|
953
|
+
end
|
954
|
+
when "%"
|
955
|
+
"%"
|
956
|
+
end
|
1000
957
|
end
|
1001
958
|
end
|
1002
|
-
array.join("\n")
|
1003
959
|
end
|
1004
960
|
end
|
1005
961
|
|
data/man/irb.1
CHANGED
@@ -140,6 +140,13 @@ Use autocompletion.
|
|
140
140
|
Don't use autocompletion.
|
141
141
|
.Pp
|
142
142
|
.Pp
|
143
|
+
.It Fl -regexp-completor
|
144
|
+
Use regexp based completion.
|
145
|
+
.Pp
|
146
|
+
.It Fl -type-completor
|
147
|
+
Use type based completion.
|
148
|
+
.Pp
|
149
|
+
.Pp
|
143
150
|
.It Fl -verbose
|
144
151
|
Show details.
|
145
152
|
.Pp
|