зеркало из https://github.com/github/ruby.git
258 строки
6.7 KiB
Ruby
Executable File
258 строки
6.7 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
|
|
|
|
require 'bundler'
|
|
Bundler.require
|
|
|
|
require 'reline'
|
|
require 'optparse'
|
|
require_relative 'termination_checker'
|
|
|
|
opt = OptionParser.new
|
|
opt.on('--dynamic-prompt') {
|
|
Reline.prompt_proc = proc { |lines|
|
|
lines.each_with_index.map { |l, i|
|
|
"\e[1m[%04d]>\e[m " % i
|
|
}
|
|
}
|
|
}
|
|
opt.on('--broken-dynamic-prompt') {
|
|
Reline.prompt_proc = proc { |lines|
|
|
range = lines.size > 1 ? (0..(lines.size - 2)) : (0..0)
|
|
lines[range].each_with_index.map { |l, i|
|
|
'[%04d]> ' % i
|
|
}
|
|
}
|
|
}
|
|
opt.on('--dynamic-prompt-returns-empty') {
|
|
Reline.prompt_proc = proc { |l| [] }
|
|
}
|
|
opt.on('--dynamic-prompt-with-newline') {
|
|
Reline.prompt_proc = proc { |lines|
|
|
range = lines.size > 1 ? (0..(lines.size - 2)) : (0..0)
|
|
lines[range].each_with_index.map { |l, i|
|
|
'[%04d\n]> ' % i
|
|
}
|
|
}
|
|
}
|
|
opt.on('--broken-dynamic-prompt-assert-no-escape-sequence') {
|
|
Reline.prompt_proc = proc { |lines|
|
|
has_escape_sequence = lines.join.include?("\e")
|
|
(lines.size + 1).times.map { |i|
|
|
has_escape_sequence ? 'error>' : '[%04d]> ' % i
|
|
}
|
|
}
|
|
}
|
|
opt.on('--color-bold') {
|
|
Reline.output_modifier_proc = ->(output, complete:){
|
|
output.gsub(/./) { |c| "\e[1m#{c}\e[0m" }
|
|
}
|
|
}
|
|
opt.on('--dynamic-prompt-show-line') {
|
|
Reline.prompt_proc = proc { |lines|
|
|
lines.map { |l|
|
|
'[%4.4s]> ' % l
|
|
}
|
|
}
|
|
}
|
|
|
|
def assert_auto_indent_params(lines, line_index, byte_pointer, is_newline)
|
|
raise 'Wrong lines type' unless lines.all?(String)
|
|
|
|
line = lines[line_index]
|
|
raise 'Wrong line_index value' unless line
|
|
|
|
# The condition `byte_pointer <= line.bytesize` is not satisfied. Maybe bug.
|
|
# Instead, loose constraint `byte_pointer <= line.bytesize + 1` seems to be satisfied when is_newline is false.
|
|
return if is_newline
|
|
|
|
raise 'byte_pointer out of bounds' unless byte_pointer <= line.bytesize + 1
|
|
raise 'Invalid byte_pointer' unless line.byteslice(0, byte_pointer).valid_encoding?
|
|
end
|
|
|
|
opt.on('--auto-indent') {
|
|
Reline.auto_indent_proc = lambda do |lines, line_index, byte_pointer, is_newline|
|
|
assert_auto_indent_params(lines, line_index, byte_pointer, is_newline)
|
|
AutoIndent.calculate_indent(lines, line_index, byte_pointer, is_newline)
|
|
end
|
|
}
|
|
opt.on('--dialog VAL') { |v|
|
|
Reline.add_dialog_proc(:simple_dialog, lambda {
|
|
return nil if v.include?('nil')
|
|
if v.include?('simple')
|
|
contents = <<~RUBY.split("\n")
|
|
Ruby is...
|
|
A dynamic, open source programming
|
|
language with a focus on simplicity
|
|
and productivity. It has an elegant
|
|
syntax that is natural to read and
|
|
easy to write.
|
|
RUBY
|
|
elsif v.include?('long')
|
|
contents = <<~RUBY.split("\n")
|
|
Ruby is...
|
|
A dynamic, open
|
|
source programming
|
|
language with a
|
|
focus on simplicity
|
|
and productivity.
|
|
It has an elegant
|
|
syntax that is
|
|
natural to read
|
|
and easy to write.
|
|
RUBY
|
|
elsif v.include?('fullwidth')
|
|
contents = <<~RUBY.split("\n")
|
|
Rubyとは...
|
|
|
|
オープンソースの動的なプログラミン
|
|
グ言語で、シンプルさと高い生産性を
|
|
備えています。エレガントな文法を持
|
|
ち、自然に読み書きができます。
|
|
RUBY
|
|
end
|
|
if v.include?('scrollkey')
|
|
dialog.trap_key = nil
|
|
if key and key.match?(dialog.name)
|
|
if dialog.pointer.nil?
|
|
dialog.pointer = 0
|
|
elsif dialog.pointer >= (contents.size - 1)
|
|
dialog.pointer = 0
|
|
else
|
|
dialog.pointer += 1
|
|
end
|
|
end
|
|
dialog.trap_key = [?j.ord]
|
|
height = 4
|
|
end
|
|
scrollbar = false
|
|
if v.include?('scrollbar')
|
|
scrollbar = true
|
|
end
|
|
if v.include?('alt-scrollbar')
|
|
scrollbar = true
|
|
end
|
|
Reline::DialogRenderInfo.new(pos: cursor_pos, contents: contents, height: height, scrollbar: scrollbar, face: :completion_dialog)
|
|
})
|
|
if v.include?('alt-scrollbar')
|
|
ENV['RELINE_ALT_SCROLLBAR'] = '1'
|
|
end
|
|
}
|
|
opt.on('--complete') {
|
|
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
|
|
%w{String ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) }
|
|
}
|
|
}
|
|
opt.on('--complete-menu-with-perfect-match') {
|
|
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
|
|
%w{abs abs2}.select{ |c| c.start_with?(target) }
|
|
}
|
|
}
|
|
opt.on('--autocomplete') {
|
|
Reline.autocompletion = true
|
|
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
|
|
%w{String Struct Symbol ScriptError SyntaxError Signal}.select{ |c| c.start_with?(target) }
|
|
}
|
|
}
|
|
opt.on('--autocomplete-empty') {
|
|
Reline.autocompletion = true
|
|
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil| [] }
|
|
}
|
|
opt.on('--autocomplete-long') {
|
|
Reline.autocompletion = true
|
|
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
|
|
%w{
|
|
String
|
|
Struct
|
|
Symbol
|
|
StopIteration
|
|
SystemCallError
|
|
SystemExit
|
|
SystemStackError
|
|
ScriptError
|
|
SyntaxError
|
|
Signal
|
|
SizedQueue
|
|
Set
|
|
SecureRandom
|
|
Socket
|
|
StringIO
|
|
StringScanner
|
|
Shellwords
|
|
Syslog
|
|
Singleton
|
|
SDBM
|
|
}.select{ |c| c.start_with?(target) }
|
|
}
|
|
}
|
|
opt.on('--autocomplete-super-long') {
|
|
Reline.autocompletion = true
|
|
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
|
|
c = +'A'
|
|
2000.times.map{ s = "Str_#{c}"; c.succ!; s }.select{ |c| c.start_with?(target) }
|
|
}
|
|
}
|
|
|
|
opt.on('--autocomplete-width-long') {
|
|
Reline.autocompletion = true
|
|
Reline.completion_proc = lambda { |target, preposing = nil, postposing = nil|
|
|
%w{
|
|
remove_instance_variable
|
|
respond_to?
|
|
ruby2_keywords
|
|
rand
|
|
readline
|
|
readlines
|
|
require
|
|
require_relative
|
|
raise
|
|
respond_to_missing?
|
|
redo
|
|
rescue
|
|
retry
|
|
return
|
|
}.select{ |c| c.start_with?(target) }
|
|
}
|
|
}
|
|
opt.parse!(ARGV)
|
|
|
|
begin
|
|
stty_save = `stty -g`.chomp
|
|
rescue
|
|
end
|
|
|
|
begin
|
|
prompt = ENV['RELINE_TEST_PROMPT'] || "\e[1mprompt>\e[m "
|
|
puts 'Multiline REPL.'
|
|
while code = Reline.readmultiline(prompt, true) { |code| TerminationChecker.terminated?(code) }
|
|
case code.chomp
|
|
when 'exit', 'quit', 'q'
|
|
exit 0
|
|
when ''
|
|
# NOOP
|
|
else
|
|
begin
|
|
result = eval(code)
|
|
puts "=> #{result.inspect}"
|
|
rescue ScriptError, StandardError => e
|
|
puts "Traceback (most recent call last):"
|
|
e.backtrace.reverse_each do |f|
|
|
puts " #{f}"
|
|
end
|
|
puts e.message
|
|
end
|
|
end
|
|
end
|
|
rescue Interrupt
|
|
puts '^C'
|
|
`stty #{stty_save}` if stty_save
|
|
exit 0
|
|
ensure
|
|
`stty #{stty_save}` if stty_save
|
|
end
|
|
begin
|
|
puts
|
|
rescue Errno::EIO
|
|
# Maybe the I/O has been closed.
|
|
end
|