irb 1.8.1 → 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 +102 -1
- data/Rakefile +2 -2
- data/lib/irb/cmd/irb_info.rb +1 -0
- data/lib/irb/cmd/show_source.rb +11 -6
- data/lib/irb/completion.rb +87 -94
- data/lib/irb/context.rb +39 -2
- data/lib/irb/debug/ui.rb +2 -3
- data/lib/irb/debug.rb +2 -5
- data/lib/irb/easter-egg.rb +16 -6
- data/lib/irb/history.rb +3 -1
- data/lib/irb/init.rb +41 -0
- data/lib/irb/input-method.rb +155 -83
- data/lib/irb/lc/help-message +3 -0
- data/lib/irb/lc/ja/help-message +3 -0
- data/lib/irb/ruby-lex.rb +14 -41
- data/lib/irb/ruby_logo.aa +43 -0
- data/lib/irb/source_finder.rb +2 -2
- 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 +103 -142
- data/man/irb.1 +7 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 810aa12a1fbfdbd0ff9f9c4d5c4ac71e62e8241f87cb1a306be1ff81aaef08cb
|
4
|
+
data.tar.gz: 781d169232ac355b9723e8dc03d6c0de4c16327b4a4a3339cd1e90bad7e1c0b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51d97e80d977c6ce100f66cc0ad4becae17600d36653be88cc7c2f1e6cd0b7127cec01344bc69b04de1b043f8d45a1d07f6b4b8ad3fad4584585aca269cfa65f
|
7
|
+
data.tar.gz: a197cf8c07a1ea728a3c9d0d70fdd28a2a5b9a4e9ebf72a8fd8d6495627cf4c369e6831879a766c5dd8819438bb1f126b0d4d669becc4c63a7ad6c4ea51a3a79
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -52,6 +52,10 @@ $ gem install irb
|
|
52
52
|
|
53
53
|
## Usage
|
54
54
|
|
55
|
+
> **Note**
|
56
|
+
>
|
57
|
+
> We're working hard to match Pry's variety of powerful features in IRB, and you can track our progress or find contribution ideas in [this document](https://github.com/ruby/irb/blob/master/COMPARED_WITH_PRY.md).
|
58
|
+
|
55
59
|
### The `irb` Executable
|
56
60
|
|
57
61
|
You can start a fresh IRB session by typing `irb` in your terminal.
|
@@ -150,7 +154,7 @@ Context
|
|
150
154
|
|
151
155
|
Starting from version 1.8.0, IRB boasts a powerful integration with `debug.gem`, providing a debugging experience akin to `pry-byebug`.
|
152
156
|
|
153
|
-
After hitting a `binding.irb` breakpoint, you can activate the debugger with the `debug` command.
|
157
|
+
After hitting a `binding.irb` breakpoint, you can activate the debugger with the `debug` command. Alternatively, if the `debug` method happens to already be defined in the current scope, you can call `irb_debug`.
|
154
158
|
|
155
159
|
```shell
|
156
160
|
From: test.rb @ line 3 :
|
@@ -231,6 +235,79 @@ However, there are also some limitations to be aware of:
|
|
231
235
|
2. As IRB [doesn't currently support remote-connection](https://github.com/ruby/irb/issues/672), it can't be used with `debug.gem`'s remote debugging feature.
|
232
236
|
3. Access to the previous return value via the underscore `_` is not supported.
|
233
237
|
|
238
|
+
## Type Based Completion
|
239
|
+
|
240
|
+
IRB's default completion `IRB::RegexpCompletor` uses Regexp. IRB has another experimental completion `IRB::TypeCompletion` that uses type analysis.
|
241
|
+
|
242
|
+
### How to Enable IRB::TypeCompletion
|
243
|
+
|
244
|
+
To enable IRB::TypeCompletion, run IRB with `--type-completor` option
|
245
|
+
```
|
246
|
+
$ irb --type-completor
|
247
|
+
```
|
248
|
+
Or write the code below to IRB's rc-file.
|
249
|
+
```ruby
|
250
|
+
IRB.conf[:COMPLETOR] = :type # default is :regexp
|
251
|
+
```
|
252
|
+
You also need `gem prism` and `gem rbs` to use this feature.
|
253
|
+
|
254
|
+
To check if it's enabled, type `irb_info` into IRB and see the `Completion` section.
|
255
|
+
```
|
256
|
+
irb(main):001> irb_info
|
257
|
+
...
|
258
|
+
# Enabled
|
259
|
+
Completion: Autocomplete, TypeCompletion::Completor(Prism: 0.17.1, RBS: 3.3.0)
|
260
|
+
# Not enabled
|
261
|
+
Completion: Autocomplete, RegexpCompletor
|
262
|
+
...
|
263
|
+
```
|
264
|
+
If you have `sig/` directory or `rbs_collection.lock.yaml` in current directory, IRB will load it.
|
265
|
+
|
266
|
+
### Advantage over Default IRB::RegexpCompletor
|
267
|
+
|
268
|
+
IRB::TypeCompletion can autocomplete chained methods, block parameters and more if type information is available.
|
269
|
+
These are some examples IRB::RegexpCompletor cannot complete.
|
270
|
+
|
271
|
+
```ruby
|
272
|
+
irb(main):001> 'Ruby'.upcase.chars.s # Array methods (sample, select, shift, size)
|
273
|
+
```
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
irb(main):001> 10.times.map(&:to_s).each do |s|
|
277
|
+
irb(main):002> s.up # String methods (upcase, upcase!, upto)
|
278
|
+
```
|
279
|
+
|
280
|
+
```ruby
|
281
|
+
irb(main):001> class User < ApplicationRecord
|
282
|
+
irb(main):002> def foo
|
283
|
+
irb(main):003> sa # save, save!
|
284
|
+
```
|
285
|
+
|
286
|
+
As a trade-off, completion calculation takes more time than IRB::RegexpCompletor.
|
287
|
+
|
288
|
+
### Difference between Steep's Completion
|
289
|
+
|
290
|
+
Compared with Steep, IRB::TypeCompletion has some difference and limitations.
|
291
|
+
```ruby
|
292
|
+
[0, 'a'].sample.
|
293
|
+
# Steep completes intersection of Integer methods and String methods
|
294
|
+
# IRB::TypeCompletion completes both Integer and String methods
|
295
|
+
```
|
296
|
+
|
297
|
+
Some features like type narrowing is not implemented.
|
298
|
+
```ruby
|
299
|
+
def f(arg = [0, 'a'].sample)
|
300
|
+
if arg.is_a?(String)
|
301
|
+
arg. # Completes both Integer and String methods
|
302
|
+
```
|
303
|
+
|
304
|
+
Unlike other static type checker, IRB::TypeCompletion uses runtime information to provide better completion.
|
305
|
+
```ruby
|
306
|
+
irb(main):001> a = [1]
|
307
|
+
=> [1]
|
308
|
+
irb(main):002> a.first. # Completes Integer methods
|
309
|
+
```
|
310
|
+
|
234
311
|
## Configuration
|
235
312
|
|
236
313
|
### Environment Variables
|
@@ -269,6 +346,30 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
269
346
|
|
270
347
|
Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/irb.
|
271
348
|
|
349
|
+
### Set up the environment
|
350
|
+
|
351
|
+
1. Fork the project to your GithHub account
|
352
|
+
2. Clone the fork with `git clone git@github.com:[your_username]/irb.git`
|
353
|
+
3. Run `bundle install`
|
354
|
+
4. Run `bundle exec rake` to make sure tests pass locally
|
355
|
+
|
356
|
+
### Run integration tests
|
357
|
+
|
358
|
+
If your changes affect component rendering, such as the autocompletion's dialog/dropdown, you may need to run IRB's integration tests, known as `yamatanarroroti`.
|
359
|
+
|
360
|
+
Before running these tests, ensure that you have `libvterm` installed. If you're using Homebrew, you can install it by running:
|
361
|
+
|
362
|
+
```bash
|
363
|
+
brew install libvterm
|
364
|
+
```
|
365
|
+
|
366
|
+
After installing `libvterm`, you can run the integration tests using the following commands:
|
367
|
+
|
368
|
+
```bash
|
369
|
+
WITH_VTERM=1 bundle install
|
370
|
+
WITH_VTERM=1 bundle exec rake test test_yamatanooroti
|
371
|
+
```
|
372
|
+
|
272
373
|
## Releasing
|
273
374
|
|
274
375
|
```
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ Rake::TestTask.new(:test) do |t|
|
|
5
5
|
t.libs << "test" << "test/lib"
|
6
6
|
t.libs << "lib"
|
7
7
|
t.ruby_opts << "-rhelper"
|
8
|
-
t.test_files = FileList["test/irb/test_*.rb"]
|
8
|
+
t.test_files = FileList["test/irb/test_*.rb", "test/irb/type_completion/test_*.rb"]
|
9
9
|
end
|
10
10
|
|
11
11
|
# To make sure they have been correctly setup for Ruby CI.
|
@@ -13,7 +13,7 @@ desc "Run each irb test file in isolation."
|
|
13
13
|
task :test_in_isolation do
|
14
14
|
failed = false
|
15
15
|
|
16
|
-
FileList["test/irb/test_*.rb"].each do |test_file|
|
16
|
+
FileList["test/irb/test_*.rb", "test/irb/type_completion/test_*.rb"].each do |test_file|
|
17
17
|
ENV["TEST"] = test_file
|
18
18
|
begin
|
19
19
|
Rake::Task["test"].execute
|
data/lib/irb/cmd/irb_info.rb
CHANGED
@@ -14,6 +14,7 @@ module IRB
|
|
14
14
|
str = "Ruby version: #{RUBY_VERSION}\n"
|
15
15
|
str += "IRB version: #{IRB.version}\n"
|
16
16
|
str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
|
17
|
+
str += "Completion: #{IRB.CurrentContext.io.respond_to?(:completion_info) ? IRB.CurrentContext.io.completion_info : 'off'}\n"
|
17
18
|
str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
|
18
19
|
str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
|
19
20
|
str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
|
data/lib/irb/cmd/show_source.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative "nop"
|
4
4
|
require_relative "../source_finder"
|
5
|
+
require_relative "../pager"
|
5
6
|
require_relative "../color"
|
6
7
|
|
7
8
|
module IRB
|
@@ -40,12 +41,16 @@ module IRB
|
|
40
41
|
private
|
41
42
|
|
42
43
|
def show_source(source)
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
file_content = IRB::Color.colorize_code(File.read(source.file))
|
45
|
+
code = file_content.lines[(source.first_line - 1)...source.last_line].join
|
46
|
+
content = <<~CONTENT
|
47
|
+
|
48
|
+
#{bold("From")}: #{source.file}:#{source.first_line}
|
49
|
+
|
50
|
+
#{code}
|
51
|
+
CONTENT
|
52
|
+
|
53
|
+
Pager.page_content(content)
|
49
54
|
end
|
50
55
|
|
51
56
|
def bold(str)
|
data/lib/irb/completion.rb
CHANGED
@@ -8,30 +8,7 @@
|
|
8
8
|
require_relative 'ruby-lex'
|
9
9
|
|
10
10
|
module IRB
|
11
|
-
|
12
|
-
using Module.new {
|
13
|
-
refine ::Binding do
|
14
|
-
def eval_methods
|
15
|
-
::Kernel.instance_method(:methods).bind(eval("self")).call
|
16
|
-
end
|
17
|
-
|
18
|
-
def eval_private_methods
|
19
|
-
::Kernel.instance_method(:private_methods).bind(eval("self")).call
|
20
|
-
end
|
21
|
-
|
22
|
-
def eval_instance_variables
|
23
|
-
::Kernel.instance_method(:instance_variables).bind(eval("self")).call
|
24
|
-
end
|
25
|
-
|
26
|
-
def eval_global_variables
|
27
|
-
::Kernel.instance_method(:global_variables).bind(eval("self")).call
|
28
|
-
end
|
29
|
-
|
30
|
-
def eval_class_constants
|
31
|
-
::Module.instance_method(:constants).bind(eval("self.class")).call
|
32
|
-
end
|
33
|
-
end
|
34
|
-
}
|
11
|
+
class BaseCompletor # :nodoc:
|
35
12
|
|
36
13
|
# Set of reserved words used by Ruby, you should not use these for
|
37
14
|
# constants or variables
|
@@ -56,7 +33,13 @@ module IRB
|
|
56
33
|
yield
|
57
34
|
]
|
58
35
|
|
59
|
-
|
36
|
+
def completion_candidates(preposing, target, postposing, bind:)
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
def doc_namespace(preposing, matched, postposing, bind:)
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
60
43
|
|
61
44
|
GEM_PATHS =
|
62
45
|
if defined?(Gem::Specification)
|
@@ -73,7 +56,7 @@ module IRB
|
|
73
56
|
[]
|
74
57
|
end.freeze
|
75
58
|
|
76
|
-
def
|
59
|
+
def retrieve_gem_and_system_load_path
|
77
60
|
candidates = (GEM_PATHS | $LOAD_PATH)
|
78
61
|
candidates.map do |p|
|
79
62
|
if p.respond_to?(:to_path)
|
@@ -84,8 +67,8 @@ module IRB
|
|
84
67
|
end.compact.sort
|
85
68
|
end
|
86
69
|
|
87
|
-
def
|
88
|
-
|
70
|
+
def retrieve_files_to_require_from_load_path
|
71
|
+
@files_from_load_path ||=
|
89
72
|
(
|
90
73
|
shortest = []
|
91
74
|
rest = retrieve_gem_and_system_load_path.each_with_object([]) { |path, result|
|
@@ -103,13 +86,43 @@ module IRB
|
|
103
86
|
)
|
104
87
|
end
|
105
88
|
|
106
|
-
def
|
107
|
-
|
89
|
+
def retrieve_files_to_require_relative_from_current_dir
|
90
|
+
@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
|
108
91
|
path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
|
109
92
|
}
|
110
93
|
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class RegexpCompletor < BaseCompletor # :nodoc:
|
97
|
+
using Module.new {
|
98
|
+
refine ::Binding do
|
99
|
+
def eval_methods
|
100
|
+
::Kernel.instance_method(:methods).bind(eval("self")).call
|
101
|
+
end
|
102
|
+
|
103
|
+
def eval_private_methods
|
104
|
+
::Kernel.instance_method(:private_methods).bind(eval("self")).call
|
105
|
+
end
|
106
|
+
|
107
|
+
def eval_instance_variables
|
108
|
+
::Kernel.instance_method(:instance_variables).bind(eval("self")).call
|
109
|
+
end
|
110
|
+
|
111
|
+
def eval_global_variables
|
112
|
+
::Kernel.instance_method(:global_variables).bind(eval("self")).call
|
113
|
+
end
|
114
|
+
|
115
|
+
def eval_class_constants
|
116
|
+
::Module.instance_method(:constants).bind(eval("self.class")).call
|
117
|
+
end
|
118
|
+
end
|
119
|
+
}
|
120
|
+
|
121
|
+
def inspect
|
122
|
+
'RegexpCompletor'
|
123
|
+
end
|
111
124
|
|
112
|
-
|
125
|
+
def complete_require_path(target, preposing, postposing)
|
113
126
|
if target =~ /\A(['"])([^'"]+)\Z/
|
114
127
|
quote = $1
|
115
128
|
actual_target = $2
|
@@ -124,39 +137,37 @@ module IRB
|
|
124
137
|
break
|
125
138
|
end
|
126
139
|
end
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
end
|
140
|
+
return unless tok&.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
|
141
|
+
|
142
|
+
case tok.tok
|
143
|
+
when 'require'
|
144
|
+
retrieve_files_to_require_from_load_path.select { |path|
|
145
|
+
path.start_with?(actual_target)
|
146
|
+
}.map { |path|
|
147
|
+
quote + path
|
148
|
+
}
|
149
|
+
when 'require_relative'
|
150
|
+
retrieve_files_to_require_relative_from_current_dir.select { |path|
|
151
|
+
path.start_with?(actual_target)
|
152
|
+
}.map { |path|
|
153
|
+
quote + path
|
154
|
+
}
|
143
155
|
end
|
144
|
-
|
145
|
-
}
|
156
|
+
end
|
146
157
|
|
147
|
-
|
158
|
+
def completion_candidates(preposing, target, postposing, bind:)
|
148
159
|
if preposing && postposing
|
149
|
-
result =
|
150
|
-
|
151
|
-
result = retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
|
152
|
-
end
|
153
|
-
result
|
154
|
-
else
|
155
|
-
retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
|
160
|
+
result = complete_require_path(target, preposing, postposing)
|
161
|
+
return result if result
|
156
162
|
end
|
157
|
-
|
163
|
+
retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
|
164
|
+
end
|
158
165
|
|
159
|
-
def
|
166
|
+
def doc_namespace(_preposing, matched, _postposing, bind:)
|
167
|
+
retrieve_completion_data(matched, bind: bind, doc_namespace: true)
|
168
|
+
end
|
169
|
+
|
170
|
+
def retrieve_completion_data(input, bind:, doc_namespace:)
|
160
171
|
case input
|
161
172
|
# this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting
|
162
173
|
# details are described in: https://github.com/ruby/irb/pull/523
|
@@ -394,44 +405,10 @@ module IRB
|
|
394
405
|
end
|
395
406
|
end
|
396
407
|
|
397
|
-
PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) {
|
398
|
-
begin
|
399
|
-
require 'rdoc'
|
400
|
-
rescue LoadError
|
401
|
-
return
|
402
|
-
end
|
403
|
-
|
404
|
-
RDocRIDriver ||= RDoc::RI::Driver.new
|
405
|
-
|
406
|
-
if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
|
407
|
-
IRB.__send__(:easter_egg)
|
408
|
-
return
|
409
|
-
end
|
410
|
-
|
411
|
-
namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true)
|
412
|
-
return unless namespace
|
413
|
-
|
414
|
-
if namespace.is_a?(Array)
|
415
|
-
out = RDoc::Markup::Document.new
|
416
|
-
namespace.each do |m|
|
417
|
-
begin
|
418
|
-
RDocRIDriver.add_method(out, m)
|
419
|
-
rescue RDoc::RI::Driver::NotFoundError
|
420
|
-
end
|
421
|
-
end
|
422
|
-
RDocRIDriver.display(out)
|
423
|
-
else
|
424
|
-
begin
|
425
|
-
RDocRIDriver.display_names([namespace])
|
426
|
-
rescue RDoc::RI::Driver::NotFoundError
|
427
|
-
end
|
428
|
-
end
|
429
|
-
}
|
430
|
-
|
431
408
|
# Set of available operators in Ruby
|
432
409
|
Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~]
|
433
410
|
|
434
|
-
def
|
411
|
+
def select_message(receiver, message, candidates, sep = ".")
|
435
412
|
candidates.grep(/^#{Regexp.quote(message)}/).collect do |e|
|
436
413
|
case e
|
437
414
|
when /^[a-zA-Z_]/
|
@@ -443,4 +420,20 @@ module IRB
|
|
443
420
|
end
|
444
421
|
end
|
445
422
|
end
|
423
|
+
|
424
|
+
module InputCompletor
|
425
|
+
class << self
|
426
|
+
private def regexp_completor
|
427
|
+
@regexp_completor ||= RegexpCompletor.new
|
428
|
+
end
|
429
|
+
|
430
|
+
def retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
|
431
|
+
regexp_completor.retrieve_completion_data(input, bind: bind, doc_namespace: doc_namespace)
|
432
|
+
end
|
433
|
+
end
|
434
|
+
CompletionProc = ->(target, preposing = nil, postposing = nil) {
|
435
|
+
regexp_completor.completion_candidates(preposing, target, postposing, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding)
|
436
|
+
}
|
437
|
+
end
|
438
|
+
deprecate_constant :InputCompletor
|
446
439
|
end
|
data/lib/irb/context.rb
CHANGED
@@ -86,14 +86,14 @@ module IRB
|
|
86
86
|
when nil
|
87
87
|
if STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
|
88
88
|
# Both of multiline mode and singleline mode aren't specified.
|
89
|
-
@io = RelineInputMethod.new
|
89
|
+
@io = RelineInputMethod.new(build_completor)
|
90
90
|
else
|
91
91
|
@io = nil
|
92
92
|
end
|
93
93
|
when false
|
94
94
|
@io = nil
|
95
95
|
when true
|
96
|
-
@io = RelineInputMethod.new
|
96
|
+
@io = RelineInputMethod.new(build_completor)
|
97
97
|
end
|
98
98
|
unless @io
|
99
99
|
case use_singleline?
|
@@ -149,6 +149,43 @@ module IRB
|
|
149
149
|
@command_aliases = IRB.conf[:COMMAND_ALIASES]
|
150
150
|
end
|
151
151
|
|
152
|
+
private def build_completor
|
153
|
+
completor_type = IRB.conf[:COMPLETOR]
|
154
|
+
case completor_type
|
155
|
+
when :regexp
|
156
|
+
return RegexpCompletor.new
|
157
|
+
when :type
|
158
|
+
completor = build_type_completor
|
159
|
+
return completor if completor
|
160
|
+
else
|
161
|
+
warn "Invalid value for IRB.conf[:COMPLETOR]: #{completor_type}"
|
162
|
+
end
|
163
|
+
# Fallback to RegexpCompletor
|
164
|
+
RegexpCompletor.new
|
165
|
+
end
|
166
|
+
|
167
|
+
TYPE_COMPLETION_REQUIRED_PRISM_VERSION = '0.17.1'
|
168
|
+
|
169
|
+
private def build_type_completor
|
170
|
+
unless Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0') && RUBY_ENGINE != 'truffleruby'
|
171
|
+
warn 'TypeCompletion requires RUBY_VERSION >= 3.0.0'
|
172
|
+
return
|
173
|
+
end
|
174
|
+
begin
|
175
|
+
require 'prism'
|
176
|
+
rescue LoadError => e
|
177
|
+
warn "TypeCompletion requires Prism: #{e.message}"
|
178
|
+
return
|
179
|
+
end
|
180
|
+
unless Gem::Version.new(Prism::VERSION) >= Gem::Version.new(TYPE_COMPLETION_REQUIRED_PRISM_VERSION)
|
181
|
+
warn "TypeCompletion requires Prism::VERSION >= #{TYPE_COMPLETION_REQUIRED_PRISM_VERSION}"
|
182
|
+
return
|
183
|
+
end
|
184
|
+
require 'irb/type_completion/completor'
|
185
|
+
TypeCompletion::Types.preload_in_thread
|
186
|
+
TypeCompletion::Completor.new
|
187
|
+
end
|
188
|
+
|
152
189
|
def save_history=(val)
|
153
190
|
IRB.conf[:SAVE_HISTORY] = val
|
154
191
|
end
|
data/lib/irb/debug/ui.rb
CHANGED
@@ -4,8 +4,7 @@ require 'debug/console'
|
|
4
4
|
module IRB
|
5
5
|
module Debug
|
6
6
|
class UI < DEBUGGER__::UI_Base
|
7
|
-
def initialize(
|
8
|
-
@thread = thread
|
7
|
+
def initialize(irb)
|
9
8
|
@irb = irb
|
10
9
|
end
|
11
10
|
|
@@ -56,7 +55,7 @@ module IRB
|
|
56
55
|
|
57
56
|
def readline _
|
58
57
|
setup_interrupt do
|
59
|
-
tc = DEBUGGER__::SESSION.
|
58
|
+
tc = DEBUGGER__::SESSION.instance_variable_get(:@tc)
|
60
59
|
cmd = @irb.debug_readline(tc.current_frame.binding || TOPLEVEL_BINDING)
|
61
60
|
|
62
61
|
case cmd
|
data/lib/irb/debug.rb
CHANGED
@@ -32,17 +32,14 @@ module IRB
|
|
32
32
|
end
|
33
33
|
DEBUGGER__::CONFIG.set_config
|
34
34
|
configure_irb_for_debugger(irb)
|
35
|
-
thread = Thread.current
|
36
35
|
|
37
|
-
DEBUGGER__.initialize_session{ IRB::Debug::UI.new(
|
36
|
+
DEBUGGER__.initialize_session{ IRB::Debug::UI.new(irb) }
|
38
37
|
end
|
39
38
|
|
40
39
|
# When debug session was previously started but not by IRB
|
41
40
|
if defined?(DEBUGGER__::SESSION) && !irb.context.with_debugger
|
42
41
|
configure_irb_for_debugger(irb)
|
43
|
-
|
44
|
-
|
45
|
-
DEBUGGER__::SESSION.reset_ui(IRB::Debug::UI.new(thread, irb))
|
42
|
+
DEBUGGER__::SESSION.reset_ui(IRB::Debug::UI.new(irb))
|
46
43
|
end
|
47
44
|
|
48
45
|
# Apply patches to debug gem so it skips IRB frames
|
data/lib/irb/easter-egg.rb
CHANGED
@@ -98,18 +98,26 @@ module IRB
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
+
private def easter_egg_logo(type)
|
102
|
+
@easter_egg_logos ||= File.read(File.join(__dir__, 'ruby_logo.aa'), encoding: 'UTF-8:UTF-8')
|
103
|
+
.split(/TYPE: ([A-Z]+)\n/)[1..]
|
104
|
+
.each_slice(2)
|
105
|
+
.to_h
|
106
|
+
@easter_egg_logos[type.to_s.upcase]
|
107
|
+
end
|
108
|
+
|
101
109
|
private def easter_egg(type = nil)
|
102
110
|
type ||= [:logo, :dancing].sample
|
103
111
|
case type
|
104
112
|
when :logo
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
IO.copy_stream(f, io)
|
109
|
-
end
|
113
|
+
require "rdoc"
|
114
|
+
RDoc::RI::Driver.new.page do |io|
|
115
|
+
io.write easter_egg_logo(:large)
|
110
116
|
end
|
111
117
|
when :dancing
|
112
|
-
|
118
|
+
STDOUT.cooked do
|
119
|
+
interrupted = false
|
120
|
+
prev_trap = trap("SIGINT") { interrupted = true }
|
113
121
|
canvas = Canvas.new(Reline.get_screen_size)
|
114
122
|
Reline::IOGate.set_winch_handler do
|
115
123
|
canvas = Canvas.new(Reline.get_screen_size)
|
@@ -125,10 +133,12 @@ module IRB
|
|
125
133
|
buff[0, 20] = "\e[0mPress Ctrl+C to stop\e[31m\e[1m"
|
126
134
|
print "\e[H" + buff
|
127
135
|
sleep 0.05
|
136
|
+
break if interrupted
|
128
137
|
end
|
129
138
|
rescue Interrupt
|
130
139
|
ensure
|
131
140
|
print "\e[0m\e[?1049l"
|
141
|
+
trap("SIGINT", prev_trap)
|
132
142
|
end
|
133
143
|
end
|
134
144
|
end
|
data/lib/irb/history.rb
CHANGED
@@ -10,6 +10,7 @@ module IRB
|
|
10
10
|
|
11
11
|
def load_history
|
12
12
|
history = self.class::HISTORY
|
13
|
+
|
13
14
|
if history_file = IRB.conf[:HISTORY_FILE]
|
14
15
|
history_file = File.expand_path(history_file)
|
15
16
|
end
|
@@ -32,7 +33,8 @@ module IRB
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def save_history
|
35
|
-
history = self.class::HISTORY
|
36
|
+
history = self.class::HISTORY.to_a
|
37
|
+
|
36
38
|
if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) != 0
|
37
39
|
if history_file = IRB.conf[:HISTORY_FILE]
|
38
40
|
history_file = File.expand_path(history_file)
|