irb 1.3.4 → 1.3.8.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +10 -0
- data/Rakefile +8 -1
- data/irb.gemspec +2 -49
- data/lib/irb/cmd/info.rb +6 -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/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 +47 -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.rb +28 -11
- metadata +10 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98ac31009e423fdea5f0151f5b48e3199dc98427484d5465088e1a9e0bac88fd
|
4
|
+
data.tar.gz: 180d9637906858acb3abba279ee49934d397979da0f4e9e7fab373c4d7313d4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89acce9899ac0fefa699639a514ada88bb2b9e3c18e3a1b5f83e139800d99b18445269ef5703b45c794f69a186c99cfd4f02fbfd24a883ed2164c9d1eacceb21
|
7
|
+
data.tar.gz: a16a4ba0f9505da943a29a6138b29b8d92e9fff6cad5fcea14ca3666095d0e02b467eaaf83eb425b4da4971c047b10eab73ba28bde5794d2e46f58d67476a182
|
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.1
|
85
|
-
spec.add_development_dependency "bundler"
|
86
|
-
spec.add_development_dependency "rake"
|
39
|
+
spec.add_dependency "reline", ">= 0.2.8.pre.1"
|
87
40
|
end
|
data/lib/irb/cmd/info.rb
CHANGED
@@ -14,6 +14,12 @@ module IRB
|
|
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
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
|
17
23
|
str
|
18
24
|
end
|
19
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/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
@@ -14,6 +14,7 @@ require_relative 'magic-file'
|
|
14
14
|
require_relative 'completion'
|
15
15
|
require 'io/console'
|
16
16
|
require 'reline'
|
17
|
+
require 'rdoc'
|
17
18
|
|
18
19
|
module IRB
|
19
20
|
STDIN_FILE_NAME = "(line)" # :nodoc:
|
@@ -280,6 +281,7 @@ module IRB
|
|
280
281
|
Reline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
|
281
282
|
end
|
282
283
|
Reline.completion_append_character = nil
|
284
|
+
Reline.completer_quote_characters = ''
|
283
285
|
Reline.completion_proc = IRB::InputCompletor::CompletionProc
|
284
286
|
Reline.output_modifier_proc =
|
285
287
|
if IRB.conf[:USE_COLORIZE]
|
@@ -307,6 +309,50 @@ module IRB
|
|
307
309
|
@auto_indent_proc = block
|
308
310
|
end
|
309
311
|
|
312
|
+
SHOW_DOC_DIALOG = ->() {
|
313
|
+
begin
|
314
|
+
require 'rdoc'
|
315
|
+
rescue LoadError
|
316
|
+
return nil
|
317
|
+
end
|
318
|
+
if just_cursor_moving and completion_journey_data.nil?
|
319
|
+
return nil
|
320
|
+
end
|
321
|
+
cursor_pos_to_render, result, pointer = context.pop(3)
|
322
|
+
return nil if result.nil? or pointer.nil?
|
323
|
+
name = result[pointer]
|
324
|
+
|
325
|
+
driver = RDoc::RI::Driver.new
|
326
|
+
begin
|
327
|
+
name = driver.expand_name(name)
|
328
|
+
rescue RDoc::RI::Driver::NotFoundError
|
329
|
+
return nil
|
330
|
+
end
|
331
|
+
doc = nil
|
332
|
+
used_for_class = false
|
333
|
+
if not name =~ /#|\./
|
334
|
+
found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
|
335
|
+
if not found.empty?
|
336
|
+
doc = driver.class_document(name, found, klasses, includes, extends)
|
337
|
+
used_for_class = true
|
338
|
+
end
|
339
|
+
end
|
340
|
+
unless used_for_class
|
341
|
+
doc = RDoc::Markup::Document.new
|
342
|
+
begin
|
343
|
+
driver.add_method(doc, name)
|
344
|
+
rescue RDoc::RI::Driver::NotFoundError
|
345
|
+
doc = nil
|
346
|
+
end
|
347
|
+
end
|
348
|
+
return nil if doc.nil?
|
349
|
+
formatter = RDoc::Markup::ToAnsi.new
|
350
|
+
formatter.width = 40
|
351
|
+
str = doc.accept(formatter)
|
352
|
+
|
353
|
+
[Reline::CursorPos.new(cursor_pos_to_render.x + 40, cursor_pos_to_render.y + pointer), str.split("\n"), nil, '49']
|
354
|
+
}
|
355
|
+
|
310
356
|
# Reads the next line from this input method.
|
311
357
|
#
|
312
358
|
# See IO#gets for more information.
|
@@ -315,6 +361,7 @@ module IRB
|
|
315
361
|
Reline.output = @stdout
|
316
362
|
Reline.prompt_proc = @prompt_proc
|
317
363
|
Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc
|
364
|
+
Reline.add_dialog_proc(:show_doc, SHOW_DOC_DIALOG, Reline::DEFAULT_DIALOG_CONTEXT)
|
318
365
|
if l = readmultiline(@prompt, false, &@check_termination_proc)
|
319
366
|
HISTORY.push(l) if !l.empty?
|
320
367
|
@line[@line_no += 1] = l + "\n"
|
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.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
|
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.8.pre.1
|
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-29 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.1
|
19
|
+
version: 0.2.8.pre.1
|
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.1
|
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.8.pre.1
|
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
|
@@ -133,11 +108,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
108
|
version: '2.5'
|
134
109
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
110
|
requirements:
|
136
|
-
- - "
|
111
|
+
- - ">"
|
137
112
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
113
|
+
version: 1.3.1
|
139
114
|
requirements: []
|
140
|
-
rubygems_version: 3.
|
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).
|