mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00

* [ruby/irb] Update help message for next context-mode of 4 While here, fixing tab/space issues in help message, and sync rdoc for IRB class to match the help message. https://github.com/ruby/irb/commit/ef8e3901cc * [ruby/irb] Do not continue line if last expression is an endless range Fixes [Bug #14824] https://github.com/ruby/irb/commit/63414f8465 * [ruby/irb] Add a test for not continuing when endless range at eol https://github.com/ruby/irb/commit/1020ac9c65 * [ruby/irb] Make save-history extension safe for concurrent use This makes the save-history extension check for modifications to the history file before saving it. If the history file was modified after the history was loaded and before it was saved, append only the new history lines to the history file. This can result in more lines in the history file than SAVE_HISTORY allows. However, that will be fixed the next time irb is run and the history is saved. Fixes [Bug #13654] https://github.com/ruby/irb/commit/041ef53845 * Fix errors when XDG_CONFIG_HOME points to non-writable directory `$HOME/.config` is not writable on CI because I think tests should not corrupt user's data. And GitHub Actions CI sets `XDG_CONFIG_HOME` since `Version: 20210309.1`. https://github.com/ruby/actions/runs/2130811016?check_suite_focus=true#step:16:301 ``` Errno::EACCES: Permission denied @ dir_s_mkdir - /home/runner/.config/irb ``` * Try to fix errors in TestIRB::TestHistory too https://github.com/ruby/actions/runs/2137935523?check_suite_focus=true#step:9:562 ``` 1) Error: TestIRB::TestHistory#test_history_concurrent_use: Errno::EACCES: Permission denied @ dir_s_mkdir - /home/runner/.config/irb /home/runner/work/actions/actions/ruby/lib/fileutils.rb:253:in `mkdir' /home/runner/work/actions/actions/ruby/lib/fileutils.rb:253:in `fu_mkdir' /home/runner/work/actions/actions/ruby/lib/fileutils.rb:231:in `block (2 levels) in mkdir_p' /home/runner/work/actions/actions/ruby/lib/fileutils.rb:229:in `reverse_each' /home/runner/work/actions/actions/ruby/lib/fileutils.rb:229:in `block in mkdir_p' /home/runner/work/actions/actions/ruby/lib/fileutils.rb:211:in `each' /home/runner/work/actions/actions/ruby/lib/fileutils.rb:211:in `mkdir_p' /home/runner/work/actions/actions/ruby/lib/irb/init.rb:355:in `rc_file_generators' /home/runner/work/actions/actions/ruby/lib/irb/init.rb:330:in `rc_file' /home/runner/work/actions/actions/ruby/test/irb/test_history.rb:170:in `block in assert_history' /home/runner/work/actions/actions/ruby/lib/tmpdir.rb:96:in `mktmpdir' /home/runner/work/actions/actions/ruby/test/irb/test_history.rb:168:in `assert_history' /home/runner/work/actions/actions/ruby/test/irb/test_history.rb:133:in `test_history_concurrent_use' ``` * [ruby/irb] Define "measure" command without forced override https://github.com/ruby/irb/commit/9587ba13b5 * [ruby/irb] Add all lib files automatically https://github.com/ruby/irb/commit/ecc82336b7 * [ruby/irb] Don't call Ruby 2.4+'s String#pretty_print https://github.com/ruby/irb/commit/89bcf107be * [ruby/irb] Implement ls command https://github.com/ruby/irb/commit/19b6c20604 * [ruby/irb] Add whereami command https://github.com/ruby/irb/commit/bc822e4aac * [ruby/irb] Fix column overflow on ls output https://github.com/ruby/irb/commit/6115754623 * [ruby/irb] Fix step's argument cols.size was calling Integer#size, which returns 8. Fixing a bug of https://github.com/ruby/irb/pull/209 https://github.com/ruby/irb/commit/c93ae4be71 * [ruby/irb] Deal with different screen sizes e.g. http://rubyci.s3.amazonaws.com/centos8/ruby-master/log/20210321T063003Z.fail.html.gz https://github.com/ruby/irb/commit/ddb3472ba2 * [ruby/irb] Have some right padding instead of filling out an entire line https://github.com/ruby/irb/commit/6ac8f45f5f * Suppress verbose messages Get rid of warnings in the parallel test. ``` unknown command: "Switch to inspect mode." ``` * [ruby/irb] Change ripper_lex_without_warning to a class method https://github.com/ruby/irb/commit/d9f8abc17e * [ruby/irb] Complete require and require_relative https://github.com/ruby/irb/commit/1c61178b4c * [ruby/reline] Add Reline.ungetc to control buffer https://github.com/ruby/reline/commit/43ac03c624 * [ruby/reline] Reline.delete_text removes the current line in multiline https://github.com/ruby/reline/commit/da90c094a1 * [ruby/reline] Support preposing and postposing for Reline.completion_proc https://github.com/ruby/reline/commit/1f469de90c * [ruby/reline] Suppress crashing when completer_{quote,word_break}_characters is empty https://github.com/ruby/reline/commit/c6f1164942 * [ruby/irb] fix completion test when out-of-place build * [ruby/irb] Cache completion files to require https://github.com/ruby/irb/commit/612ebcb311 * [ruby/irb] Always add input method when calling Irb.new in tests When passes input method as nil to Context.new through Irb.new, ReidlineInputMethod.new is executed and the global internal state of Reline is rewritten, therefore other tests are failed in the Ruby repository. This commit changes to use TestInputMethod. https://github.com/ruby/irb/commit/010dce9210 * [ruby/irb] Prevent the completion from crashing if rdoc is missing There are cases where ruby is installed without rdoc and e.g. lib/irb/cmd/help.rb also handles the LoadError Here is how to replicate the issue: ``` $ docker run -it alpine:3.13.3 sh / # apk add ruby ruby-irb ruby-io-console / # irb irb(main):001:0> Class[TAB][TAB] ``` And you end up with something like: ``` irb(main):001:0> ClassTraceback (most recent call last): 34: from /usr/bin/irb:23:in `<main>' 33: from /usr/bin/irb:23:in `load' 32: from /usr/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>' 31: from /usr/lib/ruby/2.7.0/irb.rb:400:in `start' 30: from /usr/lib/ruby/2.7.0/irb.rb:471:in `run' 29: from /usr/lib/ruby/2.7.0/irb.rb:471:in `catch' 28: from /usr/lib/ruby/2.7.0/irb.rb:472:in `block in run' 27: from /usr/lib/ruby/2.7.0/irb.rb:537:in `eval_input' 26: from /usr/lib/ruby/2.7.0/irb/ruby-lex.rb:150:in `each_top_level_statement' 25: from /usr/lib/ruby/2.7.0/irb/ruby-lex.rb:150:in `catch' 24: from /usr/lib/ruby/2.7.0/irb/ruby-lex.rb:151:in `block in each_top_level_statement' 23: from /usr/lib/ruby/2.7.0/irb/ruby-lex.rb:151:in `loop' 22: from /usr/lib/ruby/2.7.0/irb/ruby-lex.rb:154:in `block (2 levels) in each_top_level_statement' 21: from /usr/lib/ruby/2.7.0/irb/ruby-lex.rb:182:in `lex' 20: from /usr/lib/ruby/2.7.0/irb.rb:518:in `block in eval_input' 19: from /usr/lib/ruby/2.7.0/irb.rb:704:in `signal_status' 18: from /usr/lib/ruby/2.7.0/irb.rb:519:in `block (2 levels) in eval_input' 17: from /usr/lib/ruby/2.7.0/irb/input-method.rb:294:in `gets' 16: from /usr/lib/ruby/2.7.0/forwardable.rb:235:in `readmultiline' 15: from /usr/lib/ruby/2.7.0/forwardable.rb:235:in `readmultiline' 14: from /usr/lib/ruby/2.7.0/reline.rb:175:in `readmultiline' 13: from /usr/lib/ruby/2.7.0/reline.rb:238:in `inner_readline' 12: from /usr/lib/ruby/2.7.0/reline.rb:238:in `loop' 11: from /usr/lib/ruby/2.7.0/reline.rb:239:in `block in inner_readline' 10: from /usr/lib/ruby/2.7.0/reline.rb:270:in `read_io' 9: from /usr/lib/ruby/2.7.0/reline.rb:270:in `loop' 8: from /usr/lib/ruby/2.7.0/reline.rb:311:in `block in read_io' 7: from /usr/lib/ruby/2.7.0/reline.rb:240:in `block (2 levels) in inner_readline' 6: from /usr/lib/ruby/2.7.0/reline.rb:240:in `each' 5: from /usr/lib/ruby/2.7.0/reline.rb:241:in `block (3 levels) in inner_readline' 4: from /usr/lib/ruby/2.7.0/reline/line_editor.rb:820:in `input_key' 3: from /usr/lib/ruby/2.7.0/reline/line_editor.rb:608:in `complete' 2: from /usr/lib/ruby/2.7.0/irb/completion.rb:269:in `block in <module:InputCompletor>' 1: from /usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require' /usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require': cannot load such file -- rdoc (LoadError) ``` https://github.com/ruby/irb/commit/a2d299c2ac * [ruby/irb] Suppress verbose messages in the parallel test `:VERBOSE` flag needs to be set prior to `IRB::Irb.new`. https://github.com/ruby/irb/commit/78604682d9 * [ruby/irb] SIGINT should raise Interrupt after IRB session https://github.com/ruby/irb/commit/5832cfe75b * [ruby/irb] Colorize `__END__` as keyword https://github.com/ruby/irb/commit/9b84018311 * [ruby/irb] Add show_source command https://github.com/ruby/irb/commit/108cb04352 * [ruby/reline] Reset @rest_height when clear screen https://github.com/ruby/reline/commit/3a7019b0d5 * [ruby/irb] process multi-line pastes as a single entity this allows pasting leading-dot chained methods correctly: ```ruby class A def a; self; end def b; true; end end a = A.new a .a .b ``` will properly return `true` instead of erroring on the `.a` line: ``` irb(main):001:1* class A irb(main):002:1* def a; self; end irb(main):003:0> end irb(main):004:0* irb(main):005:0> a = A.new irb(main):006:0* irb(main):007:0> a irb(main):008:0> .a irb(main):009:0> .a => #<A:0x00007f984211fbe8> ``` https://github.com/ruby/irb/commit/45aeb52575 * [ruby/irb] Add yamatanooroti test example https://github.com/ruby/irb/commit/279155fcee * [ruby/irb] Add test for multiline paste https://github.com/ruby/irb/commit/e93c9cb54d * [ruby/irb] Evaluate each toplevel statement https://github.com/ruby/irb/commit/bc1b1d8bc3 * [ruby/irb] Version 1.3.5 https://github.com/ruby/irb/commit/22e2ddf715 * [ruby/reline] Version 0.2.5 https://github.com/ruby/reline/commit/22ce5651e5 Co-authored-by: Jeremy Evans <code@jeremyevans.net> Co-authored-by: Kazuhiro NISHIYAMA <zn@mbf.nifty.com> Co-authored-by: Takashi Kokubun <takashikkbn@gmail.com> Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org> Co-authored-by: Aleksandar Ivanov <aivanov92@gmail.com> Co-authored-by: Koichi Sasada <ko1@atdot.net> Co-authored-by: Cody Cutrer <cody@instructure.com>
471 lines
14 KiB
Ruby
471 lines
14 KiB
Ruby
require 'io/console'
|
|
require 'timeout'
|
|
require 'forwardable'
|
|
require 'reline/version'
|
|
require 'reline/config'
|
|
require 'reline/key_actor'
|
|
require 'reline/key_stroke'
|
|
require 'reline/line_editor'
|
|
require 'reline/history'
|
|
require 'rbconfig'
|
|
|
|
module Reline
|
|
FILENAME_COMPLETION_PROC = nil
|
|
USERNAME_COMPLETION_PROC = nil
|
|
|
|
Key = Struct.new('Key', :char, :combined_char, :with_meta)
|
|
CursorPos = Struct.new(:x, :y)
|
|
|
|
class Core
|
|
ATTR_READER_NAMES = %i(
|
|
completion_append_character
|
|
basic_word_break_characters
|
|
completer_word_break_characters
|
|
basic_quote_characters
|
|
completer_quote_characters
|
|
filename_quote_characters
|
|
special_prefixes
|
|
completion_proc
|
|
output_modifier_proc
|
|
prompt_proc
|
|
auto_indent_proc
|
|
pre_input_hook
|
|
dig_perfect_match_proc
|
|
).each(&method(:attr_reader))
|
|
|
|
attr_accessor :config
|
|
attr_accessor :key_stroke
|
|
attr_accessor :line_editor
|
|
attr_accessor :last_incremental_search
|
|
attr_reader :output
|
|
|
|
def initialize
|
|
self.output = STDOUT
|
|
yield self
|
|
@completion_quote_character = nil
|
|
@bracketed_paste_finished = false
|
|
end
|
|
|
|
def encoding
|
|
Reline::IOGate.encoding
|
|
end
|
|
|
|
def completion_append_character=(val)
|
|
if val.nil?
|
|
@completion_append_character = nil
|
|
elsif val.size == 1
|
|
@completion_append_character = val.encode(Reline::IOGate.encoding)
|
|
elsif val.size > 1
|
|
@completion_append_character = val[0].encode(Reline::IOGate.encoding)
|
|
else
|
|
@completion_append_character = nil
|
|
end
|
|
end
|
|
|
|
def basic_word_break_characters=(v)
|
|
@basic_word_break_characters = v.encode(Reline::IOGate.encoding)
|
|
end
|
|
|
|
def completer_word_break_characters=(v)
|
|
@completer_word_break_characters = v.encode(Reline::IOGate.encoding)
|
|
end
|
|
|
|
def basic_quote_characters=(v)
|
|
@basic_quote_characters = v.encode(Reline::IOGate.encoding)
|
|
end
|
|
|
|
def completer_quote_characters=(v)
|
|
@completer_quote_characters = v.encode(Reline::IOGate.encoding)
|
|
end
|
|
|
|
def filename_quote_characters=(v)
|
|
@filename_quote_characters = v.encode(Reline::IOGate.encoding)
|
|
end
|
|
|
|
def special_prefixes=(v)
|
|
@special_prefixes = v.encode(Reline::IOGate.encoding)
|
|
end
|
|
|
|
def completion_case_fold=(v)
|
|
@config.completion_ignore_case = v
|
|
end
|
|
|
|
def completion_case_fold
|
|
@config.completion_ignore_case
|
|
end
|
|
|
|
def completion_quote_character
|
|
@completion_quote_character
|
|
end
|
|
|
|
def completion_proc=(p)
|
|
raise ArgumentError unless p.respond_to?(:call) or p.nil?
|
|
@completion_proc = p
|
|
end
|
|
|
|
def output_modifier_proc=(p)
|
|
raise ArgumentError unless p.respond_to?(:call) or p.nil?
|
|
@output_modifier_proc = p
|
|
end
|
|
|
|
def prompt_proc=(p)
|
|
raise ArgumentError unless p.respond_to?(:call) or p.nil?
|
|
@prompt_proc = p
|
|
end
|
|
|
|
def auto_indent_proc=(p)
|
|
raise ArgumentError unless p.respond_to?(:call) or p.nil?
|
|
@auto_indent_proc = p
|
|
end
|
|
|
|
def pre_input_hook=(p)
|
|
@pre_input_hook = p
|
|
end
|
|
|
|
def dig_perfect_match_proc=(p)
|
|
raise ArgumentError unless p.respond_to?(:call) or p.nil?
|
|
@dig_perfect_match_proc = p
|
|
end
|
|
|
|
def input=(val)
|
|
raise TypeError unless val.respond_to?(:getc) or val.nil?
|
|
if val.respond_to?(:getc)
|
|
if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
|
|
Reline::ANSI.input = val
|
|
elsif Reline::IOGate == Reline::GeneralIO
|
|
Reline::GeneralIO.input = val
|
|
end
|
|
end
|
|
end
|
|
|
|
def output=(val)
|
|
raise TypeError unless val.respond_to?(:write) or val.nil?
|
|
@output = val
|
|
if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
|
|
Reline::ANSI.output = val
|
|
end
|
|
end
|
|
|
|
def vi_editing_mode
|
|
config.editing_mode = :vi_insert
|
|
nil
|
|
end
|
|
|
|
def emacs_editing_mode
|
|
config.editing_mode = :emacs
|
|
nil
|
|
end
|
|
|
|
def vi_editing_mode?
|
|
config.editing_mode_is?(:vi_insert, :vi_command)
|
|
end
|
|
|
|
def emacs_editing_mode?
|
|
config.editing_mode_is?(:emacs)
|
|
end
|
|
|
|
def get_screen_size
|
|
Reline::IOGate.get_screen_size
|
|
end
|
|
|
|
def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
|
|
unless confirm_multiline_termination
|
|
raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
|
|
end
|
|
inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
|
|
|
|
whole_buffer = line_editor.whole_buffer.dup
|
|
whole_buffer.taint if RUBY_VERSION < '2.7'
|
|
if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
|
|
Reline::HISTORY << whole_buffer
|
|
end
|
|
|
|
line_editor.reset_line if line_editor.whole_buffer.nil?
|
|
whole_buffer
|
|
end
|
|
|
|
def readline(prompt = '', add_hist = false)
|
|
inner_readline(prompt, add_hist, false)
|
|
|
|
line = line_editor.line.dup
|
|
line.taint if RUBY_VERSION < '2.7'
|
|
if add_hist and line and line.chomp("\n").size > 0
|
|
Reline::HISTORY << line.chomp("\n")
|
|
end
|
|
|
|
line_editor.reset_line if line_editor.line.nil?
|
|
line
|
|
end
|
|
|
|
private def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
|
|
if ENV['RELINE_STDERR_TTY']
|
|
if Reline::IOGate.win?
|
|
$stderr = File.open(ENV['RELINE_STDERR_TTY'], 'a')
|
|
else
|
|
$stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
|
|
end
|
|
$stderr.sync = true
|
|
$stderr.puts "Reline is used by #{Process.pid}"
|
|
end
|
|
otio = Reline::IOGate.prep
|
|
|
|
may_req_ambiguous_char_width
|
|
line_editor.reset(prompt, encoding: Reline::IOGate.encoding)
|
|
if multiline
|
|
line_editor.multiline_on
|
|
if block_given?
|
|
line_editor.confirm_multiline_termination_proc = confirm_multiline_termination
|
|
end
|
|
else
|
|
line_editor.multiline_off
|
|
end
|
|
line_editor.output = output
|
|
line_editor.completion_proc = completion_proc
|
|
line_editor.completion_append_character = completion_append_character
|
|
line_editor.output_modifier_proc = output_modifier_proc
|
|
line_editor.prompt_proc = prompt_proc
|
|
line_editor.auto_indent_proc = auto_indent_proc
|
|
line_editor.dig_perfect_match_proc = dig_perfect_match_proc
|
|
line_editor.pre_input_hook = pre_input_hook
|
|
|
|
unless config.test_mode
|
|
config.read
|
|
config.reset_default_key_bindings
|
|
Reline::IOGate::RAW_KEYSTROKE_CONFIG.each_pair do |key, func|
|
|
config.add_default_key_binding(key, func)
|
|
end
|
|
end
|
|
|
|
line_editor.rerender
|
|
|
|
begin
|
|
prev_pasting_state = false
|
|
loop do
|
|
prev_pasting_state = Reline::IOGate.in_pasting?
|
|
read_io(config.keyseq_timeout) { |inputs|
|
|
line_editor.set_pasting_state(Reline::IOGate.in_pasting?)
|
|
inputs.each { |c|
|
|
line_editor.input_key(c)
|
|
line_editor.rerender
|
|
}
|
|
if @bracketed_paste_finished
|
|
line_editor.rerender_all
|
|
@bracketed_paste_finished = false
|
|
end
|
|
}
|
|
if prev_pasting_state == true and not Reline::IOGate.in_pasting? and not line_editor.finished?
|
|
line_editor.set_pasting_state(false)
|
|
prev_pasting_state = false
|
|
line_editor.rerender_all
|
|
end
|
|
break if line_editor.finished?
|
|
end
|
|
Reline::IOGate.move_cursor_column(0)
|
|
rescue Errno::EIO
|
|
# Maybe the I/O has been closed.
|
|
rescue StandardError => e
|
|
line_editor.finalize
|
|
Reline::IOGate.deprep(otio)
|
|
raise e
|
|
end
|
|
|
|
line_editor.finalize
|
|
Reline::IOGate.deprep(otio)
|
|
end
|
|
|
|
# Keystrokes of GNU Readline will timeout it with the specification of
|
|
# "keyseq-timeout" when waiting for the 2nd character after the 1st one.
|
|
# If the 2nd character comes after 1st ESC without timeout it has a
|
|
# meta-property of meta-key to discriminate modified key with meta-key
|
|
# from multibyte characters that come with 8th bit on.
|
|
#
|
|
# GNU Readline will wait for the 2nd character with "keyseq-timeout"
|
|
# milli-seconds but wait forever after 3rd characters.
|
|
private def read_io(keyseq_timeout, &block)
|
|
buffer = []
|
|
loop do
|
|
c = Reline::IOGate.getc
|
|
if c == -1
|
|
result = :unmatched
|
|
@bracketed_paste_finished = true
|
|
else
|
|
buffer << c
|
|
result = key_stroke.match_status(buffer)
|
|
end
|
|
case result
|
|
when :matched
|
|
expanded = key_stroke.expand(buffer).map{ |expanded_c|
|
|
Reline::Key.new(expanded_c, expanded_c, false)
|
|
}
|
|
block.(expanded)
|
|
break
|
|
when :matching
|
|
if buffer.size == 1
|
|
begin
|
|
succ_c = nil
|
|
Timeout.timeout(keyseq_timeout / 1000.0) {
|
|
succ_c = Reline::IOGate.getc
|
|
}
|
|
rescue Timeout::Error # cancel matching only when first byte
|
|
block.([Reline::Key.new(c, c, false)])
|
|
break
|
|
else
|
|
if key_stroke.match_status(buffer.dup.push(succ_c)) == :unmatched
|
|
if c == "\e".ord
|
|
block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
|
|
else
|
|
block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
|
|
end
|
|
break
|
|
else
|
|
Reline::IOGate.ungetc(succ_c)
|
|
end
|
|
end
|
|
end
|
|
when :unmatched
|
|
if buffer.size == 1 and c == "\e".ord
|
|
read_escaped_key(keyseq_timeout, c, block)
|
|
else
|
|
expanded = buffer.map{ |expanded_c|
|
|
Reline::Key.new(expanded_c, expanded_c, false)
|
|
}
|
|
block.(expanded)
|
|
end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
private def read_escaped_key(keyseq_timeout, c, block)
|
|
begin
|
|
escaped_c = nil
|
|
Timeout.timeout(keyseq_timeout / 1000.0) {
|
|
escaped_c = Reline::IOGate.getc
|
|
}
|
|
rescue Timeout::Error # independent ESC
|
|
block.([Reline::Key.new(c, c, false)])
|
|
else
|
|
if escaped_c.nil?
|
|
block.([Reline::Key.new(c, c, false)])
|
|
elsif escaped_c >= 128 # maybe, first byte of multi byte
|
|
block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
|
|
elsif escaped_c == "\e".ord # escape twice
|
|
block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
|
|
else
|
|
block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
|
|
end
|
|
end
|
|
end
|
|
|
|
def ambiguous_width
|
|
may_req_ambiguous_char_width unless defined? @ambiguous_width
|
|
@ambiguous_width
|
|
end
|
|
|
|
private def may_req_ambiguous_char_width
|
|
@ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
|
|
return if @ambiguous_width
|
|
Reline::IOGate.move_cursor_column(0)
|
|
begin
|
|
output.write "\u{25bd}"
|
|
rescue Encoding::UndefinedConversionError
|
|
# LANG=C
|
|
@ambiguous_width = 1
|
|
else
|
|
@ambiguous_width = Reline::IOGate.cursor_pos.x
|
|
end
|
|
Reline::IOGate.move_cursor_column(0)
|
|
Reline::IOGate.erase_after_cursor
|
|
end
|
|
end
|
|
|
|
extend Forwardable
|
|
extend SingleForwardable
|
|
|
|
#--------------------------------------------------------
|
|
# Documented API
|
|
#--------------------------------------------------------
|
|
|
|
(Core::ATTR_READER_NAMES).each { |name|
|
|
def_single_delegators :core, "#{name}", "#{name}="
|
|
}
|
|
def_single_delegators :core, :input=, :output=
|
|
def_single_delegators :core, :vi_editing_mode, :emacs_editing_mode
|
|
def_single_delegators :core, :readline
|
|
def_single_delegators :core, :completion_case_fold, :completion_case_fold=
|
|
def_single_delegators :core, :completion_quote_character
|
|
def_instance_delegators self, :readline
|
|
private :readline
|
|
|
|
|
|
#--------------------------------------------------------
|
|
# Undocumented API
|
|
#--------------------------------------------------------
|
|
|
|
# Testable in original
|
|
def_single_delegators :core, :get_screen_size
|
|
def_single_delegators :line_editor, :eof?
|
|
def_instance_delegators self, :eof?
|
|
def_single_delegators :line_editor, :delete_text
|
|
def_single_delegator :line_editor, :line, :line_buffer
|
|
def_single_delegator :line_editor, :byte_pointer, :point
|
|
def_single_delegator :line_editor, :byte_pointer=, :point=
|
|
|
|
def self.insert_text(*args, &block)
|
|
line_editor.insert_text(*args, &block)
|
|
self
|
|
end
|
|
|
|
# Untestable in original
|
|
def_single_delegator :line_editor, :rerender, :redisplay
|
|
def_single_delegators :core, :vi_editing_mode?, :emacs_editing_mode?
|
|
def_single_delegators :core, :ambiguous_width
|
|
def_single_delegators :core, :last_incremental_search
|
|
def_single_delegators :core, :last_incremental_search=
|
|
|
|
def_single_delegators :core, :readmultiline
|
|
def_instance_delegators self, :readmultiline
|
|
private :readmultiline
|
|
|
|
def self.encoding_system_needs
|
|
self.core.encoding
|
|
end
|
|
|
|
def self.core
|
|
@core ||= Core.new { |core|
|
|
core.config = Reline::Config.new
|
|
core.key_stroke = Reline::KeyStroke.new(core.config)
|
|
core.line_editor = Reline::LineEditor.new(core.config, Reline::IOGate.encoding)
|
|
|
|
core.basic_word_break_characters = " \t\n`><=;|&{("
|
|
core.completer_word_break_characters = " \t\n`><=;|&{("
|
|
core.basic_quote_characters = '"\''
|
|
core.completer_quote_characters = '"\''
|
|
core.filename_quote_characters = ""
|
|
core.special_prefixes = ""
|
|
}
|
|
end
|
|
|
|
def self.ungetc(c)
|
|
Reline::IOGate.ungetc(c)
|
|
end
|
|
|
|
def self.line_editor
|
|
core.line_editor
|
|
end
|
|
end
|
|
|
|
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
|
require 'reline/windows'
|
|
if Reline::Windows.msys_tty?
|
|
require 'reline/ansi'
|
|
Reline::IOGate = Reline::ANSI
|
|
else
|
|
Reline::IOGate = Reline::Windows
|
|
end
|
|
else
|
|
require 'reline/ansi'
|
|
Reline::IOGate = Reline::ANSI
|
|
end
|
|
Reline::HISTORY = Reline::History.new(Reline.core.config)
|
|
require 'reline/general_io'
|