irb 1.8.1 → 1.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/irb/cmd/show_source.rb +11 -6
- data/lib/irb/completion.rb +89 -117
- data/lib/irb/debug/ui.rb +2 -3
- data/lib/irb/debug.rb +2 -5
- data/lib/irb/history.rb +3 -1
- data/lib/irb/input-method.rb +132 -81
- data/lib/irb/ruby-lex.rb +14 -41
- data/lib/irb/source_finder.rb +2 -2
- data/lib/irb/version.rb +2 -2
- data/lib/irb.rb +52 -47
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 811c1b4343957dac57d58178adbc13195e6d53de980f63810ec83eec09d1f8c1
|
4
|
+
data.tar.gz: bbc99d3f46a8e7afa6a7a8e32dc137300e3da15935631e05a56b203a901887fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76b770cf0a8012031f11306cc96879173d819cbd0501efdd41c434571028c3dee8bc12b5928696232d61215f6e22ecec3b9a6e3ff93e085349282c035c9389ec
|
7
|
+
data.tar.gz: f48e1f3912d5bb59acfa041718014dafb24d7f39ac23e1f0b267047ca4e4f937af77bdb0d40a940813da71f5920f53b5bbdc987b9dc50d16e5bdb85a754e02b7
|
data/README.md
CHANGED
@@ -150,7 +150,7 @@ Context
|
|
150
150
|
|
151
151
|
Starting from version 1.8.0, IRB boasts a powerful integration with `debug.gem`, providing a debugging experience akin to `pry-byebug`.
|
152
152
|
|
153
|
-
After hitting a `binding.irb` breakpoint, you can activate the debugger with the `debug` command.
|
153
|
+
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
154
|
|
155
155
|
```shell
|
156
156
|
From: test.rb @ line 3 :
|
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,55 +8,14 @@
|
|
8
8
|
require_relative 'ruby-lex'
|
9
9
|
|
10
10
|
module IRB
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
}
|
35
|
-
|
36
|
-
# Set of reserved words used by Ruby, you should not use these for
|
37
|
-
# constants or variables
|
38
|
-
ReservedWords = %w[
|
39
|
-
__ENCODING__ __LINE__ __FILE__
|
40
|
-
BEGIN END
|
41
|
-
alias and
|
42
|
-
begin break
|
43
|
-
case class
|
44
|
-
def defined? do
|
45
|
-
else elsif end ensure
|
46
|
-
false for
|
47
|
-
if in
|
48
|
-
module
|
49
|
-
next nil not
|
50
|
-
or
|
51
|
-
redo rescue retry return
|
52
|
-
self super
|
53
|
-
then true
|
54
|
-
undef unless until
|
55
|
-
when while
|
56
|
-
yield
|
57
|
-
]
|
11
|
+
class BaseCompletor # :nodoc:
|
12
|
+
def completion_candidates(preposing, target, postposing, bind:)
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
58
15
|
|
59
|
-
|
16
|
+
def doc_namespace(preposing, matched, postposing, bind:)
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
60
19
|
|
61
20
|
GEM_PATHS =
|
62
21
|
if defined?(Gem::Specification)
|
@@ -73,7 +32,7 @@ module IRB
|
|
73
32
|
[]
|
74
33
|
end.freeze
|
75
34
|
|
76
|
-
def
|
35
|
+
def retrieve_gem_and_system_load_path
|
77
36
|
candidates = (GEM_PATHS | $LOAD_PATH)
|
78
37
|
candidates.map do |p|
|
79
38
|
if p.respond_to?(:to_path)
|
@@ -84,8 +43,8 @@ module IRB
|
|
84
43
|
end.compact.sort
|
85
44
|
end
|
86
45
|
|
87
|
-
def
|
88
|
-
|
46
|
+
def retrieve_files_to_require_from_load_path
|
47
|
+
@files_from_load_path ||=
|
89
48
|
(
|
90
49
|
shortest = []
|
91
50
|
rest = retrieve_gem_and_system_load_path.each_with_object([]) { |path, result|
|
@@ -103,13 +62,62 @@ module IRB
|
|
103
62
|
)
|
104
63
|
end
|
105
64
|
|
106
|
-
def
|
107
|
-
|
65
|
+
def retrieve_files_to_require_relative_from_current_dir
|
66
|
+
@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
|
108
67
|
path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
|
109
68
|
}
|
110
69
|
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class RegexpCompletor < BaseCompletor # :nodoc:
|
73
|
+
using Module.new {
|
74
|
+
refine ::Binding do
|
75
|
+
def eval_methods
|
76
|
+
::Kernel.instance_method(:methods).bind(eval("self")).call
|
77
|
+
end
|
78
|
+
|
79
|
+
def eval_private_methods
|
80
|
+
::Kernel.instance_method(:private_methods).bind(eval("self")).call
|
81
|
+
end
|
82
|
+
|
83
|
+
def eval_instance_variables
|
84
|
+
::Kernel.instance_method(:instance_variables).bind(eval("self")).call
|
85
|
+
end
|
86
|
+
|
87
|
+
def eval_global_variables
|
88
|
+
::Kernel.instance_method(:global_variables).bind(eval("self")).call
|
89
|
+
end
|
90
|
+
|
91
|
+
def eval_class_constants
|
92
|
+
::Module.instance_method(:constants).bind(eval("self.class")).call
|
93
|
+
end
|
94
|
+
end
|
95
|
+
}
|
111
96
|
|
112
|
-
|
97
|
+
# Set of reserved words used by Ruby, you should not use these for
|
98
|
+
# constants or variables
|
99
|
+
ReservedWords = %w[
|
100
|
+
__ENCODING__ __LINE__ __FILE__
|
101
|
+
BEGIN END
|
102
|
+
alias and
|
103
|
+
begin break
|
104
|
+
case class
|
105
|
+
def defined? do
|
106
|
+
else elsif end ensure
|
107
|
+
false for
|
108
|
+
if in
|
109
|
+
module
|
110
|
+
next nil not
|
111
|
+
or
|
112
|
+
redo rescue retry return
|
113
|
+
self super
|
114
|
+
then true
|
115
|
+
undef unless until
|
116
|
+
when while
|
117
|
+
yield
|
118
|
+
]
|
119
|
+
|
120
|
+
def complete_require_path(target, preposing, postposing)
|
113
121
|
if target =~ /\A(['"])([^'"]+)\Z/
|
114
122
|
quote = $1
|
115
123
|
actual_target = $2
|
@@ -124,39 +132,37 @@ module IRB
|
|
124
132
|
break
|
125
133
|
end
|
126
134
|
end
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
end
|
135
|
+
return unless tok&.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
|
136
|
+
|
137
|
+
case tok.tok
|
138
|
+
when 'require'
|
139
|
+
retrieve_files_to_require_from_load_path.select { |path|
|
140
|
+
path.start_with?(actual_target)
|
141
|
+
}.map { |path|
|
142
|
+
quote + path
|
143
|
+
}
|
144
|
+
when 'require_relative'
|
145
|
+
retrieve_files_to_require_relative_from_current_dir.select { |path|
|
146
|
+
path.start_with?(actual_target)
|
147
|
+
}.map { |path|
|
148
|
+
quote + path
|
149
|
+
}
|
143
150
|
end
|
144
|
-
|
145
|
-
}
|
151
|
+
end
|
146
152
|
|
147
|
-
|
153
|
+
def completion_candidates(preposing, target, postposing, bind:)
|
148
154
|
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) }
|
155
|
+
result = complete_require_path(target, preposing, postposing)
|
156
|
+
return result if result
|
156
157
|
end
|
157
|
-
|
158
|
+
retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
|
159
|
+
end
|
160
|
+
|
161
|
+
def doc_namespace(_preposing, matched, _postposing, bind:)
|
162
|
+
retrieve_completion_data(matched, bind: bind, doc_namespace: true)
|
163
|
+
end
|
158
164
|
|
159
|
-
def
|
165
|
+
def retrieve_completion_data(input, bind:, doc_namespace:)
|
160
166
|
case input
|
161
167
|
# this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting
|
162
168
|
# details are described in: https://github.com/ruby/irb/pull/523
|
@@ -394,44 +400,10 @@ module IRB
|
|
394
400
|
end
|
395
401
|
end
|
396
402
|
|
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
403
|
# Set of available operators in Ruby
|
432
404
|
Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~]
|
433
405
|
|
434
|
-
def
|
406
|
+
def select_message(receiver, message, candidates, sep = ".")
|
435
407
|
candidates.grep(/^#{Regexp.quote(message)}/).collect do |e|
|
436
408
|
case e
|
437
409
|
when /^[a-zA-Z_]/
|
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/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)
|
data/lib/irb/input-method.rb
CHANGED
@@ -11,6 +11,8 @@ require 'reline'
|
|
11
11
|
|
12
12
|
module IRB
|
13
13
|
class InputMethod
|
14
|
+
BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
|
15
|
+
|
14
16
|
# The irb prompt associated with this input method
|
15
17
|
attr_accessor :prompt
|
16
18
|
|
@@ -179,12 +181,16 @@ module IRB
|
|
179
181
|
super
|
180
182
|
|
181
183
|
@eof = false
|
184
|
+
@completor = RegexpCompletor.new
|
182
185
|
|
183
186
|
if Readline.respond_to?("basic_word_break_characters=")
|
184
|
-
Readline.basic_word_break_characters =
|
187
|
+
Readline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
|
185
188
|
end
|
186
189
|
Readline.completion_append_character = nil
|
187
|
-
Readline.completion_proc =
|
190
|
+
Readline.completion_proc = ->(target) {
|
191
|
+
bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
|
192
|
+
@completor.completion_candidates('', target, '', bind: bind)
|
193
|
+
}
|
188
194
|
end
|
189
195
|
|
190
196
|
# Reads the next line from this input method.
|
@@ -230,11 +236,16 @@ module IRB
|
|
230
236
|
super
|
231
237
|
|
232
238
|
@eof = false
|
239
|
+
@completor = RegexpCompletor.new
|
233
240
|
|
234
|
-
Reline.basic_word_break_characters =
|
241
|
+
Reline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
|
235
242
|
Reline.completion_append_character = nil
|
236
243
|
Reline.completer_quote_characters = ''
|
237
|
-
Reline.completion_proc =
|
244
|
+
Reline.completion_proc = ->(target, preposing, postposing) {
|
245
|
+
bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
|
246
|
+
@completion_params = [preposing, target, postposing, bind]
|
247
|
+
@completor.completion_candidates(preposing, target, postposing, bind: bind)
|
248
|
+
}
|
238
249
|
Reline.output_modifier_proc =
|
239
250
|
if IRB.conf[:USE_COLORIZE]
|
240
251
|
proc do |output, complete: |
|
@@ -247,13 +258,13 @@ module IRB
|
|
247
258
|
Reline::Unicode.escape_for_print(output)
|
248
259
|
end
|
249
260
|
end
|
250
|
-
Reline.dig_perfect_match_proc =
|
261
|
+
Reline.dig_perfect_match_proc = ->(matched) { display_document(matched) }
|
251
262
|
Reline.autocompletion = IRB.conf[:USE_AUTOCOMPLETE]
|
252
263
|
|
253
264
|
if IRB.conf[:USE_AUTOCOMPLETE]
|
254
265
|
begin
|
255
266
|
require 'rdoc'
|
256
|
-
Reline.add_dialog_proc(:show_doc,
|
267
|
+
Reline.add_dialog_proc(:show_doc, show_doc_dialog_proc, Reline::DEFAULT_DIALOG_CONTEXT)
|
257
268
|
rescue LoadError
|
258
269
|
end
|
259
270
|
end
|
@@ -271,100 +282,140 @@ module IRB
|
|
271
282
|
@auto_indent_proc = block
|
272
283
|
end
|
273
284
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
285
|
+
def show_doc_dialog_proc
|
286
|
+
doc_namespace = ->(matched) {
|
287
|
+
preposing, _target, postposing, bind = @completion_params
|
288
|
+
@completor.doc_namespace(preposing, matched, postposing, bind: bind)
|
289
|
+
}
|
290
|
+
->() {
|
291
|
+
dialog.trap_key = nil
|
292
|
+
alt_d = [
|
293
|
+
[Reline::Key.new(nil, 0xE4, true)], # Normal Alt+d.
|
294
|
+
[27, 100], # Normal Alt+d when convert-meta isn't used.
|
295
|
+
[195, 164], # The "ä" that appears when Alt+d is pressed on xterm.
|
296
|
+
[226, 136, 130] # The "∂" that appears when Alt+d in pressed on iTerm2.
|
297
|
+
]
|
298
|
+
|
299
|
+
if just_cursor_moving and completion_journey_data.nil?
|
300
|
+
return nil
|
301
|
+
end
|
302
|
+
cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
|
303
|
+
return nil if result.nil? or pointer.nil? or pointer < 0
|
282
304
|
|
283
|
-
|
284
|
-
return nil
|
285
|
-
end
|
286
|
-
cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
|
287
|
-
return nil if result.nil? or pointer.nil? or pointer < 0
|
288
|
-
name = result[pointer]
|
289
|
-
name = IRB::InputCompletor.retrieve_completion_data(name, doc_namespace: true)
|
305
|
+
name = doc_namespace.call(result[pointer])
|
290
306
|
|
291
|
-
|
292
|
-
|
293
|
-
|
307
|
+
options = {}
|
308
|
+
options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
|
309
|
+
driver = RDoc::RI::Driver.new(options)
|
294
310
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
311
|
+
if key.match?(dialog.name)
|
312
|
+
begin
|
313
|
+
driver.display_names([name])
|
314
|
+
rescue RDoc::RI::Driver::NotFoundError
|
315
|
+
end
|
299
316
|
end
|
300
|
-
end
|
301
317
|
|
302
|
-
begin
|
303
|
-
name = driver.expand_name(name)
|
304
|
-
rescue RDoc::RI::Driver::NotFoundError
|
305
|
-
return nil
|
306
|
-
rescue
|
307
|
-
return nil # unknown error
|
308
|
-
end
|
309
|
-
doc = nil
|
310
|
-
used_for_class = false
|
311
|
-
if not name =~ /#|\./
|
312
|
-
found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
|
313
|
-
if not found.empty?
|
314
|
-
doc = driver.class_document(name, found, klasses, includes, extends)
|
315
|
-
used_for_class = true
|
316
|
-
end
|
317
|
-
end
|
318
|
-
unless used_for_class
|
319
|
-
doc = RDoc::Markup::Document.new
|
320
318
|
begin
|
321
|
-
driver.
|
319
|
+
name = driver.expand_name(name)
|
322
320
|
rescue RDoc::RI::Driver::NotFoundError
|
323
|
-
|
321
|
+
return nil
|
324
322
|
rescue
|
325
323
|
return nil # unknown error
|
326
324
|
end
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
325
|
+
doc = nil
|
326
|
+
used_for_class = false
|
327
|
+
if not name =~ /#|\./
|
328
|
+
found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
|
329
|
+
if not found.empty?
|
330
|
+
doc = driver.class_document(name, found, klasses, includes, extends)
|
331
|
+
used_for_class = true
|
332
|
+
end
|
333
|
+
end
|
334
|
+
unless used_for_class
|
335
|
+
doc = RDoc::Markup::Document.new
|
336
|
+
begin
|
337
|
+
driver.add_method(doc, name)
|
338
|
+
rescue RDoc::RI::Driver::NotFoundError
|
339
|
+
doc = nil
|
340
|
+
rescue
|
341
|
+
return nil # unknown error
|
342
|
+
end
|
343
|
+
end
|
344
|
+
return nil if doc.nil?
|
345
|
+
width = 40
|
346
|
+
|
347
|
+
right_x = cursor_pos_to_render.x + autocomplete_dialog.width
|
348
|
+
if right_x + width > screen_width
|
349
|
+
right_width = screen_width - (right_x + 1)
|
350
|
+
left_x = autocomplete_dialog.column - width
|
351
|
+
left_x = 0 if left_x < 0
|
352
|
+
left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
|
353
|
+
if right_width.positive? and left_width.positive?
|
354
|
+
if right_width >= left_width
|
355
|
+
width = right_width
|
356
|
+
x = right_x
|
357
|
+
else
|
358
|
+
width = left_width
|
359
|
+
x = left_x
|
360
|
+
end
|
361
|
+
elsif right_width.positive? and left_width <= 0
|
339
362
|
width = right_width
|
340
363
|
x = right_x
|
341
|
-
|
364
|
+
elsif right_width <= 0 and left_width.positive?
|
342
365
|
width = left_width
|
343
366
|
x = left_x
|
367
|
+
else # Both are negative width.
|
368
|
+
return nil
|
344
369
|
end
|
345
|
-
|
346
|
-
width = right_width
|
370
|
+
else
|
347
371
|
x = right_x
|
348
|
-
elsif right_width <= 0 and left_width.positive?
|
349
|
-
width = left_width
|
350
|
-
x = left_x
|
351
|
-
else # Both are negative width.
|
352
|
-
return nil
|
353
372
|
end
|
373
|
+
formatter = RDoc::Markup::ToAnsi.new
|
374
|
+
formatter.width = width
|
375
|
+
dialog.trap_key = alt_d
|
376
|
+
mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
|
377
|
+
message = "Press #{mod_key}+d to read the full document"
|
378
|
+
contents = [message] + doc.accept(formatter).split("\n")
|
379
|
+
contents = contents.take(preferred_dialog_height)
|
380
|
+
|
381
|
+
y = cursor_pos_to_render.y
|
382
|
+
Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
|
383
|
+
}
|
384
|
+
end
|
385
|
+
|
386
|
+
def display_document(matched, driver: nil)
|
387
|
+
begin
|
388
|
+
require 'rdoc'
|
389
|
+
rescue LoadError
|
390
|
+
return
|
391
|
+
end
|
392
|
+
|
393
|
+
if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
|
394
|
+
IRB.__send__(:easter_egg)
|
395
|
+
return
|
396
|
+
end
|
397
|
+
|
398
|
+
_target, preposing, postposing, bind = @completion_params
|
399
|
+
namespace = @completor.doc_namespace(preposing, matched, postposing, bind: bind)
|
400
|
+
return unless namespace
|
401
|
+
|
402
|
+
driver ||= RDoc::RI::Driver.new
|
403
|
+
if namespace.is_a?(Array)
|
404
|
+
out = RDoc::Markup::Document.new
|
405
|
+
namespace.each do |m|
|
406
|
+
begin
|
407
|
+
driver.add_method(out, m)
|
408
|
+
rescue RDoc::RI::Driver::NotFoundError
|
409
|
+
end
|
410
|
+
end
|
411
|
+
driver.display(out)
|
354
412
|
else
|
355
|
-
|
413
|
+
begin
|
414
|
+
driver.display_names([namespace])
|
415
|
+
rescue RDoc::RI::Driver::NotFoundError
|
416
|
+
end
|
356
417
|
end
|
357
|
-
|
358
|
-
formatter.width = width
|
359
|
-
dialog.trap_key = alt_d
|
360
|
-
mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
|
361
|
-
message = "Press #{mod_key}+d to read the full document"
|
362
|
-
contents = [message] + doc.accept(formatter).split("\n")
|
363
|
-
contents = contents.take(preferred_dialog_height)
|
364
|
-
|
365
|
-
y = cursor_pos_to_render.y
|
366
|
-
Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
|
367
|
-
}
|
418
|
+
end
|
368
419
|
|
369
420
|
# Reads the next line from this input method.
|
370
421
|
#
|
data/lib/irb/ruby-lex.rb
CHANGED
@@ -42,14 +42,6 @@ module IRB
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
attr_reader :line_no
|
46
|
-
|
47
|
-
def initialize(context)
|
48
|
-
@context = context
|
49
|
-
@line_no = 1
|
50
|
-
@prompt = nil
|
51
|
-
end
|
52
|
-
|
53
45
|
def self.compile_with_errors_suppressed(code, line_no: 1)
|
54
46
|
begin
|
55
47
|
result = yield code, line_no
|
@@ -67,10 +59,6 @@ module IRB
|
|
67
59
|
result
|
68
60
|
end
|
69
61
|
|
70
|
-
def set_prompt(&block)
|
71
|
-
@prompt = block
|
72
|
-
end
|
73
|
-
|
74
62
|
ERROR_TOKENS = [
|
75
63
|
:on_parse_error,
|
76
64
|
:compile_error,
|
@@ -116,9 +104,9 @@ module IRB
|
|
116
104
|
interpolated
|
117
105
|
end
|
118
106
|
|
119
|
-
def self.ripper_lex_without_warning(code,
|
107
|
+
def self.ripper_lex_without_warning(code, local_variables: [])
|
120
108
|
verbose, $VERBOSE = $VERBOSE, nil
|
121
|
-
lvars_code = generate_local_variables_assign_code(
|
109
|
+
lvars_code = generate_local_variables_assign_code(local_variables)
|
122
110
|
original_code = code
|
123
111
|
if lvars_code
|
124
112
|
code = "#{lvars_code}\n#{code}"
|
@@ -146,20 +134,14 @@ module IRB
|
|
146
134
|
$VERBOSE = verbose
|
147
135
|
end
|
148
136
|
|
149
|
-
def
|
150
|
-
|
151
|
-
indent_level = calc_indent_level(opens)
|
152
|
-
@prompt&.call(ltype, indent_level, opens.any? || continue, @line_no + line_num_offset)
|
153
|
-
end
|
154
|
-
|
155
|
-
def check_code_state(code)
|
156
|
-
tokens = self.class.ripper_lex_without_warning(code, context: @context)
|
137
|
+
def check_code_state(code, local_variables:)
|
138
|
+
tokens = self.class.ripper_lex_without_warning(code, local_variables: local_variables)
|
157
139
|
opens = NestingParser.open_tokens(tokens)
|
158
|
-
[tokens, opens, code_terminated?(code, tokens, opens)]
|
140
|
+
[tokens, opens, code_terminated?(code, tokens, opens, local_variables: local_variables)]
|
159
141
|
end
|
160
142
|
|
161
|
-
def code_terminated?(code, tokens, opens)
|
162
|
-
case check_code_syntax(code)
|
143
|
+
def code_terminated?(code, tokens, opens, local_variables:)
|
144
|
+
case check_code_syntax(code, local_variables: local_variables)
|
163
145
|
when :unrecoverable_error
|
164
146
|
true
|
165
147
|
when :recoverable_error
|
@@ -171,16 +153,7 @@ module IRB
|
|
171
153
|
end
|
172
154
|
end
|
173
155
|
|
174
|
-
def
|
175
|
-
# Implicitly saves prompt string to `@context.io.prompt`. This will be used in the next `@input.call`.
|
176
|
-
prompt(opens, continue, line_num_offset)
|
177
|
-
end
|
178
|
-
|
179
|
-
def increase_line_no(addition)
|
180
|
-
@line_no += addition
|
181
|
-
end
|
182
|
-
|
183
|
-
def assignment_expression?(code)
|
156
|
+
def assignment_expression?(code, local_variables:)
|
184
157
|
# Try to parse the code and check if the last of possibly multiple
|
185
158
|
# expressions is an assignment type.
|
186
159
|
|
@@ -190,7 +163,7 @@ module IRB
|
|
190
163
|
# array of parsed expressions. The first element of each expression is the
|
191
164
|
# expression's type.
|
192
165
|
verbose, $VERBOSE = $VERBOSE, nil
|
193
|
-
code = "#{RubyLex.generate_local_variables_assign_code(
|
166
|
+
code = "#{RubyLex.generate_local_variables_assign_code(local_variables) || 'nil;'}\n#{code}"
|
194
167
|
# Get the last node_type of the line. drop(1) is to ignore the local_variables_assign_code part.
|
195
168
|
node_type = Ripper.sexp(code)&.dig(1)&.drop(1)&.dig(-1, 0)
|
196
169
|
ASSIGNMENT_NODE_TYPES.include?(node_type)
|
@@ -222,8 +195,8 @@ module IRB
|
|
222
195
|
false
|
223
196
|
end
|
224
197
|
|
225
|
-
def check_code_syntax(code)
|
226
|
-
lvars_code = RubyLex.generate_local_variables_assign_code(
|
198
|
+
def check_code_syntax(code, local_variables:)
|
199
|
+
lvars_code = RubyLex.generate_local_variables_assign_code(local_variables)
|
227
200
|
code = "#{lvars_code}\n#{code}"
|
228
201
|
|
229
202
|
begin # check if parser error are available
|
@@ -455,8 +428,8 @@ module IRB
|
|
455
428
|
end
|
456
429
|
end
|
457
430
|
|
458
|
-
def check_termination_in_prev_line(code)
|
459
|
-
tokens = self.class.ripper_lex_without_warning(code,
|
431
|
+
def check_termination_in_prev_line(code, local_variables:)
|
432
|
+
tokens = self.class.ripper_lex_without_warning(code, local_variables: local_variables)
|
460
433
|
past_first_newline = false
|
461
434
|
index = tokens.rindex do |t|
|
462
435
|
# traverse first token before last line
|
@@ -486,7 +459,7 @@ module IRB
|
|
486
459
|
tokens_without_last_line = tokens[0..index]
|
487
460
|
code_without_last_line = tokens_without_last_line.map(&:tok).join
|
488
461
|
opens_without_last_line = NestingParser.open_tokens(tokens_without_last_line)
|
489
|
-
if code_terminated?(code_without_last_line, tokens_without_last_line, opens_without_last_line)
|
462
|
+
if code_terminated?(code_without_last_line, tokens_without_last_line, opens_without_last_line, local_variables: local_variables)
|
490
463
|
return last_line_tokens.map(&:tok).join
|
491
464
|
end
|
492
465
|
end
|
data/lib/irb/source_finder.rb
CHANGED
@@ -43,7 +43,7 @@ module IRB
|
|
43
43
|
private
|
44
44
|
|
45
45
|
def find_end(file, first_line)
|
46
|
-
lex = RubyLex.new
|
46
|
+
lex = RubyLex.new
|
47
47
|
lines = File.read(file).lines[(first_line - 1)..-1]
|
48
48
|
tokens = RubyLex.ripper_lex_without_warning(lines.join)
|
49
49
|
prev_tokens = []
|
@@ -53,7 +53,7 @@ module IRB
|
|
53
53
|
code = lines[0..lnum].join
|
54
54
|
prev_tokens.concat chunk
|
55
55
|
continue = lex.should_continue?(prev_tokens)
|
56
|
-
syntax = lex.check_code_syntax(code)
|
56
|
+
syntax = lex.check_code_syntax(code, local_variables: [])
|
57
57
|
if !continue && syntax == :valid
|
58
58
|
return first_line + lnum
|
59
59
|
end
|
data/lib/irb/version.rb
CHANGED
data/lib/irb.rb
CHANGED
@@ -436,7 +436,8 @@ module IRB
|
|
436
436
|
@context = Context.new(self, workspace, input_method)
|
437
437
|
@context.workspace.load_commands_to_main
|
438
438
|
@signal_status = :IN_IRB
|
439
|
-
@scanner = RubyLex.new
|
439
|
+
@scanner = RubyLex.new
|
440
|
+
@line_no = 1
|
440
441
|
end
|
441
442
|
|
442
443
|
# A hook point for `debug` command's breakpoint after :IRB_EXIT as well as its clean-up
|
@@ -454,7 +455,7 @@ module IRB
|
|
454
455
|
workspace = IRB::WorkSpace.new(binding)
|
455
456
|
context.workspace = workspace
|
456
457
|
context.workspace.load_commands_to_main
|
457
|
-
|
458
|
+
@line_no += 1
|
458
459
|
|
459
460
|
# When users run:
|
460
461
|
# 1. Debugging commands, like `step 2`
|
@@ -476,7 +477,7 @@ module IRB
|
|
476
477
|
end
|
477
478
|
|
478
479
|
if input&.include?("\n")
|
479
|
-
|
480
|
+
@line_no += input.count("\n") - 1
|
480
481
|
end
|
481
482
|
|
482
483
|
input
|
@@ -513,34 +514,38 @@ module IRB
|
|
513
514
|
# The lexer used by this irb session
|
514
515
|
attr_accessor :scanner
|
515
516
|
|
516
|
-
|
517
|
-
|
518
|
-
@scanner.
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
f =
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
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
|
540
542
|
end
|
541
|
-
@context.io.prompt
|
542
543
|
end
|
544
|
+
p
|
545
|
+
end
|
543
546
|
|
547
|
+
# Evaluates input for this session.
|
548
|
+
def eval_input
|
544
549
|
configure_io
|
545
550
|
|
546
551
|
each_top_level_statement do |statement, line_no|
|
@@ -572,8 +577,9 @@ module IRB
|
|
572
577
|
end
|
573
578
|
end
|
574
579
|
|
575
|
-
def read_input
|
580
|
+
def read_input(prompt)
|
576
581
|
signal_status(:IN_INPUT) do
|
582
|
+
@context.io.prompt = prompt
|
577
583
|
if l = @context.io.gets
|
578
584
|
print l if @context.verbose?
|
579
585
|
else
|
@@ -591,16 +597,16 @@ module IRB
|
|
591
597
|
end
|
592
598
|
|
593
599
|
def readmultiline
|
594
|
-
|
600
|
+
prompt = generate_prompt([], false, 0)
|
595
601
|
|
596
602
|
# multiline
|
597
|
-
return read_input if @context.io.respond_to?(:check_termination)
|
603
|
+
return read_input(prompt) if @context.io.respond_to?(:check_termination)
|
598
604
|
|
599
605
|
# nomultiline
|
600
606
|
code = ''
|
601
607
|
line_offset = 0
|
602
608
|
loop do
|
603
|
-
line = read_input
|
609
|
+
line = read_input(prompt)
|
604
610
|
unless line
|
605
611
|
return code.empty? ? nil : code
|
606
612
|
end
|
@@ -610,12 +616,12 @@ module IRB
|
|
610
616
|
# Accept any single-line input for symbol aliases or commands that transform args
|
611
617
|
return code if single_line_command?(code)
|
612
618
|
|
613
|
-
tokens, opens, terminated = @scanner.check_code_state(code)
|
619
|
+
tokens, opens, terminated = @scanner.check_code_state(code, local_variables: @context.local_variables)
|
614
620
|
return code if terminated
|
615
621
|
|
616
622
|
line_offset += 1
|
617
623
|
continue = @scanner.should_continue?(tokens)
|
618
|
-
|
624
|
+
prompt = generate_prompt(opens, continue, line_offset)
|
619
625
|
end
|
620
626
|
end
|
621
627
|
|
@@ -625,9 +631,9 @@ module IRB
|
|
625
631
|
break unless code
|
626
632
|
|
627
633
|
if code != "\n"
|
628
|
-
yield build_statement(code), @
|
634
|
+
yield build_statement(code), @line_no
|
629
635
|
end
|
630
|
-
@
|
636
|
+
@line_no += code.count("\n")
|
631
637
|
rescue RubyLex::TerminateLineInput
|
632
638
|
end
|
633
639
|
end
|
@@ -643,7 +649,8 @@ module IRB
|
|
643
649
|
if command_class
|
644
650
|
Statement::Command.new(code, command, arg, command_class)
|
645
651
|
else
|
646
|
-
|
652
|
+
is_assignment_expression = @scanner.assignment_expression?(code, local_variables: @context.local_variables)
|
653
|
+
Statement::Expression.new(code, is_assignment_expression)
|
647
654
|
end
|
648
655
|
end
|
649
656
|
|
@@ -656,7 +663,7 @@ module IRB
|
|
656
663
|
if @context.io.respond_to?(:check_termination)
|
657
664
|
@context.io.check_termination do |code|
|
658
665
|
if Reline::IOGate.in_pasting?
|
659
|
-
rest = @scanner.check_termination_in_prev_line(code)
|
666
|
+
rest = @scanner.check_termination_in_prev_line(code, local_variables: @context.local_variables)
|
660
667
|
if rest
|
661
668
|
Reline.delete_text
|
662
669
|
rest.bytes.reverse_each do |c|
|
@@ -670,7 +677,7 @@ module IRB
|
|
670
677
|
# Accept any single-line input for symbol aliases or commands that transform args
|
671
678
|
next true if single_line_command?(code)
|
672
679
|
|
673
|
-
_tokens, _opens, terminated = @scanner.check_code_state(code)
|
680
|
+
_tokens, _opens, terminated = @scanner.check_code_state(code, local_variables: @context.local_variables)
|
674
681
|
terminated
|
675
682
|
end
|
676
683
|
end
|
@@ -678,7 +685,7 @@ module IRB
|
|
678
685
|
if @context.io.respond_to?(:dynamic_prompt)
|
679
686
|
@context.io.dynamic_prompt do |lines|
|
680
687
|
lines << '' if lines.empty?
|
681
|
-
tokens = RubyLex.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join,
|
688
|
+
tokens = RubyLex.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, local_variables: @context.local_variables)
|
682
689
|
line_results = IRB::NestingParser.parse_by_line(tokens)
|
683
690
|
tokens_until_line = []
|
684
691
|
line_results.map.with_index do |(line_tokens, _prev_opens, next_opens, _min_depth), line_num_offset|
|
@@ -687,7 +694,7 @@ module IRB
|
|
687
694
|
tokens_until_line << token if token != tokens_until_line.last
|
688
695
|
end
|
689
696
|
continue = @scanner.should_continue?(tokens_until_line)
|
690
|
-
|
697
|
+
generate_prompt(next_opens, continue, line_num_offset)
|
691
698
|
end
|
692
699
|
end
|
693
700
|
end
|
@@ -698,7 +705,7 @@ module IRB
|
|
698
705
|
next nil if !is_newline && lines[line_index]&.byteslice(0, byte_pointer)&.match?(/\A\s*\z/)
|
699
706
|
|
700
707
|
code = lines[0..line_index].map { |l| "#{l}\n" }.join
|
701
|
-
tokens = RubyLex.ripper_lex_without_warning(code,
|
708
|
+
tokens = RubyLex.ripper_lex_without_warning(code, local_variables: @context.local_variables)
|
702
709
|
@scanner.process_indent_level(tokens, lines, line_index, is_newline)
|
703
710
|
end
|
704
711
|
end
|
@@ -873,7 +880,7 @@ module IRB
|
|
873
880
|
end
|
874
881
|
end
|
875
882
|
|
876
|
-
def truncate_prompt_main(str) # :nodoc:
|
883
|
+
private def truncate_prompt_main(str) # :nodoc:
|
877
884
|
str = str.tr(CONTROL_CHARACTERS_PATTERN, ' ')
|
878
885
|
if str.size <= PROMPT_MAIN_TRUNCATE_LENGTH
|
879
886
|
str
|
@@ -882,9 +889,8 @@ module IRB
|
|
882
889
|
end
|
883
890
|
end
|
884
891
|
|
885
|
-
def
|
886
|
-
|
887
|
-
p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
|
892
|
+
private def format_prompt(format, ltype, indent, line_no) # :nodoc:
|
893
|
+
format.gsub(/%([0-9]+)?([a-zA-Z])/) do
|
888
894
|
case $2
|
889
895
|
when "N"
|
890
896
|
@context.irb_name
|
@@ -918,7 +924,6 @@ module IRB
|
|
918
924
|
"%"
|
919
925
|
end
|
920
926
|
end
|
921
|
-
p
|
922
927
|
end
|
923
928
|
|
924
929
|
def output_value(omit = false) # :nodoc:
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: irb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.8.
|
4
|
+
version: 1.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-10-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: reline
|