summaryrefslogtreecommitdiff
path: root/lib/reline.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/reline.rb')
-rw-r--r--lib/reline.rb473
1 files changed, 0 insertions, 473 deletions
diff --git a/lib/reline.rb b/lib/reline.rb
deleted file mode 100644
index bf8967c561..0000000000
--- a/lib/reline.rb
+++ /dev/null
@@ -1,473 +0,0 @@
-require 'io/console'
-require 'timeout'
-require 'reline/version'
-require 'reline/config'
-require 'reline/key_actor'
-require 'reline/key_stroke'
-require 'reline/line_editor'
-
-module Reline
- Key = Struct.new('Key', :char, :combined_char, :with_meta)
-
- extend self
- FILENAME_COMPLETION_PROC = nil
- USERNAME_COMPLETION_PROC = nil
-
- if RUBY_PLATFORM =~ /mswin|mingw/
- IS_WINDOWS = true
- else
- IS_WINDOWS = false
- end
-
- CursorPos = Struct.new(:x, :y)
-
- @@config = Reline::Config.new
- @@key_stroke = Reline::KeyStroke.new(@@config)
- @@line_editor = Reline::LineEditor.new(@@config)
- @@ambiguous_width = nil
-
- HISTORY = Class.new(Array) {
- def initialize(config)
- @config = config
- end
-
- def to_s
- 'HISTORY'
- end
-
- def delete_at(index)
- index = check_index(index)
- super(index)
- end
-
- def [](index)
- index = check_index(index)
- super(index)
- end
-
- def []=(index, val)
- index = check_index(index)
- super(index, String.new(val, encoding: Encoding::default_external))
- end
-
- def concat(*val)
- val.each do |v|
- push(*v)
- end
- end
-
- def push(*val)
- diff = size + val.size - @config.history_size
- if diff > 0
- if diff <= size
- shift(diff)
- else
- diff -= size
- clear
- val.shift(diff)
- end
- end
- super(*(val.map{ |v| String.new(v, encoding: Encoding::default_external) }))
- end
-
- def <<(val)
- shift if size + 1 > @config.history_size
- super(String.new(val, encoding: Encoding::default_external))
- end
-
- private def check_index(index)
- index += size if index < 0
- raise RangeError.new("index=<#{index}>") if index < -@config.history_size or @config.history_size < index
- raise IndexError.new("index=<#{index}>") if index < 0 or size <= index
- index
- end
-
- private def set_config(config)
- @config = config
- end
- }.new(@@config)
-
- @@completion_append_character = nil
- def self.completion_append_character
- @@completion_append_character
- end
- def self.completion_append_character=(val)
- if val.nil?
- @@completion_append_character = nil
- elsif val.size == 1
- @@completion_append_character = val.encode(Encoding::default_external)
- elsif val.size > 1
- @@completion_append_character = val[0].encode(Encoding::default_external)
- else
- @@completion_append_character = nil
- end
- end
-
- @@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.encode(Encoding::default_external)
- end
-
- @@completer_word_break_characters = @@basic_word_break_characters.dup
- def self.completer_word_break_characters
- @@completer_word_break_characters
- end
- def self.completer_word_break_characters=(v)
- @@completer_word_break_characters = v.encode(Encoding::default_external)
- end
-
- @@basic_quote_characters = '"\''
- def self.basic_quote_characters
- @@basic_quote_characters
- end
- def self.basic_quote_characters=(v)
- @@basic_quote_characters = v.encode(Encoding::default_external)
- end
-
- @@completer_quote_characters = '"\''
- def self.completer_quote_characters
- @@completer_quote_characters
- end
- def self.completer_quote_characters=(v)
- @@completer_quote_characters = v.encode(Encoding::default_external)
- end
-
- @@filename_quote_characters = ''
- def self.filename_quote_characters
- @@filename_quote_characters
- end
- def self.filename_quote_characters=(v)
- @@filename_quote_characters = v.encode(Encoding::default_external)
- end
-
- @@special_prefixes = ''
- def self.special_prefixes
- @@special_prefixes
- end
- def self.special_prefixes=(v)
- @@special_prefixes = v.encode(Encoding::default_external)
- end
-
- @@completion_case_fold = nil
- def self.completion_case_fold
- @@completion_case_fold
- end
- def self.completion_case_fold=(v)
- @@completion_case_fold = v
- end
-
- @@completion_proc = nil
- def self.completion_proc
- @@completion_proc
- end
- def self.completion_proc=(p)
- raise ArgumentError unless p.is_a?(Proc)
- @@completion_proc = p
- end
-
- @@output_modifier_proc = nil
- def self.output_modifier_proc
- @@output_modifier_proc
- end
- def self.output_modifier_proc=(p)
- raise ArgumentError unless p.is_a?(Proc)
- @@output_modifier_proc = p
- end
-
- @@prompt_proc = nil
- def self.prompt_proc
- @@prompt_proc
- end
- def self.prompt_proc=(p)
- raise ArgumentError unless p.is_a?(Proc)
- @@prompt_proc = p
- end
-
- @@auto_indent_proc = nil
- def self.auto_indent_proc
- @@auto_indent_proc
- end
- def self.auto_indent_proc=(p)
- raise ArgumentError unless p.is_a?(Proc)
- @@auto_indent_proc = p
- end
-
- @@pre_input_hook = nil
- def self.pre_input_hook
- @@pre_input_hook
- end
- def self.pre_input_hook=(p)
- @@pre_input_hook = 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)
- raise ArgumentError unless p.is_a?(Proc)
- @@dig_perfect_match_proc = p
- end
-
- def self.insert_text(text)
- @@line_editor&.insert_text(text)
- self
- end
-
- def self.redisplay
- @@line_editor&.rerender
- end
-
- def self.line_buffer
- @@line_editor&.line
- end
-
- def self.point
- @@line_editor ? @@line_editor.byte_pointer : 0
- end
-
- def self.point=(val)
- @@line_editor.byte_pointer = val
- end
-
- def self.delete_text(start = nil, length = nil)
- @@line_editor&.delete_text(start, length)
- end
-
- private_class_method def self.test_mode
- remove_const('IOGate') if const_defined?('IOGate')
- const_set('IOGate', Reline::GeneralIO)
- @@config.instance_variable_set(:@test_mode, true)
- @@config.reset
- end
-
- def self.input=(val)
- raise TypeError unless val.respond_to?(:getc) or val.nil?
- if val.respond_to?(:getc)
- if defined?(Reline::ANSI) and IOGate == Reline::ANSI
- Reline::ANSI.input = val
- elsif IOGate == Reline::GeneralIO
- Reline::GeneralIO.input = val
- end
- end
- end
-
- @@output = STDOUT
- def self.output=(val)
- raise TypeError unless val.respond_to?(:write) or val.nil?
- @@output = val
- if defined?(Reline::ANSI) and IOGate == Reline::ANSI
- Reline::ANSI.output = val
- end
- end
-
- def self.vi_editing_mode
- @@config.editing_mode = :vi_insert
- nil
- end
-
- def self.emacs_editing_mode
- @@config.editing_mode = :emacs
- nil
- end
-
- def self.vi_editing_mode?
- @@config.editing_mode_is?(:vi_insert, :vi_command)
- end
-
- def self.emacs_editing_mode?
- @@config.editing_mode_is?(:emacs)
- end
-
- def self.get_screen_size
- Reline::IOGate.get_screen_size
- end
-
- def eof?
- @@line_editor.eof?
- 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 add_hist and whole_buffer and whole_buffer.chomp.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 add_hist and line and line.chomp.size > 0
- Reline::HISTORY << line.chomp
- end
-
- @@line_editor.reset_line if @@line_editor.line.nil?
- line
- end
-
- def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
- if ENV['RELINE_STDERR_TTY']
- $stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
- $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)
- 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.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
- @@line_editor.rerender
-
- 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
-
- begin
- loop do
- read_io(@@config.keyseq_timeout) { |inputs|
- inputs.each { |c|
- @@line_editor.input_key(c)
- @@line_editor.rerender
- }
- }
- break if @@line_editor.finished?
- end
- Reline::IOGate.move_cursor_column(0)
- 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.
- def read_io(keyseq_timeout, &block)
- buffer = []
- loop do
- c = Reline::IOGate.getc
- buffer << c
- result = @@key_stroke.match_status(buffer)
- case result
- when :matched
- block.(@@key_stroke.expand(buffer).map{ |c| Reline::Key.new(c, c, false) })
- 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, buffer, block)
- else
- block.(buffer.map{ |c| Reline::Key.new(c, c, false) })
- end
- break
- end
- end
- end
-
- def read_escaped_key(keyseq_timeout, buffer, 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 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)
- print "\u{25bd}"
- @@ambiguous_width = Reline::IOGate.cursor_pos.x
- Reline::IOGate.move_cursor_column(0)
- Reline::IOGate.erase_after_cursor
- end
-
- def self.ambiguous_width
- @@ambiguous_width
- end
-end
-
-if Reline::IS_WINDOWS
- require 'reline/windows'
- Reline::IOGate = Reline::Windows
-else
- require 'reline/ansi'
- Reline::IOGate = Reline::ANSI
-end
-require 'reline/general_io'