diff options
author | aycabta <aycabta@gmail.com> | 2019-04-23 18:09:46 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2019-04-23 20:08:02 +0900 |
commit | f2cd4f4cd0a1e352fcc48a216127beaeda2b2399 (patch) | |
tree | 8e02f39a8df8fa5708e446aeb8d42d45d8a28abe /lib/reline.rb | |
parent | 87cf45a512a7803f266e4782c49e0a99c06a4039 (diff) | |
download | ruby-f2cd4f4cd0a1e352fcc48a216127beaeda2b2399.tar.gz |
IRB is improved with Reline and RDoc, take 2
Diffstat (limited to 'lib/reline.rb')
-rw-r--r-- | lib/reline.rb | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/lib/reline.rb b/lib/reline.rb new file mode 100644 index 0000000000..b1d7718b7e --- /dev/null +++ b/lib/reline.rb @@ -0,0 +1,196 @@ +require 'io/console' +require 'reline/version' +require 'reline/config' +require 'reline/key_actor' +require 'reline/key_stroke' +require 'reline/line_editor' + +module Reline + extend self + FILENAME_COMPLETION_PROC = nil + USERNAME_COMPLETION_PROC = nil + HISTORY = Array.new + + if RUBY_PLATFORM =~ /mswin|mingw/ + require 'Win32API' + IS_WINDOWS = true + else + IS_WINDOWS = false + end + + CursorPos = Struct.new(:x, :y) + + class << self + attr_accessor :basic_quote_characters + attr_accessor :completer_quote_characters + attr_accessor :completer_word_break_characters + attr_reader :completion_append_character + attr_accessor :completion_case_fold + attr_accessor :filename_quote_characters + attr_writer :input + attr_writer :output + end + + @@ambiguous_width = nil + @@config = nil + + @basic_quote_characters = '"\'' + @completer_quote_characters + @completer_word_break_characters = @basic_word_break_characters.dup + @completion_append_character + def self.completion_append_character=(val) + if val.nil? + @completion_append_character = nil + elsif val.size == 1 + @completion_append_character = val + elsif val.size > 1 + @completion_append_character = val[0] + else + @completion_append_character = val + end + end + @completion_case_fold + @filename_quote_characters + + @@basic_word_break_characters = " \t\n`><=;|&{(" + def self.basic_word_break_characters + @@basic_word_break_characters + end + def self.basic_word_break_characters=(v) + @@basic_word_break_characters = v + end + + @@completion_proc = nil + def self.completion_proc + @@completion_proc + end + def self.completion_proc=(p) + @@completion_proc = p + end + + @@dig_perfect_match_proc = nil + def self.dig_perfect_match_proc + @@dig_perfect_match_proc + end + def self.dig_perfect_match_proc=(p) + @@dig_perfect_match_proc = p + end + + if IS_WINDOWS + require 'reline/windows' + else + require 'reline/ansi' + end + + def retrieve_completion_block(line, byte_pointer) + break_regexp = /[#{Regexp.escape(@@basic_word_break_characters)}]/ + before_pointer = line.byteslice(0, byte_pointer) + break_point = before_pointer.rindex(break_regexp) + if break_point + preposing = before_pointer[0..(break_point)] + block = before_pointer[(break_point + 1)..-1] + else + preposing = '' + block = before_pointer + end + postposing = line.byteslice(byte_pointer, line.bytesize) + [preposing, block, postposing] + end + + def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination) + if block_given? + inner_readline(prompt, add_hist, true, &confirm_multiline_termination) + else + inner_readline(prompt, add_hist, true) + end + + if add_hist and @line_editor.whole_buffer and @line_editor.whole_buffer.chomp.size > 0 + Reline::HISTORY << @line_editor.whole_buffer + end + + @line_editor.whole_buffer + end + + def readline(prompt = '', add_hist = false) + inner_readline(prompt, add_hist, false) + + if add_hist and @line_editor.line and @line_editor.line.chomp.size > 0 + Reline::HISTORY << @line_editor.line.chomp + end + + @line_editor.line + end + + def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination) + if @@config.nil? + @@config = Reline::Config.new + @@config.read + end + otio = prep + + may_req_ambiguous_char_width + @line_editor = Reline::LineEditor.new(@@config, prompt) + if multiline + @line_editor.multiline_on + if block_given? + @line_editor.confirm_multiline_termination_proc = confirm_multiline_termination + end + end + @line_editor.completion_proc = @@completion_proc + @line_editor.dig_perfect_match_proc = @@dig_perfect_match_proc + @line_editor.retrieve_completion_block = method(:retrieve_completion_block) + @line_editor.rerender + + if IS_WINDOWS + config = { + key_mapping: { + [224, 72] => :ed_prev_history, # ↑ + [224, 80] => :ed_next_history, # ↓ + [224, 77] => :ed_next_char, # → + [224, 75] => :ed_prev_char # ← + } + } + else + config = { + key_mapping: { + [27, 91, 65] => :ed_prev_history, # ↑ + [27, 91, 66] => :ed_next_history, # ↓ + [27, 91, 67] => :ed_next_char, # → + [27, 91, 68] => :ed_prev_char # ← + } + } + end + + key_stroke = Reline::KeyStroke.new(config) + begin + while c = getc + key_stroke.input_to!(c)&.then { |inputs| + inputs.each { |c| + @line_editor.input_key(c) + @line_editor.rerender + } + } + break if @line_editor.finished? + end + Reline.move_cursor_column(0) + rescue StandardError => e + deprep(otio) + raise e + end + + deprep(otio) + end + + def may_req_ambiguous_char_width + return if @@ambiguous_width + Reline.move_cursor_column(0) + print "\u{25bd}" + @@ambiguous_width = Reline.cursor_pos.x + Reline.move_cursor_column(0) + Reline.erase_after_cursor + end + + def self.ambiguous_width + @@ambiguous_width + end +end |