irb 1.8.1 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|