Files
77700bf023 Backport lib/reline, and lib/irb for 3.0.1 2nd (#4157)
* [ruby/irb] Stub a screen size for tests

https://github.com/ruby/irb/commit/6663057083

* [ruby/irb] Support GitHub Actions

https://github.com/ruby/irb/commit/8e9e6c4037

* [ruby/irb] Stub a screen size for test_context

http://ci.rvm.jp/logfiles/brlog.trunk-random1.20210119-074232

https://github.com/ruby/irb/commit/ea87592d4a

* [ruby/irb] Use a real screen size for pp by default

https://github.com/ruby/irb/commit/9b9300dec2

* [ruby/irb] Rescue Errno::EINVAL on IRB pp

http://rubyci.s3.amazonaws.com/solaris11-gcc/ruby-master/log/20210119T070008Z.log.html.gz
is caused by:

/export/home/chkbuild/chkbuild-gcc/tmp/build/20210119T150010Z/ruby/lib/reline/ansi.rb:157:in `winsize': Invalid argument - <STDIN> (Errno::EINVAL)
        from /export/home/chkbuild/chkbuild-gcc/tmp/build/20210119T150010Z/ruby/lib/reline/ansi.rb:157:in `get_screen_size'
        from /export/home/chkbuild/chkbuild-gcc/tmp/build/20210119T150010Z/ruby/lib/reline.rb:168:in `get_screen_size'
        from /export/home/chkbuild/chkbuild-gcc/tmp/build/20210119T150010Z/ruby/lib/forwardable.rb:238:in `get_screen_size'
        from /export/home/chkbuild/chkbuild-gcc/tmp/build/20210119T150010Z/ruby/lib/irb/color_printer.rb:7:in `pp'
        from -e:1:in `<main>'

https://github.com/ruby/irb/commit/1719514598

* [ruby/irb] Split test files for IRB::Color and IRB::ColorPrinter

https://github.com/ruby/irb/commit/d95e8daab3

* [ruby/irb] Undefine unused constants

https://github.com/ruby/irb/commit/eea9c16804

* [ruby/irb] Remove pp-specific stub from TestColor

because it was for TestColorPrinter

https://github.com/ruby/irb/commit/7569206fd4

* [ruby/irb] Delete a doodle-level memo comment...

https://github.com/ruby/irb/commit/fc3e1d9e0c

* [ruby/irb] Indent correctly with keyword "for" and "in"

https://github.com/ruby/irb/commit/47c83ea724

* [ruby/irb] Indent correctly with method calling with receiver

https://github.com/ruby/irb/commit/e7c68e74a0

* [ruby/irb] add `IRB::FileInputMethod.open` to ensure closing associated File

* tweak some methods not to raise exception after `#close`
* use it in `IRB::IrbLoader#{source_file,load_file}

https://github.com/ruby/irb/commit/ec2947acbd

* [ruby/irb] use `RubyLex::TerminateLineInput` appropriately [Bug #17564]

* using the appropriciate exception instead of `break` so that the session
  can be continue after the `irb_source` and `irb_load` commands
* suppress extra new line due to one more `#prompt` call

https://github.com/ruby/irb/commit/bdefaa7cfd

* [ruby/irb] specify the `VERBOSE` to `false` and fix tests to fit

https://github.com/ruby/irb/commit/502c590925

* In test, need to pass a context to IRB::WorkSpace.new explicitly

* Fix absolute path predicate on Windows

A path starts with '/' is not an absolute path on Windows, because
of drive letter or UNC.

* [ruby/irb] follow up the actual line number

https://github.com/ruby/irb/commit/7aed8fe3b1

* [ruby/irb] Add info.rb to gemspec

https://github.com/ruby/irb/commit/adbba19adf

* [ruby/irb] Allow "measure" command to take block

https://github.com/ruby/irb/commit/20f1ca23e9

* [ruby/irb] Enable to reassign a new block with "measure" command

https://github.com/ruby/irb/commit/b444573aa2

* [ruby/reline] Cache pasting state in processing a key

Because it's too slow.

The rendering time in IRB has been reduced as follows:

  start = Time.now

  def each_top_level_statement
    initialize_input
    catch(:TERM_INPUT) do
      loop do
        begin
          prompt
          unless l = lex
            throw :TERM_INPUT if @line == ''
          else
            @line_no += l.count("\n")
            next if l == "\n"
            @line.concat l
            if @code_block_open or @ltype or @continue or @indent > 0
              next
            end
          end
          if @line != "\n"
            @line.force_encoding(@io.encoding)
            yield @line, @exp_line_no
          end
          break if @io.eof?
          @line = ''
          @exp_line_no = @line_no

          @indent = 0
        rescue TerminateLineInput
          initialize_input
          prompt
        end
      end
    end
  end

  puts "Duration: #{Time.now - start} seconds"

0.22sec -> 0.14sec

https://github.com/ruby/reline/commit/b8b3dd52c0

* [ruby/reline] Initialize uninitialized variables in tests

https://github.com/ruby/reline/commit/25af4bb64b

* [ruby/reline] Remove an unused variable

https://github.com/ruby/reline/commit/123ea51166

* [ruby/reline] Scroll down when ^C is pressed

https://github.com/ruby/reline/commit/6877a7e3f5

* [ruby/reline] Show all lines higher than the screen when finished

On Unix-like OSes, logs prior to the screen are not editable. When the code
is higher than the screen, the code is only shown on the screen until input
is finished, but when it is finished, all lines are outputted.

https://github.com/ruby/reline/commit/8cd9132a39

* [ruby/reline] Handle past logs correctly when the code is higher than the screen

https://github.com/ruby/reline/commit/f197139b4a

* [ruby/reline] Update cursor info by inserting newline even if not in pasting

https://github.com/ruby/reline/commit/92d314f514

* [ruby/reline] Move cursor just after the last line when finished

https://github.com/ruby/reline/commit/ba06e4c480

* [ruby/reline] The vi_histedit supports multiline

This closes ruby/reline#253.

https://github.com/ruby/reline/commit/f131f86d71

* [ruby/reline] Autowrap correctly when inserting chars in the middle of a line

https://github.com/ruby/reline/commit/ebaf37255f

* [ruby/reline] Terminate correctly in the middle of lines higher than the screen

https://github.com/ruby/reline/commit/e1d9240ada

* [ruby/irb] Version 1.3.3

https://github.com/ruby/irb/commit/4c87035b7c

* [ruby/reline] Version 0.2.3

https://github.com/ruby/reline/commit/b26c7d60c8

Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com>
Co-authored-by: Nobuhiro IMAI <nov@yo.rim.or.jp>
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
Co-authored-by: ima1zumi <mariimaizumi5@gmail.com>
2021-02-07 21:04:32 +09:00

402 lines
11 KiB
Ruby

# frozen_string_literal: false
#
# irb/init.rb - irb initialize module
# $Release Version: 0.9.6$
# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
# --
#
#
#
module IRB # :nodoc:
# initialize config
def IRB.setup(ap_path, argv: ::ARGV)
IRB.init_config(ap_path)
IRB.init_error
IRB.parse_opts(argv: argv)
IRB.run_config
IRB.load_modules
unless @CONF[:PROMPT][@CONF[:PROMPT_MODE]]
fail UndefinedPromptMode, @CONF[:PROMPT_MODE]
end
end
# @CONF default setting
def IRB.init_config(ap_path)
# class instance variables
@TRACER_INITIALIZED = false
# default configurations
unless ap_path and @CONF[:AP_NAME]
ap_path = File.join(File.dirname(File.dirname(__FILE__)), "irb.rb")
end
@CONF[:AP_NAME] = File::basename(ap_path, ".rb")
@CONF[:IRB_NAME] = "irb"
@CONF[:IRB_LIB_PATH] = File.dirname(__FILE__)
@CONF[:RC] = true
@CONF[:LOAD_MODULES] = []
@CONF[:IRB_RC] = nil
@CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod)
@CONF[:USE_COLORIZE] = true
@CONF[:INSPECT_MODE] = true
@CONF[:USE_TRACER] = false
@CONF[:USE_LOADER] = false
@CONF[:IGNORE_SIGINT] = true
@CONF[:IGNORE_EOF] = false
@CONF[:ECHO] = nil
@CONF[:ECHO_ON_ASSIGNMENT] = nil
@CONF[:VERBOSE] = nil
@CONF[:EVAL_HISTORY] = nil
@CONF[:SAVE_HISTORY] = 1000
@CONF[:BACK_TRACE_LIMIT] = 16
@CONF[:PROMPT] = {
:NULL => {
:PROMPT_I => nil,
:PROMPT_N => nil,
:PROMPT_S => nil,
:PROMPT_C => nil,
:RETURN => "%s\n"
},
:DEFAULT => {
:PROMPT_I => "%N(%m):%03n:%i> ",
:PROMPT_N => "%N(%m):%03n:%i> ",
:PROMPT_S => "%N(%m):%03n:%i%l ",
:PROMPT_C => "%N(%m):%03n:%i* ",
:RETURN => "=> %s\n"
},
:CLASSIC => {
:PROMPT_I => "%N(%m):%03n:%i> ",
:PROMPT_N => "%N(%m):%03n:%i> ",
:PROMPT_S => "%N(%m):%03n:%i%l ",
:PROMPT_C => "%N(%m):%03n:%i* ",
:RETURN => "%s\n"
},
:SIMPLE => {
:PROMPT_I => ">> ",
:PROMPT_N => ">> ",
:PROMPT_S => "%l> ",
:PROMPT_C => "?> ",
:RETURN => "=> %s\n"
},
:INF_RUBY => {
:PROMPT_I => "%N(%m):%03n:%i> ",
:PROMPT_N => nil,
:PROMPT_S => nil,
:PROMPT_C => nil,
:RETURN => "%s\n",
:AUTO_INDENT => true
},
:XMP => {
:PROMPT_I => nil,
:PROMPT_N => nil,
:PROMPT_S => nil,
:PROMPT_C => nil,
:RETURN => " ==>%s\n"
}
}
@CONF[:PROMPT_MODE] = (STDIN.tty? ? :DEFAULT : :NULL)
@CONF[:AUTO_INDENT] = true
@CONF[:CONTEXT_MODE] = 4 # use a copy of TOPLEVEL_BINDING
@CONF[:SINGLE_IRB] = false
@CONF[:MEASURE] = false
@CONF[:MEASURE_PROC] = {}
@CONF[:MEASURE_PROC][:TIME] = proc { |context, code, line_no, &block|
time = Time.now
result = block.()
now = Time.now
puts 'processing time: %fs' % (now - time) if IRB.conf[:MEASURE]
result
}
@CONF[:MEASURE_PROC][:STACKPROF] = proc { |context, code, line_no, arg, &block|
success = false
begin
require 'stackprof'
success = true
rescue LoadError
puts 'Please run "gem install stackprof" before measuring by StackProf.'
end
if success
result = nil
stackprof_result = StackProf.run(mode: arg ? arg : :cpu) do
result = block.()
end
StackProf::Report.new(stackprof_result).print_text if IRB.conf[:MEASURE]
result
else
block.()
end
}
@CONF[:MEASURE_CALLBACKS] = []
@CONF[:LC_MESSAGES] = Locale.new
@CONF[:AT_EXIT] = []
end
def IRB.set_measure_callback(type = nil, arg = nil, &block)
added = nil
if type
type_sym = type.upcase.to_sym
if IRB.conf[:MEASURE_PROC][type_sym]
added = [type_sym, IRB.conf[:MEASURE_PROC][type_sym], arg]
end
elsif IRB.conf[:MEASURE_PROC][:CUSTOM]
added = [:CUSTOM, IRB.conf[:MEASURE_PROC][:CUSTOM], arg]
elsif block_given?
added = [:BLOCK, block, arg]
found = IRB.conf[:MEASURE_CALLBACKS].find{ |m| m[0] == added[0] && m[2] == added[2] }
if found
found[1] = block
return added
else
IRB.conf[:MEASURE_CALLBACKS] << added
return added
end
else
added = [:TIME, IRB.conf[:MEASURE_PROC][:TIME], arg]
end
if added
found = IRB.conf[:MEASURE_CALLBACKS].find{ |m| m[0] == added[0] && m[2] == added[2] }
if found
# already added
nil
else
IRB.conf[:MEASURE_CALLBACKS] << added if added
added
end
else
nil
end
end
def IRB.unset_measure_callback(type = nil)
if type.nil?
IRB.conf[:MEASURE_CALLBACKS].clear
else
type_sym = type.upcase.to_sym
IRB.conf[:MEASURE_CALLBACKS].reject!{ |t, | t == type_sym }
end
end
def IRB.init_error
@CONF[:LC_MESSAGES].load("irb/error.rb")
end
# option analyzing
def IRB.parse_opts(argv: ::ARGV)
load_path = []
while opt = argv.shift
case opt
when "-f"
@CONF[:RC] = false
when "-d"
$DEBUG = true
$VERBOSE = true
when "-w"
Warning[:deprecated] = $VERBOSE = true
when /^-W(.+)?/
opt = $1 || argv.shift
case opt
when "0"
$VERBOSE = nil
when "1"
$VERBOSE = false
else
Warning[:deprecated] = $VERBOSE = true
end
when /^-r(.+)?/
opt = $1 || argv.shift
@CONF[:LOAD_MODULES].push opt if opt
when /^-I(.+)?/
opt = $1 || argv.shift
load_path.concat(opt.split(File::PATH_SEPARATOR)) if opt
when '-U'
set_encoding("UTF-8", "UTF-8")
when /^-E(.+)?/, /^--encoding(?:=(.+))?/
opt = $1 || argv.shift
set_encoding(*opt.split(':', 2))
when "--inspect"
if /^-/ !~ argv.first
@CONF[:INSPECT_MODE] = argv.shift
else
@CONF[:INSPECT_MODE] = true
end
when "--noinspect"
@CONF[:INSPECT_MODE] = false
when "--singleline", "--readline", "--legacy"
@CONF[:USE_SINGLELINE] = true
when "--nosingleline", "--noreadline"
@CONF[:USE_SINGLELINE] = false
when "--multiline", "--reidline"
@CONF[:USE_MULTILINE] = true
when "--nomultiline", "--noreidline"
@CONF[:USE_MULTILINE] = false
when "--echo"
@CONF[:ECHO] = true
when "--noecho"
@CONF[:ECHO] = false
when "--echo-on-assignment"
@CONF[:ECHO_ON_ASSIGNMENT] = true
when "--noecho-on-assignment"
@CONF[:ECHO_ON_ASSIGNMENT] = false
when "--truncate-echo-on-assignment"
@CONF[:ECHO_ON_ASSIGNMENT] = :truncate
when "--verbose"
@CONF[:VERBOSE] = true
when "--noverbose"
@CONF[:VERBOSE] = false
when "--colorize"
@CONF[:USE_COLORIZE] = true
when "--nocolorize"
@CONF[:USE_COLORIZE] = false
when /^--prompt-mode(?:=(.+))?/, /^--prompt(?:=(.+))?/
opt = $1 || argv.shift
prompt_mode = opt.upcase.tr("-", "_").intern
@CONF[:PROMPT_MODE] = prompt_mode
when "--noprompt"
@CONF[:PROMPT_MODE] = :NULL
when "--inf-ruby-mode"
@CONF[:PROMPT_MODE] = :INF_RUBY
when "--sample-book-mode", "--simple-prompt"
@CONF[:PROMPT_MODE] = :SIMPLE
when "--tracer"
@CONF[:USE_TRACER] = true
when /^--back-trace-limit(?:=(.+))?/
@CONF[:BACK_TRACE_LIMIT] = ($1 || argv.shift).to_i
when /^--context-mode(?:=(.+))?/
@CONF[:CONTEXT_MODE] = ($1 || argv.shift).to_i
when "--single-irb"
@CONF[:SINGLE_IRB] = true
when "-v", "--version"
print IRB.version, "\n"
exit 0
when "-h", "--help"
require_relative "help"
IRB.print_usage
exit 0
when "--"
if opt = argv.shift
@CONF[:SCRIPT] = opt
$0 = opt
end
break
when /^-/
fail UnrecognizedSwitch, opt
else
@CONF[:SCRIPT] = opt
$0 = opt
break
end
end
load_path.collect! do |path|
/\A\.\// =~ path ? path : File.expand_path(path)
end
$LOAD_PATH.unshift(*load_path)
end
# running config
def IRB.run_config
if @CONF[:RC]
begin
load rc_file
rescue LoadError, Errno::ENOENT
rescue # StandardError, ScriptError
print "load error: #{rc_file}\n"
print $!.class, ": ", $!, "\n"
for err in $@[0, $@.size - 2]
print "\t", err, "\n"
end
end
end
end
IRBRC_EXT = "rc"
def IRB.rc_file(ext = IRBRC_EXT)
if !@CONF[:RC_NAME_GENERATOR]
rc_file_generators do |rcgen|
@CONF[:RC_NAME_GENERATOR] ||= rcgen
if File.exist?(rcgen.call(IRBRC_EXT))
@CONF[:RC_NAME_GENERATOR] = rcgen
break
end
end
end
case rc_file = @CONF[:RC_NAME_GENERATOR].call(ext)
when String
return rc_file
else
fail IllegalRCNameGenerator
end
end
# enumerate possible rc-file base name generators
def IRB.rc_file_generators
if irbrc = ENV["IRBRC"]
yield proc{|rc| rc == "rc" ? irbrc : irbrc+rc}
end
if xdg_config_home = ENV["XDG_CONFIG_HOME"]
irb_home = File.join(xdg_config_home, "irb")
unless File.exist? irb_home
require 'fileutils'
FileUtils.mkdir_p irb_home
end
yield proc{|rc| irb_home + "/irb#{rc}"}
end
if home = ENV["HOME"]
yield proc{|rc| home+"/.irb#{rc}"}
end
current_dir = Dir.pwd
yield proc{|rc| current_dir+"/.config/irb/irb#{rc}"}
yield proc{|rc| current_dir+"/.irb#{rc}"}
yield proc{|rc| current_dir+"/irb#{rc.sub(/\A_?/, '.')}"}
yield proc{|rc| current_dir+"/_irb#{rc}"}
yield proc{|rc| current_dir+"/$irb#{rc}"}
end
# loading modules
def IRB.load_modules
for m in @CONF[:LOAD_MODULES]
begin
require m
rescue LoadError => err
warn "#{err.class}: #{err}", uplevel: 0
end
end
end
DefaultEncodings = Struct.new(:external, :internal)
class << IRB
private
def set_encoding(extern, intern = nil, override: true)
verbose, $VERBOSE = $VERBOSE, nil
Encoding.default_external = extern unless extern.nil? || extern.empty?
Encoding.default_internal = intern unless intern.nil? || intern.empty?
[$stdin, $stdout, $stderr].each do |io|
io.set_encoding(extern, intern)
end
if override
@CONF[:LC_MESSAGES].instance_variable_set(:@override_encoding, extern)
else
@CONF[:LC_MESSAGES].instance_variable_set(:@encoding, extern)
end
ensure
$VERBOSE = verbose
end
end
end