irb 1.3.3 → 1.3.7
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 +10 -0
- data/Rakefile +8 -1
- data/irb.gemspec +2 -49
- data/lib/irb.rb +28 -11
- data/lib/irb/cmd/info.rb +7 -0
- data/lib/irb/cmd/ls.rb +101 -0
- data/lib/irb/cmd/measure.rb +3 -0
- data/lib/irb/cmd/nop.rb +10 -4
- data/lib/irb/cmd/show_source.rb +96 -0
- data/lib/irb/cmd/whereami.rb +20 -0
- data/lib/irb/color.rb +13 -15
- data/lib/irb/color_printer.rb +9 -0
- data/lib/irb/completion.rb +73 -3
- data/lib/irb/ext/loader.rb +2 -2
- data/lib/irb/ext/save-history.rb +15 -5
- data/lib/irb/extend-command.rb +21 -4
- data/lib/irb/init.rb +16 -4
- data/lib/irb/input-method.rb +1 -0
- data/lib/irb/lc/help-message +6 -6
- data/lib/irb/ruby-lex.rb +97 -22
- data/lib/irb/version.rb +2 -2
- data/lib/irb/workspace.rb +1 -1
- metadata +8 -33
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ddb63fc9d57700014a7da313e20504596ca42dfee0952547fa545d726f08d7d6
|
|
4
|
+
data.tar.gz: cc4ee2f880d56dc7f792ecc406f489f8555601d19499f45d8f8828cc260ed1b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c5b128b8ce5457862489e313231af33167802619c3847da526dda30c83f7fc96d1a248d2916e17da4cbd45f8d30aee8c181237182b97b5741cf4bc4c13568bfb
|
|
7
|
+
data.tar.gz: 61147b2b4e76f34076043feaa84feeb2e893a140d3d7d1e5013a00f87f27f694802f8ae21788709a7ee03c5b41ee445735aec93bfedbeaa9fcf02d6bf06f705d
|
data/Gemfile
CHANGED
|
@@ -3,3 +3,13 @@ source "https://rubygems.org"
|
|
|
3
3
|
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
|
4
4
|
|
|
5
5
|
gemspec
|
|
6
|
+
|
|
7
|
+
group :development do
|
|
8
|
+
gem "bundler"
|
|
9
|
+
is_unix = RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
|
|
10
|
+
is_truffleruby = RUBY_DESCRIPTION =~ /truffleruby/
|
|
11
|
+
gem 'vterm', '>= 0.0.5' if is_unix && ENV['WITH_VTERM']
|
|
12
|
+
gem 'yamatanooroti', '>= 0.0.6'
|
|
13
|
+
gem "rake"
|
|
14
|
+
gem "stackprof" if is_unix && !is_truffleruby
|
|
15
|
+
end
|
data/Rakefile
CHANGED
|
@@ -4,7 +4,14 @@ require "rake/testtask"
|
|
|
4
4
|
Rake::TestTask.new(:test) do |t|
|
|
5
5
|
t.libs << "test" << "test/lib"
|
|
6
6
|
t.libs << "lib"
|
|
7
|
-
t.test_files = FileList["test
|
|
7
|
+
t.test_files = FileList["test/irb/test_*.rb"]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Rake::TestTask.new(:test_yamatanooroti) do |t|
|
|
11
|
+
t.libs << 'test'
|
|
12
|
+
t.libs << 'lib'
|
|
13
|
+
#t.loader = :direct
|
|
14
|
+
t.pattern = 'test/irb/yamatanooroti/test_*.rb'
|
|
8
15
|
end
|
|
9
16
|
|
|
10
17
|
task :default => :test
|
data/irb.gemspec
CHANGED
|
@@ -28,60 +28,13 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
"doc/irb/irb.rd.ja",
|
|
29
29
|
"exe/irb",
|
|
30
30
|
"irb.gemspec",
|
|
31
|
-
"lib/irb.rb",
|
|
32
|
-
"lib/irb/cmd/chws.rb",
|
|
33
|
-
"lib/irb/cmd/fork.rb",
|
|
34
|
-
"lib/irb/cmd/help.rb",
|
|
35
|
-
"lib/irb/cmd/info.rb",
|
|
36
|
-
"lib/irb/cmd/load.rb",
|
|
37
|
-
"lib/irb/cmd/measure.rb",
|
|
38
|
-
"lib/irb/cmd/nop.rb",
|
|
39
|
-
"lib/irb/cmd/pushws.rb",
|
|
40
|
-
"lib/irb/cmd/subirb.rb",
|
|
41
|
-
"lib/irb/color.rb",
|
|
42
|
-
"lib/irb/color_printer.rb",
|
|
43
|
-
"lib/irb/completion.rb",
|
|
44
|
-
"lib/irb/context.rb",
|
|
45
|
-
"lib/irb/easter-egg.rb",
|
|
46
|
-
"lib/irb/ext/change-ws.rb",
|
|
47
|
-
"lib/irb/ext/history.rb",
|
|
48
|
-
"lib/irb/ext/loader.rb",
|
|
49
|
-
"lib/irb/ext/multi-irb.rb",
|
|
50
|
-
"lib/irb/ext/save-history.rb",
|
|
51
|
-
"lib/irb/ext/tracer.rb",
|
|
52
|
-
"lib/irb/ext/use-loader.rb",
|
|
53
|
-
"lib/irb/ext/workspaces.rb",
|
|
54
|
-
"lib/irb/extend-command.rb",
|
|
55
|
-
"lib/irb/frame.rb",
|
|
56
|
-
"lib/irb/help.rb",
|
|
57
|
-
"lib/irb/init.rb",
|
|
58
|
-
"lib/irb/input-method.rb",
|
|
59
|
-
"lib/irb/inspector.rb",
|
|
60
|
-
"lib/irb/lc/error.rb",
|
|
61
|
-
"lib/irb/lc/help-message",
|
|
62
|
-
"lib/irb/lc/ja/encoding_aliases.rb",
|
|
63
|
-
"lib/irb/lc/ja/error.rb",
|
|
64
|
-
"lib/irb/lc/ja/help-message",
|
|
65
|
-
"lib/irb/locale.rb",
|
|
66
|
-
"lib/irb/magic-file.rb",
|
|
67
|
-
"lib/irb/notifier.rb",
|
|
68
|
-
"lib/irb/output-method.rb",
|
|
69
|
-
"lib/irb/ruby-lex.rb",
|
|
70
|
-
"lib/irb/ruby_logo.aa",
|
|
71
|
-
"lib/irb/src_encoding.rb",
|
|
72
|
-
"lib/irb/version.rb",
|
|
73
|
-
"lib/irb/workspace.rb",
|
|
74
|
-
"lib/irb/ws-for-case-2.rb",
|
|
75
|
-
"lib/irb/xmp.rb",
|
|
76
31
|
"man/irb.1",
|
|
77
|
-
]
|
|
32
|
+
] + Dir.glob("lib/**/*")
|
|
78
33
|
spec.bindir = "exe"
|
|
79
34
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
80
35
|
spec.require_paths = ["lib"]
|
|
81
36
|
|
|
82
37
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.5")
|
|
83
38
|
|
|
84
|
-
spec.add_dependency "reline", ">= 0.
|
|
85
|
-
spec.add_development_dependency "bundler"
|
|
86
|
-
spec.add_development_dependency "rake"
|
|
39
|
+
spec.add_dependency "reline", ">= 0.2.7"
|
|
87
40
|
end
|
data/lib/irb.rb
CHANGED
|
@@ -60,7 +60,11 @@ require_relative "irb/easter-egg"
|
|
|
60
60
|
# -E enc Same as `ruby -E`
|
|
61
61
|
# -w Same as `ruby -w`
|
|
62
62
|
# -W[level=2] Same as `ruby -W`
|
|
63
|
-
# --
|
|
63
|
+
# --context-mode n Set n[0-4] to method to create Binding Object,
|
|
64
|
+
# when new workspace was created
|
|
65
|
+
# --echo Show result(default)
|
|
66
|
+
# --noecho Don't show result
|
|
67
|
+
# --inspect Use `inspect' for output
|
|
64
68
|
# --noinspect Don't use inspect for output
|
|
65
69
|
# --multiline Use multiline editor module
|
|
66
70
|
# --nomultiline Don't use multiline editor module
|
|
@@ -68,19 +72,24 @@ require_relative "irb/easter-egg"
|
|
|
68
72
|
# --nosingleline Don't use singleline editor module
|
|
69
73
|
# --colorize Use colorization
|
|
70
74
|
# --nocolorize Don't use colorization
|
|
71
|
-
# --prompt prompt-mode
|
|
72
|
-
# --prompt-mode prompt-mode
|
|
75
|
+
# --prompt prompt-mode/--prompt-mode prompt-mode
|
|
73
76
|
# Switch prompt mode. Pre-defined prompt modes are
|
|
74
77
|
# `default', `simple', `xmp' and `inf-ruby'
|
|
75
78
|
# --inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs.
|
|
76
79
|
# Suppresses --multiline and --singleline.
|
|
77
|
-
# --simple-prompt
|
|
80
|
+
# --sample-book-mode/--simple-prompt
|
|
81
|
+
# Simple prompt mode
|
|
78
82
|
# --noprompt No prompt mode
|
|
83
|
+
# --single-irb Share self with sub-irb.
|
|
79
84
|
# --tracer Display trace for each execution of commands.
|
|
80
85
|
# --back-trace-limit n
|
|
81
86
|
# Display backtrace top n and tail n. The default
|
|
82
87
|
# value is 16.
|
|
83
|
-
#
|
|
88
|
+
# --verbose Show details
|
|
89
|
+
# --noverbose Don't show details
|
|
90
|
+
# -v, --version Print the version of irb
|
|
91
|
+
# -h, --help Print help
|
|
92
|
+
# -- Separate options of irb from the list of command-line args
|
|
84
93
|
#
|
|
85
94
|
# == Configuration
|
|
86
95
|
#
|
|
@@ -463,7 +472,7 @@ module IRB
|
|
|
463
472
|
conf[:IRB_RC].call(context) if conf[:IRB_RC]
|
|
464
473
|
conf[:MAIN_CONTEXT] = context
|
|
465
474
|
|
|
466
|
-
trap("SIGINT") do
|
|
475
|
+
prev_trap = trap("SIGINT") do
|
|
467
476
|
signal_handle
|
|
468
477
|
end
|
|
469
478
|
|
|
@@ -472,6 +481,7 @@ module IRB
|
|
|
472
481
|
eval_input
|
|
473
482
|
end
|
|
474
483
|
ensure
|
|
484
|
+
trap("SIGINT", prev_trap)
|
|
475
485
|
conf[:AT_EXIT].each{|hook| hook.call}
|
|
476
486
|
end
|
|
477
487
|
end
|
|
@@ -514,7 +524,7 @@ module IRB
|
|
|
514
524
|
@context.io.prompt
|
|
515
525
|
end
|
|
516
526
|
|
|
517
|
-
@scanner.set_input(@context.io) do
|
|
527
|
+
@scanner.set_input(@context.io, context: @context) do
|
|
518
528
|
signal_status(:IN_INPUT) do
|
|
519
529
|
if l = @context.io.gets
|
|
520
530
|
print l if @context.verbose?
|
|
@@ -580,9 +590,15 @@ module IRB
|
|
|
580
590
|
end
|
|
581
591
|
end
|
|
582
592
|
|
|
583
|
-
def convert_invalid_byte_sequence(str)
|
|
584
|
-
str
|
|
585
|
-
|
|
593
|
+
def convert_invalid_byte_sequence(str, enc)
|
|
594
|
+
str.force_encoding(enc)
|
|
595
|
+
str.scrub { |c|
|
|
596
|
+
c.bytes.map{ |b| "\\x#{b.to_s(16).upcase}" }.join
|
|
597
|
+
}
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
def encode_with_invalid_byte_sequence(str, enc)
|
|
601
|
+
conv = Encoding::Converter.new(str.encoding, enc)
|
|
586
602
|
dst = String.new
|
|
587
603
|
begin
|
|
588
604
|
ret = conv.primitive_convert(str, dst)
|
|
@@ -630,7 +646,8 @@ module IRB
|
|
|
630
646
|
message = exc.full_message(order: :top)
|
|
631
647
|
order = :top
|
|
632
648
|
end
|
|
633
|
-
message = convert_invalid_byte_sequence(message)
|
|
649
|
+
message = convert_invalid_byte_sequence(message, exc.message.encoding)
|
|
650
|
+
message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s)
|
|
634
651
|
message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
|
|
635
652
|
case order
|
|
636
653
|
when :top
|
data/lib/irb/cmd/info.rb
CHANGED
|
@@ -13,6 +13,13 @@ module IRB
|
|
|
13
13
|
str += "IRB version: #{IRB.version}\n"
|
|
14
14
|
str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
|
|
15
15
|
str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
|
|
16
|
+
str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
|
|
17
|
+
str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
|
|
18
|
+
str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
|
|
19
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
|
20
|
+
codepage = `chcp`.sub(/.*: (\d+)\n/, '\1')
|
|
21
|
+
str += "Code page: #{codepage}\n"
|
|
22
|
+
end
|
|
16
23
|
str
|
|
17
24
|
end
|
|
18
25
|
alias_method :to_s, :inspect
|
data/lib/irb/cmd/ls.rb
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "reline"
|
|
4
|
+
require_relative "nop"
|
|
5
|
+
require_relative "../color"
|
|
6
|
+
|
|
7
|
+
# :stopdoc:
|
|
8
|
+
module IRB
|
|
9
|
+
module ExtendCommand
|
|
10
|
+
class Ls < Nop
|
|
11
|
+
def execute(*arg, grep: nil)
|
|
12
|
+
o = Output.new(grep: grep)
|
|
13
|
+
|
|
14
|
+
obj = arg.empty? ? irb_context.workspace.main : arg.first
|
|
15
|
+
locals = arg.empty? ? irb_context.workspace.binding.local_variables : []
|
|
16
|
+
klass = (obj.class == Class || obj.class == Module ? obj : obj.class)
|
|
17
|
+
|
|
18
|
+
o.dump("constants", obj.constants) if obj.respond_to?(:constants)
|
|
19
|
+
dump_methods(o, klass, obj)
|
|
20
|
+
o.dump("instance variables", obj.instance_variables)
|
|
21
|
+
o.dump("class variables", klass.class_variables)
|
|
22
|
+
o.dump("locals", locals)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def dump_methods(o, klass, obj)
|
|
26
|
+
singleton_class = begin obj.singleton_class; rescue TypeError; nil end
|
|
27
|
+
maps = class_method_map((singleton_class || klass).ancestors)
|
|
28
|
+
maps.each do |mod, methods|
|
|
29
|
+
name = mod == singleton_class ? "#{klass}.methods" : "#{mod}#methods"
|
|
30
|
+
o.dump(name, methods)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def class_method_map(classes)
|
|
35
|
+
dumped = Array.new
|
|
36
|
+
classes.reject { |mod| mod >= Object }.map do |mod|
|
|
37
|
+
methods = mod.public_instance_methods(false).select do |m|
|
|
38
|
+
dumped.push(m) unless dumped.include?(m)
|
|
39
|
+
end
|
|
40
|
+
[mod, methods]
|
|
41
|
+
end.reverse
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class Output
|
|
45
|
+
MARGIN = " "
|
|
46
|
+
|
|
47
|
+
def initialize(grep: nil)
|
|
48
|
+
@grep = grep
|
|
49
|
+
@line_width = screen_width - MARGIN.length # right padding
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def dump(name, strs)
|
|
53
|
+
strs = strs.grep(@grep) if @grep
|
|
54
|
+
strs = strs.sort
|
|
55
|
+
return if strs.empty?
|
|
56
|
+
|
|
57
|
+
# Attempt a single line
|
|
58
|
+
print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
|
|
59
|
+
if fits_on_line?(strs, cols: strs.size, offset: "#{name}: ".length)
|
|
60
|
+
puts strs.join(MARGIN)
|
|
61
|
+
return
|
|
62
|
+
end
|
|
63
|
+
puts
|
|
64
|
+
|
|
65
|
+
# Dump with the largest # of columns that fits on a line
|
|
66
|
+
cols = strs.size
|
|
67
|
+
until fits_on_line?(strs, cols: cols, offset: MARGIN.length) || cols == 1
|
|
68
|
+
cols -= 1
|
|
69
|
+
end
|
|
70
|
+
widths = col_widths(strs, cols: cols)
|
|
71
|
+
strs.each_slice(cols) do |ss|
|
|
72
|
+
puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def fits_on_line?(strs, cols:, offset: 0)
|
|
79
|
+
width = col_widths(strs, cols: cols).sum + MARGIN.length * (cols - 1)
|
|
80
|
+
width <= @line_width - offset
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def col_widths(strs, cols:)
|
|
84
|
+
cols.times.map do |col|
|
|
85
|
+
(col...strs.size).step(cols).map do |i|
|
|
86
|
+
strs[i].length
|
|
87
|
+
end.max
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def screen_width
|
|
92
|
+
Reline.get_screen_size.last
|
|
93
|
+
rescue Errno::EINVAL # in `winsize': Invalid argument - <STDIN>
|
|
94
|
+
80
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
private_constant :Output
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
# :startdoc:
|
data/lib/irb/cmd/measure.rb
CHANGED
|
@@ -9,6 +9,9 @@ module IRB
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def execute(type = nil, arg = nil, &block)
|
|
12
|
+
# Please check IRB.init_config in lib/irb/init.rb that sets
|
|
13
|
+
# IRB.conf[:MEASURE_PROC] to register default "measure" methods,
|
|
14
|
+
# "measure :time" (abbreviated as "measure") and "measure :stackprof".
|
|
12
15
|
case type
|
|
13
16
|
when :off
|
|
14
17
|
IRB.conf[:MEASURE] = nil
|
data/lib/irb/cmd/nop.rb
CHANGED
|
@@ -14,10 +14,16 @@ module IRB
|
|
|
14
14
|
module ExtendCommand
|
|
15
15
|
class Nop
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
|
|
18
|
+
def self.execute(conf, *opts, **kwargs, &block)
|
|
19
|
+
command = new(conf)
|
|
20
|
+
command.execute(*opts, **kwargs, &block)
|
|
21
|
+
end
|
|
22
|
+
else
|
|
23
|
+
def self.execute(conf, *opts, &block)
|
|
24
|
+
command = new(conf)
|
|
25
|
+
command.execute(*opts, &block)
|
|
26
|
+
end
|
|
21
27
|
end
|
|
22
28
|
|
|
23
29
|
def initialize(conf)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "nop"
|
|
4
|
+
require_relative "../color"
|
|
5
|
+
require_relative "../ruby-lex"
|
|
6
|
+
|
|
7
|
+
# :stopdoc:
|
|
8
|
+
module IRB
|
|
9
|
+
module ExtendCommand
|
|
10
|
+
class ShowSource < Nop
|
|
11
|
+
def execute(str = nil)
|
|
12
|
+
unless str.is_a?(String)
|
|
13
|
+
puts "Error: Expected a string but got #{str.inspect}"
|
|
14
|
+
return
|
|
15
|
+
end
|
|
16
|
+
source = find_source(str)
|
|
17
|
+
if source && File.exist?(source.file)
|
|
18
|
+
show_source(source)
|
|
19
|
+
else
|
|
20
|
+
puts "Error: Couldn't locate a definition for #{str}"
|
|
21
|
+
end
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# @param [IRB::ExtendCommand::ShowSource::Source] source
|
|
28
|
+
def show_source(source)
|
|
29
|
+
puts
|
|
30
|
+
puts "#{bold("From")}: #{source.file}:#{source.first_line}"
|
|
31
|
+
puts
|
|
32
|
+
code = IRB::Color.colorize_code(File.read(source.file))
|
|
33
|
+
puts code.lines[(source.first_line - 1)...source.last_line].join
|
|
34
|
+
puts
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def find_source(str)
|
|
38
|
+
case str
|
|
39
|
+
when /\A[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
|
|
40
|
+
eval(str, irb_context.workspace.binding) # trigger autoload
|
|
41
|
+
base = irb_context.workspace.binding.receiver.yield_self { |r| r.is_a?(Module) ? r : Object }
|
|
42
|
+
file, line = base.const_source_location(str) if base.respond_to?(:const_source_location) # Ruby 2.7+
|
|
43
|
+
when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
|
|
44
|
+
owner = eval(Regexp.last_match[:owner], irb_context.workspace.binding)
|
|
45
|
+
method = Regexp.last_match[:method]
|
|
46
|
+
if owner.respond_to?(:instance_method) && owner.instance_methods.include?(method.to_sym)
|
|
47
|
+
file, line = owner.instance_method(method).source_location
|
|
48
|
+
end
|
|
49
|
+
when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
|
|
50
|
+
receiver = eval(Regexp.last_match[:receiver] || 'self', irb_context.workspace.binding)
|
|
51
|
+
method = Regexp.last_match[:method]
|
|
52
|
+
file, line = receiver.method(method).source_location if receiver.respond_to?(method)
|
|
53
|
+
end
|
|
54
|
+
if file && line
|
|
55
|
+
Source.new(file: file, first_line: line, last_line: find_end(file, line))
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def find_end(file, first_line)
|
|
60
|
+
return first_line unless File.exist?(file)
|
|
61
|
+
lex = RubyLex.new
|
|
62
|
+
lines = File.read(file).lines[(first_line - 1)..-1]
|
|
63
|
+
tokens = RubyLex.ripper_lex_without_warning(lines.join)
|
|
64
|
+
|
|
65
|
+
code = +""
|
|
66
|
+
prev_tokens = []
|
|
67
|
+
|
|
68
|
+
# chunk with line number
|
|
69
|
+
tokens.chunk { |tok| tok[0][0] }.each do |lnum, chunk|
|
|
70
|
+
code << lines[lnum]
|
|
71
|
+
prev_tokens.concat chunk
|
|
72
|
+
|
|
73
|
+
continue = lex.process_continue(prev_tokens)
|
|
74
|
+
code_block_open = lex.check_code_block(code, prev_tokens)
|
|
75
|
+
if !continue && !code_block_open
|
|
76
|
+
return first_line + lnum
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
first_line
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def bold(str)
|
|
83
|
+
Color.colorize(str, [:BOLD])
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
Source = Struct.new(
|
|
87
|
+
:file, # @param [String] - file name
|
|
88
|
+
:first_line, # @param [String] - first line
|
|
89
|
+
:last_line, # @param [String] - last line
|
|
90
|
+
keyword_init: true,
|
|
91
|
+
)
|
|
92
|
+
private_constant :Source
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
# :startdoc:
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "nop"
|
|
4
|
+
|
|
5
|
+
# :stopdoc:
|
|
6
|
+
module IRB
|
|
7
|
+
module ExtendCommand
|
|
8
|
+
class Whereami < Nop
|
|
9
|
+
def execute(*)
|
|
10
|
+
code = irb_context.workspace.code_around_binding
|
|
11
|
+
if code
|
|
12
|
+
puts code
|
|
13
|
+
else
|
|
14
|
+
puts "The current context doesn't have code."
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
# :startdoc:
|
data/lib/irb/color.rb
CHANGED
|
@@ -64,6 +64,7 @@ module IRB # :nodoc:
|
|
|
64
64
|
on_alias_error: [[RED, REVERSE], ALL],
|
|
65
65
|
on_class_name_error:[[RED, REVERSE], ALL],
|
|
66
66
|
on_param_error: [[RED, REVERSE], ALL],
|
|
67
|
+
on___end__: [[GREEN], ALL],
|
|
67
68
|
}
|
|
68
69
|
rescue NameError
|
|
69
70
|
# Give up highlighting Ripper-incompatible older Ruby
|
|
@@ -76,7 +77,7 @@ module IRB # :nodoc:
|
|
|
76
77
|
|
|
77
78
|
class << self
|
|
78
79
|
def colorable?
|
|
79
|
-
$stdout.tty? &&
|
|
80
|
+
$stdout.tty? && (/mswin|mingw/ =~ RUBY_PLATFORM || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
|
|
80
81
|
end
|
|
81
82
|
|
|
82
83
|
def inspect_colorable?(obj, seen: {}.compare_by_identity)
|
|
@@ -100,26 +101,27 @@ module IRB # :nodoc:
|
|
|
100
101
|
end
|
|
101
102
|
end
|
|
102
103
|
|
|
103
|
-
def clear
|
|
104
|
-
return '' unless colorable
|
|
104
|
+
def clear(colorable: colorable?)
|
|
105
|
+
return '' unless colorable
|
|
105
106
|
"\e[#{CLEAR}m"
|
|
106
107
|
end
|
|
107
108
|
|
|
108
|
-
def colorize(text, seq)
|
|
109
|
-
return text unless colorable
|
|
109
|
+
def colorize(text, seq, colorable: colorable?)
|
|
110
|
+
return text unless colorable
|
|
110
111
|
seq = seq.map { |s| "\e[#{const_get(s)}m" }.join('')
|
|
111
|
-
"#{seq}#{text}#{clear}"
|
|
112
|
+
"#{seq}#{text}#{clear(colorable: colorable)}"
|
|
112
113
|
end
|
|
113
114
|
|
|
114
115
|
# If `complete` is false (code is incomplete), this does not warn compile_error.
|
|
115
116
|
# This option is needed to avoid warning a user when the compile_error is happening
|
|
116
117
|
# because the input is not wrong but just incomplete.
|
|
117
|
-
def colorize_code(code, complete: true, ignore_error: false)
|
|
118
|
-
return code unless colorable
|
|
118
|
+
def colorize_code(code, complete: true, ignore_error: false, colorable: colorable?)
|
|
119
|
+
return code unless colorable
|
|
119
120
|
|
|
120
121
|
symbol_state = SymbolState.new
|
|
121
122
|
colored = +''
|
|
122
123
|
length = 0
|
|
124
|
+
end_seen = false
|
|
123
125
|
|
|
124
126
|
scan(code, allow_last_error: !complete) do |token, str, expr|
|
|
125
127
|
# IRB::ColorPrinter skips colorizing fragments with any invalid token
|
|
@@ -132,16 +134,17 @@ module IRB # :nodoc:
|
|
|
132
134
|
line = Reline::Unicode.escape_for_print(line)
|
|
133
135
|
if seq = dispatch_seq(token, expr, line, in_symbol: in_symbol)
|
|
134
136
|
colored << seq.map { |s| "\e[#{s}m" }.join('')
|
|
135
|
-
colored << line.sub(/\Z/, clear)
|
|
137
|
+
colored << line.sub(/\Z/, clear(colorable: colorable))
|
|
136
138
|
else
|
|
137
139
|
colored << line
|
|
138
140
|
end
|
|
139
141
|
end
|
|
140
142
|
length += str.bytesize
|
|
143
|
+
end_seen = true if token == :on___end__
|
|
141
144
|
end
|
|
142
145
|
|
|
143
146
|
# give up colorizing incomplete Ripper tokens
|
|
144
|
-
|
|
147
|
+
unless end_seen or length == code.bytesize
|
|
145
148
|
return Reline::Unicode.escape_for_print(code)
|
|
146
149
|
end
|
|
147
150
|
|
|
@@ -158,11 +161,6 @@ module IRB # :nodoc:
|
|
|
158
161
|
seen.delete(obj)
|
|
159
162
|
end
|
|
160
163
|
|
|
161
|
-
def supported?
|
|
162
|
-
return @supported if defined?(@supported)
|
|
163
|
-
@supported = Ripper::Lexer::Elem.method_defined?(:state)
|
|
164
|
-
end
|
|
165
|
-
|
|
166
164
|
def scan(code, allow_last_error:)
|
|
167
165
|
pos = [1, 0]
|
|
168
166
|
|
data/lib/irb/color_printer.rb
CHANGED
|
@@ -21,6 +21,15 @@ module IRB
|
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
def pp(obj)
|
|
25
|
+
if obj.is_a?(String)
|
|
26
|
+
# Avoid calling Ruby 2.4+ String#pretty_print that splits a string by "\n"
|
|
27
|
+
text(obj.inspect)
|
|
28
|
+
else
|
|
29
|
+
super
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
24
33
|
def text(str, width = nil)
|
|
25
34
|
unless str.is_a?(String)
|
|
26
35
|
str = str.inspect
|
data/lib/irb/completion.rb
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# From Original Idea of shugo@ruby-lang.org
|
|
8
8
|
#
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
require_relative 'ruby-lex'
|
|
11
11
|
|
|
12
12
|
module IRB
|
|
13
13
|
module InputCompletor # :nodoc:
|
|
@@ -38,8 +38,69 @@ module IRB
|
|
|
38
38
|
|
|
39
39
|
BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
def self.retrieve_files_to_require_from_load_path
|
|
42
|
+
@@files_from_load_path ||= $LOAD_PATH.flat_map { |path|
|
|
43
|
+
begin
|
|
44
|
+
Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: path)
|
|
45
|
+
rescue Errno::ENOENT
|
|
46
|
+
[]
|
|
47
|
+
end
|
|
48
|
+
}.uniq.map { |path|
|
|
49
|
+
path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.retrieve_files_to_require_relative_from_current_dir
|
|
54
|
+
@@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
|
|
55
|
+
path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
CompletionRequireProc = lambda { |target, preposing = nil, postposing = nil|
|
|
60
|
+
if target =~ /\A(['"])([^'"]+)\Z/
|
|
61
|
+
quote = $1
|
|
62
|
+
actual_target = $2
|
|
63
|
+
else
|
|
64
|
+
return nil # It's not String literal
|
|
65
|
+
end
|
|
66
|
+
tokens = RubyLex.ripper_lex_without_warning(preposing.gsub(/\s*\z/, ''))
|
|
67
|
+
tok = nil
|
|
68
|
+
tokens.reverse_each do |t|
|
|
69
|
+
unless [:on_lparen, :on_sp, :on_ignored_sp, :on_nl, :on_ignored_nl, :on_comment].include?(t.event)
|
|
70
|
+
tok = t
|
|
71
|
+
break
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
result = []
|
|
75
|
+
if tok && tok.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
|
|
76
|
+
case tok.tok
|
|
77
|
+
when 'require'
|
|
78
|
+
result = retrieve_files_to_require_from_load_path.select { |path|
|
|
79
|
+
path.start_with?(actual_target)
|
|
80
|
+
}.map { |path|
|
|
81
|
+
quote + path
|
|
82
|
+
}
|
|
83
|
+
when 'require_relative'
|
|
84
|
+
result = retrieve_files_to_require_relative_from_current_dir.select { |path|
|
|
85
|
+
path.start_with?(actual_target)
|
|
86
|
+
}.map { |path|
|
|
87
|
+
quote + path
|
|
88
|
+
}
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
result
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
CompletionProc = lambda { |target, preposing = nil, postposing = nil|
|
|
95
|
+
if preposing && postposing
|
|
96
|
+
result = CompletionRequireProc.(target, preposing, postposing)
|
|
97
|
+
unless result
|
|
98
|
+
result = retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
|
|
99
|
+
end
|
|
100
|
+
result
|
|
101
|
+
else
|
|
102
|
+
retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
|
|
103
|
+
end
|
|
43
104
|
}
|
|
44
105
|
|
|
45
106
|
def self.retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
|
|
@@ -266,13 +327,22 @@ module IRB
|
|
|
266
327
|
end
|
|
267
328
|
|
|
268
329
|
PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) {
|
|
330
|
+
begin
|
|
331
|
+
require 'rdoc'
|
|
332
|
+
rescue LoadError
|
|
333
|
+
return
|
|
334
|
+
end
|
|
335
|
+
|
|
269
336
|
RDocRIDriver ||= RDoc::RI::Driver.new
|
|
337
|
+
|
|
270
338
|
if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
|
|
271
339
|
IRB.__send__(:easter_egg)
|
|
272
340
|
return
|
|
273
341
|
end
|
|
342
|
+
|
|
274
343
|
namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true)
|
|
275
344
|
return unless namespace
|
|
345
|
+
|
|
276
346
|
if namespace.is_a?(Array)
|
|
277
347
|
out = RDoc::Markup::Document.new
|
|
278
348
|
namespace.each do |m|
|
data/lib/irb/ext/loader.rb
CHANGED
data/lib/irb/ext/save-history.rb
CHANGED
|
@@ -81,6 +81,8 @@ module IRB
|
|
|
81
81
|
end
|
|
82
82
|
}
|
|
83
83
|
end
|
|
84
|
+
@loaded_history_lines = history.size
|
|
85
|
+
@loaded_history_mtime = File.mtime(history_file)
|
|
84
86
|
end
|
|
85
87
|
end
|
|
86
88
|
|
|
@@ -105,12 +107,20 @@ module IRB
|
|
|
105
107
|
raise
|
|
106
108
|
end
|
|
107
109
|
|
|
108
|
-
|
|
110
|
+
if File.exist?(history_file) && @loaded_history_mtime &&
|
|
111
|
+
File.mtime(history_file) != @loaded_history_mtime
|
|
112
|
+
history = history[@loaded_history_lines..-1]
|
|
113
|
+
append_history = true
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
open(history_file, "#{append_history ? 'a' : 'w'}:#{IRB.conf[:LC_MESSAGES].encoding}", 0600) do |f|
|
|
109
117
|
hist = history.map{ |l| l.split("\n").join("\\\n") }
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
unless append_history
|
|
119
|
+
begin
|
|
120
|
+
hist = hist.last(num) if hist.size > num and num > 0
|
|
121
|
+
rescue RangeError # bignum too big to convert into `long'
|
|
122
|
+
# Do nothing because the bignum should be treated as inifinity
|
|
123
|
+
end
|
|
114
124
|
end
|
|
115
125
|
f.puts(hist)
|
|
116
126
|
end
|
data/lib/irb/extend-command.rb
CHANGED
|
@@ -126,7 +126,23 @@ module IRB # :nodoc:
|
|
|
126
126
|
],
|
|
127
127
|
|
|
128
128
|
[
|
|
129
|
-
:
|
|
129
|
+
:irb_ls, :Ls, "irb/cmd/ls",
|
|
130
|
+
[:ls, NO_OVERRIDE],
|
|
131
|
+
],
|
|
132
|
+
|
|
133
|
+
[
|
|
134
|
+
:irb_measure, :Measure, "irb/cmd/measure",
|
|
135
|
+
[:measure, NO_OVERRIDE],
|
|
136
|
+
],
|
|
137
|
+
|
|
138
|
+
[
|
|
139
|
+
:irb_show_source, :ShowSource, "irb/cmd/show_source",
|
|
140
|
+
[:show_source, NO_OVERRIDE],
|
|
141
|
+
],
|
|
142
|
+
|
|
143
|
+
[
|
|
144
|
+
:irb_whereami, :Whereami, "irb/cmd/whereami",
|
|
145
|
+
[:whereami, NO_OVERRIDE],
|
|
130
146
|
],
|
|
131
147
|
|
|
132
148
|
]
|
|
@@ -168,12 +184,13 @@ module IRB # :nodoc:
|
|
|
168
184
|
end
|
|
169
185
|
|
|
170
186
|
if load_file
|
|
187
|
+
kwargs = ", **kwargs" if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
|
|
171
188
|
line = __LINE__; eval %[
|
|
172
|
-
def #{cmd_name}(*opts, &b)
|
|
189
|
+
def #{cmd_name}(*opts#{kwargs}, &b)
|
|
173
190
|
require "#{load_file}"
|
|
174
191
|
arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity
|
|
175
192
|
args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s }
|
|
176
|
-
args << "*opts" if arity < 0
|
|
193
|
+
args << "*opts#{kwargs}" if arity < 0
|
|
177
194
|
args << "&block"
|
|
178
195
|
args = args.join(", ")
|
|
179
196
|
line = __LINE__; eval %[
|
|
@@ -184,7 +201,7 @@ module IRB # :nodoc:
|
|
|
184
201
|
end
|
|
185
202
|
end
|
|
186
203
|
], nil, __FILE__, line
|
|
187
|
-
__send__ :#{cmd_name}_, *opts, &b
|
|
204
|
+
__send__ :#{cmd_name}_, *opts#{kwargs}, &b
|
|
188
205
|
end
|
|
189
206
|
], nil, __FILE__, line
|
|
190
207
|
else
|
data/lib/irb/init.rb
CHANGED
|
@@ -44,7 +44,7 @@ module IRB # :nodoc:
|
|
|
44
44
|
@CONF[:IRB_RC] = nil
|
|
45
45
|
|
|
46
46
|
@CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod)
|
|
47
|
-
@CONF[:USE_COLORIZE] =
|
|
47
|
+
@CONF[:USE_COLORIZE] = !ENV['NO_COLOR']
|
|
48
48
|
@CONF[:INSPECT_MODE] = true
|
|
49
49
|
@CONF[:USE_TRACER] = false
|
|
50
50
|
@CONF[:USE_LOADER] = false
|
|
@@ -120,7 +120,11 @@ module IRB # :nodoc:
|
|
|
120
120
|
puts 'processing time: %fs' % (now - time) if IRB.conf[:MEASURE]
|
|
121
121
|
result
|
|
122
122
|
}
|
|
123
|
+
# arg can be either a symbol for the mode (:cpu, :wall, ..) or a hash for
|
|
124
|
+
# a more complete configuration.
|
|
125
|
+
# See https://github.com/tmm1/stackprof#all-options.
|
|
123
126
|
@CONF[:MEASURE_PROC][:STACKPROF] = proc { |context, code, line_no, arg, &block|
|
|
127
|
+
return block.() unless IRB.conf[:MEASURE]
|
|
124
128
|
success = false
|
|
125
129
|
begin
|
|
126
130
|
require 'stackprof'
|
|
@@ -130,10 +134,18 @@ module IRB # :nodoc:
|
|
|
130
134
|
end
|
|
131
135
|
if success
|
|
132
136
|
result = nil
|
|
133
|
-
|
|
137
|
+
arg = { mode: arg || :cpu } unless arg.is_a?(Hash)
|
|
138
|
+
stackprof_result = StackProf.run(**arg) do
|
|
134
139
|
result = block.()
|
|
135
140
|
end
|
|
136
|
-
|
|
141
|
+
case stackprof_result
|
|
142
|
+
when File
|
|
143
|
+
puts "StackProf report saved to #{stackprof_result.path}"
|
|
144
|
+
when Hash
|
|
145
|
+
StackProf::Report.new(stackprof_result).print_text
|
|
146
|
+
else
|
|
147
|
+
puts "Stackprof ran with #{arg.inspect}"
|
|
148
|
+
end
|
|
137
149
|
result
|
|
138
150
|
else
|
|
139
151
|
block.()
|
|
@@ -301,11 +313,11 @@ module IRB # :nodoc:
|
|
|
301
313
|
break
|
|
302
314
|
end
|
|
303
315
|
end
|
|
316
|
+
|
|
304
317
|
load_path.collect! do |path|
|
|
305
318
|
/\A\.\// =~ path ? path : File.expand_path(path)
|
|
306
319
|
end
|
|
307
320
|
$LOAD_PATH.unshift(*load_path)
|
|
308
|
-
|
|
309
321
|
end
|
|
310
322
|
|
|
311
323
|
# running config
|
data/lib/irb/input-method.rb
CHANGED
|
@@ -280,6 +280,7 @@ module IRB
|
|
|
280
280
|
Reline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
|
|
281
281
|
end
|
|
282
282
|
Reline.completion_append_character = nil
|
|
283
|
+
Reline.completer_quote_characters = ''
|
|
283
284
|
Reline.completion_proc = IRB::InputCompletor::CompletionProc
|
|
284
285
|
Reline.output_modifier_proc =
|
|
285
286
|
if IRB.conf[:USE_COLORIZE]
|
data/lib/irb/lc/help-message
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
#
|
|
11
11
|
#
|
|
12
12
|
Usage: irb.rb [options] [programfile] [arguments]
|
|
13
|
-
-f
|
|
13
|
+
-f Suppress read of ~/.irbrc
|
|
14
14
|
-d Set $DEBUG to true (same as `ruby -d')
|
|
15
15
|
-r load-module Same as `ruby -r'
|
|
16
16
|
-I path Specify $LOAD_PATH directory
|
|
@@ -18,7 +18,7 @@ Usage: irb.rb [options] [programfile] [arguments]
|
|
|
18
18
|
-E enc Same as `ruby -E`
|
|
19
19
|
-w Same as `ruby -w`
|
|
20
20
|
-W[level=2] Same as `ruby -W`
|
|
21
|
-
--context-mode n Set n[0-
|
|
21
|
+
--context-mode n Set n[0-4] to method to create Binding Object,
|
|
22
22
|
when new workspace was created
|
|
23
23
|
--echo Show result(default)
|
|
24
24
|
--noecho Don't show result
|
|
@@ -31,8 +31,8 @@ Usage: irb.rb [options] [programfile] [arguments]
|
|
|
31
31
|
--colorize Use colorization
|
|
32
32
|
--nocolorize Don't use colorization
|
|
33
33
|
--prompt prompt-mode/--prompt-mode prompt-mode
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
Switch prompt mode. Pre-defined prompt modes are
|
|
35
|
+
`default', `simple', `xmp' and `inf-ruby'
|
|
36
36
|
--inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs.
|
|
37
37
|
Suppresses --multiline and --singleline.
|
|
38
38
|
--sample-book-mode/--simple-prompt
|
|
@@ -41,8 +41,8 @@ Usage: irb.rb [options] [programfile] [arguments]
|
|
|
41
41
|
--single-irb Share self with sub-irb.
|
|
42
42
|
--tracer Display trace for each execution of commands.
|
|
43
43
|
--back-trace-limit n
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
Display backtrace top n and tail n. The default
|
|
45
|
+
value is 16.
|
|
46
46
|
--verbose Show details
|
|
47
47
|
--noverbose Don't show details
|
|
48
48
|
-v, --version Print the version of irb
|
data/lib/irb/ruby-lex.rb
CHANGED
|
@@ -30,29 +30,48 @@ class RubyLex
|
|
|
30
30
|
@prompt = nil
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def self.compile_with_errors_suppressed(code)
|
|
34
|
-
line_no = 1
|
|
33
|
+
def self.compile_with_errors_suppressed(code, line_no: 1)
|
|
35
34
|
begin
|
|
36
35
|
result = yield code, line_no
|
|
37
36
|
rescue ArgumentError
|
|
37
|
+
# Ruby can issue an error for the code if there is an
|
|
38
|
+
# incomplete magic comment for encoding in it. Force an
|
|
39
|
+
# expression with a new line before the code in this
|
|
40
|
+
# case to prevent magic comment handling. To make sure
|
|
41
|
+
# line numbers in the lexed code remain the same,
|
|
42
|
+
# decrease the line number by one.
|
|
38
43
|
code = ";\n#{code}"
|
|
39
|
-
line_no
|
|
44
|
+
line_no -= 1
|
|
40
45
|
result = yield code, line_no
|
|
41
46
|
end
|
|
42
47
|
result
|
|
43
48
|
end
|
|
44
49
|
|
|
45
50
|
# io functions
|
|
46
|
-
def set_input(io, p = nil, &block)
|
|
51
|
+
def set_input(io, p = nil, context: nil, &block)
|
|
47
52
|
@io = io
|
|
48
53
|
if @io.respond_to?(:check_termination)
|
|
49
54
|
@io.check_termination do |code|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
if Reline::IOGate.in_pasting?
|
|
56
|
+
lex = RubyLex.new
|
|
57
|
+
rest = lex.check_termination_in_prev_line(code, context: context)
|
|
58
|
+
if rest
|
|
59
|
+
Reline.delete_text
|
|
60
|
+
rest.bytes.reverse_each do |c|
|
|
61
|
+
Reline.ungetc(c)
|
|
62
|
+
end
|
|
63
|
+
true
|
|
64
|
+
else
|
|
65
|
+
false
|
|
66
|
+
end
|
|
54
67
|
else
|
|
55
|
-
|
|
68
|
+
code.gsub!(/\s*\z/, '').concat("\n")
|
|
69
|
+
ltype, indent, continue, code_block_open = check_state(code, context: context)
|
|
70
|
+
if ltype or indent > 0 or continue or code_block_open
|
|
71
|
+
false
|
|
72
|
+
else
|
|
73
|
+
true
|
|
74
|
+
end
|
|
56
75
|
end
|
|
57
76
|
end
|
|
58
77
|
end
|
|
@@ -60,7 +79,7 @@ class RubyLex
|
|
|
60
79
|
@io.dynamic_prompt do |lines|
|
|
61
80
|
lines << '' if lines.empty?
|
|
62
81
|
result = []
|
|
63
|
-
tokens = ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join)
|
|
82
|
+
tokens = self.class.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, context: context)
|
|
64
83
|
code = String.new
|
|
65
84
|
partial_tokens = []
|
|
66
85
|
unprocessed_tokens = []
|
|
@@ -72,7 +91,7 @@ class RubyLex
|
|
|
72
91
|
t_str = t[2]
|
|
73
92
|
t_str.each_line("\n") do |s|
|
|
74
93
|
code << s << "\n"
|
|
75
|
-
ltype, indent, continue, code_block_open = check_state(code, partial_tokens)
|
|
94
|
+
ltype, indent, continue, code_block_open = check_state(code, partial_tokens, context: context)
|
|
76
95
|
result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
|
|
77
96
|
line_num_offset += 1
|
|
78
97
|
end
|
|
@@ -82,7 +101,7 @@ class RubyLex
|
|
|
82
101
|
end
|
|
83
102
|
end
|
|
84
103
|
unless unprocessed_tokens.empty?
|
|
85
|
-
ltype, indent, continue, code_block_open = check_state(code, unprocessed_tokens)
|
|
104
|
+
ltype, indent, continue, code_block_open = check_state(code, unprocessed_tokens, context: context)
|
|
86
105
|
result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
|
|
87
106
|
end
|
|
88
107
|
result
|
|
@@ -115,15 +134,25 @@ class RubyLex
|
|
|
115
134
|
:on_param_error
|
|
116
135
|
]
|
|
117
136
|
|
|
118
|
-
def ripper_lex_without_warning(code)
|
|
137
|
+
def self.ripper_lex_without_warning(code, context: nil)
|
|
119
138
|
verbose, $VERBOSE = $VERBOSE, nil
|
|
139
|
+
if context
|
|
140
|
+
lvars = context&.workspace&.binding&.local_variables
|
|
141
|
+
if lvars && !lvars.empty?
|
|
142
|
+
code = "#{lvars.join('=')}=nil\n#{code}"
|
|
143
|
+
line_no = 0
|
|
144
|
+
else
|
|
145
|
+
line_no = 1
|
|
146
|
+
end
|
|
147
|
+
end
|
|
120
148
|
tokens = nil
|
|
121
|
-
|
|
149
|
+
compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
|
|
122
150
|
lexer = Ripper::Lexer.new(inner_code, '-', line_no)
|
|
123
151
|
if lexer.respond_to?(:scan) # Ruby 2.7+
|
|
124
152
|
tokens = []
|
|
125
153
|
pos_to_index = {}
|
|
126
154
|
lexer.scan.each do |t|
|
|
155
|
+
next if t.pos.first == 0
|
|
127
156
|
if pos_to_index.has_key?(t[0])
|
|
128
157
|
index = pos_to_index[t[0]]
|
|
129
158
|
found_tk = tokens[index]
|
|
@@ -168,7 +197,7 @@ class RubyLex
|
|
|
168
197
|
if @io.respond_to?(:auto_indent) and context.auto_indent_mode
|
|
169
198
|
@io.auto_indent do |lines, line_index, byte_pointer, is_newline|
|
|
170
199
|
if is_newline
|
|
171
|
-
@tokens = ripper_lex_without_warning(lines[0..line_index].join("\n"))
|
|
200
|
+
@tokens = self.class.ripper_lex_without_warning(lines[0..line_index].join("\n"), context: context)
|
|
172
201
|
prev_spaces = find_prev_spaces(line_index)
|
|
173
202
|
depth_difference = check_newline_depth_difference
|
|
174
203
|
depth_difference = 0 if depth_difference < 0
|
|
@@ -177,7 +206,7 @@ class RubyLex
|
|
|
177
206
|
code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
|
|
178
207
|
last_line = lines[line_index]&.byteslice(0, byte_pointer)
|
|
179
208
|
code += last_line if last_line
|
|
180
|
-
@tokens = ripper_lex_without_warning(code)
|
|
209
|
+
@tokens = self.class.ripper_lex_without_warning(code, context: context)
|
|
181
210
|
corresponding_token_depth = check_corresponding_token_depth
|
|
182
211
|
if corresponding_token_depth
|
|
183
212
|
corresponding_token_depth
|
|
@@ -189,8 +218,8 @@ class RubyLex
|
|
|
189
218
|
end
|
|
190
219
|
end
|
|
191
220
|
|
|
192
|
-
def check_state(code, tokens = nil)
|
|
193
|
-
tokens = ripper_lex_without_warning(code) unless tokens
|
|
221
|
+
def check_state(code, tokens = nil, context: nil)
|
|
222
|
+
tokens = self.class.ripper_lex_without_warning(code, context: context) unless tokens
|
|
194
223
|
ltype = process_literal_type(tokens)
|
|
195
224
|
indent = process_nesting_level(tokens)
|
|
196
225
|
continue = process_continue(tokens)
|
|
@@ -256,7 +285,7 @@ class RubyLex
|
|
|
256
285
|
end
|
|
257
286
|
code = @line + (line.nil? ? '' : line)
|
|
258
287
|
code.gsub!(/\s*\z/, '').concat("\n")
|
|
259
|
-
@tokens = ripper_lex_without_warning(code)
|
|
288
|
+
@tokens = self.class.ripper_lex_without_warning(code)
|
|
260
289
|
@continue = process_continue
|
|
261
290
|
@code_block_open = check_code_block(code)
|
|
262
291
|
@indent = process_nesting_level
|
|
@@ -277,8 +306,9 @@ class RubyLex
|
|
|
277
306
|
return true
|
|
278
307
|
elsif tokens.size >= 1 and tokens[-1][1] == :on_heredoc_end # "EOH\n"
|
|
279
308
|
return false
|
|
280
|
-
elsif tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME)
|
|
309
|
+
elsif tokens.size >= 2 and defined?(Ripper::EXPR_BEG) and tokens[-2][3].anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME) and tokens[-2][2] !~ /\A\.\.\.?\z/
|
|
281
310
|
# end of literal except for regexp
|
|
311
|
+
# endless range at end of line is not a continue
|
|
282
312
|
return true
|
|
283
313
|
end
|
|
284
314
|
false
|
|
@@ -324,7 +354,7 @@ class RubyLex
|
|
|
324
354
|
# "syntax error, unexpected end-of-input, expecting keyword_end"
|
|
325
355
|
#
|
|
326
356
|
# example:
|
|
327
|
-
# if
|
|
357
|
+
# if true
|
|
328
358
|
# hoge
|
|
329
359
|
# if false
|
|
330
360
|
# fuga
|
|
@@ -685,7 +715,7 @@ class RubyLex
|
|
|
685
715
|
start_token << t
|
|
686
716
|
end_type << :on_regexp_end
|
|
687
717
|
when :on_symbeg
|
|
688
|
-
acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw}
|
|
718
|
+
acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw on_int}
|
|
689
719
|
if (i + 1) < tokens.size and acceptable_single_tokens.all?{ |st| tokens[i + 1][1] != st }
|
|
690
720
|
start_token << t
|
|
691
721
|
end_type << :on_tstring_end
|
|
@@ -738,5 +768,50 @@ class RubyLex
|
|
|
738
768
|
nil
|
|
739
769
|
end
|
|
740
770
|
end
|
|
771
|
+
|
|
772
|
+
def check_termination_in_prev_line(code, context: nil)
|
|
773
|
+
tokens = self.class.ripper_lex_without_warning(code, context: context)
|
|
774
|
+
past_first_newline = false
|
|
775
|
+
index = tokens.rindex do |t|
|
|
776
|
+
# traverse first token before last line
|
|
777
|
+
if past_first_newline
|
|
778
|
+
if t.tok.include?("\n")
|
|
779
|
+
true
|
|
780
|
+
end
|
|
781
|
+
elsif t.tok.include?("\n")
|
|
782
|
+
past_first_newline = true
|
|
783
|
+
false
|
|
784
|
+
else
|
|
785
|
+
false
|
|
786
|
+
end
|
|
787
|
+
end
|
|
788
|
+
if index
|
|
789
|
+
first_token = nil
|
|
790
|
+
last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
|
|
791
|
+
last_line_tokens.each do |t|
|
|
792
|
+
unless [:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
|
|
793
|
+
first_token = t
|
|
794
|
+
break
|
|
795
|
+
end
|
|
796
|
+
end
|
|
797
|
+
if first_token.nil?
|
|
798
|
+
return false
|
|
799
|
+
elsif first_token && first_token.state == Ripper::EXPR_DOT
|
|
800
|
+
return false
|
|
801
|
+
else
|
|
802
|
+
tokens_without_last_line = tokens[0..index]
|
|
803
|
+
ltype = process_literal_type(tokens_without_last_line)
|
|
804
|
+
indent = process_nesting_level(tokens_without_last_line)
|
|
805
|
+
continue = process_continue(tokens_without_last_line)
|
|
806
|
+
code_block_open = check_code_block(tokens_without_last_line.map(&:tok).join(''), tokens_without_last_line)
|
|
807
|
+
if ltype or indent > 0 or continue or code_block_open
|
|
808
|
+
return false
|
|
809
|
+
else
|
|
810
|
+
return last_line_tokens.map(&:tok).join('')
|
|
811
|
+
end
|
|
812
|
+
end
|
|
813
|
+
end
|
|
814
|
+
false
|
|
815
|
+
end
|
|
741
816
|
end
|
|
742
817
|
# :startdoc:
|
data/lib/irb/version.rb
CHANGED
data/lib/irb/workspace.rb
CHANGED
|
@@ -175,7 +175,7 @@ EOF
|
|
|
175
175
|
body = (start_pos..end_pos).map do |current_pos|
|
|
176
176
|
sprintf(fmt, pos == current_pos ? '=>' : '', current_pos + 1, lines[current_pos])
|
|
177
177
|
end.join("")
|
|
178
|
-
"\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n"
|
|
178
|
+
"\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear if use_colorize}\n"
|
|
179
179
|
end
|
|
180
180
|
|
|
181
181
|
def IRB.delete_caller
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: irb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Keiju ISHITSUKA
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-08-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: reline
|
|
@@ -16,42 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 0.
|
|
19
|
+
version: 0.2.7
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 0.
|
|
27
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: bundler
|
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
|
30
|
-
requirements:
|
|
31
|
-
- - ">="
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0'
|
|
34
|
-
type: :development
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - ">="
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0'
|
|
41
|
-
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: rake
|
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
|
44
|
-
requirements:
|
|
45
|
-
- - ">="
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: '0'
|
|
48
|
-
type: :development
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - ">="
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: '0'
|
|
26
|
+
version: 0.2.7
|
|
55
27
|
description: Interactive Ruby command-line tool for REPL (Read Eval Print Loop).
|
|
56
28
|
email:
|
|
57
29
|
- keiju@ruby-lang.org
|
|
@@ -77,10 +49,13 @@ files:
|
|
|
77
49
|
- lib/irb/cmd/help.rb
|
|
78
50
|
- lib/irb/cmd/info.rb
|
|
79
51
|
- lib/irb/cmd/load.rb
|
|
52
|
+
- lib/irb/cmd/ls.rb
|
|
80
53
|
- lib/irb/cmd/measure.rb
|
|
81
54
|
- lib/irb/cmd/nop.rb
|
|
82
55
|
- lib/irb/cmd/pushws.rb
|
|
56
|
+
- lib/irb/cmd/show_source.rb
|
|
83
57
|
- lib/irb/cmd/subirb.rb
|
|
58
|
+
- lib/irb/cmd/whereami.rb
|
|
84
59
|
- lib/irb/color.rb
|
|
85
60
|
- lib/irb/color_printer.rb
|
|
86
61
|
- lib/irb/completion.rb
|
|
@@ -137,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
137
112
|
- !ruby/object:Gem::Version
|
|
138
113
|
version: '0'
|
|
139
114
|
requirements: []
|
|
140
|
-
rubygems_version: 3.2.
|
|
115
|
+
rubygems_version: 3.2.22
|
|
141
116
|
signing_key:
|
|
142
117
|
specification_version: 4
|
|
143
118
|
summary: Interactive Ruby command-line tool for REPL (Read Eval Print Loop).
|