summaryrefslogtreecommitdiff
path: root/lib/reline
diff options
context:
space:
mode:
Diffstat (limited to 'lib/reline')
-rw-r--r--lib/reline/ansi.rb355
-rw-r--r--lib/reline/config.rb401
-rw-r--r--lib/reline/general_io.rb113
-rw-r--r--lib/reline/history.rb76
-rw-r--r--lib/reline/key_actor.rb7
-rw-r--r--lib/reline/key_actor/base.rb19
-rw-r--r--lib/reline/key_actor/emacs.rb517
-rw-r--r--lib/reline/key_actor/vi_command.rb518
-rw-r--r--lib/reline/key_actor/vi_insert.rb517
-rw-r--r--lib/reline/key_stroke.rb105
-rw-r--r--lib/reline/kill_ring.rb125
-rw-r--r--lib/reline/line_editor.rb3347
-rw-r--r--lib/reline/reline.gemspec25
-rw-r--r--lib/reline/terminfo.rb174
-rw-r--r--lib/reline/unicode.rb665
-rw-r--r--lib/reline/unicode/east_asian_width.rb1196
-rw-r--r--lib/reline/version.rb3
-rw-r--r--lib/reline/windows.rb501
18 files changed, 0 insertions, 8664 deletions
diff --git a/lib/reline/ansi.rb b/lib/reline/ansi.rb
deleted file mode 100644
index 42a3913387..0000000000
--- a/lib/reline/ansi.rb
+++ /dev/null
@@ -1,355 +0,0 @@
-require 'io/console'
-require 'io/wait'
-require 'timeout'
-require_relative 'terminfo'
-
-class Reline::ANSI
- CAPNAME_KEY_BINDINGS = {
- 'khome' => :ed_move_to_beg,
- 'kend' => :ed_move_to_end,
- 'kdch1' => :key_delete,
- 'kcuu1' => :ed_prev_history,
- 'kcud1' => :ed_next_history,
- 'kcuf1' => :ed_next_char,
- 'kcub1' => :ed_prev_char,
- 'cuu' => :ed_prev_history,
- 'cud' => :ed_next_history,
- 'cuf' => :ed_next_char,
- 'cub' => :ed_prev_char,
- }
-
- if Reline::Terminfo.enabled?
- Reline::Terminfo.setupterm(0, 2)
- end
-
- def self.encoding
- Encoding.default_external
- end
-
- def self.win?
- false
- end
-
- def self.set_default_key_bindings(config, allow_terminfo: true)
- if allow_terminfo && Reline::Terminfo.enabled?
- set_default_key_bindings_terminfo(config)
- else
- set_default_key_bindings_comprehensive_list(config)
- end
- {
- # extended entries of terminfo
- [27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→, extended entry
- [27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←, extended entry
- [27, 91, 49, 59, 51, 67] => :em_next_word, # Meta+→, extended entry
- [27, 91, 49, 59, 51, 68] => :ed_prev_word, # Meta+←, extended entry
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
- {
- [27, 91, 90] => :completion_journey_up, # S-Tab
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- end
- {
- # default bindings
- [27, 32] => :em_set_mark, # M-<space>
- [24, 24] => :em_exchange_mark, # C-x C-x
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- end
- end
-
- def self.set_default_key_bindings_terminfo(config)
- key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
- begin
- key_code = Reline::Terminfo.tigetstr(capname)
- case capname
- # Escape sequences that omit the move distance and are set to defaults
- # value 1 may be sometimes sent by pressing the arrow-key.
- when 'cuu', 'cud', 'cuf', 'cub'
- [ key_code.sub(/%p1%d/, '').bytes, key_binding ]
- else
- [ key_code.bytes, key_binding ]
- end
- rescue Reline::Terminfo::TerminfoError
- # capname is undefined
- end
- end.compact.to_h
-
- key_bindings.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
- end
-
- def self.set_default_key_bindings_comprehensive_list(config)
- {
- # Console (80x25)
- [27, 91, 49, 126] => :ed_move_to_beg, # Home
- [27, 91, 52, 126] => :ed_move_to_end, # End
- [27, 91, 51, 126] => :key_delete, # Del
- [27, 91, 65] => :ed_prev_history, # ↑
- [27, 91, 66] => :ed_next_history, # ↓
- [27, 91, 67] => :ed_next_char, # →
- [27, 91, 68] => :ed_prev_char, # ←
-
- # KDE
- [27, 91, 72] => :ed_move_to_beg, # Home
- [27, 91, 70] => :ed_move_to_end, # End
- # Del is 0x08
- [27, 71, 65] => :ed_prev_history, # ↑
- [27, 71, 66] => :ed_next_history, # ↓
- [27, 71, 67] => :ed_next_char, # →
- [27, 71, 68] => :ed_prev_char, # ←
-
- # urxvt / exoterm
- [27, 91, 55, 126] => :ed_move_to_beg, # Home
- [27, 91, 56, 126] => :ed_move_to_end, # End
-
- # GNOME
- [27, 79, 72] => :ed_move_to_beg, # Home
- [27, 79, 70] => :ed_move_to_end, # End
- # Del is 0x08
- # Arrow keys are the same of KDE
-
- # iTerm2
- [27, 27, 91, 67] => :em_next_word, # Option+→, extended entry
- [27, 27, 91, 68] => :ed_prev_word, # Option+←, extended entry
- [195, 166] => :em_next_word, # Option+f
- [195, 162] => :ed_prev_word, # Option+b
-
- [27, 79, 65] => :ed_prev_history, # ↑
- [27, 79, 66] => :ed_next_history, # ↓
- [27, 79, 67] => :ed_next_char, # →
- [27, 79, 68] => :ed_prev_char, # ←
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
- end
-
- @@input = STDIN
- def self.input=(val)
- @@input = val
- end
-
- @@output = STDOUT
- def self.output=(val)
- @@output = val
- end
-
- def self.with_raw_input
- @@input.raw { yield }
- end
-
- @@buf = []
- def self.inner_getc
- unless @@buf.empty?
- return @@buf.shift
- end
- until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
- Reline.core.line_editor.resize
- end
- (c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
- rescue Errno::EIO
- # Maybe the I/O has been closed.
- nil
- rescue Errno::ENOTTY
- nil
- end
-
- @@in_bracketed_paste_mode = false
- START_BRACKETED_PASTE = String.new("\e[200~,", encoding: Encoding::ASCII_8BIT)
- END_BRACKETED_PASTE = String.new("\e[200~.", encoding: Encoding::ASCII_8BIT)
- def self.getc_with_bracketed_paste
- buffer = String.new(encoding: Encoding::ASCII_8BIT)
- buffer << inner_getc
- while START_BRACKETED_PASTE.start_with?(buffer) or END_BRACKETED_PASTE.start_with?(buffer) do
- if START_BRACKETED_PASTE == buffer
- @@in_bracketed_paste_mode = true
- return inner_getc
- elsif END_BRACKETED_PASTE == buffer
- @@in_bracketed_paste_mode = false
- ungetc(-1)
- return inner_getc
- end
- begin
- succ_c = nil
- Timeout.timeout(Reline.core.config.keyseq_timeout * 100) {
- succ_c = inner_getc
- }
- rescue Timeout::Error
- break
- else
- buffer << succ_c
- end
- end
- buffer.bytes.reverse_each do |ch|
- ungetc ch
- end
- inner_getc
- end
-
- def self.getc
- if Reline.core.config.enable_bracketed_paste
- getc_with_bracketed_paste
- else
- inner_getc
- end
- end
-
- def self.in_pasting?
- @@in_bracketed_paste_mode or (not Reline::IOGate.empty_buffer?)
- end
-
- def self.empty_buffer?
- unless @@buf.empty?
- return false
- end
- !@@input.wait_readable(0)
- end
-
- def self.ungetc(c)
- @@buf.unshift(c)
- end
-
- def self.retrieve_keybuffer
- begin
- return unless @@input.wait_readable(0.001)
- str = @@input.read_nonblock(1024)
- str.bytes.each do |c|
- @@buf.push(c)
- end
- rescue EOFError
- end
- end
-
- def self.get_screen_size
- s = @@input.winsize
- return s if s[0] > 0 && s[1] > 0
- s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
- return s if s[0] > 0 && s[1] > 0
- [24, 80]
- rescue Errno::ENOTTY
- [24, 80]
- end
-
- def self.set_screen_size(rows, columns)
- @@input.winsize = [rows, columns]
- self
- rescue Errno::ENOTTY
- self
- end
-
- def self.cursor_pos
- begin
- res = +''
- m = nil
- @@input.raw do |stdin|
- @@output << "\e[6n"
- @@output.flush
- loop do
- c = stdin.getc
- next if c.nil?
- res << c
- m = res.match(/\e\[(?<row>\d+);(?<column>\d+)R/)
- break if m
- end
- (m.pre_match + m.post_match).chars.reverse_each do |ch|
- stdin.ungetc ch
- end
- end
- column = m[:column].to_i - 1
- row = m[:row].to_i - 1
- rescue Errno::ENOTTY
- begin
- buf = @@output.pread(@@output.pos, 0)
- row = buf.count("\n")
- column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
- rescue Errno::ESPIPE
- # Just returns column 1 for ambiguous width because this I/O is not
- # tty and can't seek.
- row = 0
- column = 1
- end
- end
- Reline::CursorPos.new(column, row)
- end
-
- def self.move_cursor_column(x)
- @@output.write "\e[#{x + 1}G"
- end
-
- def self.move_cursor_up(x)
- if x > 0
- @@output.write "\e[#{x}A"
- elsif x < 0
- move_cursor_down(-x)
- end
- end
-
- def self.move_cursor_down(x)
- if x > 0
- @@output.write "\e[#{x}B"
- elsif x < 0
- move_cursor_up(-x)
- end
- end
-
- def self.hide_cursor
- if Reline::Terminfo.enabled?
- begin
- @@output.write Reline::Terminfo.tigetstr('civis')
- rescue Reline::Terminfo::TerminfoError
- # civis is undefined
- end
- else
- # ignored
- end
- end
-
- def self.show_cursor
- if Reline::Terminfo.enabled?
- begin
- @@output.write Reline::Terminfo.tigetstr('cnorm')
- rescue Reline::Terminfo::TerminfoError
- # cnorm is undefined
- end
- else
- # ignored
- end
- end
-
- def self.erase_after_cursor
- @@output.write "\e[K"
- end
-
- def self.scroll_down(x)
- return if x.zero?
- @@output.write "\e[#{x}S"
- end
-
- def self.clear_screen
- @@output.write "\e[2J"
- @@output.write "\e[1;1H"
- end
-
- @@old_winch_handler = nil
- def self.set_winch_handler(&handler)
- @@old_winch_handler = Signal.trap('WINCH', &handler)
- end
-
- def self.prep
- retrieve_keybuffer
- nil
- end
-
- def self.deprep(otio)
- Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
- end
-end
diff --git a/lib/reline/config.rb b/lib/reline/config.rb
deleted file mode 100644
index 87726393a6..0000000000
--- a/lib/reline/config.rb
+++ /dev/null
@@ -1,401 +0,0 @@
-class Reline::Config
- attr_reader :test_mode
-
- KEYSEQ_PATTERN = /\\(?:C|Control)-[A-Za-z_]|\\(?:M|Meta)-[0-9A-Za-z_]|\\(?:C|Control)-(?:M|Meta)-[A-Za-z_]|\\(?:M|Meta)-(?:C|Control)-[A-Za-z_]|\\e|\\[\\\"\'abdfnrtv]|\\\d{1,3}|\\x\h{1,2}|./
-
- class InvalidInputrc < RuntimeError
- attr_accessor :file, :lineno
- end
-
- VARIABLE_NAMES = %w{
- bind-tty-special-chars
- blink-matching-paren
- byte-oriented
- completion-ignore-case
- convert-meta
- disable-completion
- enable-keypad
- expand-tilde
- history-preserve-point
- history-size
- horizontal-scroll-mode
- input-meta
- keyseq-timeout
- mark-directories
- mark-modified-lines
- mark-symlinked-directories
- match-hidden-files
- meta-flag
- output-meta
- page-completions
- prefer-visible-bell
- print-completions-horizontally
- show-all-if-ambiguous
- show-all-if-unmodified
- visible-stats
- show-mode-in-prompt
- vi-cmd-mode-string
- vi-ins-mode-string
- emacs-mode-string
- enable-bracketed-paste
- isearch-terminators
- }
- VARIABLE_NAME_SYMBOLS = VARIABLE_NAMES.map { |v| :"#{v.tr(?-, ?_)}" }
- VARIABLE_NAME_SYMBOLS.each do |v|
- attr_accessor v
- end
-
- attr_accessor :autocompletion
-
- def initialize
- @additional_key_bindings = {} # from inputrc
- @additional_key_bindings[:emacs] = {}
- @additional_key_bindings[:vi_insert] = {}
- @additional_key_bindings[:vi_command] = {}
- @oneshot_key_bindings = {}
- @skip_section = nil
- @if_stack = nil
- @editing_mode_label = :emacs
- @keymap_label = :emacs
- @keymap_prefix = []
- @key_actors = {}
- @key_actors[:emacs] = Reline::KeyActor::Emacs.new
- @key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new
- @key_actors[:vi_command] = Reline::KeyActor::ViCommand.new
- @vi_cmd_mode_string = '(cmd)'
- @vi_ins_mode_string = '(ins)'
- @emacs_mode_string = '@'
- # https://tiswww.case.edu/php/chet/readline/readline.html#IDX25
- @history_size = -1 # unlimited
- @keyseq_timeout = 500
- @test_mode = false
- @autocompletion = false
- @convert_meta = true if seven_bit_encoding?(Reline::IOGate.encoding)
- end
-
- def reset
- if editing_mode_is?(:vi_command)
- @editing_mode_label = :vi_insert
- end
- @additional_key_bindings.keys.each do |key|
- @additional_key_bindings[key].clear
- end
- @oneshot_key_bindings.clear
- reset_default_key_bindings
- end
-
- def editing_mode
- @key_actors[@editing_mode_label]
- end
-
- def editing_mode=(val)
- @editing_mode_label = val
- end
-
- def editing_mode_is?(*val)
- val.any?(@editing_mode_label)
- end
-
- def keymap
- @key_actors[@keymap_label]
- end
-
- def inputrc_path
- case ENV['INPUTRC']
- when nil, ''
- else
- return File.expand_path(ENV['INPUTRC'])
- end
-
- # In the XDG Specification, if ~/.config/readline/inputrc exists, then
- # ~/.inputrc should not be read, but for compatibility with GNU Readline,
- # if ~/.inputrc exists, then it is given priority.
- home_rc_path = File.expand_path('~/.inputrc')
- return home_rc_path if File.exist?(home_rc_path)
-
- case path = ENV['XDG_CONFIG_HOME']
- when nil, ''
- else
- path = File.join(path, 'readline/inputrc')
- return path if File.exist?(path) and path == File.expand_path(path)
- end
-
- path = File.expand_path('~/.config/readline/inputrc')
- return path if File.exist?(path)
-
- return home_rc_path
- end
-
- private def default_inputrc_path
- @default_inputrc_path ||= inputrc_path
- end
-
- def read(file = nil)
- file ||= default_inputrc_path
- begin
- if file.respond_to?(:readlines)
- lines = file.readlines
- else
- lines = File.readlines(file)
- end
- rescue Errno::ENOENT
- return nil
- end
-
- read_lines(lines, file)
- self
- rescue InvalidInputrc => e
- warn e.message
- nil
- end
-
- def key_bindings
- # The key bindings for each editing mode will be overwritten by the user-defined ones.
- kb = @key_actors[@editing_mode_label].default_key_bindings.dup
- kb.merge!(@additional_key_bindings[@editing_mode_label])
- kb.merge!(@oneshot_key_bindings)
- kb
- end
-
- def add_oneshot_key_binding(keystroke, target)
- @oneshot_key_bindings[keystroke] = target
- end
-
- def reset_oneshot_key_bindings
- @oneshot_key_bindings.clear
- end
-
- def add_default_key_binding_by_keymap(keymap, keystroke, target)
- @key_actors[keymap].default_key_bindings[keystroke] = target
- end
-
- def add_default_key_binding(keystroke, target)
- @key_actors[@keymap_label].default_key_bindings[keystroke] = target
- end
-
- def reset_default_key_bindings
- @key_actors.values.each do |ka|
- ka.reset_default_key_bindings
- end
- end
-
- def read_lines(lines, file = nil)
- if not lines.empty? and lines.first.encoding != Reline.encoding_system_needs
- begin
- lines = lines.map do |l|
- l.encode(Reline.encoding_system_needs)
- rescue Encoding::UndefinedConversionError
- mes = "The inputrc encoded in #{lines.first.encoding.name} can't be converted to the locale #{Reline.encoding_system_needs.name}."
- raise Reline::ConfigEncodingConversionError.new(mes)
- end
- end
- end
- conditions = [@skip_section, @if_stack]
- @skip_section = nil
- @if_stack = []
-
- lines.each_with_index do |line, no|
- next if line.match(/\A\s*#/)
-
- no += 1
-
- line = line.chomp.lstrip
- if line.start_with?('$')
- handle_directive(line[1..-1], file, no)
- next
- end
-
- next if @skip_section
-
- case line
- when /^set +([^ ]+) +([^ ]+)/i
- var, value = $1.downcase, $2
- bind_variable(var, value)
- next
- when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
- key, func_name = $1, $2
- keystroke, func = bind_key(key, func_name)
- next unless keystroke
- @additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func
- end
- end
- unless @if_stack.empty?
- raise InvalidInputrc, "#{file}:#{@if_stack.last[1]}: unclosed if"
- end
- ensure
- @skip_section, @if_stack = conditions
- end
-
- def handle_directive(directive, file, no)
- directive, args = directive.split(' ')
- case directive
- when 'if'
- condition = false
- case args
- when 'mode'
- when 'term'
- when 'version'
- else # application name
- condition = true if args == 'Ruby'
- condition = true if args == 'Reline'
- end
- @if_stack << [file, no, @skip_section]
- @skip_section = !condition
- when 'else'
- if @if_stack.empty?
- raise InvalidInputrc, "#{file}:#{no}: unmatched else"
- end
- @skip_section = !@skip_section
- when 'endif'
- if @if_stack.empty?
- raise InvalidInputrc, "#{file}:#{no}: unmatched endif"
- end
- @skip_section = @if_stack.pop
- when 'include'
- read(args)
- end
- end
-
- def bind_variable(name, value)
- case name
- when 'history-size'
- begin
- @history_size = Integer(value)
- rescue ArgumentError
- @history_size = 500
- end
- when 'bell-style'
- @bell_style =
- case value
- when 'none', 'off'
- :none
- when 'audible', 'on'
- :audible
- when 'visible'
- :visible
- else
- :audible
- end
- when 'comment-begin'
- @comment_begin = value.dup
- when 'completion-query-items'
- @completion_query_items = value.to_i
- when 'isearch-terminators'
- @isearch_terminators = retrieve_string(value)
- when 'editing-mode'
- case value
- when 'emacs'
- @editing_mode_label = :emacs
- @keymap_label = :emacs
- @keymap_prefix = []
- when 'vi'
- @editing_mode_label = :vi_insert
- @keymap_label = :vi_insert
- @keymap_prefix = []
- end
- when 'keymap'
- case value
- when 'emacs', 'emacs-standard'
- @keymap_label = :emacs
- @keymap_prefix = []
- when 'emacs-ctlx'
- @keymap_label = :emacs
- @keymap_prefix = [?\C-x.ord]
- when 'emacs-meta'
- @keymap_label = :emacs
- @keymap_prefix = [?\e.ord]
- when 'vi', 'vi-move', 'vi-command'
- @keymap_label = :vi_command
- @keymap_prefix = []
- when 'vi-insert'
- @keymap_label = :vi_insert
- @keymap_prefix = []
- end
- when 'keyseq-timeout'
- @keyseq_timeout = value.to_i
- when 'show-mode-in-prompt'
- case value
- when 'off'
- @show_mode_in_prompt = false
- when 'on'
- @show_mode_in_prompt = true
- else
- @show_mode_in_prompt = false
- end
- when 'vi-cmd-mode-string'
- @vi_cmd_mode_string = retrieve_string(value)
- when 'vi-ins-mode-string'
- @vi_ins_mode_string = retrieve_string(value)
- when 'emacs-mode-string'
- @emacs_mode_string = retrieve_string(value)
- when *VARIABLE_NAMES then
- variable_name = :"@#{name.tr(?-, ?_)}"
- instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
- end
- end
-
- def retrieve_string(str)
- str = $1 if str =~ /\A"(.*)"\z/
- parse_keyseq(str).map { |c| c.chr(Reline.encoding_system_needs) }.join
- end
-
- def bind_key(key, func_name)
- if key =~ /\A"(.*)"\z/
- keyseq = parse_keyseq($1)
- else
- keyseq = nil
- end
- if func_name =~ /"(.*)"/
- func = parse_keyseq($1)
- else
- func = func_name.tr(?-, ?_).to_sym # It must be macro.
- end
- [keyseq, func]
- end
-
- def key_notation_to_code(notation)
- case notation
- when /\\(?:C|Control)-([A-Za-z_])/
- (1 + $1.downcase.ord - ?a.ord)
- when /\\(?:M|Meta)-([0-9A-Za-z_])/
- modified_key = $1
- case $1
- when /[0-9]/
- ?\M-0.bytes.first + (modified_key.ord - ?0.ord)
- when /[A-Z]/
- ?\M-A.bytes.first + (modified_key.ord - ?A.ord)
- when /[a-z]/
- ?\M-a.bytes.first + (modified_key.ord - ?a.ord)
- end
- when /\\(?:C|Control)-(?:M|Meta)-[A-Za-z_]/, /\\(?:M|Meta)-(?:C|Control)-[A-Za-z_]/
- # 129 M-^A
- when /\\(\d{1,3})/ then $1.to_i(8) # octal
- when /\\x(\h{1,2})/ then $1.to_i(16) # hexadecimal
- when "\\e" then ?\e.ord
- when "\\\\" then ?\\.ord
- when "\\\"" then ?".ord
- when "\\'" then ?'.ord
- when "\\a" then ?\a.ord
- when "\\b" then ?\b.ord
- when "\\d" then ?\d.ord
- when "\\f" then ?\f.ord
- when "\\n" then ?\n.ord
- when "\\r" then ?\r.ord
- when "\\t" then ?\t.ord
- when "\\v" then ?\v.ord
- else notation.ord
- end
- end
-
- def parse_keyseq(str)
- ret = []
- str.scan(KEYSEQ_PATTERN) do
- ret << key_notation_to_code($&)
- end
- ret
- end
-
- private def seven_bit_encoding?(encoding)
- encoding == Encoding::US_ASCII
- end
-end
diff --git a/lib/reline/general_io.rb b/lib/reline/general_io.rb
deleted file mode 100644
index 9929846568..0000000000
--- a/lib/reline/general_io.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-require 'timeout'
-require 'io/wait'
-
-class Reline::GeneralIO
- def self.reset(encoding: nil)
- @@pasting = false
- @@encoding = encoding
- end
-
- def self.encoding
- if defined?(@@encoding)
- @@encoding
- elsif RUBY_PLATFORM =~ /mswin|mingw/
- Encoding::UTF_8
- else
- Encoding::default_external
- end
- end
-
- def self.win?
- false
- end
-
- def self.set_default_key_bindings(_)
- end
-
- @@buf = []
- @@input = STDIN
-
- def self.input=(val)
- @@input = val
- end
-
- def self.with_raw_input
- yield
- end
-
- def self.getc
- unless @@buf.empty?
- return @@buf.shift
- end
- c = nil
- loop do
- result = @@input.wait_readable(0.1)
- next if result.nil?
- c = @@input.read(1)
- break
- end
- c&.ord
- end
-
- def self.ungetc(c)
- @@buf.unshift(c)
- end
-
- def self.get_screen_size
- [1, 1]
- end
-
- def self.cursor_pos
- Reline::CursorPos.new(1, 1)
- end
-
- def self.hide_cursor
- end
-
- def self.show_cursor
- end
-
- def self.move_cursor_column(val)
- end
-
- def self.move_cursor_up(val)
- end
-
- def self.move_cursor_down(val)
- end
-
- def self.erase_after_cursor
- end
-
- def self.scroll_down(val)
- end
-
- def self.clear_screen
- end
-
- def self.set_screen_size(rows, columns)
- end
-
- def self.set_winch_handler(&handler)
- end
-
- @@pasting = false
-
- def self.in_pasting?
- @@pasting
- end
-
- def self.start_pasting
- @@pasting = true
- end
-
- def self.finish_pasting
- @@pasting = false
- end
-
- def self.prep
- end
-
- def self.deprep(otio)
- end
-end
diff --git a/lib/reline/history.rb b/lib/reline/history.rb
deleted file mode 100644
index 7a1ed6b90b..0000000000
--- a/lib/reline/history.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-class Reline::History < 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) unless index.is_a?(Range)
- super(index)
- end
-
- def []=(index, val)
- index = check_index(index)
- super(index, String.new(val, encoding: Reline.encoding_system_needs))
- end
-
- def concat(*val)
- val.each do |v|
- push(*v)
- end
- end
-
- def push(*val)
- # If history_size is zero, all histories are dropped.
- return self if @config.history_size.zero?
- # If history_size is negative, history size is unlimited.
- if @config.history_size.positive?
- diff = size + val.size - @config.history_size
- if diff > 0
- if diff <= size
- shift(diff)
- else
- diff -= size
- clear
- val.shift(diff)
- end
- end
- end
- super(*(val.map{ |v|
- String.new(v, encoding: Reline.encoding_system_needs)
- }))
- end
-
- def <<(val)
- # If history_size is zero, all histories are dropped.
- return self if @config.history_size.zero?
- # If history_size is negative, history size is unlimited.
- if @config.history_size.positive?
- shift if size + 1 > @config.history_size
- end
- super(String.new(val, encoding: Reline.encoding_system_needs))
- end
-
- private def check_index(index)
- index += size if index < 0
- if index < -2147483648 or 2147483647 < index
- raise RangeError.new("integer #{index} too big to convert to `int'")
- end
- # If history_size is negative, history size is unlimited.
- if @config.history_size.positive?
- if index < -@config.history_size or @config.history_size < index
- raise RangeError.new("index=<#{index}>")
- end
- end
- raise IndexError.new("index=<#{index}>") if index < 0 or size <= index
- index
- end
-end
diff --git a/lib/reline/key_actor.rb b/lib/reline/key_actor.rb
deleted file mode 100644
index ebe09d2009..0000000000
--- a/lib/reline/key_actor.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-module Reline::KeyActor
-end
-
-require 'reline/key_actor/base'
-require 'reline/key_actor/emacs'
-require 'reline/key_actor/vi_command'
-require 'reline/key_actor/vi_insert'
diff --git a/lib/reline/key_actor/base.rb b/lib/reline/key_actor/base.rb
deleted file mode 100644
index a1cd7fb2a1..0000000000
--- a/lib/reline/key_actor/base.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class Reline::KeyActor::Base
- MAPPING = Array.new(256)
-
- def get_method(key)
- self.class::MAPPING[key]
- end
-
- def initialize
- @default_key_bindings = {}
- end
-
- def default_key_bindings
- @default_key_bindings
- end
-
- def reset_default_key_bindings
- @default_key_bindings.clear
- end
-end
diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb
deleted file mode 100644
index a561feee57..0000000000
--- a/lib/reline/key_actor/emacs.rb
+++ /dev/null
@@ -1,517 +0,0 @@
-class Reline::KeyActor::Emacs < Reline::KeyActor::Base
- MAPPING = [
- # 0 ^@
- :em_set_mark,
- # 1 ^A
- :ed_move_to_beg,
- # 2 ^B
- :ed_prev_char,
- # 3 ^C
- :ed_ignore,
- # 4 ^D
- :em_delete,
- # 5 ^E
- :ed_move_to_end,
- # 6 ^F
- :ed_next_char,
- # 7 ^G
- :ed_unassigned,
- # 8 ^H
- :em_delete_prev_char,
- # 9 ^I
- :ed_unassigned,
- # 10 ^J
- :ed_newline,
- # 11 ^K
- :ed_kill_line,
- # 12 ^L
- :ed_clear_screen,
- # 13 ^M
- :ed_newline,
- # 14 ^N
- :ed_next_history,
- # 15 ^O
- :ed_ignore,
- # 16 ^P
- :ed_prev_history,
- # 17 ^Q
- :ed_quoted_insert,
- # 18 ^R
- :vi_search_prev,
- # 19 ^S
- :vi_search_next,
- # 20 ^T
- :ed_transpose_chars,
- # 21 ^U
- :unix_line_discard,
- # 22 ^V
- :ed_quoted_insert,
- # 23 ^W
- :em_kill_region,
- # 24 ^X
- :ed_sequence_lead_in,
- # 25 ^Y
- :em_yank,
- # 26 ^Z
- :ed_ignore,
- # 27 ^[
- :em_meta_next,
- # 28 ^\
- :ed_ignore,
- # 29 ^]
- :ed_ignore,
- # 30 ^^
- :ed_unassigned,
- # 31 ^_
- :ed_unassigned,
- # 32 SPACE
- :ed_insert,
- # 33 !
- :ed_insert,
- # 34 "
- :ed_insert,
- # 35 #
- :ed_insert,
- # 36 $
- :ed_insert,
- # 37 %
- :ed_insert,
- # 38 &
- :ed_insert,
- # 39 '
- :ed_insert,
- # 40 (
- :ed_insert,
- # 41 )
- :ed_insert,
- # 42 *
- :ed_insert,
- # 43 +
- :ed_insert,
- # 44 ,
- :ed_insert,
- # 45 -
- :ed_insert,
- # 46 .
- :ed_insert,
- # 47 /
- :ed_insert,
- # 48 0
- :ed_digit,
- # 49 1
- :ed_digit,
- # 50 2
- :ed_digit,
- # 51 3
- :ed_digit,
- # 52 4
- :ed_digit,
- # 53 5
- :ed_digit,
- # 54 6
- :ed_digit,
- # 55 7
- :ed_digit,
- # 56 8
- :ed_digit,
- # 57 9
- :ed_digit,
- # 58 :
- :ed_insert,
- # 59 ;
- :ed_insert,
- # 60 <
- :ed_insert,
- # 61 =
- :ed_insert,
- # 62 >
- :ed_insert,
- # 63 ?
- :ed_insert,
- # 64 @
- :ed_insert,
- # 65 A
- :ed_insert,
- # 66 B
- :ed_insert,
- # 67 C
- :ed_insert,
- # 68 D
- :ed_insert,
- # 69 E
- :ed_insert,
- # 70 F
- :ed_insert,
- # 71 G
- :ed_insert,
- # 72 H
- :ed_insert,
- # 73 I
- :ed_insert,
- # 74 J
- :ed_insert,
- # 75 K
- :ed_insert,
- # 76 L
- :ed_insert,
- # 77 M
- :ed_insert,
- # 78 N
- :ed_insert,
- # 79 O
- :ed_insert,
- # 80 P
- :ed_insert,
- # 81 Q
- :ed_insert,
- # 82 R
- :ed_insert,
- # 83 S
- :ed_insert,
- # 84 T
- :ed_insert,
- # 85 U
- :ed_insert,
- # 86 V
- :ed_insert,
- # 87 W
- :ed_insert,
- # 88 X
- :ed_insert,
- # 89 Y
- :ed_insert,
- # 90 Z
- :ed_insert,
- # 91 [
- :ed_insert,
- # 92 \
- :ed_insert,
- # 93 ]
- :ed_insert,
- # 94 ^
- :ed_insert,
- # 95 _
- :ed_insert,
- # 96 `
- :ed_insert,
- # 97 a
- :ed_insert,
- # 98 b
- :ed_insert,
- # 99 c
- :ed_insert,
- # 100 d
- :ed_insert,
- # 101 e
- :ed_insert,
- # 102 f
- :ed_insert,
- # 103 g
- :ed_insert,
- # 104 h
- :ed_insert,
- # 105 i
- :ed_insert,
- # 106 j
- :ed_insert,
- # 107 k
- :ed_insert,
- # 108 l
- :ed_insert,
- # 109 m
- :ed_insert,
- # 110 n
- :ed_insert,
- # 111 o
- :ed_insert,
- # 112 p
- :ed_insert,
- # 113 q
- :ed_insert,
- # 114 r
- :ed_insert,
- # 115 s
- :ed_insert,
- # 116 t
- :ed_insert,
- # 117 u
- :ed_insert,
- # 118 v
- :ed_insert,
- # 119 w
- :ed_insert,
- # 120 x
- :ed_insert,
- # 121 y
- :ed_insert,
- # 122 z
- :ed_insert,
- # 123 {
- :ed_insert,
- # 124 |
- :ed_insert,
- # 125 }
- :ed_insert,
- # 126 ~
- :ed_insert,
- # 127 ^?
- :em_delete_prev_char,
- # 128 M-^@
- :ed_unassigned,
- # 129 M-^A
- :ed_unassigned,
- # 130 M-^B
- :ed_unassigned,
- # 131 M-^C
- :ed_unassigned,
- # 132 M-^D
- :ed_unassigned,
- # 133 M-^E
- :ed_unassigned,
- # 134 M-^F
- :ed_unassigned,
- # 135 M-^G
- :ed_unassigned,
- # 136 M-^H
- :ed_delete_prev_word,
- # 137 M-^I
- :ed_unassigned,
- # 138 M-^J
- :key_newline,
- # 139 M-^K
- :ed_unassigned,
- # 140 M-^L
- :ed_clear_screen,
- # 141 M-^M
- :key_newline,
- # 142 M-^N
- :ed_unassigned,
- # 143 M-^O
- :ed_unassigned,
- # 144 M-^P
- :ed_unassigned,
- # 145 M-^Q
- :ed_unassigned,
- # 146 M-^R
- :ed_unassigned,
- # 147 M-^S
- :ed_unassigned,
- # 148 M-^T
- :ed_unassigned,
- # 149 M-^U
- :ed_unassigned,
- # 150 M-^V
- :ed_unassigned,
- # 151 M-^W
- :ed_unassigned,
- # 152 M-^X
- :ed_unassigned,
- # 153 M-^Y
- :em_yank_pop,
- # 154 M-^Z
- :ed_unassigned,
- # 155 M-^[
- :ed_unassigned,
- # 156 M-^\
- :ed_unassigned,
- # 157 M-^]
- :ed_unassigned,
- # 158 M-^^
- :ed_unassigned,
- # 159 M-^_
- :em_copy_prev_word,
- # 160 M-SPACE
- :ed_unassigned,
- # 161 M-!
- :ed_unassigned,
- # 162 M-"
- :ed_unassigned,
- # 163 M-#
- :ed_unassigned,
- # 164 M-$
- :ed_unassigned,
- # 165 M-%
- :ed_unassigned,
- # 166 M-&
- :ed_unassigned,
- # 167 M-'
- :ed_unassigned,
- # 168 M-(
- :ed_unassigned,
- # 169 M-)
- :ed_unassigned,
- # 170 M-*
- :ed_unassigned,
- # 171 M-+
- :ed_unassigned,
- # 172 M-,
- :ed_unassigned,
- # 173 M--
- :ed_unassigned,
- # 174 M-.
- :ed_unassigned,
- # 175 M-/
- :ed_unassigned,
- # 176 M-0
- :ed_argument_digit,
- # 177 M-1
- :ed_argument_digit,
- # 178 M-2
- :ed_argument_digit,
- # 179 M-3
- :ed_argument_digit,
- # 180 M-4
- :ed_argument_digit,
- # 181 M-5
- :ed_argument_digit,
- # 182 M-6
- :ed_argument_digit,
- # 183 M-7
- :ed_argument_digit,
- # 184 M-8
- :ed_argument_digit,
- # 185 M-9
- :ed_argument_digit,
- # 186 M-:
- :ed_unassigned,
- # 187 M-;
- :ed_unassigned,
- # 188 M-<
- :ed_unassigned,
- # 189 M-=
- :ed_unassigned,
- # 190 M->
- :ed_unassigned,
- # 191 M-?
- :ed_unassigned,
- # 192 M-@
- :ed_unassigned,
- # 193 M-A
- :ed_unassigned,
- # 194 M-B
- :ed_prev_word,
- # 195 M-C
- :em_capitol_case,
- # 196 M-D
- :em_delete_next_word,
- # 197 M-E
- :ed_unassigned,
- # 198 M-F
- :em_next_word,
- # 199 M-G
- :ed_unassigned,
- # 200 M-H
- :ed_unassigned,
- # 201 M-I
- :ed_unassigned,
- # 202 M-J
- :ed_unassigned,
- # 203 M-K
- :ed_unassigned,
- # 204 M-L
- :em_lower_case,
- # 205 M-M
- :ed_unassigned,
- # 206 M-N
- :vi_search_next,
- # 207 M-O
- :ed_sequence_lead_in,
- # 208 M-P
- :vi_search_prev,
- # 209 M-Q
- :ed_unassigned,
- # 210 M-R
- :ed_unassigned,
- # 211 M-S
- :ed_unassigned,
- # 212 M-T
- :ed_unassigned,
- # 213 M-U
- :em_upper_case,
- # 214 M-V
- :ed_unassigned,
- # 215 M-W
- :em_copy_region,
- # 216 M-X
- :ed_command,
- # 217 M-Y
- :ed_unassigned,
- # 218 M-Z
- :ed_unassigned,
- # 219 M-[
- :ed_sequence_lead_in,
- # 220 M-\
- :ed_unassigned,
- # 221 M-]
- :ed_unassigned,
- # 222 M-^
- :ed_unassigned,
- # 223 M-_
- :ed_unassigned,
- # 224 M-`
- :ed_unassigned,
- # 225 M-a
- :ed_unassigned,
- # 226 M-b
- :ed_prev_word,
- # 227 M-c
- :em_capitol_case,
- # 228 M-d
- :em_delete_next_word,
- # 229 M-e
- :ed_unassigned,
- # 230 M-f
- :em_next_word,
- # 231 M-g
- :ed_unassigned,
- # 232 M-h
- :ed_unassigned,
- # 233 M-i
- :ed_unassigned,
- # 234 M-j
- :ed_unassigned,
- # 235 M-k
- :ed_unassigned,
- # 236 M-l
- :em_lower_case,
- # 237 M-m
- :ed_unassigned,
- # 238 M-n
- :vi_search_next,
- # 239 M-o
- :ed_unassigned,
- # 240 M-p
- :vi_search_prev,
- # 241 M-q
- :ed_unassigned,
- # 242 M-r
- :ed_unassigned,
- # 243 M-s
- :ed_unassigned,
- # 244 M-t
- :ed_transpose_words,
- # 245 M-u
- :em_upper_case,
- # 246 M-v
- :ed_unassigned,
- # 247 M-w
- :em_copy_region,
- # 248 M-x
- :ed_command,
- # 249 M-y
- :ed_unassigned,
- # 250 M-z
- :ed_unassigned,
- # 251 M-{
- :ed_unassigned,
- # 252 M-|
- :ed_unassigned,
- # 253 M-}
- :ed_unassigned,
- # 254 M-~
- :ed_unassigned,
- # 255 M-^?
- :ed_delete_prev_word
- # EOF
- ]
-end
diff --git a/lib/reline/key_actor/vi_command.rb b/lib/reline/key_actor/vi_command.rb
deleted file mode 100644
index 98146d2f77..0000000000
--- a/lib/reline/key_actor/vi_command.rb
+++ /dev/null
@@ -1,518 +0,0 @@
-class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
- MAPPING = [
- # 0 ^@
- :ed_unassigned,
- # 1 ^A
- :ed_move_to_beg,
- # 2 ^B
- :ed_unassigned,
- # 3 ^C
- :ed_ignore,
- # 4 ^D
- :vi_end_of_transmission,
- # 5 ^E
- :ed_move_to_end,
- # 6 ^F
- :ed_unassigned,
- # 7 ^G
- :ed_unassigned,
- # 8 ^H
- :ed_unassigned,
- # 9 ^I
- :ed_unassigned,
- # 10 ^J
- :ed_newline,
- # 11 ^K
- :ed_kill_line,
- # 12 ^L
- :ed_clear_screen,
- # 13 ^M
- :ed_newline,
- # 14 ^N
- :ed_next_history,
- # 15 ^O
- :ed_ignore,
- # 16 ^P
- :ed_prev_history,
- # 17 ^Q
- :ed_ignore,
- # 18 ^R
- :vi_search_prev,
- # 19 ^S
- :ed_ignore,
- # 20 ^T
- :ed_unassigned,
- # 21 ^U
- :vi_kill_line_prev,
- # 22 ^V
- :ed_quoted_insert,
- # 23 ^W
- :ed_delete_prev_word,
- # 24 ^X
- :ed_unassigned,
- # 25 ^Y
- :ed_unassigned,
- # 26 ^Z
- :ed_unassigned,
- # 27 ^[
- :ed_unassigned,
- # 28 ^\
- :ed_ignore,
- # 29 ^]
- :ed_unassigned,
- # 30 ^^
- :ed_unassigned,
- # 31 ^_
- :ed_unassigned,
- # 32 SPACE
- :ed_next_char,
- # 33 !
- :ed_unassigned,
- # 34 "
- :ed_unassigned,
- # 35 #
- :vi_comment_out,
- # 36 $
- :ed_move_to_end,
- # 37 %
- :vi_match,
- # 38 &
- :ed_unassigned,
- # 39 '
- :ed_unassigned,
- # 40 (
- :ed_unassigned,
- # 41 )
- :ed_unassigned,
- # 42 *
- :ed_unassigned,
- # 43 +
- :ed_next_history,
- # 44 ,
- :vi_repeat_prev_char,
- # 45 -
- :ed_prev_history,
- # 46 .
- :vi_redo,
- # 47 /
- :vi_search_prev,
- # 48 0
- :vi_zero,
- # 49 1
- :ed_argument_digit,
- # 50 2
- :ed_argument_digit,
- # 51 3
- :ed_argument_digit,
- # 52 4
- :ed_argument_digit,
- # 53 5
- :ed_argument_digit,
- # 54 6
- :ed_argument_digit,
- # 55 7
- :ed_argument_digit,
- # 56 8
- :ed_argument_digit,
- # 57 9
- :ed_argument_digit,
- # 58 :
- :ed_command,
- # 59 ;
- :vi_repeat_next_char,
- # 60 <
- :ed_unassigned,
- # 61 =
- :ed_unassigned,
- # 62 >
- :ed_unassigned,
- # 63 ?
- :vi_search_next,
- # 64 @
- :vi_alias,
- # 65 A
- :vi_add_at_eol,
- # 66 B
- :vi_prev_big_word,
- # 67 C
- :vi_change_to_eol,
- # 68 D
- :ed_kill_line,
- # 69 E
- :vi_end_big_word,
- # 70 F
- :vi_prev_char,
- # 71 G
- :vi_to_history_line,
- # 72 H
- :ed_unassigned,
- # 73 I
- :vi_insert_at_bol,
- # 74 J
- :vi_join_lines,
- # 75 K
- :vi_search_prev,
- # 76 L
- :ed_unassigned,
- # 77 M
- :ed_unassigned,
- # 78 N
- :vi_repeat_search_prev,
- # 79 O
- :ed_sequence_lead_in,
- # 80 P
- :vi_paste_prev,
- # 81 Q
- :ed_unassigned,
- # 82 R
- :vi_replace_mode,
- # 83 S
- :vi_substitute_line,
- # 84 T
- :vi_to_prev_char,
- # 85 U
- :vi_undo_line,
- # 86 V
- :ed_unassigned,
- # 87 W
- :vi_next_big_word,
- # 88 X
- :ed_delete_prev_char,
- # 89 Y
- :vi_yank_end,
- # 90 Z
- :ed_unassigned,
- # 91 [
- :ed_sequence_lead_in,
- # 92 \
- :ed_unassigned,
- # 93 ]
- :ed_unassigned,
- # 94 ^
- :vi_first_print,
- # 95 _
- :vi_history_word,
- # 96 `
- :ed_unassigned,
- # 97 a
- :vi_add,
- # 98 b
- :vi_prev_word,
- # 99 c
- :vi_change_meta,
- # 100 d
- :vi_delete_meta,
- # 101 e
- :vi_end_word,
- # 102 f
- :vi_next_char,
- # 103 g
- :ed_unassigned,
- # 104 h
- :ed_prev_char,
- # 105 i
- :vi_insert,
- # 106 j
- :ed_next_history,
- # 107 k
- :ed_prev_history,
- # 108 l
- :ed_next_char,
- # 109 m
- :ed_unassigned,
- # 110 n
- :vi_repeat_search_next,
- # 111 o
- :ed_unassigned,
- # 112 p
- :vi_paste_next,
- # 113 q
- :ed_unassigned,
- # 114 r
- :vi_replace_char,
- # 115 s
- :vi_substitute_char,
- # 116 t
- :vi_to_next_char,
- # 117 u
- :vi_undo,
- # 118 v
- :vi_histedit,
- # 119 w
- :vi_next_word,
- # 120 x
- :ed_delete_next_char,
- # 121 y
- :vi_yank,
- # 122 z
- :ed_unassigned,
- # 123 {
- :ed_unassigned,
- # 124 |
- :vi_to_column,
- # 125 }
- :ed_unassigned,
- # 126 ~
- :vi_change_case,
- # 127 ^?
- :ed_unassigned,
- # 128 M-^@
- :ed_unassigned,
- # 129 M-^A
- :ed_unassigned,
- # 130 M-^B
- :ed_unassigned,
- # 131 M-^C
- :ed_unassigned,
- # 132 M-^D
- :ed_unassigned,
- # 133 M-^E
- :ed_unassigned,
- # 134 M-^F
- :ed_unassigned,
- # 135 M-^G
- :ed_unassigned,
- # 136 M-^H
- :ed_unassigned,
- # 137 M-^I
- :ed_unassigned,
- # 138 M-^J
- :ed_unassigned,
- # 139 M-^K
- :ed_unassigned,
- # 140 M-^L
- :ed_unassigned,
- # 141 M-^M
- :ed_unassigned,
- # 142 M-^N
- :ed_unassigned,
- # 143 M-^O
- :ed_unassigned,
- # 144 M-^P
- :ed_unassigned,
- # 145 M-^Q
- :ed_unassigned,
- # 146 M-^R
- :ed_unassigned,
- # 147 M-^S
- :ed_unassigned,
- # 148 M-^T
- :ed_unassigned,
- # 149 M-^U
- :ed_unassigned,
- # 150 M-^V
- :ed_unassigned,
- # 151 M-^W
- :ed_unassigned,
- # 152 M-^X
- :ed_unassigned,
- # 153 M-^Y
- :ed_unassigned,
- # 154 M-^Z
- :ed_unassigned,
- # 155 M-^[
- :ed_unassigned,
- # 156 M-^\
- :ed_unassigned,
- # 157 M-^]
- :ed_unassigned,
- # 158 M-^^
- :ed_unassigned,
- # 159 M-^_
- :ed_unassigned,
- # 160 M-SPACE
- :ed_unassigned,
- # 161 M-!
- :ed_unassigned,
- # 162 M-"
- :ed_unassigned,
- # 163 M-#
- :ed_unassigned,
- # 164 M-$
- :ed_unassigned,
- # 165 M-%
- :ed_unassigned,
- # 166 M-&
- :ed_unassigned,
- # 167 M-'
- :ed_unassigned,
- # 168 M-(
- :ed_unassigned,
- # 169 M-)
- :ed_unassigned,
- # 170 M-*
- :ed_unassigned,
- # 171 M-+
- :ed_unassigned,
- # 172 M-,
- :ed_unassigned,
- # 173 M--
- :ed_unassigned,
- # 174 M-.
- :ed_unassigned,
- # 175 M-/
- :ed_unassigned,
- # 176 M-0
- :ed_unassigned,
- # 177 M-1
- :ed_unassigned,
- # 178 M-2
- :ed_unassigned,
- # 179 M-3
- :ed_unassigned,
- # 180 M-4
- :ed_unassigned,
- # 181 M-5
- :ed_unassigned,
- # 182 M-6
- :ed_unassigned,
- # 183 M-7
- :ed_unassigned,
- # 184 M-8
- :ed_unassigned,
- # 185 M-9
- :ed_unassigned,
- # 186 M-:
- :ed_unassigned,
- # 187 M-;
- :ed_unassigned,
- # 188 M-<
- :ed_unassigned,
- # 189 M-=
- :ed_unassigned,
- # 190 M->
- :ed_unassigned,
- # 191 M-?
- :ed_unassigned,
- # 192 M-@
- :ed_unassigned,
- # 193 M-A
- :ed_unassigned,
- # 194 M-B
- :ed_unassigned,
- # 195 M-C
- :ed_unassigned,
- # 196 M-D
- :ed_unassigned,
- # 197 M-E
- :ed_unassigned,
- # 198 M-F
- :ed_unassigned,
- # 199 M-G
- :ed_unassigned,
- # 200 M-H
- :ed_unassigned,
- # 201 M-I
- :ed_unassigned,
- # 202 M-J
- :ed_unassigned,
- # 203 M-K
- :ed_unassigned,
- # 204 M-L
- :ed_unassigned,
- # 205 M-M
- :ed_unassigned,
- # 206 M-N
- :ed_unassigned,
- # 207 M-O
- :ed_sequence_lead_in,
- # 208 M-P
- :ed_unassigned,
- # 209 M-Q
- :ed_unassigned,
- # 210 M-R
- :ed_unassigned,
- # 211 M-S
- :ed_unassigned,
- # 212 M-T
- :ed_unassigned,
- # 213 M-U
- :ed_unassigned,
- # 214 M-V
- :ed_unassigned,
- # 215 M-W
- :ed_unassigned,
- # 216 M-X
- :ed_unassigned,
- # 217 M-Y
- :ed_unassigned,
- # 218 M-Z
- :ed_unassigned,
- # 219 M-[
- :ed_sequence_lead_in,
- # 220 M-\
- :ed_unassigned,
- # 221 M-]
- :ed_unassigned,
- # 222 M-^
- :ed_unassigned,
- # 223 M-_
- :ed_unassigned,
- # 224 M-`
- :ed_unassigned,
- # 225 M-a
- :ed_unassigned,
- # 226 M-b
- :ed_unassigned,
- # 227 M-c
- :ed_unassigned,
- # 228 M-d
- :ed_unassigned,
- # 229 M-e
- :ed_unassigned,
- # 230 M-f
- :ed_unassigned,
- # 231 M-g
- :ed_unassigned,
- # 232 M-h
- :ed_unassigned,
- # 233 M-i
- :ed_unassigned,
- # 234 M-j
- :ed_unassigned,
- # 235 M-k
- :ed_unassigned,
- # 236 M-l
- :ed_unassigned,
- # 237 M-m
- :ed_unassigned,
- # 238 M-n
- :ed_unassigned,
- # 239 M-o
- :ed_unassigned,
- # 240 M-p
- :ed_unassigned,
- # 241 M-q
- :ed_unassigned,
- # 242 M-r
- :ed_unassigned,
- # 243 M-s
- :ed_unassigned,
- # 244 M-t
- :ed_unassigned,
- # 245 M-u
- :ed_unassigned,
- # 246 M-v
- :ed_unassigned,
- # 247 M-w
- :ed_unassigned,
- # 248 M-x
- :ed_unassigned,
- # 249 M-y
- :ed_unassigned,
- # 250 M-z
- :ed_unassigned,
- # 251 M-{
- :ed_unassigned,
- # 252 M-|
- :ed_unassigned,
- # 253 M-}
- :ed_unassigned,
- # 254 M-~
- :ed_unassigned,
- # 255 M-^?
- :ed_unassigned
- # EOF
- ]
-end
-
diff --git a/lib/reline/key_actor/vi_insert.rb b/lib/reline/key_actor/vi_insert.rb
deleted file mode 100644
index b8e89f81d8..0000000000
--- a/lib/reline/key_actor/vi_insert.rb
+++ /dev/null
@@ -1,517 +0,0 @@
-class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
- MAPPING = [
- # 0 ^@
- :ed_unassigned,
- # 1 ^A
- :ed_insert,
- # 2 ^B
- :ed_insert,
- # 3 ^C
- :ed_insert,
- # 4 ^D
- :vi_list_or_eof,
- # 5 ^E
- :ed_insert,
- # 6 ^F
- :ed_insert,
- # 7 ^G
- :ed_insert,
- # 8 ^H
- :vi_delete_prev_char,
- # 9 ^I
- :ed_insert,
- # 10 ^J
- :ed_newline,
- # 11 ^K
- :ed_insert,
- # 12 ^L
- :ed_insert,
- # 13 ^M
- :ed_newline,
- # 14 ^N
- :ed_insert,
- # 15 ^O
- :ed_insert,
- # 16 ^P
- :ed_insert,
- # 17 ^Q
- :ed_ignore,
- # 18 ^R
- :vi_search_prev,
- # 19 ^S
- :vi_search_next,
- # 20 ^T
- :ed_insert,
- # 21 ^U
- :vi_kill_line_prev,
- # 22 ^V
- :ed_quoted_insert,
- # 23 ^W
- :ed_delete_prev_word,
- # 24 ^X
- :ed_insert,
- # 25 ^Y
- :ed_insert,
- # 26 ^Z
- :ed_insert,
- # 27 ^[
- :vi_command_mode,
- # 28 ^\
- :ed_ignore,
- # 29 ^]
- :ed_insert,
- # 30 ^^
- :ed_insert,
- # 31 ^_
- :ed_insert,
- # 32 SPACE
- :ed_insert,
- # 33 !
- :ed_insert,
- # 34 "
- :ed_insert,
- # 35 #
- :ed_insert,
- # 36 $
- :ed_insert,
- # 37 %
- :ed_insert,
- # 38 &
- :ed_insert,
- # 39 '
- :ed_insert,
- # 40 (
- :ed_insert,
- # 41 )
- :ed_insert,
- # 42 *
- :ed_insert,
- # 43 +
- :ed_insert,
- # 44 ,
- :ed_insert,
- # 45 -
- :ed_insert,
- # 46 .
- :ed_insert,
- # 47 /
- :ed_insert,
- # 48 0
- :ed_insert,
- # 49 1
- :ed_insert,
- # 50 2
- :ed_insert,
- # 51 3
- :ed_insert,
- # 52 4
- :ed_insert,
- # 53 5
- :ed_insert,
- # 54 6
- :ed_insert,
- # 55 7
- :ed_insert,
- # 56 8
- :ed_insert,
- # 57 9
- :ed_insert,
- # 58 :
- :ed_insert,
- # 59 ;
- :ed_insert,
- # 60 <
- :ed_insert,
- # 61 =
- :ed_insert,
- # 62 >
- :ed_insert,
- # 63 ?
- :ed_insert,
- # 64 @
- :ed_insert,
- # 65 A
- :ed_insert,
- # 66 B
- :ed_insert,
- # 67 C
- :ed_insert,
- # 68 D
- :ed_insert,
- # 69 E
- :ed_insert,
- # 70 F
- :ed_insert,
- # 71 G
- :ed_insert,
- # 72 H
- :ed_insert,
- # 73 I
- :ed_insert,
- # 74 J
- :ed_insert,
- # 75 K
- :ed_insert,
- # 76 L
- :ed_insert,
- # 77 M
- :ed_insert,
- # 78 N
- :ed_insert,
- # 79 O
- :ed_insert,
- # 80 P
- :ed_insert,
- # 81 Q
- :ed_insert,
- # 82 R
- :ed_insert,
- # 83 S
- :ed_insert,
- # 84 T
- :ed_insert,
- # 85 U
- :ed_insert,
- # 86 V
- :ed_insert,
- # 87 W
- :ed_insert,
- # 88 X
- :ed_insert,
- # 89 Y
- :ed_insert,
- # 90 Z
- :ed_insert,
- # 91 [
- :ed_insert,
- # 92 \
- :ed_insert,
- # 93 ]
- :ed_insert,
- # 94 ^
- :ed_insert,
- # 95 _
- :ed_insert,
- # 96 `
- :ed_insert,
- # 97 a
- :ed_insert,
- # 98 b
- :ed_insert,
- # 99 c
- :ed_insert,
- # 100 d
- :ed_insert,
- # 101 e
- :ed_insert,
- # 102 f
- :ed_insert,
- # 103 g
- :ed_insert,
- # 104 h
- :ed_insert,
- # 105 i
- :ed_insert,
- # 106 j
- :ed_insert,
- # 107 k
- :ed_insert,
- # 108 l
- :ed_insert,
- # 109 m
- :ed_insert,
- # 110 n
- :ed_insert,
- # 111 o
- :ed_insert,
- # 112 p
- :ed_insert,
- # 113 q
- :ed_insert,
- # 114 r
- :ed_insert,
- # 115 s
- :ed_insert,
- # 116 t
- :ed_insert,
- # 117 u
- :ed_insert,
- # 118 v
- :ed_insert,
- # 119 w
- :ed_insert,
- # 120 x
- :ed_insert,
- # 121 y
- :ed_insert,
- # 122 z
- :ed_insert,
- # 123 {
- :ed_insert,
- # 124 |
- :ed_insert,
- # 125 }
- :ed_insert,
- # 126 ~
- :ed_insert,
- # 127 ^?
- :vi_delete_prev_char,
- # 128 M-^@
- :ed_unassigned,
- # 129 M-^A
- :ed_unassigned,
- # 130 M-^B
- :ed_unassigned,
- # 131 M-^C
- :ed_unassigned,
- # 132 M-^D
- :ed_unassigned,
- # 133 M-^E
- :ed_unassigned,
- # 134 M-^F
- :ed_unassigned,
- # 135 M-^G
- :ed_unassigned,
- # 136 M-^H
- :ed_unassigned,
- # 137 M-^I
- :ed_unassigned,
- # 138 M-^J
- :key_newline,
- # 139 M-^K
- :ed_unassigned,
- # 140 M-^L
- :ed_unassigned,
- # 141 M-^M
- :key_newline,
- # 142 M-^N
- :ed_unassigned,
- # 143 M-^O
- :ed_unassigned,
- # 144 M-^P
- :ed_unassigned,
- # 145 M-^Q
- :ed_unassigned,
- # 146 M-^R
- :ed_unassigned,
- # 147 M-^S
- :ed_unassigned,
- # 148 M-^T
- :ed_unassigned,
- # 149 M-^U
- :ed_unassigned,
- # 150 M-^V
- :ed_unassigned,
- # 151 M-^W
- :ed_unassigned,
- # 152 M-^X
- :ed_unassigned,
- # 153 M-^Y
- :ed_unassigned,
- # 154 M-^Z
- :ed_unassigned,
- # 155 M-^[
- :ed_unassigned,
- # 156 M-^\
- :ed_unassigned,
- # 157 M-^]
- :ed_unassigned,
- # 158 M-^^
- :ed_unassigned,
- # 159 M-^_
- :ed_unassigned,
- # 160 M-SPACE
- :ed_unassigned,
- # 161 M-!
- :ed_unassigned,
- # 162 M-"
- :ed_unassigned,
- # 163 M-#
- :ed_unassigned,
- # 164 M-$
- :ed_unassigned,
- # 165 M-%
- :ed_unassigned,
- # 166 M-&
- :ed_unassigned,
- # 167 M-'
- :ed_unassigned,
- # 168 M-(
- :ed_unassigned,
- # 169 M-)
- :ed_unassigned,
- # 170 M-*
- :ed_unassigned,
- # 171 M-+
- :ed_unassigned,
- # 172 M-,
- :ed_unassigned,
- # 173 M--
- :ed_unassigned,
- # 174 M-.
- :ed_unassigned,
- # 175 M-/
- :ed_unassigned,
- # 176 M-0
- :ed_unassigned,
- # 177 M-1
- :ed_unassigned,
- # 178 M-2
- :ed_unassigned,
- # 179 M-3
- :ed_unassigned,
- # 180 M-4
- :ed_unassigned,
- # 181 M-5
- :ed_unassigned,
- # 182 M-6
- :ed_unassigned,
- # 183 M-7
- :ed_unassigned,
- # 184 M-8
- :ed_unassigned,
- # 185 M-9
- :ed_unassigned,
- # 186 M-:
- :ed_unassigned,
- # 187 M-;
- :ed_unassigned,
- # 188 M-<
- :ed_unassigned,
- # 189 M-=
- :ed_unassigned,
- # 190 M->
- :ed_unassigned,
- # 191 M-?
- :ed_unassigned,
- # 192 M-@
- :ed_unassigned,
- # 193 M-A
- :ed_unassigned,
- # 194 M-B
- :ed_unassigned,
- # 195 M-C
- :ed_unassigned,
- # 196 M-D
- :ed_unassigned,
- # 197 M-E
- :ed_unassigned,
- # 198 M-F
- :ed_unassigned,
- # 199 M-G
- :ed_unassigned,
- # 200 M-H
- :ed_unassigned,
- # 201 M-I
- :ed_unassigned,
- # 202 M-J
- :ed_unassigned,
- # 203 M-K
- :ed_unassigned,
- # 204 M-L
- :ed_unassigned,
- # 205 M-M
- :ed_unassigned,
- # 206 M-N
- :ed_unassigned,
- # 207 M-O
- :ed_unassigned,
- # 208 M-P
- :ed_unassigned,
- # 209 M-Q
- :ed_unassigned,
- # 210 M-R
- :ed_unassigned,
- # 211 M-S
- :ed_unassigned,
- # 212 M-T
- :ed_unassigned,
- # 213 M-U
- :ed_unassigned,
- # 214 M-V
- :ed_unassigned,
- # 215 M-W
- :ed_unassigned,
- # 216 M-X
- :ed_unassigned,
- # 217 M-Y
- :ed_unassigned,
- # 218 M-Z
- :ed_unassigned,
- # 219 M-[
- :ed_unassigned,
- # 220 M-\
- :ed_unassigned,
- # 221 M-]
- :ed_unassigned,
- # 222 M-^
- :ed_unassigned,
- # 223 M-_
- :ed_unassigned,
- # 224 M-`
- :ed_unassigned,
- # 225 M-a
- :ed_unassigned,
- # 226 M-b
- :ed_unassigned,
- # 227 M-c
- :ed_unassigned,
- # 228 M-d
- :ed_unassigned,
- # 229 M-e
- :ed_unassigned,
- # 230 M-f
- :ed_unassigned,
- # 231 M-g
- :ed_unassigned,
- # 232 M-h
- :ed_unassigned,
- # 233 M-i
- :ed_unassigned,
- # 234 M-j
- :ed_unassigned,
- # 235 M-k
- :ed_unassigned,
- # 236 M-l
- :ed_unassigned,
- # 237 M-m
- :ed_unassigned,
- # 238 M-n
- :ed_unassigned,
- # 239 M-o
- :ed_unassigned,
- # 240 M-p
- :ed_unassigned,
- # 241 M-q
- :ed_unassigned,
- # 242 M-r
- :ed_unassigned,
- # 243 M-s
- :ed_unassigned,
- # 244 M-t
- :ed_unassigned,
- # 245 M-u
- :ed_unassigned,
- # 246 M-v
- :ed_unassigned,
- # 247 M-w
- :ed_unassigned,
- # 248 M-x
- :ed_unassigned,
- # 249 M-y
- :ed_unassigned,
- # 250 M-z
- :ed_unassigned,
- # 251 M-{
- :ed_unassigned,
- # 252 M-|
- :ed_unassigned,
- # 253 M-}
- :ed_unassigned,
- # 254 M-~
- :ed_unassigned,
- # 255 M-^?
- :ed_unassigned
- # EOF
- ]
-end
diff --git a/lib/reline/key_stroke.rb b/lib/reline/key_stroke.rb
deleted file mode 100644
index c1c61513a9..0000000000
--- a/lib/reline/key_stroke.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-class Reline::KeyStroke
- def initialize(config)
- @config = config
- end
-
- def compress_meta_key(ary)
- return ary unless @config.convert_meta
- ary.inject([]) { |result, key|
- if result.size > 0 and result.last == "\e".ord
- result[result.size - 1] = Reline::Key.new(key, key | 0b10000000, true)
- else
- result << key
- end
- result
- }
- end
-
- def start_with?(me, other)
- compressed_me = compress_meta_key(me)
- compressed_other = compress_meta_key(other)
- i = 0
- loop do
- my_c = compressed_me[i]
- other_c = compressed_other[i]
- other_is_last = (i + 1) == compressed_other.size
- me_is_last = (i + 1) == compressed_me.size
- if my_c != other_c
- if other_c == "\e".ord and other_is_last and my_c.is_a?(Reline::Key) and my_c.with_meta
- return true
- else
- return false
- end
- elsif other_is_last
- return true
- elsif me_is_last
- return false
- end
- i += 1
- end
- end
-
- def equal?(me, other)
- case me
- when Array
- compressed_me = compress_meta_key(me)
- compressed_other = compress_meta_key(other)
- compressed_me.size == compressed_other.size and [compressed_me, compressed_other].transpose.all?{ |i| equal?(i[0], i[1]) }
- when Integer
- if other.is_a?(Reline::Key)
- if other.combined_char == "\e".ord
- false
- else
- other.combined_char == me
- end
- else
- me == other
- end
- when Reline::Key
- if other.is_a?(Integer)
- me.combined_char == other
- else
- me == other
- end
- end
- end
-
- def match_status(input)
- key_mapping.keys.select { |lhs|
- start_with?(lhs, input)
- }.tap { |it|
- return :matched if it.size == 1 && equal?(it[0], input)
- return :matching if it.size == 1 && !equal?(it[0], input)
- return :matched if it.max_by(&:size)&.size&.< input.size
- return :matching if it.size > 1
- }
- key_mapping.keys.select { |lhs|
- start_with?(input, lhs)
- }.tap { |it|
- return it.size > 0 ? :matched : :unmatched
- }
- end
-
- def expand(input)
- input = compress_meta_key(input)
- lhs = key_mapping.keys.select { |item| start_with?(input, item) }.sort_by(&:size).last
- return input unless lhs
- rhs = key_mapping[lhs]
-
- case rhs
- when String
- rhs_bytes = rhs.bytes
- expand(expand(rhs_bytes) + expand(input.drop(lhs.size)))
- when Symbol
- [rhs] + expand(input.drop(lhs.size))
- when Array
- rhs
- end
- end
-
- private
-
- def key_mapping
- @config.key_bindings
- end
-end
diff --git a/lib/reline/kill_ring.rb b/lib/reline/kill_ring.rb
deleted file mode 100644
index bb3684b42b..0000000000
--- a/lib/reline/kill_ring.rb
+++ /dev/null
@@ -1,125 +0,0 @@
-class Reline::KillRing
- include Enumerable
-
- module State
- FRESH = :fresh
- CONTINUED = :continued
- PROCESSED = :processed
- YANK = :yank
- end
-
- RingPoint = Struct.new(:backward, :forward, :str) do
- def initialize(str)
- super(nil, nil, str)
- end
-
- def ==(other)
- object_id == other.object_id
- end
- end
-
- class RingBuffer
- attr_reader :size
- attr_reader :head
-
- def initialize(max = 1024)
- @max = max
- @size = 0
- @head = nil # reading head of ring-shaped tape
- end
-
- def <<(point)
- if @size.zero?
- @head = point
- @head.backward = @head
- @head.forward = @head
- @size = 1
- elsif @size >= @max
- tail = @head.forward
- new_tail = tail.forward
- @head.forward = point
- point.backward = @head
- new_tail.backward = point
- point.forward = new_tail
- @head = point
- else
- tail = @head.forward
- @head.forward = point
- point.backward = @head
- tail.backward = point
- point.forward = tail
- @head = point
- @size += 1
- end
- end
-
- def empty?
- @size.zero?
- end
- end
-
- def initialize(max = 1024)
- @ring = RingBuffer.new(max)
- @ring_pointer = nil
- @buffer = nil
- @state = State::FRESH
- end
-
- def append(string, before_p = false)
- case @state
- when State::FRESH, State::YANK
- @ring << RingPoint.new(string)
- @state = State::CONTINUED
- when State::CONTINUED, State::PROCESSED
- if before_p
- @ring.head.str.prepend(string)
- else
- @ring.head.str.concat(string)
- end
- @state = State::CONTINUED
- end
- end
-
- def process
- case @state
- when State::FRESH
- # nothing to do
- when State::CONTINUED
- @state = State::PROCESSED
- when State::PROCESSED
- @state = State::FRESH
- when State::YANK
- # nothing to do
- end
- end
-
- def yank
- unless @ring.empty?
- @state = State::YANK
- @ring_pointer = @ring.head
- @ring_pointer.str
- else
- nil
- end
- end
-
- def yank_pop
- if @state == State::YANK
- prev_yank = @ring_pointer.str
- @ring_pointer = @ring_pointer.backward
- [@ring_pointer.str, prev_yank]
- else
- nil
- end
- end
-
- def each
- start = head = @ring.head
- loop do
- break if head.nil?
- yield head.str
- head = head.backward
- break if head == start
- end
- end
-end
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
deleted file mode 100644
index 87ce7fba5d..0000000000
--- a/lib/reline/line_editor.rb
+++ /dev/null
@@ -1,3347 +0,0 @@
-require 'reline/kill_ring'
-require 'reline/unicode'
-
-require 'tempfile'
-
-class Reline::LineEditor
- # TODO: undo
- # TODO: Use "private alias_method" idiom after drop Ruby 2.5.
- attr_reader :line
- attr_reader :byte_pointer
- attr_accessor :confirm_multiline_termination_proc
- attr_accessor :completion_proc
- attr_accessor :completion_append_character
- attr_accessor :output_modifier_proc
- attr_accessor :prompt_proc
- attr_accessor :auto_indent_proc
- attr_accessor :pre_input_hook
- attr_accessor :dig_perfect_match_proc
- attr_writer :output
-
- VI_MOTIONS = %i{
- ed_prev_char
- ed_next_char
- vi_zero
- ed_move_to_beg
- ed_move_to_end
- vi_to_column
- vi_next_char
- vi_prev_char
- vi_next_word
- vi_prev_word
- vi_to_next_char
- vi_to_prev_char
- vi_end_word
- vi_next_big_word
- vi_prev_big_word
- vi_end_big_word
- vi_repeat_next_char
- vi_repeat_prev_char
- }
-
- module CompletionState
- NORMAL = :normal
- COMPLETION = :completion
- MENU = :menu
- JOURNEY = :journey
- MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
- PERFECT_MATCH = :perfect_match
- end
-
- CompletionJourneyData = Struct.new('CompletionJourneyData', :preposing, :postposing, :list, :pointer)
- MenuInfo = Struct.new('MenuInfo', :target, :list)
-
- PROMPT_LIST_CACHE_TIMEOUT = 0.5
- MINIMUM_SCROLLBAR_HEIGHT = 1
-
- def initialize(config, encoding)
- @config = config
- @completion_append_character = ''
- reset_variables(encoding: encoding)
- end
-
- def set_pasting_state(in_pasting)
- @in_pasting = in_pasting
- end
-
- def simplified_rendering?
- if finished?
- false
- elsif @just_cursor_moving and not @rerender_all
- true
- else
- not @rerender_all and not finished? and @in_pasting
- end
- end
-
- private def check_mode_string
- mode_string = nil
- if @config.show_mode_in_prompt
- if @config.editing_mode_is?(:vi_command)
- mode_string = @config.vi_cmd_mode_string
- elsif @config.editing_mode_is?(:vi_insert)
- mode_string = @config.vi_ins_mode_string
- elsif @config.editing_mode_is?(:emacs)
- mode_string = @config.emacs_mode_string
- else
- mode_string = '?'
- end
- end
- if mode_string != @prev_mode_string
- @rerender_all = true
- end
- @prev_mode_string = mode_string
- mode_string
- end
-
- private def check_multiline_prompt(buffer)
- if @vi_arg
- prompt = "(arg: #{@vi_arg}) "
- @rerender_all = true
- elsif @searching_prompt
- prompt = @searching_prompt
- @rerender_all = true
- else
- prompt = @prompt
- end
- if simplified_rendering?
- mode_string = check_mode_string
- prompt = mode_string + prompt if mode_string
- return [prompt, calculate_width(prompt, true), [prompt] * buffer.size]
- end
- if @prompt_proc
- use_cached_prompt_list = false
- if @cached_prompt_list
- if @just_cursor_moving
- use_cached_prompt_list = true
- elsif Time.now.to_f < (@prompt_cache_time + PROMPT_LIST_CACHE_TIMEOUT) and buffer.size == @cached_prompt_list.size
- use_cached_prompt_list = true
- end
- end
- use_cached_prompt_list = false if @rerender_all
- if use_cached_prompt_list
- prompt_list = @cached_prompt_list
- else
- prompt_list = @cached_prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
- @prompt_cache_time = Time.now.to_f
- end
- prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
- prompt_list = [prompt] if prompt_list.empty?
- mode_string = check_mode_string
- prompt_list = prompt_list.map{ |pr| mode_string + pr } if mode_string
- prompt = prompt_list[@line_index]
- prompt = prompt_list[0] if prompt.nil?
- prompt = prompt_list.last if prompt.nil?
- if buffer.size > prompt_list.size
- (buffer.size - prompt_list.size).times do
- prompt_list << prompt_list.last
- end
- end
- prompt_width = calculate_width(prompt, true)
- [prompt, prompt_width, prompt_list]
- else
- mode_string = check_mode_string
- prompt = mode_string + prompt if mode_string
- prompt_width = calculate_width(prompt, true)
- [prompt, prompt_width, nil]
- end
- end
-
- def reset(prompt = '', encoding:)
- @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
- @screen_size = Reline::IOGate.get_screen_size
- @screen_height = @screen_size.first
- reset_variables(prompt, encoding: encoding)
- Reline::IOGate.set_winch_handler do
- @resized = true
- end
- if ENV.key?('RELINE_ALT_SCROLLBAR')
- @full_block = '::'
- @upper_half_block = "''"
- @lower_half_block = '..'
- @block_elem_width = 2
- elsif Reline::IOGate.win?
- @full_block = '█'
- @upper_half_block = '▀'
- @lower_half_block = '▄'
- @block_elem_width = 1
- elsif @encoding == Encoding::UTF_8
- @full_block = '█'
- @upper_half_block = '▀'
- @lower_half_block = '▄'
- @block_elem_width = Reline::Unicode.calculate_width('█')
- else
- @full_block = '::'
- @upper_half_block = "''"
- @lower_half_block = '..'
- @block_elem_width = 2
- end
- end
-
- def resize
- return unless @resized
- @resized = false
- @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
- old_screen_size = @screen_size
- @screen_size = Reline::IOGate.get_screen_size
- @screen_height = @screen_size.first
- if old_screen_size.last < @screen_size.last # columns increase
- @rerender_all = true
- rerender
- else
- back = 0
- new_buffer = whole_lines
- prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
- new_buffer.each_with_index do |line, index|
- prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
- width = prompt_width + calculate_width(line)
- height = calculate_height_by_width(width)
- back += height
- end
- @highest_in_all = back
- @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
- @first_line_started_from =
- if @line_index.zero?
- 0
- else
- calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
- end
- if @prompt_proc
- prompt = prompt_list[@line_index]
- prompt_width = calculate_width(prompt, true)
- end
- calculate_nearest_cursor
- @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
- Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
- @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
- @rerender_all = true
- end
- end
-
- def set_signal_handlers
- @old_trap = Signal.trap('INT') {
- clear_dialog
- if @scroll_partial_screen
- move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1)
- else
- move_cursor_down(@highest_in_all - @line_index - 1)
- end
- Reline::IOGate.move_cursor_column(0)
- scroll_down(1)
- case @old_trap
- when 'DEFAULT', 'SYSTEM_DEFAULT'
- raise Interrupt
- when 'IGNORE'
- # Do nothing
- when 'EXIT'
- exit
- else
- @old_trap.call if @old_trap.respond_to?(:call)
- end
- }
- begin
- @old_tstp_trap = Signal.trap('TSTP') {
- Reline::IOGate.ungetc("\C-z".ord)
- @old_tstp_trap.call if @old_tstp_trap.respond_to?(:call)
- }
- rescue ArgumentError
- end
- end
-
- def finalize
- Signal.trap('INT', @old_trap)
- begin
- Signal.trap('TSTP', @old_tstp_trap)
- rescue ArgumentError
- end
- end
-
- def eof?
- @eof
- end
-
- def reset_variables(prompt = '', encoding:)
- @prompt = prompt.gsub("\n", "\\n")
- @mark_pointer = nil
- @encoding = encoding
- @is_multiline = false
- @finished = false
- @cleared = false
- @rerender_all = false
- @history_pointer = nil
- @kill_ring ||= Reline::KillRing.new
- @vi_clipboard = ''
- @vi_arg = nil
- @waiting_proc = nil
- @waiting_operator_proc = nil
- @waiting_operator_vi_arg = nil
- @completion_journey_data = nil
- @completion_state = CompletionState::NORMAL
- @perfect_matched = nil
- @menu_info = nil
- @first_prompt = true
- @searching_prompt = nil
- @first_char = true
- @add_newline_to_end_of_buffer = false
- @just_cursor_moving = nil
- @cached_prompt_list = nil
- @prompt_cache_time = nil
- @eof = false
- @continuous_insertion_buffer = String.new(encoding: @encoding)
- @scroll_partial_screen = nil
- @prev_mode_string = nil
- @drop_terminate_spaces = false
- @in_pasting = false
- @auto_indent_proc = nil
- @dialogs = []
- @last_key = nil
- @resized = false
- reset_line
- end
-
- def reset_line
- @cursor = 0
- @cursor_max = 0
- @byte_pointer = 0
- @buffer_of_lines = [String.new(encoding: @encoding)]
- @line_index = 0
- @previous_line_index = nil
- @line = @buffer_of_lines[0]
- @first_line_started_from = 0
- @move_up = 0
- @started_from = 0
- @highest_in_this = 1
- @highest_in_all = 1
- @line_backup_in_history = nil
- @multibyte_buffer = String.new(encoding: 'ASCII-8BIT')
- @check_new_auto_indent = false
- end
-
- def multiline_on
- @is_multiline = true
- end
-
- def multiline_off
- @is_multiline = false
- end
-
- private def calculate_height_by_lines(lines, prompt)
- result = 0
- prompt_list = prompt.is_a?(Array) ? prompt : nil
- lines.each_with_index { |line, i|
- prompt = prompt_list[i] if prompt_list and prompt_list[i]
- result += calculate_height_by_width(calculate_width(prompt, true) + calculate_width(line))
- }
- result
- end
-
- private def insert_new_line(cursor_line, next_line)
- @line = cursor_line
- @buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding: @encoding))
- @previous_line_index = @line_index
- @line_index += 1
- @just_cursor_moving = false
- end
-
- private def calculate_height_by_width(width)
- width.div(@screen_size.last) + 1
- end
-
- private def split_by_width(str, max_width)
- Reline::Unicode.split_by_width(str, max_width, @encoding)
- end
-
- private def scroll_down(val)
- if val <= @rest_height
- Reline::IOGate.move_cursor_down(val)
- @rest_height -= val
- else
- Reline::IOGate.move_cursor_down(@rest_height)
- Reline::IOGate.scroll_down(val - @rest_height)
- @rest_height = 0
- end
- end
-
- private def move_cursor_up(val)
- if val > 0
- Reline::IOGate.move_cursor_up(val)
- @rest_height += val
- elsif val < 0
- move_cursor_down(-val)
- end
- end
-
- private def move_cursor_down(val)
- if val > 0
- Reline::IOGate.move_cursor_down(val)
- @rest_height -= val
- @rest_height = 0 if @rest_height < 0
- elsif val < 0
- move_cursor_up(-val)
- end
- end
-
- private def calculate_nearest_cursor(line_to_calc = @line, cursor = @cursor, started_from = @started_from, byte_pointer = @byte_pointer, update = true)
- new_cursor_max = calculate_width(line_to_calc)
- new_cursor = 0
- new_byte_pointer = 0
- height = 1
- max_width = @screen_size.last
- if @config.editing_mode_is?(:vi_command)
- last_byte_size = Reline::Unicode.get_prev_mbchar_size(line_to_calc, line_to_calc.bytesize)
- if last_byte_size > 0
- last_mbchar = line_to_calc.byteslice(line_to_calc.bytesize - last_byte_size, last_byte_size)
- last_width = Reline::Unicode.get_mbchar_width(last_mbchar)
- end_of_line_cursor = new_cursor_max - last_width
- else
- end_of_line_cursor = new_cursor_max
- end
- else
- end_of_line_cursor = new_cursor_max
- end
- line_to_calc.grapheme_clusters.each do |gc|
- mbchar = gc.encode(Encoding::UTF_8)
- mbchar_width = Reline::Unicode.get_mbchar_width(mbchar)
- now = new_cursor + mbchar_width
- if now > end_of_line_cursor or now > cursor
- break
- end
- new_cursor += mbchar_width
- if new_cursor > max_width * height
- height += 1
- end
- new_byte_pointer += gc.bytesize
- end
- new_started_from = height - 1
- if update
- @cursor = new_cursor
- @cursor_max = new_cursor_max
- @started_from = new_started_from
- @byte_pointer = new_byte_pointer
- else
- [new_cursor, new_cursor_max, new_started_from, new_byte_pointer]
- end
- end
-
- def rerender_all
- @rerender_all = true
- process_insert(force: true)
- rerender
- end
-
- def rerender
- return if @line.nil?
- if @menu_info
- scroll_down(@highest_in_all - @first_line_started_from)
- @rerender_all = true
- end
- if @menu_info
- show_menu
- @menu_info = nil
- end
- prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
- if @cleared
- clear_screen_buffer(prompt, prompt_list, prompt_width)
- @cleared = false
- return
- end
- if @is_multiline and finished? and @scroll_partial_screen
- # Re-output all code higher than the screen when finished.
- Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen)
- Reline::IOGate.move_cursor_column(0)
- @scroll_partial_screen = nil
- new_lines = whole_lines
- prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
- modify_lines(new_lines).each_with_index do |line, index|
- @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\r\n"
- Reline::IOGate.erase_after_cursor
- end
- @output.flush
- clear_dialog
- return
- end
- new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line))
- rendered = false
- if @add_newline_to_end_of_buffer
- clear_dialog_with_content
- rerender_added_newline(prompt, prompt_width, prompt_list)
- @add_newline_to_end_of_buffer = false
- else
- if @just_cursor_moving and not @rerender_all
- clear_dialog_with_content
- rendered = just_move_cursor
- @just_cursor_moving = false
- return
- elsif @previous_line_index or new_highest_in_this != @highest_in_this
- clear_dialog_with_content
- rerender_changed_current_line
- @previous_line_index = nil
- rendered = true
- elsif @rerender_all
- rerender_all_lines
- @rerender_all = false
- rendered = true
- else
- end
- end
- if @is_multiline
- if finished?
- # Always rerender on finish because output_modifier_proc may return a different output.
- new_lines = whole_lines
- line = modify_lines(new_lines)[@line_index]
- clear_dialog
- prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
- render_partial(prompt, prompt_width, line, @first_line_started_from)
- move_cursor_down(@highest_in_all - (@first_line_started_from + @highest_in_this - 1) - 1)
- scroll_down(1)
- Reline::IOGate.move_cursor_column(0)
- Reline::IOGate.erase_after_cursor
- else
- if not rendered and not @in_pasting
- line = modify_lines(whole_lines)[@line_index]
- prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
- render_partial(prompt, prompt_width, line, @first_line_started_from)
- end
- render_dialog((prompt_width + @cursor) % @screen_size.last)
- end
- @buffer_of_lines[@line_index] = @line
- @rest_height = 0 if @scroll_partial_screen
- else
- line = modify_lines(whole_lines)[@line_index]
- render_partial(prompt, prompt_width, line, 0)
- if finished?
- scroll_down(1)
- Reline::IOGate.move_cursor_column(0)
- Reline::IOGate.erase_after_cursor
- end
- end
- end
-
- class DialogProcScope
- def initialize(line_editor, config, proc_to_exec, context)
- @line_editor = line_editor
- @config = config
- @proc_to_exec = proc_to_exec
- @context = context
- @cursor_pos = Reline::CursorPos.new
- end
-
- def context
- @context
- end
-
- def retrieve_completion_block(set_completion_quote_character = false)
- @line_editor.retrieve_completion_block(set_completion_quote_character)
- end
-
- def call_completion_proc_with_checking_args(pre, target, post)
- @line_editor.call_completion_proc_with_checking_args(pre, target, post)
- end
-
- def set_dialog(dialog)
- @dialog = dialog
- end
-
- def dialog
- @dialog
- end
-
- def set_cursor_pos(col, row)
- @cursor_pos.x = col
- @cursor_pos.y = row
- end
-
- def set_key(key)
- @key = key
- end
-
- def key
- @key
- end
-
- def cursor_pos
- @cursor_pos
- end
-
- def just_cursor_moving
- @line_editor.instance_variable_get(:@just_cursor_moving)
- end
-
- def screen_width
- @line_editor.instance_variable_get(:@screen_size).last
- end
-
- def completion_journey_data
- @line_editor.instance_variable_get(:@completion_journey_data)
- end
-
- def config
- @config
- end
-
- def call
- instance_exec(&@proc_to_exec)
- end
- end
-
- class Dialog
- attr_reader :name, :contents, :width
- attr_accessor :scroll_top, :scrollbar_pos, :pointer, :column, :vertical_offset, :lines_backup, :trap_key
-
- def initialize(name, config, proc_scope)
- @name = name
- @config = config
- @proc_scope = proc_scope
- @width = nil
- @scroll_top = 0
- @trap_key = nil
- end
-
- def set_cursor_pos(col, row)
- @proc_scope.set_cursor_pos(col, row)
- end
-
- def width=(v)
- @width = v
- end
-
- def contents=(contents)
- @contents = contents
- if contents and @width.nil?
- @width = contents.map{ |line| Reline::Unicode.calculate_width(line, true) }.max
- end
- end
-
- def call(key)
- @proc_scope.set_dialog(self)
- @proc_scope.set_key(key)
- dialog_render_info = @proc_scope.call
- if @trap_key
- if @trap_key.any?{ |i| i.is_a?(Array) } # multiple trap
- @trap_key.each do |t|
- @config.add_oneshot_key_binding(t, @name)
- end
- elsif @trap_key.is_a?(Array)
- @config.add_oneshot_key_binding(@trap_key, @name)
- elsif @trap_key.is_a?(Integer) or @trap_key.is_a?(Reline::Key)
- @config.add_oneshot_key_binding([@trap_key], @name)
- end
- end
- dialog_render_info
- end
- end
-
- def add_dialog_proc(name, p, context = nil)
- dialog = Dialog.new(name, @config, DialogProcScope.new(self, @config, p, context))
- if index = @dialogs.find_index { |d| d.name == name }
- @dialogs[index] = dialog
- else
- @dialogs << dialog
- end
- end
-
- DIALOG_DEFAULT_HEIGHT = 20
- private def render_dialog(cursor_column)
- @dialogs.each do |dialog|
- render_each_dialog(dialog, cursor_column)
- end
- end
-
- private def padding_space_with_escape_sequences(str, width)
- padding_width = width - calculate_width(str, true)
- # padding_width should be only positive value. But macOS and Alacritty returns negative value.
- padding_width = 0 if padding_width < 0
- str + (' ' * padding_width)
- end
-
- private def render_each_dialog(dialog, cursor_column)
- if @in_pasting
- clear_each_dialog(dialog)
- dialog.contents = nil
- dialog.trap_key = nil
- return
- end
- dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
- dialog_render_info = dialog.call(@last_key)
- if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
- lines = whole_lines
- dialog.lines_backup = {
- unmodified_lines: lines,
- lines: modify_lines(lines),
- line_index: @line_index,
- first_line_started_from: @first_line_started_from,
- started_from: @started_from,
- byte_pointer: @byte_pointer
- }
- clear_each_dialog(dialog)
- dialog.contents = nil
- dialog.trap_key = nil
- return
- end
- old_dialog = dialog.clone
- dialog.contents = dialog_render_info.contents
- pointer = dialog.pointer
- if dialog_render_info.width
- dialog.width = dialog_render_info.width
- else
- dialog.width = dialog.contents.map { |l| calculate_width(l, true) }.max
- end
- height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT
- height = dialog.contents.size if dialog.contents.size < height
- if dialog.contents.size > height
- if dialog.pointer
- if dialog.pointer < 0
- dialog.scroll_top = 0
- elsif (dialog.pointer - dialog.scroll_top) >= (height - 1)
- dialog.scroll_top = dialog.pointer - (height - 1)
- elsif (dialog.pointer - dialog.scroll_top) < 0
- dialog.scroll_top = dialog.pointer
- end
- pointer = dialog.pointer - dialog.scroll_top
- else
- dialog.scroll_top = 0
- end
- dialog.contents = dialog.contents[dialog.scroll_top, height]
- end
- if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
- bar_max_height = height * 2
- moving_distance = (dialog_render_info.contents.size - height) * 2
- position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
- bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
- bar_height = MINIMUM_SCROLLBAR_HEIGHT if bar_height < MINIMUM_SCROLLBAR_HEIGHT
- dialog.scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
- else
- dialog.scrollbar_pos = nil
- end
- upper_space = @first_line_started_from - @started_from
- dialog.column = dialog_render_info.pos.x
- dialog.width += @block_elem_width if dialog.scrollbar_pos
- diff = (dialog.column + dialog.width) - (@screen_size.last)
- if diff > 0
- dialog.column -= diff
- end
- if (@rest_height - dialog_render_info.pos.y) >= height
- dialog.vertical_offset = dialog_render_info.pos.y + 1
- elsif upper_space >= height
- dialog.vertical_offset = dialog_render_info.pos.y - height
- else
- if (@rest_height - dialog_render_info.pos.y) < height
- scroll_down(height + dialog_render_info.pos.y)
- move_cursor_up(height + dialog_render_info.pos.y)
- end
- dialog.vertical_offset = dialog_render_info.pos.y + 1
- end
- Reline::IOGate.hide_cursor
- if dialog.column < 0
- dialog.column = 0
- dialog.width = @screen_size.last
- end
- reset_dialog(dialog, old_dialog)
- move_cursor_down(dialog.vertical_offset)
- Reline::IOGate.move_cursor_column(dialog.column)
- dialog.contents.each_with_index do |item, i|
- if i == pointer
- fg_color = dialog_render_info.pointer_fg_color
- bg_color = dialog_render_info.pointer_bg_color
- else
- fg_color = dialog_render_info.fg_color
- bg_color = dialog_render_info.bg_color
- end
- str_width = dialog.width - (dialog.scrollbar_pos.nil? ? 0 : @block_elem_width)
- str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
- @output.write "\e[#{bg_color}m\e[#{fg_color}m#{str}"
- if dialog.scrollbar_pos
- @output.write "\e[37m"
- if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height)
- @output.write @full_block
- elsif dialog.scrollbar_pos <= (i * 2) and (i * 2) < (dialog.scrollbar_pos + bar_height)
- @output.write @upper_half_block
- elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height)
- @output.write @lower_half_block
- else
- @output.write ' ' * @block_elem_width
- end
- end
- @output.write "\e[0m"
- Reline::IOGate.move_cursor_column(dialog.column)
- move_cursor_down(1) if i < (dialog.contents.size - 1)
- end
- Reline::IOGate.move_cursor_column(cursor_column)
- move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
- Reline::IOGate.show_cursor
- lines = whole_lines
- dialog.lines_backup = {
- unmodified_lines: lines,
- lines: modify_lines(lines),
- line_index: @line_index,
- first_line_started_from: @first_line_started_from,
- started_from: @started_from,
- byte_pointer: @byte_pointer
- }
- end
-
- private def reset_dialog(dialog, old_dialog)
- return if dialog.lines_backup.nil? or old_dialog.contents.nil?
- prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:unmodified_lines])
- visual_lines = []
- visual_start = nil
- dialog.lines_backup[:lines].each_with_index { |l, i|
- pr = prompt_list ? prompt_list[i] : prompt
- vl, _ = split_by_width(pr + l, @screen_size.last)
- vl.compact!
- if i == dialog.lines_backup[:line_index]
- visual_start = visual_lines.size + dialog.lines_backup[:started_from]
- end
- visual_lines.concat(vl)
- }
- old_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from]
- y = @first_line_started_from + @started_from
- y_diff = y - old_y
- if (old_y + old_dialog.vertical_offset) < (y + dialog.vertical_offset)
- # rerender top
- move_cursor_down(old_dialog.vertical_offset - y_diff)
- start = visual_start + old_dialog.vertical_offset
- line_num = dialog.vertical_offset - old_dialog.vertical_offset
- line_num.times do |i|
- Reline::IOGate.move_cursor_column(old_dialog.column)
- if visual_lines[start + i].nil?
- s = ' ' * old_dialog.width
- else
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
- s = padding_space_with_escape_sequences(s, old_dialog.width)
- end
- @output.write "\e[0m#{s}\e[0m"
- move_cursor_down(1) if i < (line_num - 1)
- end
- move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
- end
- if (old_y + old_dialog.vertical_offset + old_dialog.contents.size) > (y + dialog.vertical_offset + dialog.contents.size)
- # rerender bottom
- move_cursor_down(dialog.vertical_offset + dialog.contents.size - y_diff)
- start = visual_start + dialog.vertical_offset + dialog.contents.size
- line_num = (old_dialog.vertical_offset + old_dialog.contents.size) - (dialog.vertical_offset + dialog.contents.size)
- line_num.times do |i|
- Reline::IOGate.move_cursor_column(old_dialog.column)
- if visual_lines[start + i].nil?
- s = ' ' * old_dialog.width
- else
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
- s = padding_space_with_escape_sequences(s, old_dialog.width)
- end
- @output.write "\e[0m#{s}\e[0m"
- move_cursor_down(1) if i < (line_num - 1)
- end
- move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
- end
- if old_dialog.column < dialog.column
- # rerender left
- move_cursor_down(old_dialog.vertical_offset - y_diff)
- width = dialog.column - old_dialog.column
- start = visual_start + old_dialog.vertical_offset
- line_num = old_dialog.contents.size
- line_num.times do |i|
- Reline::IOGate.move_cursor_column(old_dialog.column)
- if visual_lines[start + i].nil?
- s = ' ' * width
- else
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
- s = padding_space_with_escape_sequences(s, dialog.width)
- end
- @output.write "\e[0m#{s}\e[0m"
- move_cursor_down(1) if i < (line_num - 1)
- end
- move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
- end
- if (old_dialog.column + old_dialog.width) > (dialog.column + dialog.width)
- # rerender right
- move_cursor_down(old_dialog.vertical_offset + y_diff)
- width = (old_dialog.column + old_dialog.width) - (dialog.column + dialog.width)
- start = visual_start + old_dialog.vertical_offset
- line_num = old_dialog.contents.size
- line_num.times do |i|
- Reline::IOGate.move_cursor_column(old_dialog.column + dialog.width)
- if visual_lines[start + i].nil?
- s = ' ' * width
- else
- s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column + dialog.width, width)
- rerender_width = old_dialog.width - dialog.width
- s = padding_space_with_escape_sequences(s, rerender_width)
- end
- Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
- @output.write "\e[0m#{s}\e[0m"
- move_cursor_down(1) if i < (line_num - 1)
- end
- move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
- end
- Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
- end
-
- private def clear_dialog
- @dialogs.each do |dialog|
- clear_each_dialog(dialog)
- end
- end
-
- private def clear_dialog_with_content
- @dialogs.each do |dialog|
- clear_each_dialog(dialog)
- dialog.contents = nil
- dialog.trap_key = nil
- end
- end
-
- private def clear_each_dialog(dialog)
- dialog.trap_key = nil
- return unless dialog.contents
- prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:unmodified_lines])
- visual_lines = []
- visual_lines_under_dialog = []
- visual_start = nil
- dialog.lines_backup[:lines].each_with_index { |l, i|
- pr = prompt_list ? prompt_list[i] : prompt
- vl, _ = split_by_width(pr + l, @screen_size.last)
- vl.compact!
- if i == dialog.lines_backup[:line_index]
- visual_start = visual_lines.size + dialog.lines_backup[:started_from] + dialog.vertical_offset
- end
- visual_lines.concat(vl)
- }
- visual_lines_under_dialog = visual_lines[visual_start, dialog.contents.size]
- visual_lines_under_dialog = [] if visual_lines_under_dialog.nil?
- Reline::IOGate.hide_cursor
- move_cursor_down(dialog.vertical_offset)
- dialog_vertical_size = dialog.contents.size
- dialog_vertical_size.times do |i|
- if i < visual_lines_under_dialog.size
- Reline::IOGate.move_cursor_column(dialog.column)
- str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
- str = padding_space_with_escape_sequences(str, dialog.width)
- @output.write "\e[0m#{str}\e[0m"
- else
- Reline::IOGate.move_cursor_column(dialog.column)
- @output.write "\e[0m#{' ' * dialog.width}\e[0m"
- end
- move_cursor_down(1) if i < (dialog_vertical_size - 1)
- end
- move_cursor_up(dialog_vertical_size - 1 + dialog.vertical_offset)
- Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
- Reline::IOGate.show_cursor
- end
-
- private def calculate_scroll_partial_screen(highest_in_all, cursor_y)
- if @screen_height < highest_in_all
- old_scroll_partial_screen = @scroll_partial_screen
- if cursor_y == 0
- @scroll_partial_screen = 0
- elsif cursor_y == (highest_in_all - 1)
- @scroll_partial_screen = highest_in_all - @screen_height
- else
- if @scroll_partial_screen
- if cursor_y <= @scroll_partial_screen
- @scroll_partial_screen = cursor_y
- elsif (@scroll_partial_screen + @screen_height - 1) < cursor_y
- @scroll_partial_screen = cursor_y - (@screen_height - 1)
- end
- else
- if cursor_y > (@screen_height - 1)
- @scroll_partial_screen = cursor_y - (@screen_height - 1)
- else
- @scroll_partial_screen = 0
- end
- end
- end
- if @scroll_partial_screen != old_scroll_partial_screen
- @rerender_all = true
- end
- else
- if @scroll_partial_screen
- @rerender_all = true
- end
- @scroll_partial_screen = nil
- end
- end
-
- private def rerender_added_newline(prompt, prompt_width, prompt_list)
- @buffer_of_lines[@previous_line_index] = @line
- @line = @buffer_of_lines[@line_index]
- @previous_line_index = nil
- if @in_pasting
- scroll_down(1)
- else
- lines = whole_lines
- prev_line_prompt = @prompt_proc ? prompt_list[@line_index - 1] : prompt
- prev_line_prompt_width = @prompt_proc ? calculate_width(prev_line_prompt, true) : prompt_width
- prev_line = modify_lines(lines)[@line_index - 1]
- render_partial(prev_line_prompt, prev_line_prompt_width, prev_line, @first_line_started_from + @started_from, with_control: false)
- scroll_down(1)
- render_partial(prompt, prompt_width, @line, @first_line_started_from + @started_from + 1, with_control: false)
- end
- @cursor = @cursor_max = calculate_width(@line)
- @byte_pointer = @line.bytesize
- @highest_in_all += @highest_in_this
- @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
- @first_line_started_from += @started_from + 1
- @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
- end
-
- def just_move_cursor
- prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines)
- move_cursor_up(@started_from)
- new_first_line_started_from =
- if @line_index.zero?
- 0
- else
- calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
- end
- first_line_diff = new_first_line_started_from - @first_line_started_from
- new_cursor, new_cursor_max, new_started_from, new_byte_pointer = calculate_nearest_cursor(@buffer_of_lines[@line_index], @cursor, @started_from, @byte_pointer, false)
- new_started_from = calculate_height_by_width(prompt_width + new_cursor) - 1
- calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from)
- @previous_line_index = nil
- if @rerender_all
- @line = @buffer_of_lines[@line_index]
- rerender_all_lines
- @rerender_all = false
- true
- else
- @line = @buffer_of_lines[@line_index]
- @first_line_started_from = new_first_line_started_from
- @started_from = new_started_from
- @cursor = new_cursor
- @cursor_max = new_cursor_max
- @byte_pointer = new_byte_pointer
- move_cursor_down(first_line_diff + @started_from)
- Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
- false
- end
- end
-
- private def rerender_changed_current_line
- new_lines = whole_lines
- prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
- all_height = calculate_height_by_lines(new_lines, prompt_list || prompt)
- diff = all_height - @highest_in_all
- move_cursor_down(@highest_in_all - @first_line_started_from - @started_from - 1)
- if diff > 0
- scroll_down(diff)
- move_cursor_up(all_height - 1)
- elsif diff < 0
- (-diff).times do
- Reline::IOGate.move_cursor_column(0)
- Reline::IOGate.erase_after_cursor
- move_cursor_up(1)
- end
- move_cursor_up(all_height - 1)
- else
- move_cursor_up(all_height - 1)
- end
- @highest_in_all = all_height
- back = render_whole_lines(new_lines, prompt_list || prompt, prompt_width)
- move_cursor_up(back)
- if @previous_line_index
- @buffer_of_lines[@previous_line_index] = @line
- @line = @buffer_of_lines[@line_index]
- end
- @first_line_started_from =
- if @line_index.zero?
- 0
- else
- calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
- end
- if @prompt_proc
- prompt = prompt_list[@line_index]
- prompt_width = calculate_width(prompt, true)
- end
- move_cursor_down(@first_line_started_from)
- calculate_nearest_cursor
- @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
- move_cursor_down(@started_from)
- Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
- @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
- end
-
- private def rerender_all_lines
- move_cursor_up(@first_line_started_from + @started_from)
- Reline::IOGate.move_cursor_column(0)
- back = 0
- new_buffer = whole_lines
- prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
- new_buffer.each_with_index do |line, index|
- prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
- width = prompt_width + calculate_width(line)
- height = calculate_height_by_width(width)
- back += height
- end
- old_highest_in_all = @highest_in_all
- if @line_index.zero?
- new_first_line_started_from = 0
- else
- new_first_line_started_from = calculate_height_by_lines(new_buffer[0..(@line_index - 1)], prompt_list || prompt)
- end
- new_started_from = calculate_height_by_width(prompt_width + @cursor) - 1
- calculate_scroll_partial_screen(back, new_first_line_started_from + new_started_from)
- if @scroll_partial_screen
- move_cursor_up(@first_line_started_from + @started_from)
- scroll_down(@screen_height - 1)
- move_cursor_up(@screen_height)
- Reline::IOGate.move_cursor_column(0)
- elsif back > old_highest_in_all
- scroll_down(back - 1)
- move_cursor_up(back - 1)
- elsif back < old_highest_in_all
- scroll_down(back)
- Reline::IOGate.erase_after_cursor
- (old_highest_in_all - back - 1).times do
- scroll_down(1)
- Reline::IOGate.erase_after_cursor
- end
- move_cursor_up(old_highest_in_all - 1)
- end
- render_whole_lines(new_buffer, prompt_list || prompt, prompt_width)
- if @prompt_proc
- prompt = prompt_list[@line_index]
- prompt_width = calculate_width(prompt, true)
- end
- @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
- @highest_in_all = back
- @first_line_started_from = new_first_line_started_from
- @started_from = new_started_from
- if @scroll_partial_screen
- Reline::IOGate.move_cursor_up(@screen_height - (@first_line_started_from + @started_from - @scroll_partial_screen) - 1)
- Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
- else
- move_cursor_down(@first_line_started_from + @started_from - back + 1)
- Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
- end
- end
-
- private def render_whole_lines(lines, prompt, prompt_width)
- rendered_height = 0
- modify_lines(lines).each_with_index do |line, index|
- if prompt.is_a?(Array)
- line_prompt = prompt[index]
- prompt_width = calculate_width(line_prompt, true)
- else
- line_prompt = prompt
- end
- height = render_partial(line_prompt, prompt_width, line, rendered_height, with_control: false)
- if index < (lines.size - 1)
- if @scroll_partial_screen
- if (@scroll_partial_screen - height) < rendered_height and (@scroll_partial_screen + @screen_height - 1) >= (rendered_height + height)
- move_cursor_down(1)
- end
- else
- scroll_down(1)
- end
- rendered_height += height
- else
- rendered_height += height - 1
- end
- end
- rendered_height
- end
-
- private def render_partial(prompt, prompt_width, line_to_render, this_started_from, with_control: true)
- visual_lines, height = split_by_width(line_to_render.nil? ? prompt : prompt + line_to_render, @screen_size.last)
- cursor_up_from_last_line = 0
- if @scroll_partial_screen
- last_visual_line = this_started_from + (height - 1)
- last_screen_line = @scroll_partial_screen + (@screen_height - 1)
- if (@scroll_partial_screen - this_started_from) >= height
- # Render nothing because this line is before the screen.
- visual_lines = []
- elsif this_started_from > last_screen_line
- # Render nothing because this line is after the screen.
- visual_lines = []
- else
- deleted_lines_before_screen = []
- if @scroll_partial_screen > this_started_from and last_visual_line >= @scroll_partial_screen
- # A part of visual lines are before the screen.
- deleted_lines_before_screen = visual_lines.shift((@scroll_partial_screen - this_started_from) * 2)
- deleted_lines_before_screen.compact!
- end
- if this_started_from <= last_screen_line and last_screen_line < last_visual_line
- # A part of visual lines are after the screen.
- visual_lines.pop((last_visual_line - last_screen_line) * 2)
- end
- move_cursor_up(deleted_lines_before_screen.size - @started_from)
- cursor_up_from_last_line = @started_from - deleted_lines_before_screen.size
- end
- end
- if with_control
- if height > @highest_in_this
- diff = height - @highest_in_this
- scroll_down(diff)
- @highest_in_all += diff
- @highest_in_this = height
- move_cursor_up(diff)
- elsif height < @highest_in_this
- diff = @highest_in_this - height
- @highest_in_all -= diff
- @highest_in_this = height
- end
- move_cursor_up(@started_from)
- @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
- cursor_up_from_last_line = height - 1 - @started_from
- end
- if Reline::Unicode::CSI_REGEXP.match?(prompt + line_to_render)
- @output.write "\e[0m" # clear character decorations
- end
- visual_lines.each_with_index do |line, index|
- Reline::IOGate.move_cursor_column(0)
- if line.nil?
- if calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last
- # reaches the end of line
- if Reline::IOGate.win? and Reline::IOGate.win_legacy_console?
- # A newline is automatically inserted if a character is rendered at
- # eol on command prompt.
- else
- # When the cursor is at the end of the line and erases characters
- # after the cursor, some terminals delete the character at the
- # cursor position.
- move_cursor_down(1)
- Reline::IOGate.move_cursor_column(0)
- end
- else
- Reline::IOGate.erase_after_cursor
- move_cursor_down(1)
- Reline::IOGate.move_cursor_column(0)
- end
- next
- end
- @output.write line
- if Reline::IOGate.win? and Reline::IOGate.win_legacy_console? and calculate_width(line, true) == Reline::IOGate.get_screen_size.last
- # A newline is automatically inserted if a character is rendered at eol on command prompt.
- @rest_height -= 1 if @rest_height > 0
- end
- @output.flush
- if @first_prompt
- @first_prompt = false
- @pre_input_hook&.call
- end
- end
- unless visual_lines.empty?
- Reline::IOGate.erase_after_cursor
- Reline::IOGate.move_cursor_column(0)
- end
- if with_control
- # Just after rendring, so the cursor is on the last line.
- if finished?
- Reline::IOGate.move_cursor_column(0)
- else
- # Moves up from bottom of lines to the cursor position.
- move_cursor_up(cursor_up_from_last_line)
- # This logic is buggy if a fullwidth char is wrapped because there is only one halfwidth at end of a line.
- Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
- end
- end
- height
- end
-
- private def modify_lines(before)
- return before if before.nil? || before.empty? || simplified_rendering?
-
- if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: finished?)
- after.lines("\n").map { |l| l.chomp('') }
- else
- before
- end
- end
-
- private def show_menu
- scroll_down(@highest_in_all - @first_line_started_from)
- @rerender_all = true
- @menu_info.list.sort!.each do |item|
- Reline::IOGate.move_cursor_column(0)
- @output.write item
- @output.flush
- scroll_down(1)
- end
- scroll_down(@highest_in_all - 1)
- move_cursor_up(@highest_in_all - 1 - @first_line_started_from)
- end
-
- private def clear_screen_buffer(prompt, prompt_list, prompt_width)
- Reline::IOGate.clear_screen
- back = 0
- modify_lines(whole_lines).each_with_index do |line, index|
- if @prompt_proc
- pr = prompt_list[index]
- height = render_partial(pr, calculate_width(pr), line, back, with_control: false)
- else
- height = render_partial(prompt, prompt_width, line, back, with_control: false)
- end
- if index < (@buffer_of_lines.size - 1)
- move_cursor_down(1)
- back += height
- end
- end
- move_cursor_up(back)
- move_cursor_down(@first_line_started_from + @started_from)
- @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
- Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
- end
-
- def editing_mode
- @config.editing_mode
- end
-
- private def menu(target, list)
- @menu_info = MenuInfo.new(target, list)
- end
-
- private def complete_internal_proc(list, is_menu)
- preposing, target, postposing = retrieve_completion_block
- list = list.select { |i|
- if i and not Encoding.compatible?(target.encoding, i.encoding)
- raise Encoding::CompatibilityError, "#{target.encoding.name} is not compatible with #{i.encoding.name}"
- end
- if @config.completion_ignore_case
- i&.downcase&.start_with?(target.downcase)
- else
- i&.start_with?(target)
- end
- }.uniq
- if is_menu
- menu(target, list)
- return nil
- end
- completed = list.inject { |memo, item|
- begin
- memo_mbchars = memo.unicode_normalize.grapheme_clusters
- item_mbchars = item.unicode_normalize.grapheme_clusters
- rescue Encoding::CompatibilityError
- memo_mbchars = memo.grapheme_clusters
- item_mbchars = item.grapheme_clusters
- end
- size = [memo_mbchars.size, item_mbchars.size].min
- result = ''
- size.times do |i|
- if @config.completion_ignore_case
- if memo_mbchars[i].casecmp?(item_mbchars[i])
- result << memo_mbchars[i]
- else
- break
- end
- else
- if memo_mbchars[i] == item_mbchars[i]
- result << memo_mbchars[i]
- else
- break
- end
- end
- end
- result
- }
- [target, preposing, completed, postposing]
- end
-
- private def complete(list, just_show_list = false)
- case @completion_state
- when CompletionState::NORMAL, CompletionState::JOURNEY
- @completion_state = CompletionState::COMPLETION
- when CompletionState::PERFECT_MATCH
- @dig_perfect_match_proc&.(@perfect_matched)
- end
- if just_show_list
- is_menu = true
- elsif @completion_state == CompletionState::MENU
- is_menu = true
- elsif @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH
- is_menu = true
- else
- is_menu = false
- end
- result = complete_internal_proc(list, is_menu)
- if @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH
- @completion_state = CompletionState::PERFECT_MATCH
- end
- return if result.nil?
- target, preposing, completed, postposing = result
- return if completed.nil?
- if target <= completed and (@completion_state == CompletionState::COMPLETION)
- if list.include?(completed)
- if list.one?
- @completion_state = CompletionState::PERFECT_MATCH
- else
- @completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
- end
- @perfect_matched = completed
- else
- @completion_state = CompletionState::MENU
- end
- if not just_show_list and target < completed
- @line = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
- line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n").last || String.new(encoding: @encoding)
- @cursor_max = calculate_width(@line)
- @cursor = calculate_width(line_to_pointer)
- @byte_pointer = line_to_pointer.bytesize
- end
- end
- end
-
- private def move_completed_list(list, direction)
- case @completion_state
- when CompletionState::NORMAL, CompletionState::COMPLETION,
- CompletionState::MENU, CompletionState::MENU_WITH_PERFECT_MATCH
- @completion_state = CompletionState::JOURNEY
- result = retrieve_completion_block
- return if result.nil?
- preposing, target, postposing = result
- @completion_journey_data = CompletionJourneyData.new(
- preposing, postposing,
- [target] + list.select{ |item| item.start_with?(target) }, 0)
- if @completion_journey_data.list.size == 1
- @completion_journey_data.pointer = 0
- else
- case direction
- when :up
- @completion_journey_data.pointer = @completion_journey_data.list.size - 1
- when :down
- @completion_journey_data.pointer = 1
- end
- end
- @completion_state = CompletionState::JOURNEY
- else
- case direction
- when :up
- @completion_journey_data.pointer -= 1
- if @completion_journey_data.pointer < 0
- @completion_journey_data.pointer = @completion_journey_data.list.size - 1
- end
- when :down
- @completion_journey_data.pointer += 1
- if @completion_journey_data.pointer >= @completion_journey_data.list.size
- @completion_journey_data.pointer = 0
- end
- end
- end
- completed = @completion_journey_data.list[@completion_journey_data.pointer]
- new_line = (@completion_journey_data.preposing + completed + @completion_journey_data.postposing).split("\n")[@line_index]
- @line = new_line.nil? ? String.new(encoding: @encoding) : new_line
- line_to_pointer = (@completion_journey_data.preposing + completed).split("\n").last
- line_to_pointer = String.new(encoding: @encoding) if line_to_pointer.nil?
- @cursor_max = calculate_width(@line)
- @cursor = calculate_width(line_to_pointer)
- @byte_pointer = line_to_pointer.bytesize
- end
-
- private def run_for_operators(key, method_symbol, &block)
- if @waiting_operator_proc
- if VI_MOTIONS.include?(method_symbol)
- old_cursor, old_byte_pointer = @cursor, @byte_pointer
- @vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg&.> 1
- block.(true)
- unless @waiting_proc
- cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer
- @cursor, @byte_pointer = old_cursor, old_byte_pointer
- @waiting_operator_proc.(cursor_diff, byte_pointer_diff)
- else
- old_waiting_proc = @waiting_proc
- old_waiting_operator_proc = @waiting_operator_proc
- current_waiting_operator_proc = @waiting_operator_proc
- @waiting_proc = proc { |k|
- old_cursor, old_byte_pointer = @cursor, @byte_pointer
- old_waiting_proc.(k)
- cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer
- @cursor, @byte_pointer = old_cursor, old_byte_pointer
- current_waiting_operator_proc.(cursor_diff, byte_pointer_diff)
- @waiting_operator_proc = old_waiting_operator_proc
- }
- end
- else
- # Ignores operator when not motion is given.
- block.(false)
- end
- @waiting_operator_proc = nil
- @waiting_operator_vi_arg = nil
- if @vi_arg
- @rerender_all = true
- @vi_arg = nil
- end
- else
- block.(false)
- end
- end
-
- private def argumentable?(method_obj)
- method_obj and method_obj.parameters.any? { |param| param[0] == :key and param[1] == :arg }
- end
-
- private def inclusive?(method_obj)
- # If a motion method with the keyword argument "inclusive" follows the
- # operator, it must contain the character at the cursor position.
- method_obj and method_obj.parameters.any? { |param| param[0] == :key and param[1] == :inclusive }
- end
-
- def wrap_method_call(method_symbol, method_obj, key, with_operator = false)
- if @config.editing_mode_is?(:emacs, :vi_insert) and @waiting_proc.nil? and @waiting_operator_proc.nil?
- not_insertion = method_symbol != :ed_insert
- process_insert(force: not_insertion)
- end
- if @vi_arg and argumentable?(method_obj)
- if with_operator and inclusive?(method_obj)
- method_obj.(key, arg: @vi_arg, inclusive: true)
- else
- method_obj.(key, arg: @vi_arg)
- end
- else
- if with_operator and inclusive?(method_obj)
- method_obj.(key, inclusive: true)
- else
- method_obj.(key)
- end
- end
- end
-
- private def process_key(key, method_symbol)
- if method_symbol and respond_to?(method_symbol, true)
- method_obj = method(method_symbol)
- else
- method_obj = nil
- end
- if method_symbol and key.is_a?(Symbol)
- if @vi_arg and argumentable?(method_obj)
- run_for_operators(key, method_symbol) do |with_operator|
- wrap_method_call(method_symbol, method_obj, key, with_operator)
- end
- else
- wrap_method_call(method_symbol, method_obj, key) if method_obj
- end
- @kill_ring.process
- if @vi_arg
- @rerender_al = true
- @vi_arg = nil
- end
- elsif @vi_arg
- if key.chr =~ /[0-9]/
- ed_argument_digit(key)
- else
- if argumentable?(method_obj)
- run_for_operators(key, method_symbol) do |with_operator|
- wrap_method_call(method_symbol, method_obj, key, with_operator)
- end
- elsif @waiting_proc
- @waiting_proc.(key)
- elsif method_obj
- wrap_method_call(method_symbol, method_obj, key)
- else
- ed_insert(key) unless @config.editing_mode_is?(:vi_command)
- end
- @kill_ring.process
- if @vi_arg
- @rerender_all = true
- @vi_arg = nil
- end
- end
- elsif @waiting_proc
- @waiting_proc.(key)
- @kill_ring.process
- elsif method_obj
- if method_symbol == :ed_argument_digit
- wrap_method_call(method_symbol, method_obj, key)
- else
- run_for_operators(key, method_symbol) do |with_operator|
- wrap_method_call(method_symbol, method_obj, key, with_operator)
- end
- end
- @kill_ring.process
- else
- ed_insert(key) unless @config.editing_mode_is?(:vi_command)
- end
- end
-
- private def normal_char(key)
- method_symbol = method_obj = nil
- if key.combined_char.is_a?(Symbol)
- process_key(key.combined_char, key.combined_char)
- return
- end
- @multibyte_buffer << key.combined_char
- if @multibyte_buffer.size > 1
- if @multibyte_buffer.dup.force_encoding(@encoding).valid_encoding?
- process_key(@multibyte_buffer.dup.force_encoding(@encoding), nil)
- @multibyte_buffer.clear
- else
- # invalid
- return
- end
- else # single byte
- return if key.char >= 128 # maybe, first byte of multi byte
- method_symbol = @config.editing_mode.get_method(key.combined_char)
- if key.with_meta and method_symbol == :ed_unassigned
- # split ESC + key
- method_symbol = @config.editing_mode.get_method("\e".ord)
- process_key("\e".ord, method_symbol)
- method_symbol = @config.editing_mode.get_method(key.char)
- process_key(key.char, method_symbol)
- else
- process_key(key.combined_char, method_symbol)
- end
- @multibyte_buffer.clear
- end
- if @config.editing_mode_is?(:vi_command) and @cursor > 0 and @cursor == @cursor_max
- byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
- @byte_pointer -= byte_size
- mbchar = @line.byteslice(@byte_pointer, byte_size)
- width = Reline::Unicode.get_mbchar_width(mbchar)
- @cursor -= width
- end
- end
-
- def input_key(key)
- @last_key = key
- @config.reset_oneshot_key_bindings
- @dialogs.each do |dialog|
- if key.char.instance_of?(Symbol) and key.char == dialog.name
- return
- end
- end
- @just_cursor_moving = nil
- if key.char.nil?
- if @first_char
- @line = nil
- end
- finish
- return
- end
- old_line = @line.dup
- @first_char = false
- completion_occurs = false
- if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
- unless @config.disable_completion
- result = call_completion_proc
- if result.is_a?(Array)
- completion_occurs = true
- process_insert
- if @config.autocompletion
- move_completed_list(result, :down)
- else
- complete(result)
- end
- end
- end
- elsif @config.editing_mode_is?(:emacs, :vi_insert) and key.char == :completion_journey_up
- if not @config.disable_completion and @config.autocompletion
- result = call_completion_proc
- if result.is_a?(Array)
- completion_occurs = true
- process_insert
- move_completed_list(result, :up)
- end
- end
- elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
- unless @config.disable_completion
- result = call_completion_proc
- if result.is_a?(Array)
- completion_occurs = true
- process_insert
- move_completed_list(result, "\C-p".ord == key.char ? :up : :down)
- end
- end
- elsif Symbol === key.char and respond_to?(key.char, true)
- process_key(key.char, key.char)
- else
- normal_char(key)
- end
- unless completion_occurs
- @completion_state = CompletionState::NORMAL
- @completion_journey_data = nil
- end
- if not @in_pasting and @just_cursor_moving.nil?
- if @previous_line_index and @buffer_of_lines[@previous_line_index] == @line
- @just_cursor_moving = true
- elsif @previous_line_index.nil? and @buffer_of_lines[@line_index] == @line and old_line == @line
- @just_cursor_moving = true
- else
- @just_cursor_moving = false
- end
- else
- @just_cursor_moving = false
- end
- if @is_multiline and @auto_indent_proc and not simplified_rendering?
- process_auto_indent
- end
- end
-
- def call_completion_proc
- result = retrieve_completion_block(true)
- pre, target, post = result
- result = call_completion_proc_with_checking_args(pre, target, post)
- Reline.core.instance_variable_set(:@completion_quote_character, nil)
- result
- end
-
- def call_completion_proc_with_checking_args(pre, target, post)
- if @completion_proc and target
- argnum = @completion_proc.parameters.inject(0) { |result, item|
- case item.first
- when :req, :opt
- result + 1
- when :rest
- break 3
- end
- }
- case argnum
- when 1
- result = @completion_proc.(target)
- when 2
- result = @completion_proc.(target, pre)
- when 3..Float::INFINITY
- result = @completion_proc.(target, pre, post)
- end
- end
- result
- end
-
- private def process_auto_indent
- return if not @check_new_auto_indent and @previous_line_index # move cursor up or down
- if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index
- # Fix indent of a line when a newline is inserted to the next
- new_lines = whole_lines
- new_indent = @auto_indent_proc.(new_lines[0..-3].push(''), @line_index - 1, 0, true)
- md = @line.match(/\A */)
- prev_indent = md[0].count(' ')
- @line = ' ' * new_indent + @line.lstrip
-
- new_indent = nil
- result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[-2].size + 1), false)
- if result
- new_indent = result
- end
- if new_indent&.>= 0
- @line = ' ' * new_indent + @line.lstrip
- end
- end
- new_lines = whole_lines
- new_indent = @auto_indent_proc.(new_lines, @line_index, @byte_pointer, @check_new_auto_indent)
- if new_indent&.>= 0
- md = new_lines[@line_index].match(/\A */)
- prev_indent = md[0].count(' ')
- if @check_new_auto_indent
- line = @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
- @cursor = new_indent
- @cursor_max = calculate_width(line)
- @byte_pointer = new_indent
- else
- @line = ' ' * new_indent + @line.lstrip
- @cursor += new_indent - prev_indent
- @cursor_max = calculate_width(@line)
- @byte_pointer += new_indent - prev_indent
- end
- end
- @check_new_auto_indent = false
- end
-
- def retrieve_completion_block(set_completion_quote_character = false)
- if Reline.completer_word_break_characters.empty?
- word_break_regexp = nil
- else
- word_break_regexp = /\A[#{Regexp.escape(Reline.completer_word_break_characters)}]/
- end
- if Reline.completer_quote_characters.empty?
- quote_characters_regexp = nil
- else
- quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/
- end
- before = @line.byteslice(0, @byte_pointer)
- rest = nil
- break_pointer = nil
- quote = nil
- closing_quote = nil
- escaped_quote = nil
- i = 0
- while i < @byte_pointer do
- slice = @line.byteslice(i, @byte_pointer - i)
- unless slice.valid_encoding?
- i += 1
- next
- end
- if quote and slice.start_with?(closing_quote)
- quote = nil
- i += 1
- rest = nil
- elsif quote and slice.start_with?(escaped_quote)
- # skip
- i += 2
- elsif quote_characters_regexp and slice =~ quote_characters_regexp # find new "
- rest = $'
- quote = $&
- closing_quote = /(?!\\)#{Regexp.escape(quote)}/
- escaped_quote = /\\#{Regexp.escape(quote)}/
- i += 1
- break_pointer = i - 1
- elsif word_break_regexp and not quote and slice =~ word_break_regexp
- rest = $'
- i += 1
- before = @line.byteslice(i, @byte_pointer - i)
- break_pointer = i
- else
- i += 1
- end
- end
- postposing = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
- if rest
- preposing = @line.byteslice(0, break_pointer)
- target = rest
- if set_completion_quote_character and quote
- Reline.core.instance_variable_set(:@completion_quote_character, quote)
- if postposing !~ /(?!\\)#{Regexp.escape(quote)}/ # closing quote
- insert_text(quote)
- end
- end
- else
- preposing = ''
- if break_pointer
- preposing = @line.byteslice(0, break_pointer)
- else
- preposing = ''
- end
- target = before
- end
- if @is_multiline
- lines = whole_lines
- if @line_index > 0
- preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
- end
- if (lines.size - 1) > @line_index
- postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
- end
- end
- [preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
- end
-
- def confirm_multiline_termination
- temp_buffer = @buffer_of_lines.dup
- if @previous_line_index and @line_index == (@buffer_of_lines.size - 1)
- temp_buffer[@previous_line_index] = @line
- else
- temp_buffer[@line_index] = @line
- end
- @confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
- end
-
- def insert_text(text)
- width = calculate_width(text)
- if @cursor == @cursor_max
- @line += text
- else
- @line = byteinsert(@line, @byte_pointer, text)
- end
- @byte_pointer += text.bytesize
- @cursor += width
- @cursor_max += width
- end
-
- def delete_text(start = nil, length = nil)
- if start.nil? and length.nil?
- if @is_multiline
- if @buffer_of_lines.size == 1
- @line&.clear
- @byte_pointer = 0
- @cursor = 0
- @cursor_max = 0
- elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
- @buffer_of_lines.pop
- @line_index -= 1
- @line = @buffer_of_lines[@line_index]
- @byte_pointer = 0
- @cursor = 0
- @cursor_max = calculate_width(@line)
- elsif @line_index < (@buffer_of_lines.size - 1)
- @buffer_of_lines.delete_at(@line_index)
- @line = @buffer_of_lines[@line_index]
- @byte_pointer = 0
- @cursor = 0
- @cursor_max = calculate_width(@line)
- end
- else
- @line&.clear
- @byte_pointer = 0
- @cursor = 0
- @cursor_max = 0
- end
- elsif not start.nil? and not length.nil?
- if @line
- before = @line.byteslice(0, start)
- after = @line.byteslice(start + length, @line.bytesize)
- @line = before + after
- @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
- str = @line.byteslice(0, @byte_pointer)
- @cursor = calculate_width(str)
- @cursor_max = calculate_width(@line)
- end
- elsif start.is_a?(Range)
- range = start
- first = range.first
- last = range.last
- last = @line.bytesize - 1 if last > @line.bytesize
- last += @line.bytesize if last < 0
- first += @line.bytesize if first < 0
- range = range.exclude_end? ? first...last : first..last
- @line = @line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(@encoding)
- @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
- str = @line.byteslice(0, @byte_pointer)
- @cursor = calculate_width(str)
- @cursor_max = calculate_width(@line)
- else
- @line = @line.byteslice(0, start)
- @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
- str = @line.byteslice(0, @byte_pointer)
- @cursor = calculate_width(str)
- @cursor_max = calculate_width(@line)
- end
- end
-
- def byte_pointer=(val)
- @byte_pointer = val
- str = @line.byteslice(0, @byte_pointer)
- @cursor = calculate_width(str)
- @cursor_max = calculate_width(@line)
- end
-
- def whole_lines
- index = @previous_line_index || @line_index
- temp_lines = @buffer_of_lines.dup
- temp_lines[index] = @line
- temp_lines
- end
-
- def whole_buffer
- if @buffer_of_lines.size == 1 and @line.nil?
- nil
- else
- whole_lines.join("\n")
- end
- end
-
- def finished?
- @finished
- end
-
- def finish
- @finished = true
- @rerender_all = true
- @config.reset
- end
-
- private def byteslice!(str, byte_pointer, size)
- new_str = str.byteslice(0, byte_pointer)
- new_str << str.byteslice(byte_pointer + size, str.bytesize)
- [new_str, str.byteslice(byte_pointer, size)]
- end
-
- private def byteinsert(str, byte_pointer, other)
- new_str = str.byteslice(0, byte_pointer)
- new_str << other
- new_str << str.byteslice(byte_pointer, str.bytesize)
- new_str
- end
-
- private def calculate_width(str, allow_escape_code = false)
- Reline::Unicode.calculate_width(str, allow_escape_code)
- end
-
- private def key_delete(key)
- if @config.editing_mode_is?(:vi_insert, :emacs)
- ed_delete_next_char(key)
- end
- end
-
- private def key_newline(key)
- if @is_multiline
- if (@buffer_of_lines.size - 1) == @line_index and @line.bytesize == @byte_pointer
- @add_newline_to_end_of_buffer = true
- end
- next_line = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
- cursor_line = @line.byteslice(0, @byte_pointer)
- insert_new_line(cursor_line, next_line)
- @cursor = 0
- @check_new_auto_indent = true unless @in_pasting
- end
- end
-
- # Editline:: +ed-unassigned+ This editor command always results in an error.
- # GNU Readline:: There is no corresponding macro.
- private def ed_unassigned(key) end # do nothing
-
- private def process_insert(force: false)
- return if @continuous_insertion_buffer.empty? or (@in_pasting and not force)
- width = Reline::Unicode.calculate_width(@continuous_insertion_buffer)
- bytesize = @continuous_insertion_buffer.bytesize
- if @cursor == @cursor_max
- @line += @continuous_insertion_buffer
- else
- @line = byteinsert(@line, @byte_pointer, @continuous_insertion_buffer)
- end
- @byte_pointer += bytesize
- @cursor += width
- @cursor_max += width
- @continuous_insertion_buffer.clear
- end
-
- # Editline:: +ed-insert+ (vi input: almost all; emacs: printable characters)
- # In insert mode, insert the input character left of the cursor
- # position. In replace mode, overwrite the character at the
- # cursor and move the cursor to the right by one character
- # position. Accept an argument to do this repeatedly. It is an
- # error if the input character is the NUL character (+Ctrl-@+).
- # Failure to enlarge the edit buffer also results in an error.
- # Editline:: +ed-digit+ (emacs: 0 to 9) If in argument input mode, append
- # the input digit to the argument being read. Otherwise, call
- # +ed-insert+. It is an error if the input character is not a
- # digit or if the existing argument is already greater than a
- # million.
- # GNU Readline:: +self-insert+ (a, b, A, 1, !, …) Insert yourself.
- private def ed_insert(key)
- str = nil
- width = nil
- bytesize = nil
- if key.instance_of?(String)
- begin
- key.encode(Encoding::UTF_8)
- rescue Encoding::UndefinedConversionError
- return
- end
- str = key
- bytesize = key.bytesize
- else
- begin
- key.chr.encode(Encoding::UTF_8)
- rescue Encoding::UndefinedConversionError
- return
- end
- str = key.chr
- bytesize = 1
- end
- if @in_pasting
- @continuous_insertion_buffer << str
- return
- elsif not @continuous_insertion_buffer.empty?
- process_insert
- end
- width = Reline::Unicode.get_mbchar_width(str)
- if @cursor == @cursor_max
- @line += str
- else
- @line = byteinsert(@line, @byte_pointer, str)
- end
- last_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
- @byte_pointer += bytesize
- last_mbchar = @line.byteslice((@byte_pointer - bytesize - last_byte_size), last_byte_size)
- combined_char = last_mbchar + str
- if last_byte_size != 0 and combined_char.grapheme_clusters.size == 1
- # combined char
- last_mbchar_width = Reline::Unicode.get_mbchar_width(last_mbchar)
- combined_char_width = Reline::Unicode.get_mbchar_width(combined_char)
- if combined_char_width > last_mbchar_width
- width = combined_char_width - last_mbchar_width
- else
- width = 0
- end
- end
- @cursor += width
- @cursor_max += width
- end
- alias_method :ed_digit, :ed_insert
- alias_method :self_insert, :ed_insert
-
- private def ed_quoted_insert(str, arg: 1)
- @waiting_proc = proc { |key|
- arg.times do
- if key == "\C-j".ord or key == "\C-m".ord
- key_newline(key)
- elsif key == 0
- # Ignore NUL.
- else
- ed_insert(key)
- end
- end
- @waiting_proc = nil
- }
- end
- alias_method :quoted_insert, :ed_quoted_insert
-
- private def ed_next_char(key, arg: 1)
- byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
- if (@byte_pointer < @line.bytesize)
- mbchar = @line.byteslice(@byte_pointer, byte_size)
- width = Reline::Unicode.get_mbchar_width(mbchar)
- @cursor += width if width
- @byte_pointer += byte_size
- elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == @line.bytesize and @line_index < @buffer_of_lines.size - 1
- next_line = @buffer_of_lines[@line_index + 1]
- @cursor = 0
- @byte_pointer = 0
- @cursor_max = calculate_width(next_line)
- @previous_line_index = @line_index
- @line_index += 1
- end
- arg -= 1
- ed_next_char(key, arg: arg) if arg > 0
- end
- alias_method :forward_char, :ed_next_char
-
- private def ed_prev_char(key, arg: 1)
- if @cursor > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
- @byte_pointer -= byte_size
- mbchar = @line.byteslice(@byte_pointer, byte_size)
- width = Reline::Unicode.get_mbchar_width(mbchar)
- @cursor -= width
- elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
- prev_line = @buffer_of_lines[@line_index - 1]
- @cursor = calculate_width(prev_line)
- @byte_pointer = prev_line.bytesize
- @cursor_max = calculate_width(prev_line)
- @previous_line_index = @line_index
- @line_index -= 1
- end
- arg -= 1
- ed_prev_char(key, arg: arg) if arg > 0
- end
- alias_method :backward_char, :ed_prev_char
-
- private def vi_first_print(key)
- @byte_pointer, @cursor = Reline::Unicode.vi_first_print(@line)
- end
-
- private def ed_move_to_beg(key)
- @byte_pointer = @cursor = 0
- end
- alias_method :beginning_of_line, :ed_move_to_beg
-
- private def ed_move_to_end(key)
- @byte_pointer = 0
- @cursor = 0
- byte_size = 0
- while @byte_pointer < @line.bytesize
- byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
- if byte_size > 0
- mbchar = @line.byteslice(@byte_pointer, byte_size)
- @cursor += Reline::Unicode.get_mbchar_width(mbchar)
- end
- @byte_pointer += byte_size
- end
- end
- alias_method :end_of_line, :ed_move_to_end
-
- private def generate_searcher
- Fiber.new do |first_key|
- prev_search_key = first_key
- search_word = String.new(encoding: @encoding)
- multibyte_buf = String.new(encoding: 'ASCII-8BIT')
- last_hit = nil
- case first_key
- when "\C-r".ord
- prompt_name = 'reverse-i-search'
- when "\C-s".ord
- prompt_name = 'i-search'
- end
- loop do
- key = Fiber.yield(search_word)
- search_again = false
- case key
- when -1 # determined
- Reline.last_incremental_search = search_word
- break
- when "\C-h".ord, "\C-?".ord
- grapheme_clusters = search_word.grapheme_clusters
- if grapheme_clusters.size > 0
- grapheme_clusters.pop
- search_word = grapheme_clusters.join
- end
- when "\C-r".ord, "\C-s".ord
- search_again = true if prev_search_key == key
- prev_search_key = key
- else
- multibyte_buf << key
- if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
- search_word << multibyte_buf.dup.force_encoding(@encoding)
- multibyte_buf.clear
- end
- end
- hit = nil
- if not search_word.empty? and @line_backup_in_history&.include?(search_word)
- @history_pointer = nil
- hit = @line_backup_in_history
- else
- if search_again
- if search_word.empty? and Reline.last_incremental_search
- search_word = Reline.last_incremental_search
- end
- if @history_pointer
- case prev_search_key
- when "\C-r".ord
- history_pointer_base = 0
- history = Reline::HISTORY[0..(@history_pointer - 1)]
- when "\C-s".ord
- history_pointer_base = @history_pointer + 1
- history = Reline::HISTORY[(@history_pointer + 1)..-1]
- end
- else
- history_pointer_base = 0
- history = Reline::HISTORY
- end
- elsif @history_pointer
- case prev_search_key
- when "\C-r".ord
- history_pointer_base = 0
- history = Reline::HISTORY[0..@history_pointer]
- when "\C-s".ord
- history_pointer_base = @history_pointer
- history = Reline::HISTORY[@history_pointer..-1]
- end
- else
- history_pointer_base = 0
- history = Reline::HISTORY
- end
- case prev_search_key
- when "\C-r".ord
- hit_index = history.rindex { |item|
- item.include?(search_word)
- }
- when "\C-s".ord
- hit_index = history.index { |item|
- item.include?(search_word)
- }
- end
- if hit_index
- @history_pointer = history_pointer_base + hit_index
- hit = Reline::HISTORY[@history_pointer]
- end
- end
- case prev_search_key
- when "\C-r".ord
- prompt_name = 'reverse-i-search'
- when "\C-s".ord
- prompt_name = 'i-search'
- end
- if hit
- if @is_multiline
- @buffer_of_lines = hit.split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = @buffer_of_lines.size - 1
- @line = @buffer_of_lines.last
- @byte_pointer = @line.bytesize
- @cursor = @cursor_max = calculate_width(@line)
- @rerender_all = true
- @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
- else
- @line = hit
- @searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
- end
- last_hit = hit
- else
- if @is_multiline
- @rerender_all = true
- @searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
- else
- @searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
- end
- end
- end
- end
- end
-
- private def incremental_search_history(key)
- unless @history_pointer
- if @is_multiline
- @line_backup_in_history = whole_buffer
- else
- @line_backup_in_history = @line
- end
- end
- searcher = generate_searcher
- searcher.resume(key)
- @searching_prompt = "(reverse-i-search)`': "
- termination_keys = ["\C-j".ord]
- termination_keys.concat(@config.isearch_terminators&.chars&.map(&:ord)) if @config.isearch_terminators
- @waiting_proc = ->(k) {
- case k
- when *termination_keys
- if @history_pointer
- buffer = Reline::HISTORY[@history_pointer]
- else
- buffer = @line_backup_in_history
- end
- if @is_multiline
- @buffer_of_lines = buffer.split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = @buffer_of_lines.size - 1
- @line = @buffer_of_lines.last
- @rerender_all = true
- else
- @line = buffer
- end
- @searching_prompt = nil
- @waiting_proc = nil
- @cursor_max = calculate_width(@line)
- @cursor = @byte_pointer = 0
- @rerender_all = true
- @cached_prompt_list = nil
- searcher.resume(-1)
- when "\C-g".ord
- if @is_multiline
- @buffer_of_lines = @line_backup_in_history.split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = @buffer_of_lines.size - 1
- @line = @buffer_of_lines.last
- @rerender_all = true
- else
- @line = @line_backup_in_history
- end
- @history_pointer = nil
- @searching_prompt = nil
- @waiting_proc = nil
- @line_backup_in_history = nil
- @cursor_max = calculate_width(@line)
- @cursor = @byte_pointer = 0
- @rerender_all = true
- else
- chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
- if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
- searcher.resume(k)
- else
- if @history_pointer
- line = Reline::HISTORY[@history_pointer]
- else
- line = @line_backup_in_history
- end
- if @is_multiline
- @line_backup_in_history = whole_buffer
- @buffer_of_lines = line.split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = @buffer_of_lines.size - 1
- @line = @buffer_of_lines.last
- @rerender_all = true
- else
- @line_backup_in_history = @line
- @line = line
- end
- @searching_prompt = nil
- @waiting_proc = nil
- @cursor_max = calculate_width(@line)
- @cursor = @byte_pointer = 0
- @rerender_all = true
- @cached_prompt_list = nil
- searcher.resume(-1)
- end
- end
- }
- end
-
- private def vi_search_prev(key)
- incremental_search_history(key)
- end
- alias_method :reverse_search_history, :vi_search_prev
-
- private def vi_search_next(key)
- incremental_search_history(key)
- end
- alias_method :forward_search_history, :vi_search_next
-
- private def ed_search_prev_history(key, arg: 1)
- history = nil
- h_pointer = nil
- line_no = nil
- substr = @line.slice(0, @byte_pointer)
- if @history_pointer.nil?
- return if not @line.empty? and substr.empty?
- history = Reline::HISTORY
- elsif @history_pointer.zero?
- history = nil
- h_pointer = nil
- else
- history = Reline::HISTORY.slice(0, @history_pointer)
- end
- return if history.nil?
- if @is_multiline
- h_pointer = history.rindex { |h|
- h.split("\n").each_with_index { |l, i|
- if l.start_with?(substr)
- line_no = i
- break
- end
- }
- not line_no.nil?
- }
- else
- h_pointer = history.rindex { |l|
- l.start_with?(substr)
- }
- end
- return if h_pointer.nil?
- @history_pointer = h_pointer
- if @is_multiline
- @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = line_no
- @line = @buffer_of_lines[@line_index]
- @rerender_all = true
- else
- @line = Reline::HISTORY[@history_pointer]
- end
- @cursor_max = calculate_width(@line)
- arg -= 1
- ed_search_prev_history(key, arg: arg) if arg > 0
- end
- alias_method :history_search_backward, :ed_search_prev_history
-
- private def ed_search_next_history(key, arg: 1)
- substr = @line.slice(0, @byte_pointer)
- if @history_pointer.nil?
- return
- elsif @history_pointer == (Reline::HISTORY.size - 1) and not substr.empty?
- return
- end
- history = Reline::HISTORY.slice((@history_pointer + 1)..-1)
- h_pointer = nil
- line_no = nil
- if @is_multiline
- h_pointer = history.index { |h|
- h.split("\n").each_with_index { |l, i|
- if l.start_with?(substr)
- line_no = i
- break
- end
- }
- not line_no.nil?
- }
- else
- h_pointer = history.index { |l|
- l.start_with?(substr)
- }
- end
- h_pointer += @history_pointer + 1 if h_pointer and @history_pointer
- return if h_pointer.nil? and not substr.empty?
- @history_pointer = h_pointer
- if @is_multiline
- if @history_pointer.nil? and substr.empty?
- @buffer_of_lines = []
- @line_index = 0
- else
- @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
- @line_index = line_no
- end
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line = @buffer_of_lines[@line_index]
- @rerender_all = true
- else
- if @history_pointer.nil? and substr.empty?
- @line = ''
- else
- @line = Reline::HISTORY[@history_pointer]
- end
- end
- @cursor_max = calculate_width(@line)
- arg -= 1
- ed_search_next_history(key, arg: arg) if arg > 0
- end
- alias_method :history_search_forward, :ed_search_next_history
-
- private def ed_prev_history(key, arg: 1)
- if @is_multiline and @line_index > 0
- @previous_line_index = @line_index
- @line_index -= 1
- return
- end
- if Reline::HISTORY.empty?
- return
- end
- if @history_pointer.nil?
- @history_pointer = Reline::HISTORY.size - 1
- if @is_multiline
- @line_backup_in_history = whole_buffer
- @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = @buffer_of_lines.size - 1
- @line = @buffer_of_lines.last
- @rerender_all = true
- else
- @line_backup_in_history = @line
- @line = Reline::HISTORY[@history_pointer]
- end
- elsif @history_pointer.zero?
- return
- else
- if @is_multiline
- Reline::HISTORY[@history_pointer] = whole_buffer
- @history_pointer -= 1
- @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = @buffer_of_lines.size - 1
- @line = @buffer_of_lines.last
- @rerender_all = true
- else
- Reline::HISTORY[@history_pointer] = @line
- @history_pointer -= 1
- @line = Reline::HISTORY[@history_pointer]
- end
- end
- if @config.editing_mode_is?(:emacs, :vi_insert)
- @cursor_max = @cursor = calculate_width(@line)
- @byte_pointer = @line.bytesize
- elsif @config.editing_mode_is?(:vi_command)
- @byte_pointer = @cursor = 0
- @cursor_max = calculate_width(@line)
- end
- arg -= 1
- ed_prev_history(key, arg: arg) if arg > 0
- end
- alias_method :previous_history, :ed_prev_history
-
- private def ed_next_history(key, arg: 1)
- if @is_multiline and @line_index < (@buffer_of_lines.size - 1)
- @previous_line_index = @line_index
- @line_index += 1
- return
- end
- if @history_pointer.nil?
- return
- elsif @history_pointer == (Reline::HISTORY.size - 1)
- if @is_multiline
- @history_pointer = nil
- @buffer_of_lines = @line_backup_in_history.split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = 0
- @line = @buffer_of_lines.first
- @rerender_all = true
- else
- @history_pointer = nil
- @line = @line_backup_in_history
- end
- else
- if @is_multiline
- Reline::HISTORY[@history_pointer] = whole_buffer
- @history_pointer += 1
- @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = 0
- @line = @buffer_of_lines.first
- @rerender_all = true
- else
- Reline::HISTORY[@history_pointer] = @line
- @history_pointer += 1
- @line = Reline::HISTORY[@history_pointer]
- end
- end
- @line = '' unless @line
- if @config.editing_mode_is?(:emacs, :vi_insert)
- @cursor_max = @cursor = calculate_width(@line)
- @byte_pointer = @line.bytesize
- elsif @config.editing_mode_is?(:vi_command)
- @byte_pointer = @cursor = 0
- @cursor_max = calculate_width(@line)
- end
- arg -= 1
- ed_next_history(key, arg: arg) if arg > 0
- end
- alias_method :next_history, :ed_next_history
-
- private def ed_newline(key)
- process_insert(force: true)
- if @is_multiline
- if @config.editing_mode_is?(:vi_command)
- if @line_index < (@buffer_of_lines.size - 1)
- ed_next_history(key) # means cursor down
- else
- # should check confirm_multiline_termination to finish?
- finish
- end
- else
- if @line_index == (@buffer_of_lines.size - 1)
- if confirm_multiline_termination
- finish
- else
- key_newline(key)
- end
- else
- # should check confirm_multiline_termination to finish?
- @previous_line_index = @line_index
- @line_index = @buffer_of_lines.size - 1
- finish
- end
- end
- else
- if @history_pointer
- Reline::HISTORY[@history_pointer] = @line
- @history_pointer = nil
- end
- finish
- end
- end
-
- private def em_delete_prev_char(key, arg: 1)
- if @is_multiline and @cursor == 0 and @line_index > 0
- @buffer_of_lines[@line_index] = @line
- @cursor = calculate_width(@buffer_of_lines[@line_index - 1])
- @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
- @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
- @line_index -= 1
- @line = @buffer_of_lines[@line_index]
- @cursor_max = calculate_width(@line)
- @rerender_all = true
- elsif @cursor > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
- @byte_pointer -= byte_size
- @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
- width = Reline::Unicode.get_mbchar_width(mbchar)
- @cursor -= width
- @cursor_max -= width
- end
- arg -= 1
- em_delete_prev_char(key, arg: arg) if arg > 0
- end
- alias_method :backward_delete_char, :em_delete_prev_char
-
- # Editline:: +ed-kill-line+ (vi command: +D+, +Ctrl-K+; emacs: +Ctrl-K+,
- # +Ctrl-U+) + Kill from the cursor to the end of the line.
- # GNU Readline:: +kill-line+ (+C-k+) Kill the text from point to the end of
- # the line. With a negative numeric argument, kill backward
- # from the cursor to the beginning of the current line.
- private def ed_kill_line(key)
- if @line.bytesize > @byte_pointer
- @line, deleted = byteslice!(@line, @byte_pointer, @line.bytesize - @byte_pointer)
- @byte_pointer = @line.bytesize
- @cursor = @cursor_max = calculate_width(@line)
- @kill_ring.append(deleted)
- elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1
- @cursor = calculate_width(@line)
- @byte_pointer = @line.bytesize
- @line += @buffer_of_lines.delete_at(@line_index + 1)
- @cursor_max = calculate_width(@line)
- @buffer_of_lines[@line_index] = @line
- @rerender_all = true
- @rest_height += 1
- end
- end
- alias_method :kill_line, :ed_kill_line
-
- # Editline:: +vi-kill-line-prev+ (vi: +Ctrl-U+) Delete the string from the
- # beginning of the edit buffer to the cursor and save it to the
- # cut buffer.
- # GNU Readline:: +unix-line-discard+ (+C-u+) Kill backward from the cursor
- # to the beginning of the current line.
- private def vi_kill_line_prev(key)
- if @byte_pointer > 0
- @line, deleted = byteslice!(@line, 0, @byte_pointer)
- @byte_pointer = 0
- @kill_ring.append(deleted, true)
- @cursor_max = calculate_width(@line)
- @cursor = 0
- end
- end
- alias_method :unix_line_discard, :vi_kill_line_prev
-
- # Editline:: +em-kill-line+ (not bound) Delete the entire contents of the
- # edit buffer and save it to the cut buffer. +vi-kill-line-prev+
- # GNU Readline:: +kill-whole-line+ (not bound) Kill all characters on the
- # current line, no matter where point is.
- private def em_kill_line(key)
- if @line.size > 0
- @kill_ring.append(@line.dup, true)
- @line.clear
- @byte_pointer = 0
- @cursor_max = 0
- @cursor = 0
- end
- end
- alias_method :kill_whole_line, :em_kill_line
-
- private def em_delete(key)
- if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
- @line = nil
- if @buffer_of_lines.size > 1
- scroll_down(@highest_in_all - @first_line_started_from)
- end
- Reline::IOGate.move_cursor_column(0)
- @eof = true
- finish
- elsif @byte_pointer < @line.bytesize
- splitted_last = @line.byteslice(@byte_pointer, @line.bytesize)
- mbchar = splitted_last.grapheme_clusters.first
- width = Reline::Unicode.get_mbchar_width(mbchar)
- @cursor_max -= width
- @line, = byteslice!(@line, @byte_pointer, mbchar.bytesize)
- elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1
- @cursor = calculate_width(@line)
- @byte_pointer = @line.bytesize
- @line += @buffer_of_lines.delete_at(@line_index + 1)
- @cursor_max = calculate_width(@line)
- @buffer_of_lines[@line_index] = @line
- @rerender_all = true
- @rest_height += 1
- end
- end
- alias_method :delete_char, :em_delete
-
- private def em_delete_or_list(key)
- if @line.empty? or @byte_pointer < @line.bytesize
- em_delete(key)
- else # show completed list
- result = call_completion_proc
- if result.is_a?(Array)
- complete(result, true)
- end
- end
- end
- alias_method :delete_char_or_list, :em_delete_or_list
-
- private def em_yank(key)
- yanked = @kill_ring.yank
- if yanked
- @line = byteinsert(@line, @byte_pointer, yanked)
- yanked_width = calculate_width(yanked)
- @cursor += yanked_width
- @cursor_max += yanked_width
- @byte_pointer += yanked.bytesize
- end
- end
- alias_method :yank, :em_yank
-
- private def em_yank_pop(key)
- yanked, prev_yank = @kill_ring.yank_pop
- if yanked
- prev_yank_width = calculate_width(prev_yank)
- @cursor -= prev_yank_width
- @cursor_max -= prev_yank_width
- @byte_pointer -= prev_yank.bytesize
- @line, = byteslice!(@line, @byte_pointer, prev_yank.bytesize)
- @line = byteinsert(@line, @byte_pointer, yanked)
- yanked_width = calculate_width(yanked)
- @cursor += yanked_width
- @cursor_max += yanked_width
- @byte_pointer += yanked.bytesize
- end
- end
- alias_method :yank_pop, :em_yank_pop
-
- private def ed_clear_screen(key)
- @cleared = true
- end
- alias_method :clear_screen, :ed_clear_screen
-
- private def em_next_word(key)
- if @line.bytesize > @byte_pointer
- byte_size, width = Reline::Unicode.em_forward_word(@line, @byte_pointer)
- @byte_pointer += byte_size
- @cursor += width
- end
- end
- alias_method :forward_word, :em_next_word
-
- private def ed_prev_word(key)
- if @byte_pointer > 0
- byte_size, width = Reline::Unicode.em_backward_word(@line, @byte_pointer)
- @byte_pointer -= byte_size
- @cursor -= width
- end
- end
- alias_method :backward_word, :ed_prev_word
-
- private def em_delete_next_word(key)
- if @line.bytesize > @byte_pointer
- byte_size, width = Reline::Unicode.em_forward_word(@line, @byte_pointer)
- @line, word = byteslice!(@line, @byte_pointer, byte_size)
- @kill_ring.append(word)
- @cursor_max -= width
- end
- end
-
- private def ed_delete_prev_word(key)
- if @byte_pointer > 0
- byte_size, width = Reline::Unicode.em_backward_word(@line, @byte_pointer)
- @line, word = byteslice!(@line, @byte_pointer - byte_size, byte_size)
- @kill_ring.append(word, true)
- @byte_pointer -= byte_size
- @cursor -= width
- @cursor_max -= width
- end
- end
-
- private def ed_transpose_chars(key)
- if @byte_pointer > 0
- if @cursor_max > @cursor
- byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
- mbchar = @line.byteslice(@byte_pointer, byte_size)
- width = Reline::Unicode.get_mbchar_width(mbchar)
- @cursor += width
- @byte_pointer += byte_size
- end
- back1_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
- if (@byte_pointer - back1_byte_size) > 0
- back2_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer - back1_byte_size)
- back2_pointer = @byte_pointer - back1_byte_size - back2_byte_size
- @line, back2_mbchar = byteslice!(@line, back2_pointer, back2_byte_size)
- @line = byteinsert(@line, @byte_pointer - back2_byte_size, back2_mbchar)
- end
- end
- end
- alias_method :transpose_chars, :ed_transpose_chars
-
- private def ed_transpose_words(key)
- left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(@line, @byte_pointer)
- before = @line.byteslice(0, left_word_start)
- left_word = @line.byteslice(left_word_start, middle_start - left_word_start)
- middle = @line.byteslice(middle_start, right_word_start - middle_start)
- right_word = @line.byteslice(right_word_start, after_start - right_word_start)
- after = @line.byteslice(after_start, @line.bytesize - after_start)
- return if left_word.empty? or right_word.empty?
- @line = before + right_word + middle + left_word + after
- from_head_to_left_word = before + right_word + middle + left_word
- @byte_pointer = from_head_to_left_word.bytesize
- @cursor = calculate_width(from_head_to_left_word)
- end
- alias_method :transpose_words, :ed_transpose_words
-
- private def em_capitol_case(key)
- if @line.bytesize > @byte_pointer
- byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(@line, @byte_pointer)
- before = @line.byteslice(0, @byte_pointer)
- after = @line.byteslice((@byte_pointer + byte_size)..-1)
- @line = before + new_str + after
- @byte_pointer += new_str.bytesize
- @cursor += calculate_width(new_str)
- end
- end
- alias_method :capitalize_word, :em_capitol_case
-
- private def em_lower_case(key)
- if @line.bytesize > @byte_pointer
- byte_size, = Reline::Unicode.em_forward_word(@line, @byte_pointer)
- part = @line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
- mbchar =~ /[A-Z]/ ? mbchar.downcase : mbchar
- }.join
- rest = @line.byteslice((@byte_pointer + byte_size)..-1)
- @line = @line.byteslice(0, @byte_pointer) + part
- @byte_pointer = @line.bytesize
- @cursor = calculate_width(@line)
- @cursor_max = @cursor + calculate_width(rest)
- @line += rest
- end
- end
- alias_method :downcase_word, :em_lower_case
-
- private def em_upper_case(key)
- if @line.bytesize > @byte_pointer
- byte_size, = Reline::Unicode.em_forward_word(@line, @byte_pointer)
- part = @line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
- mbchar =~ /[a-z]/ ? mbchar.upcase : mbchar
- }.join
- rest = @line.byteslice((@byte_pointer + byte_size)..-1)
- @line = @line.byteslice(0, @byte_pointer) + part
- @byte_pointer = @line.bytesize
- @cursor = calculate_width(@line)
- @cursor_max = @cursor + calculate_width(rest)
- @line += rest
- end
- end
- alias_method :upcase_word, :em_upper_case
-
- private def em_kill_region(key)
- if @byte_pointer > 0
- byte_size, width = Reline::Unicode.em_big_backward_word(@line, @byte_pointer)
- @line, deleted = byteslice!(@line, @byte_pointer - byte_size, byte_size)
- @byte_pointer -= byte_size
- @cursor -= width
- @cursor_max -= width
- @kill_ring.append(deleted, true)
- end
- end
- alias_method :unix_word_rubout, :em_kill_region
-
- private def copy_for_vi(text)
- if @config.editing_mode_is?(:vi_insert) or @config.editing_mode_is?(:vi_command)
- @vi_clipboard = text
- end
- end
-
- private def vi_insert(key)
- @config.editing_mode = :vi_insert
- end
-
- private def vi_add(key)
- @config.editing_mode = :vi_insert
- ed_next_char(key)
- end
-
- private def vi_command_mode(key)
- ed_prev_char(key)
- @config.editing_mode = :vi_command
- end
- alias_method :vi_movement_mode, :vi_command_mode
-
- private def vi_next_word(key, arg: 1)
- if @line.bytesize > @byte_pointer
- byte_size, width = Reline::Unicode.vi_forward_word(@line, @byte_pointer, @drop_terminate_spaces)
- @byte_pointer += byte_size
- @cursor += width
- end
- arg -= 1
- vi_next_word(key, arg: arg) if arg > 0
- end
-
- private def vi_prev_word(key, arg: 1)
- if @byte_pointer > 0
- byte_size, width = Reline::Unicode.vi_backward_word(@line, @byte_pointer)
- @byte_pointer -= byte_size
- @cursor -= width
- end
- arg -= 1
- vi_prev_word(key, arg: arg) if arg > 0
- end
-
- private def vi_end_word(key, arg: 1, inclusive: false)
- if @line.bytesize > @byte_pointer
- byte_size, width = Reline::Unicode.vi_forward_end_word(@line, @byte_pointer)
- @byte_pointer += byte_size
- @cursor += width
- end
- arg -= 1
- if inclusive and arg.zero?
- byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
- if byte_size > 0
- c = @line.byteslice(@byte_pointer, byte_size)
- width = Reline::Unicode.get_mbchar_width(c)
- @byte_pointer += byte_size
- @cursor += width
- end
- end
- vi_end_word(key, arg: arg) if arg > 0
- end
-
- private def vi_next_big_word(key, arg: 1)
- if @line.bytesize > @byte_pointer
- byte_size, width = Reline::Unicode.vi_big_forward_word(@line, @byte_pointer)
- @byte_pointer += byte_size
- @cursor += width
- end
- arg -= 1
- vi_next_big_word(key, arg: arg) if arg > 0
- end
-
- private def vi_prev_big_word(key, arg: 1)
- if @byte_pointer > 0
- byte_size, width = Reline::Unicode.vi_big_backward_word(@line, @byte_pointer)
- @byte_pointer -= byte_size
- @cursor -= width
- end
- arg -= 1
- vi_prev_big_word(key, arg: arg) if arg > 0
- end
-
- private def vi_end_big_word(key, arg: 1, inclusive: false)
- if @line.bytesize > @byte_pointer
- byte_size, width = Reline::Unicode.vi_big_forward_end_word(@line, @byte_pointer)
- @byte_pointer += byte_size
- @cursor += width
- end
- arg -= 1
- if inclusive and arg.zero?
- byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
- if byte_size > 0
- c = @line.byteslice(@byte_pointer, byte_size)
- width = Reline::Unicode.get_mbchar_width(c)
- @byte_pointer += byte_size
- @cursor += width
- end
- end
- vi_end_big_word(key, arg: arg) if arg > 0
- end
-
- private def vi_delete_prev_char(key)
- if @is_multiline and @cursor == 0 and @line_index > 0
- @buffer_of_lines[@line_index] = @line
- @cursor = calculate_width(@buffer_of_lines[@line_index - 1])
- @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
- @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
- @line_index -= 1
- @line = @buffer_of_lines[@line_index]
- @cursor_max = calculate_width(@line)
- @rerender_all = true
- elsif @cursor > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
- @byte_pointer -= byte_size
- @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
- width = Reline::Unicode.get_mbchar_width(mbchar)
- @cursor -= width
- @cursor_max -= width
- end
- end
-
- private def vi_insert_at_bol(key)
- ed_move_to_beg(key)
- @config.editing_mode = :vi_insert
- end
-
- private def vi_add_at_eol(key)
- ed_move_to_end(key)
- @config.editing_mode = :vi_insert
- end
-
- private def ed_delete_prev_char(key, arg: 1)
- deleted = ''
- arg.times do
- if @cursor > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
- @byte_pointer -= byte_size
- @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
- deleted.prepend(mbchar)
- width = Reline::Unicode.get_mbchar_width(mbchar)
- @cursor -= width
- @cursor_max -= width
- end
- end
- copy_for_vi(deleted)
- end
-
- private def vi_zero(key)
- @byte_pointer = 0
- @cursor = 0
- end
-
- private def vi_change_meta(key, arg: 1)
- @drop_terminate_spaces = true
- @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
- if byte_pointer_diff > 0
- @line, cut = byteslice!(@line, @byte_pointer, byte_pointer_diff)
- elsif byte_pointer_diff < 0
- @line, cut = byteslice!(@line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
- end
- copy_for_vi(cut)
- @cursor += cursor_diff if cursor_diff < 0
- @cursor_max -= cursor_diff.abs
- @byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
- @config.editing_mode = :vi_insert
- @drop_terminate_spaces = false
- }
- @waiting_operator_vi_arg = arg
- end
-
- private def vi_delete_meta(key, arg: 1)
- @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
- if byte_pointer_diff > 0
- @line, cut = byteslice!(@line, @byte_pointer, byte_pointer_diff)
- elsif byte_pointer_diff < 0
- @line, cut = byteslice!(@line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
- end
- copy_for_vi(cut)
- @cursor += cursor_diff if cursor_diff < 0
- @cursor_max -= cursor_diff.abs
- @byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
- }
- @waiting_operator_vi_arg = arg
- end
-
- private def vi_yank(key, arg: 1)
- @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
- if byte_pointer_diff > 0
- cut = @line.byteslice(@byte_pointer, byte_pointer_diff)
- elsif byte_pointer_diff < 0
- cut = @line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
- end
- copy_for_vi(cut)
- }
- @waiting_operator_vi_arg = arg
- end
-
- private def vi_list_or_eof(key)
- if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
- @line = nil
- if @buffer_of_lines.size > 1
- scroll_down(@highest_in_all - @first_line_started_from)
- end
- Reline::IOGate.move_cursor_column(0)
- @eof = true
- finish
- else
- ed_newline(key)
- end
- end
- alias_method :vi_end_of_transmission, :vi_list_or_eof
- alias_method :vi_eof_maybe, :vi_list_or_eof
-
- private def ed_delete_next_char(key, arg: 1)
- byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
- unless @line.empty? || byte_size == 0
- @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
- copy_for_vi(mbchar)
- width = Reline::Unicode.get_mbchar_width(mbchar)
- @cursor_max -= width
- if @cursor > 0 and @cursor >= @cursor_max
- byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
- mbchar = @line.byteslice(@byte_pointer - byte_size, byte_size)
- width = Reline::Unicode.get_mbchar_width(mbchar)
- @byte_pointer -= byte_size
- @cursor -= width
- end
- end
- arg -= 1
- ed_delete_next_char(key, arg: arg) if arg > 0
- end
-
- private def vi_to_history_line(key)
- if Reline::HISTORY.empty?
- return
- end
- if @history_pointer.nil?
- @history_pointer = 0
- @line_backup_in_history = @line
- @line = Reline::HISTORY[@history_pointer]
- @cursor_max = calculate_width(@line)
- @cursor = 0
- @byte_pointer = 0
- elsif @history_pointer.zero?
- return
- else
- Reline::HISTORY[@history_pointer] = @line
- @history_pointer = 0
- @line = Reline::HISTORY[@history_pointer]
- @cursor_max = calculate_width(@line)
- @cursor = 0
- @byte_pointer = 0
- end
- end
-
- private def vi_histedit(key)
- path = Tempfile.open { |fp|
- if @is_multiline
- fp.write whole_lines.join("\n")
- else
- fp.write @line
- end
- fp.path
- }
- system("#{ENV['EDITOR']} #{path}")
- if @is_multiline
- @buffer_of_lines = File.read(path).split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = 0
- @line = @buffer_of_lines[@line_index]
- @rerender_all = true
- else
- @line = File.read(path)
- end
- finish
- end
-
- private def vi_paste_prev(key, arg: 1)
- if @vi_clipboard.size > 0
- @line = byteinsert(@line, @byte_pointer, @vi_clipboard)
- @cursor_max += calculate_width(@vi_clipboard)
- cursor_point = @vi_clipboard.grapheme_clusters[0..-2].join
- @cursor += calculate_width(cursor_point)
- @byte_pointer += cursor_point.bytesize
- end
- arg -= 1
- vi_paste_prev(key, arg: arg) if arg > 0
- end
-
- private def vi_paste_next(key, arg: 1)
- if @vi_clipboard.size > 0
- byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
- @line = byteinsert(@line, @byte_pointer + byte_size, @vi_clipboard)
- @cursor_max += calculate_width(@vi_clipboard)
- @cursor += calculate_width(@vi_clipboard)
- @byte_pointer += @vi_clipboard.bytesize
- end
- arg -= 1
- vi_paste_next(key, arg: arg) if arg > 0
- end
-
- private def ed_argument_digit(key)
- if @vi_arg.nil?
- if key.chr.to_i.zero?
- if key.anybits?(0b10000000)
- unescaped_key = key ^ 0b10000000
- unless unescaped_key.chr.to_i.zero?
- @vi_arg = unescaped_key.chr.to_i
- end
- end
- else
- @vi_arg = key.chr.to_i
- end
- else
- @vi_arg = @vi_arg * 10 + key.chr.to_i
- end
- end
-
- private def vi_to_column(key, arg: 0)
- @byte_pointer, @cursor = @line.grapheme_clusters.inject([0, 0]) { |total, gc|
- # total has [byte_size, cursor]
- mbchar_width = Reline::Unicode.get_mbchar_width(gc)
- if (total.last + mbchar_width) >= arg
- break total
- elsif (total.last + mbchar_width) >= @cursor_max
- break total
- else
- total = [total.first + gc.bytesize, total.last + mbchar_width]
- total
- end
- }
- end
-
- private def vi_replace_char(key, arg: 1)
- @waiting_proc = ->(k) {
- if arg == 1
- byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
- before = @line.byteslice(0, @byte_pointer)
- remaining_point = @byte_pointer + byte_size
- after = @line.byteslice(remaining_point, @line.bytesize - remaining_point)
- @line = before + k.chr + after
- @cursor_max = calculate_width(@line)
- @waiting_proc = nil
- elsif arg > 1
- byte_size = 0
- arg.times do
- byte_size += Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer + byte_size)
- end
- before = @line.byteslice(0, @byte_pointer)
- remaining_point = @byte_pointer + byte_size
- after = @line.byteslice(remaining_point, @line.bytesize - remaining_point)
- replaced = k.chr * arg
- @line = before + replaced + after
- @byte_pointer += replaced.bytesize
- @cursor += calculate_width(replaced)
- @cursor_max = calculate_width(@line)
- @waiting_proc = nil
- end
- }
- end
-
- private def vi_next_char(key, arg: 1, inclusive: false)
- @waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg, inclusive: inclusive) }
- end
-
- private def vi_to_next_char(key, arg: 1, inclusive: false)
- @waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg, need_prev_char: true, inclusive: inclusive) }
- end
-
- private def search_next_char(key, arg, need_prev_char: false, inclusive: false)
- if key.instance_of?(String)
- inputed_char = key
- else
- inputed_char = key.chr
- end
- prev_total = nil
- total = nil
- found = false
- @line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
- # total has [byte_size, cursor]
- unless total
- # skip cursor point
- width = Reline::Unicode.get_mbchar_width(mbchar)
- total = [mbchar.bytesize, width]
- else
- if inputed_char == mbchar
- arg -= 1
- if arg.zero?
- found = true
- break
- end
- end
- width = Reline::Unicode.get_mbchar_width(mbchar)
- prev_total = total
- total = [total.first + mbchar.bytesize, total.last + width]
- end
- end
- if not need_prev_char and found and total
- byte_size, width = total
- @byte_pointer += byte_size
- @cursor += width
- elsif need_prev_char and found and prev_total
- byte_size, width = prev_total
- @byte_pointer += byte_size
- @cursor += width
- end
- if inclusive
- byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
- if byte_size > 0
- c = @line.byteslice(@byte_pointer, byte_size)
- width = Reline::Unicode.get_mbchar_width(c)
- @byte_pointer += byte_size
- @cursor += width
- end
- end
- @waiting_proc = nil
- end
-
- private def vi_prev_char(key, arg: 1)
- @waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg) }
- end
-
- private def vi_to_prev_char(key, arg: 1)
- @waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg, true) }
- end
-
- private def search_prev_char(key, arg, need_next_char = false)
- if key.instance_of?(String)
- inputed_char = key
- else
- inputed_char = key.chr
- end
- prev_total = nil
- total = nil
- found = false
- @line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar|
- # total has [byte_size, cursor]
- unless total
- # skip cursor point
- width = Reline::Unicode.get_mbchar_width(mbchar)
- total = [mbchar.bytesize, width]
- else
- if inputed_char == mbchar
- arg -= 1
- if arg.zero?
- found = true
- break
- end
- end
- width = Reline::Unicode.get_mbchar_width(mbchar)
- prev_total = total
- total = [total.first + mbchar.bytesize, total.last + width]
- end
- end
- if not need_next_char and found and total
- byte_size, width = total
- @byte_pointer -= byte_size
- @cursor -= width
- elsif need_next_char and found and prev_total
- byte_size, width = prev_total
- @byte_pointer -= byte_size
- @cursor -= width
- end
- @waiting_proc = nil
- end
-
- private def vi_join_lines(key, arg: 1)
- if @is_multiline and @buffer_of_lines.size > @line_index + 1
- @cursor = calculate_width(@line)
- @byte_pointer = @line.bytesize
- @line += ' ' + @buffer_of_lines.delete_at(@line_index + 1).lstrip
- @cursor_max = calculate_width(@line)
- @buffer_of_lines[@line_index] = @line
- @rerender_all = true
- @rest_height += 1
- end
- arg -= 1
- vi_join_lines(key, arg: arg) if arg > 0
- end
-
- private def em_set_mark(key)
- @mark_pointer = [@byte_pointer, @line_index]
- end
- alias_method :set_mark, :em_set_mark
-
- private def em_exchange_mark(key)
- return unless @mark_pointer
- new_pointer = [@byte_pointer, @line_index]
- @previous_line_index = @line_index
- @byte_pointer, @line_index = @mark_pointer
- @cursor = calculate_width(@line.byteslice(0, @byte_pointer))
- @cursor_max = calculate_width(@line)
- @mark_pointer = new_pointer
- end
- alias_method :exchange_point_and_mark, :em_exchange_mark
-end
diff --git a/lib/reline/reline.gemspec b/lib/reline/reline.gemspec
deleted file mode 100644
index 7bf1f8758b..0000000000
--- a/lib/reline/reline.gemspec
+++ /dev/null
@@ -1,25 +0,0 @@
-
-begin
- require_relative 'lib/reline/version'
-rescue LoadError
- require_relative 'version'
-end
-
-Gem::Specification.new do |spec|
- spec.name = 'reline'
- spec.version = Reline::VERSION
- spec.authors = ['aycabta']
- spec.email = ['aycabta@gmail.com']
-
- spec.summary = %q{Alternative GNU Readline or Editline implementation by pure Ruby.}
- spec.description = %q{Alternative GNU Readline or Editline implementation by pure Ruby.}
- spec.homepage = 'https://github.com/ruby/reline'
- spec.license = 'Ruby'
-
- spec.files = Dir['BSDL', 'COPYING', 'README.md', 'license_of_rb-readline', 'lib/**/*']
- spec.require_paths = ['lib']
-
- spec.required_ruby_version = Gem::Requirement.new('>= 2.6')
-
- spec.add_dependency 'io-console', '~> 0.5'
-end
diff --git a/lib/reline/terminfo.rb b/lib/reline/terminfo.rb
deleted file mode 100644
index f53642b919..0000000000
--- a/lib/reline/terminfo.rb
+++ /dev/null
@@ -1,174 +0,0 @@
-begin
- require 'fiddle'
- require 'fiddle/import'
-rescue LoadError
- module Reline::Terminfo
- def self.curses_dl
- false
- end
- end
-end
-
-module Reline::Terminfo
- extend Fiddle::Importer
-
- class TerminfoError < StandardError; end
-
- def self.curses_dl_files
- case RUBY_PLATFORM
- when /mingw/, /mswin/
- # aren't supported
- []
- when /cygwin/
- %w[cygncursesw-10.dll cygncurses-10.dll]
- when /darwin/
- %w[libncursesw.dylib libcursesw.dylib libncurses.dylib libcurses.dylib]
- else
- %w[libncursesw.so libcursesw.so libncurses.so libcurses.so]
- end
- end
-
- @curses_dl = false
- def self.curses_dl
- return @curses_dl unless @curses_dl == false
- if RUBY_VERSION >= '3.0.0'
- # Gem module isn't defined in test-all of the Ruby repository, and
- # Fiddle in Ruby 3.0.0 or later supports Fiddle::TYPE_VARIADIC.
- fiddle_supports_variadic = true
- elsif Fiddle.const_defined?(:VERSION,false) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
- # Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
- fiddle_supports_variadic = true
- else
- fiddle_supports_variadic = false
- end
- if fiddle_supports_variadic and not Fiddle.const_defined?(:TYPE_VARIADIC)
- # If the libffi version is not 3.0.5 or higher, there isn't TYPE_VARIADIC.
- fiddle_supports_variadic = false
- end
- if fiddle_supports_variadic
- curses_dl_files.each do |curses_name|
- result = Fiddle::Handle.new(curses_name)
- rescue Fiddle::DLError
- next
- else
- @curses_dl = result
- break
- end
- end
- @curses_dl = nil if @curses_dl == false
- @curses_dl
- end
-end if not Reline.const_defined?(:Terminfo) or not Reline::Terminfo.respond_to?(:curses_dl)
-
-module Reline::Terminfo
- dlload curses_dl
- #extern 'int setupterm(char *term, int fildes, int *errret)'
- @setupterm = Fiddle::Function.new(curses_dl['setupterm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
- #extern 'char *tigetstr(char *capname)'
- @tigetstr = Fiddle::Function.new(curses_dl['tigetstr'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
- begin
- #extern 'char *tiparm(const char *str, ...)'
- @tiparm = Fiddle::Function.new(curses_dl['tiparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
- rescue Fiddle::DLError
- # OpenBSD lacks tiparm
- #extern 'char *tparm(const char *str, ...)'
- @tiparm = Fiddle::Function.new(curses_dl['tparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
- end
- begin
- #extern 'int tigetflag(char *str)'
- @tigetflag = Fiddle::Function.new(curses_dl['tigetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
- rescue Fiddle::DLError
- # OpenBSD lacks tigetflag
- #extern 'int tgetflag(char *str)'
- @tigetflag = Fiddle::Function.new(curses_dl['tgetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
- end
- begin
- #extern 'int tigetnum(char *str)'
- @tigetnum = Fiddle::Function.new(curses_dl['tigetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
- rescue Fiddle::DLError
- # OpenBSD lacks tigetnum
- #extern 'int tgetnum(char *str)'
- @tigetnum = Fiddle::Function.new(curses_dl['tgetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
- end
-
- def self.setupterm(term, fildes)
- errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
- ret = @setupterm.(term, fildes, errret_int)
- errret = errret_int[0, Fiddle::SIZEOF_INT].unpack1('i')
- case ret
- when 0 # OK
- 0
- when -1 # ERR
- case errret
- when 1
- raise TerminfoError.new('The terminal is hardcopy, cannot be used for curses applications.')
- when 0
- raise TerminfoError.new('The terminal could not be found, or that it is a generic type, having too little information for curses applications to run.')
- when -1
- raise TerminfoError.new('The terminfo database could not be found.')
- else # unknown
- -1
- end
- else # unknown
- -2
- end
- end
-
- class StringWithTiparm < String
- def tiparm(*args) # for method chain
- Reline::Terminfo.tiparm(self, *args)
- end
- end
-
- def self.tigetstr(capname)
- raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
- capability = @tigetstr.(capname)
- case capability.to_i
- when 0, -1
- raise TerminfoError, "can't find capability: #{capname}"
- end
- StringWithTiparm.new(capability.to_s)
- end
-
- def self.tiparm(str, *args)
- new_args = []
- args.each do |a|
- new_args << Fiddle::TYPE_INT << a
- end
- @tiparm.(str, *new_args).to_s
- end
-
- def self.tigetflag(capname)
- raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
- flag = @tigetflag.(capname).to_i
- case flag
- when -1
- raise TerminfoError, "not boolean capability: #{capname}"
- when 0
- raise TerminfoError, "can't find capability: #{capname}"
- end
- flag
- end
-
- def self.tigetnum(capname)
- raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
- num = @tigetnum.(capname).to_i
- case num
- when -2
- raise TerminfoError, "not numeric capability: #{capname}"
- when -1
- raise TerminfoError, "can't find capability: #{capname}"
- end
- num
- end
-
- def self.enabled?
- true
- end
-end if Reline::Terminfo.curses_dl
-
-module Reline::Terminfo
- def self.enabled?
- false
- end
-end unless Reline::Terminfo.curses_dl
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb
deleted file mode 100644
index 6000c9f82a..0000000000
--- a/lib/reline/unicode.rb
+++ /dev/null
@@ -1,665 +0,0 @@
-class Reline::Unicode
- EscapedPairs = {
- 0x00 => '^@',
- 0x01 => '^A', # C-a
- 0x02 => '^B',
- 0x03 => '^C',
- 0x04 => '^D',
- 0x05 => '^E',
- 0x06 => '^F',
- 0x07 => '^G',
- 0x08 => '^H', # Backspace
- 0x09 => '^I',
- 0x0A => '^J',
- 0x0B => '^K',
- 0x0C => '^L',
- 0x0D => '^M', # Enter
- 0x0E => '^N',
- 0x0F => '^O',
- 0x10 => '^P',
- 0x11 => '^Q',
- 0x12 => '^R',
- 0x13 => '^S',
- 0x14 => '^T',
- 0x15 => '^U',
- 0x16 => '^V',
- 0x17 => '^W',
- 0x18 => '^X',
- 0x19 => '^Y',
- 0x1A => '^Z', # C-z
- 0x1B => '^[', # C-[ C-3
- 0x1D => '^]', # C-]
- 0x1E => '^^', # C-~ C-6
- 0x1F => '^_', # C-_ C-7
- 0x7F => '^?', # C-? C-8
- }
- EscapedChars = EscapedPairs.keys.map(&:chr)
-
- NON_PRINTING_START = "\1"
- NON_PRINTING_END = "\2"
- CSI_REGEXP = /\e\[[\d;]*[ABCDEFGHJKSTfminsuhl]/
- OSC_REGEXP = /\e\]\d+(?:;[^;]+)*\a/
- WIDTH_SCANNER = /\G(?:(#{NON_PRINTING_START})|(#{NON_PRINTING_END})|(#{CSI_REGEXP})|(#{OSC_REGEXP})|(\X))/o
- NON_PRINTING_START_INDEX = 0
- NON_PRINTING_END_INDEX = 1
- CSI_REGEXP_INDEX = 2
- OSC_REGEXP_INDEX = 3
- GRAPHEME_CLUSTER_INDEX = 4
-
- def self.get_mbchar_byte_size_by_first_char(c)
- # Checks UTF-8 character byte size
- case c.ord
- # 0b0xxxxxxx
- when ->(code) { (code ^ 0b10000000).allbits?(0b10000000) } then 1
- # 0b110xxxxx
- when ->(code) { (code ^ 0b00100000).allbits?(0b11100000) } then 2
- # 0b1110xxxx
- when ->(code) { (code ^ 0b00010000).allbits?(0b11110000) } then 3
- # 0b11110xxx
- when ->(code) { (code ^ 0b00001000).allbits?(0b11111000) } then 4
- # 0b111110xx
- when ->(code) { (code ^ 0b00000100).allbits?(0b11111100) } then 5
- # 0b1111110x
- when ->(code) { (code ^ 0b00000010).allbits?(0b11111110) } then 6
- # successor of mbchar
- else 0
- end
- end
-
- def self.escape_for_print(str)
- str.chars.map! { |gr|
- escaped = EscapedPairs[gr.ord]
- if escaped && gr != -"\n" && gr != -"\t"
- escaped
- else
- gr
- end
- }.join
- end
-
- require 'reline/unicode/east_asian_width'
-
- HalfwidthDakutenHandakuten = /[\u{FF9E}\u{FF9F}]/
-
- MBCharWidthRE = /
- (?<width_2_1>
- [#{ EscapedChars.map {|c| "\\x%02x" % c.ord }.join }] (?# ^ + char, such as ^M, ^H, ^[, ...)
- )
- | (?<width_3>^\u{2E3B}) (?# THREE-EM DASH)
- | (?<width_0>^\p{M})
- | (?<width_2_2>
- #{ EastAsianWidth::TYPE_F }
- | #{ EastAsianWidth::TYPE_W }
- )
- | (?<width_1>
- #{ EastAsianWidth::TYPE_H }
- | #{ EastAsianWidth::TYPE_NA }
- | #{ EastAsianWidth::TYPE_N }
- )(?!#{ HalfwidthDakutenHandakuten })
- | (?<width_2_3>
- (?: #{ EastAsianWidth::TYPE_H }
- | #{ EastAsianWidth::TYPE_NA }
- | #{ EastAsianWidth::TYPE_N })
- #{ HalfwidthDakutenHandakuten }
- )
- | (?<ambiguous_width>
- #{EastAsianWidth::TYPE_A}
- )
- /x
-
- def self.get_mbchar_width(mbchar)
- ord = mbchar.ord
- if (0x00 <= ord and ord <= 0x1F) # in EscapedPairs
- return 2
- elsif (0x20 <= ord and ord <= 0x7E) # printable ASCII chars
- return 1
- end
- m = mbchar.encode(Encoding::UTF_8).match(MBCharWidthRE)
- case
- when m.nil? then 1 # TODO should be U+FFFD � REPLACEMENT CHARACTER
- when m[:width_2_1], m[:width_2_2], m[:width_2_3] then 2
- when m[:width_3] then 3
- when m[:width_0] then 0
- when m[:width_1] then 1
- when m[:ambiguous_width] then Reline.ambiguous_width
- else
- nil
- end
- end
-
- def self.calculate_width(str, allow_escape_code = false)
- if allow_escape_code
- width = 0
- rest = str.encode(Encoding::UTF_8)
- in_zero_width = false
- rest.scan(WIDTH_SCANNER) do |gc|
- case
- when gc[NON_PRINTING_START_INDEX]
- in_zero_width = true
- when gc[NON_PRINTING_END_INDEX]
- in_zero_width = false
- when gc[CSI_REGEXP_INDEX], gc[OSC_REGEXP_INDEX]
- when gc[GRAPHEME_CLUSTER_INDEX]
- gc = gc[GRAPHEME_CLUSTER_INDEX]
- unless in_zero_width
- width += get_mbchar_width(gc)
- end
- end
- end
- width
- else
- str.encode(Encoding::UTF_8).grapheme_clusters.inject(0) { |w, gc|
- w + get_mbchar_width(gc)
- }
- end
- end
-
- def self.split_by_width(str, max_width, encoding = str.encoding)
- lines = [String.new(encoding: encoding)]
- height = 1
- width = 0
- rest = str.encode(Encoding::UTF_8)
- in_zero_width = false
- rest.scan(WIDTH_SCANNER) do |gc|
- case
- when gc[NON_PRINTING_START_INDEX]
- in_zero_width = true
- when gc[NON_PRINTING_END_INDEX]
- in_zero_width = false
- when gc[CSI_REGEXP_INDEX]
- lines.last << gc[CSI_REGEXP_INDEX]
- when gc[OSC_REGEXP_INDEX]
- lines.last << gc[OSC_REGEXP_INDEX]
- when gc[GRAPHEME_CLUSTER_INDEX]
- gc = gc[GRAPHEME_CLUSTER_INDEX]
- unless in_zero_width
- mbchar_width = get_mbchar_width(gc)
- if (width += mbchar_width) > max_width
- width = mbchar_width
- lines << nil
- lines << String.new(encoding: encoding)
- height += 1
- end
- end
- lines.last << gc
- end
- end
- # The cursor moves to next line in first
- if width == max_width
- lines << nil
- lines << String.new(encoding: encoding)
- height += 1
- end
- [lines, height]
- end
-
- # Take a chunk of a String cut by width with escape sequences.
- def self.take_range(str, start_col, max_width, encoding = str.encoding)
- chunk = String.new(encoding: encoding)
- total_width = 0
- rest = str.encode(Encoding::UTF_8)
- in_zero_width = false
- rest.scan(WIDTH_SCANNER) do |gc|
- case
- when gc[NON_PRINTING_START_INDEX]
- in_zero_width = true
- when gc[NON_PRINTING_END_INDEX]
- in_zero_width = false
- when gc[CSI_REGEXP_INDEX]
- chunk << gc[CSI_REGEXP_INDEX]
- when gc[OSC_REGEXP_INDEX]
- chunk << gc[OSC_REGEXP_INDEX]
- when gc[GRAPHEME_CLUSTER_INDEX]
- gc = gc[GRAPHEME_CLUSTER_INDEX]
- if in_zero_width
- chunk << gc
- else
- mbchar_width = get_mbchar_width(gc)
- total_width += mbchar_width
- break if (start_col + max_width) < total_width
- chunk << gc if start_col < total_width
- end
- end
- end
- chunk
- end
-
- def self.get_next_mbchar_size(line, byte_pointer)
- grapheme = line.byteslice(byte_pointer..-1).grapheme_clusters.first
- grapheme ? grapheme.bytesize : 0
- end
-
- def self.get_prev_mbchar_size(line, byte_pointer)
- if byte_pointer.zero?
- 0
- else
- grapheme = line.byteslice(0..(byte_pointer - 1)).grapheme_clusters.last
- grapheme ? grapheme.bytesize : 0
- end
- end
-
- def self.em_forward_word(line, byte_pointer)
- width = 0
- byte_size = 0
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [byte_size, width]
- end
-
- def self.em_forward_word_with_capitalization(line, byte_pointer)
- width = 0
- byte_size = 0
- new_str = String.new
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
- new_str += mbchar
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- first = true
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
- if first
- new_str += mbchar.upcase
- first = false
- else
- new_str += mbchar.downcase
- end
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [byte_size, width, new_str]
- end
-
- def self.em_backward_word(line, byte_pointer)
- width = 0
- byte_size = 0
- while 0 < (byte_pointer - byte_size)
- size = get_prev_mbchar_size(line, byte_pointer - byte_size)
- mbchar = line.byteslice(byte_pointer - byte_size - size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- while 0 < (byte_pointer - byte_size)
- size = get_prev_mbchar_size(line, byte_pointer - byte_size)
- mbchar = line.byteslice(byte_pointer - byte_size - size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [byte_size, width]
- end
-
- def self.em_big_backward_word(line, byte_pointer)
- width = 0
- byte_size = 0
- while 0 < (byte_pointer - byte_size)
- size = get_prev_mbchar_size(line, byte_pointer - byte_size)
- mbchar = line.byteslice(byte_pointer - byte_size - size, size)
- break if mbchar =~ /\S/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- while 0 < (byte_pointer - byte_size)
- size = get_prev_mbchar_size(line, byte_pointer - byte_size)
- mbchar = line.byteslice(byte_pointer - byte_size - size, size)
- break if mbchar =~ /\s/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [byte_size, width]
- end
-
- def self.ed_transpose_words(line, byte_pointer)
- right_word_start = nil
- size = get_next_mbchar_size(line, byte_pointer)
- mbchar = line.byteslice(byte_pointer, size)
- if size.zero?
- # ' aaa bbb [cursor]'
- byte_size = 0
- while 0 < (byte_pointer + byte_size)
- size = get_prev_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size - size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
- byte_size -= size
- end
- while 0 < (byte_pointer + byte_size)
- size = get_prev_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size - size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
- byte_size -= size
- end
- right_word_start = byte_pointer + byte_size
- byte_size = 0
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
- byte_size += size
- end
- after_start = byte_pointer + byte_size
- elsif mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
- # ' aaa bb[cursor]b'
- byte_size = 0
- while 0 < (byte_pointer + byte_size)
- size = get_prev_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size - size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
- byte_size -= size
- end
- right_word_start = byte_pointer + byte_size
- byte_size = 0
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
- byte_size += size
- end
- after_start = byte_pointer + byte_size
- else
- byte_size = 0
- while (line.bytesize - 1) > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
- byte_size += size
- end
- if (byte_pointer + byte_size) == (line.bytesize - 1)
- # ' aaa bbb [cursor] '
- after_start = line.bytesize
- while 0 < (byte_pointer + byte_size)
- size = get_prev_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size - size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
- byte_size -= size
- end
- while 0 < (byte_pointer + byte_size)
- size = get_prev_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size - size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
- byte_size -= size
- end
- right_word_start = byte_pointer + byte_size
- else
- # ' aaa [cursor] bbb '
- right_word_start = byte_pointer + byte_size
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
- byte_size += size
- end
- after_start = byte_pointer + byte_size
- end
- end
- byte_size = right_word_start - byte_pointer
- while 0 < (byte_pointer + byte_size)
- size = get_prev_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size - size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
- byte_size -= size
- end
- middle_start = byte_pointer + byte_size
- byte_size = middle_start - byte_pointer
- while 0 < (byte_pointer + byte_size)
- size = get_prev_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size - size, size)
- break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
- byte_size -= size
- end
- left_word_start = byte_pointer + byte_size
- [left_word_start, middle_start, right_word_start, after_start]
- end
-
- def self.vi_big_forward_word(line, byte_pointer)
- width = 0
- byte_size = 0
- while (line.bytesize - 1) > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar =~ /\s/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- while (line.bytesize - 1) > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar =~ /\S/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [byte_size, width]
- end
-
- def self.vi_big_forward_end_word(line, byte_pointer)
- if (line.bytesize - 1) > byte_pointer
- size = get_next_mbchar_size(line, byte_pointer)
- mbchar = line.byteslice(byte_pointer, size)
- width = get_mbchar_width(mbchar)
- byte_size = size
- else
- return [0, 0]
- end
- while (line.bytesize - 1) > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar =~ /\S/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- prev_width = width
- prev_byte_size = byte_size
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar =~ /\s/
- prev_width = width
- prev_byte_size = byte_size
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [prev_byte_size, prev_width]
- end
-
- def self.vi_big_backward_word(line, byte_pointer)
- width = 0
- byte_size = 0
- while 0 < (byte_pointer - byte_size)
- size = get_prev_mbchar_size(line, byte_pointer - byte_size)
- mbchar = line.byteslice(byte_pointer - byte_size - size, size)
- break if mbchar =~ /\S/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- while 0 < (byte_pointer - byte_size)
- size = get_prev_mbchar_size(line, byte_pointer - byte_size)
- mbchar = line.byteslice(byte_pointer - byte_size - size, size)
- break if mbchar =~ /\s/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [byte_size, width]
- end
-
- def self.vi_forward_word(line, byte_pointer, drop_terminate_spaces = false)
- if line.bytesize > byte_pointer
- size = get_next_mbchar_size(line, byte_pointer)
- mbchar = line.byteslice(byte_pointer, size)
- if mbchar =~ /\w/
- started_by = :word
- elsif mbchar =~ /\s/
- started_by = :space
- else
- started_by = :non_word_printable
- end
- width = get_mbchar_width(mbchar)
- byte_size = size
- else
- return [0, 0]
- end
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- case started_by
- when :word
- break if mbchar =~ /\W/
- when :space
- break if mbchar =~ /\S/
- when :non_word_printable
- break if mbchar =~ /\w|\s/
- end
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- return [byte_size, width] if drop_terminate_spaces
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- break if mbchar =~ /\S/
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [byte_size, width]
- end
-
- def self.vi_forward_end_word(line, byte_pointer)
- if (line.bytesize - 1) > byte_pointer
- size = get_next_mbchar_size(line, byte_pointer)
- mbchar = line.byteslice(byte_pointer, size)
- if mbchar =~ /\w/
- started_by = :word
- elsif mbchar =~ /\s/
- started_by = :space
- else
- started_by = :non_word_printable
- end
- width = get_mbchar_width(mbchar)
- byte_size = size
- else
- return [0, 0]
- end
- if (line.bytesize - 1) > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- if mbchar =~ /\w/
- second = :word
- elsif mbchar =~ /\s/
- second = :space
- else
- second = :non_word_printable
- end
- second_width = get_mbchar_width(mbchar)
- second_byte_size = size
- else
- return [byte_size, width]
- end
- if second == :space
- width += second_width
- byte_size += second_byte_size
- while (line.bytesize - 1) > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- if mbchar =~ /\S/
- if mbchar =~ /\w/
- started_by = :word
- else
- started_by = :non_word_printable
- end
- break
- end
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- else
- case [started_by, second]
- when [:word, :non_word_printable], [:non_word_printable, :word]
- started_by = second
- else
- width += second_width
- byte_size += second_byte_size
- started_by = second
- end
- end
- prev_width = width
- prev_byte_size = byte_size
- while line.bytesize > (byte_pointer + byte_size)
- size = get_next_mbchar_size(line, byte_pointer + byte_size)
- mbchar = line.byteslice(byte_pointer + byte_size, size)
- case started_by
- when :word
- break if mbchar =~ /\W/
- when :non_word_printable
- break if mbchar =~ /[\w\s]/
- end
- prev_width = width
- prev_byte_size = byte_size
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [prev_byte_size, prev_width]
- end
-
- def self.vi_backward_word(line, byte_pointer)
- width = 0
- byte_size = 0
- while 0 < (byte_pointer - byte_size)
- size = get_prev_mbchar_size(line, byte_pointer - byte_size)
- mbchar = line.byteslice(byte_pointer - byte_size - size, size)
- if mbchar =~ /\S/
- if mbchar =~ /\w/
- started_by = :word
- else
- started_by = :non_word_printable
- end
- break
- end
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- while 0 < (byte_pointer - byte_size)
- size = get_prev_mbchar_size(line, byte_pointer - byte_size)
- mbchar = line.byteslice(byte_pointer - byte_size - size, size)
- case started_by
- when :word
- break if mbchar =~ /\W/
- when :non_word_printable
- break if mbchar =~ /[\w\s]/
- end
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [byte_size, width]
- end
-
- def self.vi_first_print(line)
- width = 0
- byte_size = 0
- while (line.bytesize - 1) > byte_size
- size = get_next_mbchar_size(line, byte_size)
- mbchar = line.byteslice(byte_size, size)
- if mbchar =~ /\S/
- break
- end
- width += get_mbchar_width(mbchar)
- byte_size += size
- end
- [byte_size, width]
- end
-end
diff --git a/lib/reline/unicode/east_asian_width.rb b/lib/reline/unicode/east_asian_width.rb
deleted file mode 100644
index 97dfec4c52..0000000000
--- a/lib/reline/unicode/east_asian_width.rb
+++ /dev/null
@@ -1,1196 +0,0 @@
-class Reline::Unicode::EastAsianWidth
- # This is based on EastAsianWidth.txt
- # EastAsianWidth.txt
-
- # Fullwidth
- TYPE_F = /^[#{ %W(
- \u{3000}
- \u{FF01}-\u{FF60}
- \u{FFE0}-\u{FFE6}
- ).join }]/
-
- # Halfwidth
- TYPE_H = /^[#{ %W(
- \u{20A9}
- \u{FF61}-\u{FFBE}
- \u{FFC2}-\u{FFC7}
- \u{FFCA}-\u{FFCF}
- \u{FFD2}-\u{FFD7}
- \u{FFDA}-\u{FFDC}
- \u{FFE8}-\u{FFEE}
- ).join }]/
-
- # Wide
- TYPE_W = /^[#{ %W(
- \u{1100}-\u{115F}
- \u{231A}-\u{231B}
- \u{2329}-\u{232A}
- \u{23E9}-\u{23EC}
- \u{23F0}
- \u{23F3}
- \u{25FD}-\u{25FE}
- \u{2614}-\u{2615}
- \u{2648}-\u{2653}
- \u{267F}
- \u{2693}
- \u{26A1}
- \u{26AA}-\u{26AB}
- \u{26BD}-\u{26BE}
- \u{26C4}-\u{26C5}
- \u{26CE}
- \u{26D4}
- \u{26EA}
- \u{26F2}-\u{26F3}
- \u{26F5}
- \u{26FA}
- \u{26FD}
- \u{2705}
- \u{270A}-\u{270B}
- \u{2728}
- \u{274C}
- \u{274E}
- \u{2753}-\u{2755}
- \u{2757}
- \u{2795}-\u{2797}
- \u{27B0}
- \u{27BF}
- \u{2B1B}-\u{2B1C}
- \u{2B50}
- \u{2B55}
- \u{2E80}-\u{2E99}
- \u{2E9B}-\u{2EF3}
- \u{2F00}-\u{2FD5}
- \u{2FF0}-\u{2FFB}
- \u{3001}-\u{303E}
- \u{3041}-\u{3096}
- \u{3099}-\u{30FF}
- \u{3105}-\u{312F}
- \u{3131}-\u{318E}
- \u{3190}-\u{31E3}
- \u{31F0}-\u{321E}
- \u{3220}-\u{3247}
- \u{3250}-\u{4DBF}
- \u{4E00}-\u{A48C}
- \u{A490}-\u{A4C6}
- \u{A960}-\u{A97C}
- \u{AC00}-\u{D7A3}
- \u{F900}-\u{FAFF}
- \u{FE10}-\u{FE19}
- \u{FE30}-\u{FE52}
- \u{FE54}-\u{FE66}
- \u{FE68}-\u{FE6B}
- \u{16FE0}-\u{16FE4}
- \u{16FF0}-\u{16FF1}
- \u{17000}-\u{187F7}
- \u{18800}-\u{18CD5}
- \u{18D00}-\u{18D08}
- \u{1AFF0}-\u{1AFF3}
- \u{1AFF5}-\u{1AFFB}
- \u{1AFFD}-\u{1AFFE}
- \u{1B000}-\u{1B122}
- \u{1B132}
- \u{1B150}-\u{1B152}
- \u{1B155}
- \u{1B164}-\u{1B167}
- \u{1B170}-\u{1B2FB}
- \u{1F004}
- \u{1F0CF}
- \u{1F18E}
- \u{1F191}-\u{1F19A}
- \u{1F200}-\u{1F202}
- \u{1F210}-\u{1F23B}
- \u{1F240}-\u{1F248}
- \u{1F250}-\u{1F251}
- \u{1F260}-\u{1F265}
- \u{1F300}-\u{1F320}
- \u{1F32D}-\u{1F335}
- \u{1F337}-\u{1F37C}
- \u{1F37E}-\u{1F393}
- \u{1F3A0}-\u{1F3CA}
- \u{1F3CF}-\u{1F3D3}
- \u{1F3E0}-\u{1F3F0}
- \u{1F3F4}
- \u{1F3F8}-\u{1F43E}
- \u{1F440}
- \u{1F442}-\u{1F4FC}
- \u{1F4FF}-\u{1F53D}
- \u{1F54B}-\u{1F54E}
- \u{1F550}-\u{1F567}
- \u{1F57A}
- \u{1F595}-\u{1F596}
- \u{1F5A4}
- \u{1F5FB}-\u{1F64F}
- \u{1F680}-\u{1F6C5}
- \u{1F6CC}
- \u{1F6D0}-\u{1F6D2}
- \u{1F6D5}-\u{1F6D7}
- \u{1F6DC}-\u{1F6DF}
- \u{1F6EB}-\u{1F6EC}
- \u{1F6F4}-\u{1F6FC}
- \u{1F7E0}-\u{1F7EB}
- \u{1F7F0}
- \u{1F90C}-\u{1F93A}
- \u{1F93C}-\u{1F945}
- \u{1F947}-\u{1F9FF}
- \u{1FA70}-\u{1FA7C}
- \u{1FA80}-\u{1FA88}
- \u{1FA90}-\u{1FABD}
- \u{1FABF}-\u{1FAC5}
- \u{1FACE}-\u{1FADB}
- \u{1FAE0}-\u{1FAE8}
- \u{1FAF0}-\u{1FAF8}
- \u{20000}-\u{2FFFD}
- \u{30000}-\u{3FFFD}
- ).join }]/
-
- # Narrow
- TYPE_NA = /^[#{ %W(
- \u{0020}-\u{007E}
- \u{00A2}-\u{00A3}
- \u{00A5}-\u{00A6}
- \u{00AC}
- \u{00AF}
- \u{27E6}-\u{27ED}
- \u{2985}-\u{2986}
- ).join }]/
-
- # Ambiguous
- TYPE_A = /^[#{ %W(
- \u{00A1}
- \u{00A4}
- \u{00A7}-\u{00A8}
- \u{00AA}
- \u{00AD}-\u{00AE}
- \u{00B0}-\u{00B4}
- \u{00B6}-\u{00BA}
- \u{00BC}-\u{00BF}
- \u{00C6}
- \u{00D0}
- \u{00D7}-\u{00D8}
- \u{00DE}-\u{00E1}
- \u{00E6}
- \u{00E8}-\u{00EA}
- \u{00EC}-\u{00ED}
- \u{00F0}
- \u{00F2}-\u{00F3}
- \u{00F7}-\u{00FA}
- \u{00FC}
- \u{00FE}
- \u{0101}
- \u{0111}
- \u{0113}
- \u{011B}
- \u{0126}-\u{0127}
- \u{012B}
- \u{0131}-\u{0133}
- \u{0138}
- \u{013F}-\u{0142}
- \u{0144}
- \u{0148}-\u{014B}
- \u{014D}
- \u{0152}-\u{0153}
- \u{0166}-\u{0167}
- \u{016B}
- \u{01CE}
- \u{01D0}
- \u{01D2}
- \u{01D4}
- \u{01D6}
- \u{01D8}
- \u{01DA}
- \u{01DC}
- \u{0251}
- \u{0261}
- \u{02C4}
- \u{02C7}
- \u{02C9}-\u{02CB}
- \u{02CD}
- \u{02D0}
- \u{02D8}-\u{02DB}
- \u{02DD}
- \u{02DF}
- \u{0300}-\u{036F}
- \u{0391}-\u{03A1}
- \u{03A3}-\u{03A9}
- \u{03B1}-\u{03C1}
- \u{03C3}-\u{03C9}
- \u{0401}
- \u{0410}-\u{044F}
- \u{0451}
- \u{2010}
- \u{2013}-\u{2016}
- \u{2018}-\u{2019}
- \u{201C}-\u{201D}
- \u{2020}-\u{2022}
- \u{2024}-\u{2027}
- \u{2030}
- \u{2032}-\u{2033}
- \u{2035}
- \u{203B}
- \u{203E}
- \u{2074}
- \u{207F}
- \u{2081}-\u{2084}
- \u{20AC}
- \u{2103}
- \u{2105}
- \u{2109}
- \u{2113}
- \u{2116}
- \u{2121}-\u{2122}
- \u{2126}
- \u{212B}
- \u{2153}-\u{2154}
- \u{215B}-\u{215E}
- \u{2160}-\u{216B}
- \u{2170}-\u{2179}
- \u{2189}
- \u{2190}-\u{2199}
- \u{21B8}-\u{21B9}
- \u{21D2}
- \u{21D4}
- \u{21E7}
- \u{2200}
- \u{2202}-\u{2203}
- \u{2207}-\u{2208}
- \u{220B}
- \u{220F}
- \u{2211}
- \u{2215}
- \u{221A}
- \u{221D}-\u{2220}
- \u{2223}
- \u{2225}
- \u{2227}-\u{222C}
- \u{222E}
- \u{2234}-\u{2237}
- \u{223C}-\u{223D}
- \u{2248}
- \u{224C}
- \u{2252}
- \u{2260}-\u{2261}
- \u{2264}-\u{2267}
- \u{226A}-\u{226B}
- \u{226E}-\u{226F}
- \u{2282}-\u{2283}
- \u{2286}-\u{2287}
- \u{2295}
- \u{2299}
- \u{22A5}
- \u{22BF}
- \u{2312}
- \u{2460}-\u{24E9}
- \u{24EB}-\u{254B}
- \u{2550}-\u{2573}
- \u{2580}-\u{258F}
- \u{2592}-\u{2595}
- \u{25A0}-\u{25A1}
- \u{25A3}-\u{25A9}
- \u{25B2}-\u{25B3}
- \u{25B6}-\u{25B7}
- \u{25BC}-\u{25BD}
- \u{25C0}-\u{25C1}
- \u{25C6}-\u{25C8}
- \u{25CB}
- \u{25CE}-\u{25D1}
- \u{25E2}-\u{25E5}
- \u{25EF}
- \u{2605}-\u{2606}
- \u{2609}
- \u{260E}-\u{260F}
- \u{261C}
- \u{261E}
- \u{2640}
- \u{2642}
- \u{2660}-\u{2661}
- \u{2663}-\u{2665}
- \u{2667}-\u{266A}
- \u{266C}-\u{266D}
- \u{266F}
- \u{269E}-\u{269F}
- \u{26BF}
- \u{26C6}-\u{26CD}
- \u{26CF}-\u{26D3}
- \u{26D5}-\u{26E1}
- \u{26E3}
- \u{26E8}-\u{26E9}
- \u{26EB}-\u{26F1}
- \u{26F4}
- \u{26F6}-\u{26F9}
- \u{26FB}-\u{26FC}
- \u{26FE}-\u{26FF}
- \u{273D}
- \u{2776}-\u{277F}
- \u{2B56}-\u{2B59}
- \u{3248}-\u{324F}
- \u{E000}-\u{F8FF}
- \u{FE00}-\u{FE0F}
- \u{FFFD}
- \u{1F100}-\u{1F10A}
- \u{1F110}-\u{1F12D}
- \u{1F130}-\u{1F169}
- \u{1F170}-\u{1F18D}
- \u{1F18F}-\u{1F190}
- \u{1F19B}-\u{1F1AC}
- \u{E0100}-\u{E01EF}
- \u{F0000}-\u{FFFFD}
- \u{100000}-\u{10FFFD}
- ).join }]/
-
- # Neutral
- TYPE_N = /^[#{ %W(
- \u{0000}-\u{001F}
- \u{007F}-\u{00A0}
- \u{00A9}
- \u{00AB}
- \u{00B5}
- \u{00BB}
- \u{00C0}-\u{00C5}
- \u{00C7}-\u{00CF}
- \u{00D1}-\u{00D6}
- \u{00D9}-\u{00DD}
- \u{00E2}-\u{00E5}
- \u{00E7}
- \u{00EB}
- \u{00EE}-\u{00EF}
- \u{00F1}
- \u{00F4}-\u{00F6}
- \u{00FB}
- \u{00FD}
- \u{00FF}-\u{0100}
- \u{0102}-\u{0110}
- \u{0112}
- \u{0114}-\u{011A}
- \u{011C}-\u{0125}
- \u{0128}-\u{012A}
- \u{012C}-\u{0130}
- \u{0134}-\u{0137}
- \u{0139}-\u{013E}
- \u{0143}
- \u{0145}-\u{0147}
- \u{014C}
- \u{014E}-\u{0151}
- \u{0154}-\u{0165}
- \u{0168}-\u{016A}
- \u{016C}-\u{01CD}
- \u{01CF}
- \u{01D1}
- \u{01D3}
- \u{01D5}
- \u{01D7}
- \u{01D9}
- \u{01DB}
- \u{01DD}-\u{0250}
- \u{0252}-\u{0260}
- \u{0262}-\u{02C3}
- \u{02C5}-\u{02C6}
- \u{02C8}
- \u{02CC}
- \u{02CE}-\u{02CF}
- \u{02D1}-\u{02D7}
- \u{02DC}
- \u{02DE}
- \u{02E0}-\u{02FF}
- \u{0370}-\u{0377}
- \u{037A}-\u{037F}
- \u{0384}-\u{038A}
- \u{038C}
- \u{038E}-\u{0390}
- \u{03AA}-\u{03B0}
- \u{03C2}
- \u{03CA}-\u{0400}
- \u{0402}-\u{040F}
- \u{0450}
- \u{0452}-\u{052F}
- \u{0531}-\u{0556}
- \u{0559}-\u{058A}
- \u{058D}-\u{058F}
- \u{0591}-\u{05C7}
- \u{05D0}-\u{05EA}
- \u{05EF}-\u{05F4}
- \u{0600}-\u{070D}
- \u{070F}-\u{074A}
- \u{074D}-\u{07B1}
- \u{07C0}-\u{07FA}
- \u{07FD}-\u{082D}
- \u{0830}-\u{083E}
- \u{0840}-\u{085B}
- \u{085E}
- \u{0860}-\u{086A}
- \u{0870}-\u{088E}
- \u{0890}-\u{0891}
- \u{0898}-\u{0983}
- \u{0985}-\u{098C}
- \u{098F}-\u{0990}
- \u{0993}-\u{09A8}
- \u{09AA}-\u{09B0}
- \u{09B2}
- \u{09B6}-\u{09B9}
- \u{09BC}-\u{09C4}
- \u{09C7}-\u{09C8}
- \u{09CB}-\u{09CE}
- \u{09D7}
- \u{09DC}-\u{09DD}
- \u{09DF}-\u{09E3}
- \u{09E6}-\u{09FE}
- \u{0A01}-\u{0A03}
- \u{0A05}-\u{0A0A}
- \u{0A0F}-\u{0A10}
- \u{0A13}-\u{0A28}
- \u{0A2A}-\u{0A30}
- \u{0A32}-\u{0A33}
- \u{0A35}-\u{0A36}
- \u{0A38}-\u{0A39}
- \u{0A3C}
- \u{0A3E}-\u{0A42}
- \u{0A47}-\u{0A48}
- \u{0A4B}-\u{0A4D}
- \u{0A51}
- \u{0A59}-\u{0A5C}
- \u{0A5E}
- \u{0A66}-\u{0A76}
- \u{0A81}-\u{0A83}
- \u{0A85}-\u{0A8D}
- \u{0A8F}-\u{0A91}
- \u{0A93}-\u{0AA8}
- \u{0AAA}-\u{0AB0}
- \u{0AB2}-\u{0AB3}
- \u{0AB5}-\u{0AB9}
- \u{0ABC}-\u{0AC5}
- \u{0AC7}-\u{0AC9}
- \u{0ACB}-\u{0ACD}
- \u{0AD0}
- \u{0AE0}-\u{0AE3}
- \u{0AE6}-\u{0AF1}
- \u{0AF9}-\u{0AFF}
- \u{0B01}-\u{0B03}
- \u{0B05}-\u{0B0C}
- \u{0B0F}-\u{0B10}
- \u{0B13}-\u{0B28}
- \u{0B2A}-\u{0B30}
- \u{0B32}-\u{0B33}
- \u{0B35}-\u{0B39}
- \u{0B3C}-\u{0B44}
- \u{0B47}-\u{0B48}
- \u{0B4B}-\u{0B4D}
- \u{0B55}-\u{0B57}
- \u{0B5C}-\u{0B5D}
- \u{0B5F}-\u{0B63}
- \u{0B66}-\u{0B77}
- \u{0B82}-\u{0B83}
- \u{0B85}-\u{0B8A}
- \u{0B8E}-\u{0B90}
- \u{0B92}-\u{0B95}
- \u{0B99}-\u{0B9A}
- \u{0B9C}
- \u{0B9E}-\u{0B9F}
- \u{0BA3}-\u{0BA4}
- \u{0BA8}-\u{0BAA}
- \u{0BAE}-\u{0BB9}
- \u{0BBE}-\u{0BC2}
- \u{0BC6}-\u{0BC8}
- \u{0BCA}-\u{0BCD}
- \u{0BD0}
- \u{0BD7}
- \u{0BE6}-\u{0BFA}
- \u{0C00}-\u{0C0C}
- \u{0C0E}-\u{0C10}
- \u{0C12}-\u{0C28}
- \u{0C2A}-\u{0C39}
- \u{0C3C}-\u{0C44}
- \u{0C46}-\u{0C48}
- \u{0C4A}-\u{0C4D}
- \u{0C55}-\u{0C56}
- \u{0C58}-\u{0C5A}
- \u{0C5D}
- \u{0C60}-\u{0C63}
- \u{0C66}-\u{0C6F}
- \u{0C77}-\u{0C8C}
- \u{0C8E}-\u{0C90}
- \u{0C92}-\u{0CA8}
- \u{0CAA}-\u{0CB3}
- \u{0CB5}-\u{0CB9}
- \u{0CBC}-\u{0CC4}
- \u{0CC6}-\u{0CC8}
- \u{0CCA}-\u{0CCD}
- \u{0CD5}-\u{0CD6}
- \u{0CDD}-\u{0CDE}
- \u{0CE0}-\u{0CE3}
- \u{0CE6}-\u{0CEF}
- \u{0CF1}-\u{0CF3}
- \u{0D00}-\u{0D0C}
- \u{0D0E}-\u{0D10}
- \u{0D12}-\u{0D44}
- \u{0D46}-\u{0D48}
- \u{0D4A}-\u{0D4F}
- \u{0D54}-\u{0D63}
- \u{0D66}-\u{0D7F}
- \u{0D81}-\u{0D83}
- \u{0D85}-\u{0D96}
- \u{0D9A}-\u{0DB1}
- \u{0DB3}-\u{0DBB}
- \u{0DBD}
- \u{0DC0}-\u{0DC6}
- \u{0DCA}
- \u{0DCF}-\u{0DD4}
- \u{0DD6}
- \u{0DD8}-\u{0DDF}
- \u{0DE6}-\u{0DEF}
- \u{0DF2}-\u{0DF4}
- \u{0E01}-\u{0E3A}
- \u{0E3F}-\u{0E5B}
- \u{0E81}-\u{0E82}
- \u{0E84}
- \u{0E86}-\u{0E8A}
- \u{0E8C}-\u{0EA3}
- \u{0EA5}
- \u{0EA7}-\u{0EBD}
- \u{0EC0}-\u{0EC4}
- \u{0EC6}
- \u{0EC8}-\u{0ECE}
- \u{0ED0}-\u{0ED9}
- \u{0EDC}-\u{0EDF}
- \u{0F00}-\u{0F47}
- \u{0F49}-\u{0F6C}
- \u{0F71}-\u{0F97}
- \u{0F99}-\u{0FBC}
- \u{0FBE}-\u{0FCC}
- \u{0FCE}-\u{0FDA}
- \u{1000}-\u{10C5}
- \u{10C7}
- \u{10CD}
- \u{10D0}-\u{10FF}
- \u{1160}-\u{1248}
- \u{124A}-\u{124D}
- \u{1250}-\u{1256}
- \u{1258}
- \u{125A}-\u{125D}
- \u{1260}-\u{1288}
- \u{128A}-\u{128D}
- \u{1290}-\u{12B0}
- \u{12B2}-\u{12B5}
- \u{12B8}-\u{12BE}
- \u{12C0}
- \u{12C2}-\u{12C5}
- \u{12C8}-\u{12D6}
- \u{12D8}-\u{1310}
- \u{1312}-\u{1315}
- \u{1318}-\u{135A}
- \u{135D}-\u{137C}
- \u{1380}-\u{1399}
- \u{13A0}-\u{13F5}
- \u{13F8}-\u{13FD}
- \u{1400}-\u{169C}
- \u{16A0}-\u{16F8}
- \u{1700}-\u{1715}
- \u{171F}-\u{1736}
- \u{1740}-\u{1753}
- \u{1760}-\u{176C}
- \u{176E}-\u{1770}
- \u{1772}-\u{1773}
- \u{1780}-\u{17DD}
- \u{17E0}-\u{17E9}
- \u{17F0}-\u{17F9}
- \u{1800}-\u{1819}
- \u{1820}-\u{1878}
- \u{1880}-\u{18AA}
- \u{18B0}-\u{18F5}
- \u{1900}-\u{191E}
- \u{1920}-\u{192B}
- \u{1930}-\u{193B}
- \u{1940}
- \u{1944}-\u{196D}
- \u{1970}-\u{1974}
- \u{1980}-\u{19AB}
- \u{19B0}-\u{19C9}
- \u{19D0}-\u{19DA}
- \u{19DE}-\u{1A1B}
- \u{1A1E}-\u{1A5E}
- \u{1A60}-\u{1A7C}
- \u{1A7F}-\u{1A89}
- \u{1A90}-\u{1A99}
- \u{1AA0}-\u{1AAD}
- \u{1AB0}-\u{1ACE}
- \u{1B00}-\u{1B4C}
- \u{1B50}-\u{1B7E}
- \u{1B80}-\u{1BF3}
- \u{1BFC}-\u{1C37}
- \u{1C3B}-\u{1C49}
- \u{1C4D}-\u{1C88}
- \u{1C90}-\u{1CBA}
- \u{1CBD}-\u{1CC7}
- \u{1CD0}-\u{1CFA}
- \u{1D00}-\u{1F15}
- \u{1F18}-\u{1F1D}
- \u{1F20}-\u{1F45}
- \u{1F48}-\u{1F4D}
- \u{1F50}-\u{1F57}
- \u{1F59}
- \u{1F5B}
- \u{1F5D}
- \u{1F5F}-\u{1F7D}
- \u{1F80}-\u{1FB4}
- \u{1FB6}-\u{1FC4}
- \u{1FC6}-\u{1FD3}
- \u{1FD6}-\u{1FDB}
- \u{1FDD}-\u{1FEF}
- \u{1FF2}-\u{1FF4}
- \u{1FF6}-\u{1FFE}
- \u{2000}-\u{200F}
- \u{2011}-\u{2012}
- \u{2017}
- \u{201A}-\u{201B}
- \u{201E}-\u{201F}
- \u{2023}
- \u{2028}-\u{202F}
- \u{2031}
- \u{2034}
- \u{2036}-\u{203A}
- \u{203C}-\u{203D}
- \u{203F}-\u{2064}
- \u{2066}-\u{2071}
- \u{2075}-\u{207E}
- \u{2080}
- \u{2085}-\u{208E}
- \u{2090}-\u{209C}
- \u{20A0}-\u{20A8}
- \u{20AA}-\u{20AB}
- \u{20AD}-\u{20C0}
- \u{20D0}-\u{20F0}
- \u{2100}-\u{2102}
- \u{2104}
- \u{2106}-\u{2108}
- \u{210A}-\u{2112}
- \u{2114}-\u{2115}
- \u{2117}-\u{2120}
- \u{2123}-\u{2125}
- \u{2127}-\u{212A}
- \u{212C}-\u{2152}
- \u{2155}-\u{215A}
- \u{215F}
- \u{216C}-\u{216F}
- \u{217A}-\u{2188}
- \u{218A}-\u{218B}
- \u{219A}-\u{21B7}
- \u{21BA}-\u{21D1}
- \u{21D3}
- \u{21D5}-\u{21E6}
- \u{21E8}-\u{21FF}
- \u{2201}
- \u{2204}-\u{2206}
- \u{2209}-\u{220A}
- \u{220C}-\u{220E}
- \u{2210}
- \u{2212}-\u{2214}
- \u{2216}-\u{2219}
- \u{221B}-\u{221C}
- \u{2221}-\u{2222}
- \u{2224}
- \u{2226}
- \u{222D}
- \u{222F}-\u{2233}
- \u{2238}-\u{223B}
- \u{223E}-\u{2247}
- \u{2249}-\u{224B}
- \u{224D}-\u{2251}
- \u{2253}-\u{225F}
- \u{2262}-\u{2263}
- \u{2268}-\u{2269}
- \u{226C}-\u{226D}
- \u{2270}-\u{2281}
- \u{2284}-\u{2285}
- \u{2288}-\u{2294}
- \u{2296}-\u{2298}
- \u{229A}-\u{22A4}
- \u{22A6}-\u{22BE}
- \u{22C0}-\u{2311}
- \u{2313}-\u{2319}
- \u{231C}-\u{2328}
- \u{232B}-\u{23E8}
- \u{23ED}-\u{23EF}
- \u{23F1}-\u{23F2}
- \u{23F4}-\u{2426}
- \u{2440}-\u{244A}
- \u{24EA}
- \u{254C}-\u{254F}
- \u{2574}-\u{257F}
- \u{2590}-\u{2591}
- \u{2596}-\u{259F}
- \u{25A2}
- \u{25AA}-\u{25B1}
- \u{25B4}-\u{25B5}
- \u{25B8}-\u{25BB}
- \u{25BE}-\u{25BF}
- \u{25C2}-\u{25C5}
- \u{25C9}-\u{25CA}
- \u{25CC}-\u{25CD}
- \u{25D2}-\u{25E1}
- \u{25E6}-\u{25EE}
- \u{25F0}-\u{25FC}
- \u{25FF}-\u{2604}
- \u{2607}-\u{2608}
- \u{260A}-\u{260D}
- \u{2610}-\u{2613}
- \u{2616}-\u{261B}
- \u{261D}
- \u{261F}-\u{263F}
- \u{2641}
- \u{2643}-\u{2647}
- \u{2654}-\u{265F}
- \u{2662}
- \u{2666}
- \u{266B}
- \u{266E}
- \u{2670}-\u{267E}
- \u{2680}-\u{2692}
- \u{2694}-\u{269D}
- \u{26A0}
- \u{26A2}-\u{26A9}
- \u{26AC}-\u{26BC}
- \u{26C0}-\u{26C3}
- \u{26E2}
- \u{26E4}-\u{26E7}
- \u{2700}-\u{2704}
- \u{2706}-\u{2709}
- \u{270C}-\u{2727}
- \u{2729}-\u{273C}
- \u{273E}-\u{274B}
- \u{274D}
- \u{274F}-\u{2752}
- \u{2756}
- \u{2758}-\u{2775}
- \u{2780}-\u{2794}
- \u{2798}-\u{27AF}
- \u{27B1}-\u{27BE}
- \u{27C0}-\u{27E5}
- \u{27EE}-\u{2984}
- \u{2987}-\u{2B1A}
- \u{2B1D}-\u{2B4F}
- \u{2B51}-\u{2B54}
- \u{2B5A}-\u{2B73}
- \u{2B76}-\u{2B95}
- \u{2B97}-\u{2CF3}
- \u{2CF9}-\u{2D25}
- \u{2D27}
- \u{2D2D}
- \u{2D30}-\u{2D67}
- \u{2D6F}-\u{2D70}
- \u{2D7F}-\u{2D96}
- \u{2DA0}-\u{2DA6}
- \u{2DA8}-\u{2DAE}
- \u{2DB0}-\u{2DB6}
- \u{2DB8}-\u{2DBE}
- \u{2DC0}-\u{2DC6}
- \u{2DC8}-\u{2DCE}
- \u{2DD0}-\u{2DD6}
- \u{2DD8}-\u{2DDE}
- \u{2DE0}-\u{2E5D}
- \u{303F}
- \u{4DC0}-\u{4DFF}
- \u{A4D0}-\u{A62B}
- \u{A640}-\u{A6F7}
- \u{A700}-\u{A7CA}
- \u{A7D0}-\u{A7D1}
- \u{A7D3}
- \u{A7D5}-\u{A7D9}
- \u{A7F2}-\u{A82C}
- \u{A830}-\u{A839}
- \u{A840}-\u{A877}
- \u{A880}-\u{A8C5}
- \u{A8CE}-\u{A8D9}
- \u{A8E0}-\u{A953}
- \u{A95F}
- \u{A980}-\u{A9CD}
- \u{A9CF}-\u{A9D9}
- \u{A9DE}-\u{A9FE}
- \u{AA00}-\u{AA36}
- \u{AA40}-\u{AA4D}
- \u{AA50}-\u{AA59}
- \u{AA5C}-\u{AAC2}
- \u{AADB}-\u{AAF6}
- \u{AB01}-\u{AB06}
- \u{AB09}-\u{AB0E}
- \u{AB11}-\u{AB16}
- \u{AB20}-\u{AB26}
- \u{AB28}-\u{AB2E}
- \u{AB30}-\u{AB6B}
- \u{AB70}-\u{ABED}
- \u{ABF0}-\u{ABF9}
- \u{D7B0}-\u{D7C6}
- \u{D7CB}-\u{D7FB}
- \u{FB00}-\u{FB06}
- \u{FB13}-\u{FB17}
- \u{FB1D}-\u{FB36}
- \u{FB38}-\u{FB3C}
- \u{FB3E}
- \u{FB40}-\u{FB41}
- \u{FB43}-\u{FB44}
- \u{FB46}-\u{FBC2}
- \u{FBD3}-\u{FD8F}
- \u{FD92}-\u{FDC7}
- \u{FDCF}
- \u{FDF0}-\u{FDFF}
- \u{FE20}-\u{FE2F}
- \u{FE70}-\u{FE74}
- \u{FE76}-\u{FEFC}
- \u{FEFF}
- \u{FFF9}-\u{FFFC}
- \u{10000}-\u{1000B}
- \u{1000D}-\u{10026}
- \u{10028}-\u{1003A}
- \u{1003C}-\u{1003D}
- \u{1003F}-\u{1004D}
- \u{10050}-\u{1005D}
- \u{10080}-\u{100FA}
- \u{10100}-\u{10102}
- \u{10107}-\u{10133}
- \u{10137}-\u{1018E}
- \u{10190}-\u{1019C}
- \u{101A0}
- \u{101D0}-\u{101FD}
- \u{10280}-\u{1029C}
- \u{102A0}-\u{102D0}
- \u{102E0}-\u{102FB}
- \u{10300}-\u{10323}
- \u{1032D}-\u{1034A}
- \u{10350}-\u{1037A}
- \u{10380}-\u{1039D}
- \u{1039F}-\u{103C3}
- \u{103C8}-\u{103D5}
- \u{10400}-\u{1049D}
- \u{104A0}-\u{104A9}
- \u{104B0}-\u{104D3}
- \u{104D8}-\u{104FB}
- \u{10500}-\u{10527}
- \u{10530}-\u{10563}
- \u{1056F}-\u{1057A}
- \u{1057C}-\u{1058A}
- \u{1058C}-\u{10592}
- \u{10594}-\u{10595}
- \u{10597}-\u{105A1}
- \u{105A3}-\u{105B1}
- \u{105B3}-\u{105B9}
- \u{105BB}-\u{105BC}
- \u{10600}-\u{10736}
- \u{10740}-\u{10755}
- \u{10760}-\u{10767}
- \u{10780}-\u{10785}
- \u{10787}-\u{107B0}
- \u{107B2}-\u{107BA}
- \u{10800}-\u{10805}
- \u{10808}
- \u{1080A}-\u{10835}
- \u{10837}-\u{10838}
- \u{1083C}
- \u{1083F}-\u{10855}
- \u{10857}-\u{1089E}
- \u{108A7}-\u{108AF}
- \u{108E0}-\u{108F2}
- \u{108F4}-\u{108F5}
- \u{108FB}-\u{1091B}
- \u{1091F}-\u{10939}
- \u{1093F}
- \u{10980}-\u{109B7}
- \u{109BC}-\u{109CF}
- \u{109D2}-\u{10A03}
- \u{10A05}-\u{10A06}
- \u{10A0C}-\u{10A13}
- \u{10A15}-\u{10A17}
- \u{10A19}-\u{10A35}
- \u{10A38}-\u{10A3A}
- \u{10A3F}-\u{10A48}
- \u{10A50}-\u{10A58}
- \u{10A60}-\u{10A9F}
- \u{10AC0}-\u{10AE6}
- \u{10AEB}-\u{10AF6}
- \u{10B00}-\u{10B35}
- \u{10B39}-\u{10B55}
- \u{10B58}-\u{10B72}
- \u{10B78}-\u{10B91}
- \u{10B99}-\u{10B9C}
- \u{10BA9}-\u{10BAF}
- \u{10C00}-\u{10C48}
- \u{10C80}-\u{10CB2}
- \u{10CC0}-\u{10CF2}
- \u{10CFA}-\u{10D27}
- \u{10D30}-\u{10D39}
- \u{10E60}-\u{10E7E}
- \u{10E80}-\u{10EA9}
- \u{10EAB}-\u{10EAD}
- \u{10EB0}-\u{10EB1}
- \u{10EFD}-\u{10F27}
- \u{10F30}-\u{10F59}
- \u{10F70}-\u{10F89}
- \u{10FB0}-\u{10FCB}
- \u{10FE0}-\u{10FF6}
- \u{11000}-\u{1104D}
- \u{11052}-\u{11075}
- \u{1107F}-\u{110C2}
- \u{110CD}
- \u{110D0}-\u{110E8}
- \u{110F0}-\u{110F9}
- \u{11100}-\u{11134}
- \u{11136}-\u{11147}
- \u{11150}-\u{11176}
- \u{11180}-\u{111DF}
- \u{111E1}-\u{111F4}
- \u{11200}-\u{11211}
- \u{11213}-\u{11241}
- \u{11280}-\u{11286}
- \u{11288}
- \u{1128A}-\u{1128D}
- \u{1128F}-\u{1129D}
- \u{1129F}-\u{112A9}
- \u{112B0}-\u{112EA}
- \u{112F0}-\u{112F9}
- \u{11300}-\u{11303}
- \u{11305}-\u{1130C}
- \u{1130F}-\u{11310}
- \u{11313}-\u{11328}
- \u{1132A}-\u{11330}
- \u{11332}-\u{11333}
- \u{11335}-\u{11339}
- \u{1133B}-\u{11344}
- \u{11347}-\u{11348}
- \u{1134B}-\u{1134D}
- \u{11350}
- \u{11357}
- \u{1135D}-\u{11363}
- \u{11366}-\u{1136C}
- \u{11370}-\u{11374}
- \u{11400}-\u{1145B}
- \u{1145D}-\u{11461}
- \u{11480}-\u{114C7}
- \u{114D0}-\u{114D9}
- \u{11580}-\u{115B5}
- \u{115B8}-\u{115DD}
- \u{11600}-\u{11644}
- \u{11650}-\u{11659}
- \u{11660}-\u{1166C}
- \u{11680}-\u{116B9}
- \u{116C0}-\u{116C9}
- \u{11700}-\u{1171A}
- \u{1171D}-\u{1172B}
- \u{11730}-\u{11746}
- \u{11800}-\u{1183B}
- \u{118A0}-\u{118F2}
- \u{118FF}-\u{11906}
- \u{11909}
- \u{1190C}-\u{11913}
- \u{11915}-\u{11916}
- \u{11918}-\u{11935}
- \u{11937}-\u{11938}
- \u{1193B}-\u{11946}
- \u{11950}-\u{11959}
- \u{119A0}-\u{119A7}
- \u{119AA}-\u{119D7}
- \u{119DA}-\u{119E4}
- \u{11A00}-\u{11A47}
- \u{11A50}-\u{11AA2}
- \u{11AB0}-\u{11AF8}
- \u{11B00}-\u{11B09}
- \u{11C00}-\u{11C08}
- \u{11C0A}-\u{11C36}
- \u{11C38}-\u{11C45}
- \u{11C50}-\u{11C6C}
- \u{11C70}-\u{11C8F}
- \u{11C92}-\u{11CA7}
- \u{11CA9}-\u{11CB6}
- \u{11D00}-\u{11D06}
- \u{11D08}-\u{11D09}
- \u{11D0B}-\u{11D36}
- \u{11D3A}
- \u{11D3C}-\u{11D3D}
- \u{11D3F}-\u{11D47}
- \u{11D50}-\u{11D59}
- \u{11D60}-\u{11D65}
- \u{11D67}-\u{11D68}
- \u{11D6A}-\u{11D8E}
- \u{11D90}-\u{11D91}
- \u{11D93}-\u{11D98}
- \u{11DA0}-\u{11DA9}
- \u{11EE0}-\u{11EF8}
- \u{11F00}-\u{11F10}
- \u{11F12}-\u{11F3A}
- \u{11F3E}-\u{11F59}
- \u{11FB0}
- \u{11FC0}-\u{11FF1}
- \u{11FFF}-\u{12399}
- \u{12400}-\u{1246E}
- \u{12470}-\u{12474}
- \u{12480}-\u{12543}
- \u{12F90}-\u{12FF2}
- \u{13000}-\u{13455}
- \u{14400}-\u{14646}
- \u{16800}-\u{16A38}
- \u{16A40}-\u{16A5E}
- \u{16A60}-\u{16A69}
- \u{16A6E}-\u{16ABE}
- \u{16AC0}-\u{16AC9}
- \u{16AD0}-\u{16AED}
- \u{16AF0}-\u{16AF5}
- \u{16B00}-\u{16B45}
- \u{16B50}-\u{16B59}
- \u{16B5B}-\u{16B61}
- \u{16B63}-\u{16B77}
- \u{16B7D}-\u{16B8F}
- \u{16E40}-\u{16E9A}
- \u{16F00}-\u{16F4A}
- \u{16F4F}-\u{16F87}
- \u{16F8F}-\u{16F9F}
- \u{1BC00}-\u{1BC6A}
- \u{1BC70}-\u{1BC7C}
- \u{1BC80}-\u{1BC88}
- \u{1BC90}-\u{1BC99}
- \u{1BC9C}-\u{1BCA3}
- \u{1CF00}-\u{1CF2D}
- \u{1CF30}-\u{1CF46}
- \u{1CF50}-\u{1CFC3}
- \u{1D000}-\u{1D0F5}
- \u{1D100}-\u{1D126}
- \u{1D129}-\u{1D1EA}
- \u{1D200}-\u{1D245}
- \u{1D2C0}-\u{1D2D3}
- \u{1D2E0}-\u{1D2F3}
- \u{1D300}-\u{1D356}
- \u{1D360}-\u{1D378}
- \u{1D400}-\u{1D454}
- \u{1D456}-\u{1D49C}
- \u{1D49E}-\u{1D49F}
- \u{1D4A2}
- \u{1D4A5}-\u{1D4A6}
- \u{1D4A9}-\u{1D4AC}
- \u{1D4AE}-\u{1D4B9}
- \u{1D4BB}
- \u{1D4BD}-\u{1D4C3}
- \u{1D4C5}-\u{1D505}
- \u{1D507}-\u{1D50A}
- \u{1D50D}-\u{1D514}
- \u{1D516}-\u{1D51C}
- \u{1D51E}-\u{1D539}
- \u{1D53B}-\u{1D53E}
- \u{1D540}-\u{1D544}
- \u{1D546}
- \u{1D54A}-\u{1D550}
- \u{1D552}-\u{1D6A5}
- \u{1D6A8}-\u{1D7CB}
- \u{1D7CE}-\u{1DA8B}
- \u{1DA9B}-\u{1DA9F}
- \u{1DAA1}-\u{1DAAF}
- \u{1DF00}-\u{1DF1E}
- \u{1DF25}-\u{1DF2A}
- \u{1E000}-\u{1E006}
- \u{1E008}-\u{1E018}
- \u{1E01B}-\u{1E021}
- \u{1E023}-\u{1E024}
- \u{1E026}-\u{1E02A}
- \u{1E030}-\u{1E06D}
- \u{1E08F}
- \u{1E100}-\u{1E12C}
- \u{1E130}-\u{1E13D}
- \u{1E140}-\u{1E149}
- \u{1E14E}-\u{1E14F}
- \u{1E290}-\u{1E2AE}
- \u{1E2C0}-\u{1E2F9}
- \u{1E2FF}
- \u{1E4D0}-\u{1E4F9}
- \u{1E7E0}-\u{1E7E6}
- \u{1E7E8}-\u{1E7EB}
- \u{1E7ED}-\u{1E7EE}
- \u{1E7F0}-\u{1E7FE}
- \u{1E800}-\u{1E8C4}
- \u{1E8C7}-\u{1E8D6}
- \u{1E900}-\u{1E94B}
- \u{1E950}-\u{1E959}
- \u{1E95E}-\u{1E95F}
- \u{1EC71}-\u{1ECB4}
- \u{1ED01}-\u{1ED3D}
- \u{1EE00}-\u{1EE03}
- \u{1EE05}-\u{1EE1F}
- \u{1EE21}-\u{1EE22}
- \u{1EE24}
- \u{1EE27}
- \u{1EE29}-\u{1EE32}
- \u{1EE34}-\u{1EE37}
- \u{1EE39}
- \u{1EE3B}
- \u{1EE42}
- \u{1EE47}
- \u{1EE49}
- \u{1EE4B}
- \u{1EE4D}-\u{1EE4F}
- \u{1EE51}-\u{1EE52}
- \u{1EE54}
- \u{1EE57}
- \u{1EE59}
- \u{1EE5B}
- \u{1EE5D}
- \u{1EE5F}
- \u{1EE61}-\u{1EE62}
- \u{1EE64}
- \u{1EE67}-\u{1EE6A}
- \u{1EE6C}-\u{1EE72}
- \u{1EE74}-\u{1EE77}
- \u{1EE79}-\u{1EE7C}
- \u{1EE7E}
- \u{1EE80}-\u{1EE89}
- \u{1EE8B}-\u{1EE9B}
- \u{1EEA1}-\u{1EEA3}
- \u{1EEA5}-\u{1EEA9}
- \u{1EEAB}-\u{1EEBB}
- \u{1EEF0}-\u{1EEF1}
- \u{1F000}-\u{1F003}
- \u{1F005}-\u{1F02B}
- \u{1F030}-\u{1F093}
- \u{1F0A0}-\u{1F0AE}
- \u{1F0B1}-\u{1F0BF}
- \u{1F0C1}-\u{1F0CE}
- \u{1F0D1}-\u{1F0F5}
- \u{1F10B}-\u{1F10F}
- \u{1F12E}-\u{1F12F}
- \u{1F16A}-\u{1F16F}
- \u{1F1AD}
- \u{1F1E6}-\u{1F1FF}
- \u{1F321}-\u{1F32C}
- \u{1F336}
- \u{1F37D}
- \u{1F394}-\u{1F39F}
- \u{1F3CB}-\u{1F3CE}
- \u{1F3D4}-\u{1F3DF}
- \u{1F3F1}-\u{1F3F3}
- \u{1F3F5}-\u{1F3F7}
- \u{1F43F}
- \u{1F441}
- \u{1F4FD}-\u{1F4FE}
- \u{1F53E}-\u{1F54A}
- \u{1F54F}
- \u{1F568}-\u{1F579}
- \u{1F57B}-\u{1F594}
- \u{1F597}-\u{1F5A3}
- \u{1F5A5}-\u{1F5FA}
- \u{1F650}-\u{1F67F}
- \u{1F6C6}-\u{1F6CB}
- \u{1F6CD}-\u{1F6CF}
- \u{1F6D3}-\u{1F6D4}
- \u{1F6E0}-\u{1F6EA}
- \u{1F6F0}-\u{1F6F3}
- \u{1F700}-\u{1F776}
- \u{1F77B}-\u{1F7D9}
- \u{1F800}-\u{1F80B}
- \u{1F810}-\u{1F847}
- \u{1F850}-\u{1F859}
- \u{1F860}-\u{1F887}
- \u{1F890}-\u{1F8AD}
- \u{1F8B0}-\u{1F8B1}
- \u{1F900}-\u{1F90B}
- \u{1F93B}
- \u{1F946}
- \u{1FA00}-\u{1FA53}
- \u{1FA60}-\u{1FA6D}
- \u{1FB00}-\u{1FB92}
- \u{1FB94}-\u{1FBCA}
- \u{1FBF0}-\u{1FBF9}
- \u{E0001}
- \u{E0020}-\u{E007F}
- ).join }]/
-end
diff --git a/lib/reline/version.rb b/lib/reline/version.rb
deleted file mode 100644
index 67a3d694bd..0000000000
--- a/lib/reline/version.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-module Reline
- VERSION = '0.3.2'
-end
diff --git a/lib/reline/windows.rb b/lib/reline/windows.rb
deleted file mode 100644
index 7ea2a00f63..0000000000
--- a/lib/reline/windows.rb
+++ /dev/null
@@ -1,501 +0,0 @@
-require 'fiddle/import'
-
-class Reline::Windows
- def self.encoding
- Encoding::UTF_8
- end
-
- def self.win?
- true
- end
-
- def self.win_legacy_console?
- @@legacy_console
- end
-
- def self.set_default_key_bindings(config)
- {
- [224, 72] => :ed_prev_history, # ↑
- [224, 80] => :ed_next_history, # ↓
- [224, 77] => :ed_next_char, # →
- [224, 75] => :ed_prev_char, # ←
- [224, 83] => :key_delete, # Del
- [224, 71] => :ed_move_to_beg, # Home
- [224, 79] => :ed_move_to_end, # End
- [ 0, 41] => :ed_unassigned, # input method on/off
- [ 0, 72] => :ed_prev_history, # ↑
- [ 0, 80] => :ed_next_history, # ↓
- [ 0, 77] => :ed_next_char, # →
- [ 0, 75] => :ed_prev_char, # ←
- [ 0, 83] => :key_delete, # Del
- [ 0, 71] => :ed_move_to_beg, # Home
- [ 0, 79] => :ed_move_to_end # End
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
-
- {
- [27, 32] => :em_set_mark, # M-<space>
- [24, 24] => :em_exchange_mark, # C-x C-x
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- end
-
- # Emulate ANSI key sequence.
- {
- [27, 91, 90] => :completion_journey_up, # S-Tab
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- end
- end
-
- if defined? JRUBY_VERSION
- require 'win32api'
- else
- class Win32API
- DLL = {}
- TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
- POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
-
- WIN32_TYPES = "VPpNnLlIi"
- DL_TYPES = "0SSI"
-
- def initialize(dllname, func, import, export = "0", calltype = :stdcall)
- @proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
- import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
- export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
- calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
-
- handle = DLL[dllname] ||=
- begin
- Fiddle.dlopen(dllname)
- rescue Fiddle::DLError
- raise unless File.extname(dllname).empty?
- Fiddle.dlopen(dllname + ".dll")
- end
-
- @func = Fiddle::Function.new(handle[func], import, export, calltype)
- rescue Fiddle::DLError => e
- raise LoadError, e.message, e.backtrace
- end
-
- def call(*args)
- import = @proto.split("")
- args.each_with_index do |x, i|
- args[i], = [x == 0 ? nil : x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
- args[i], = [x].pack("I").unpack("i") if import[i] == "I"
- end
- ret, = @func.call(*args)
- return ret || 0
- end
- end
- end
-
- VK_RETURN = 0x0D
- VK_MENU = 0x12 # ALT key
- VK_LMENU = 0xA4
- VK_CONTROL = 0x11
- VK_SHIFT = 0x10
- VK_DIVIDE = 0x6F
-
- KEY_EVENT = 0x01
- WINDOW_BUFFER_SIZE_EVENT = 0x04
-
- CAPSLOCK_ON = 0x0080
- ENHANCED_KEY = 0x0100
- LEFT_ALT_PRESSED = 0x0002
- LEFT_CTRL_PRESSED = 0x0008
- NUMLOCK_ON = 0x0020
- RIGHT_ALT_PRESSED = 0x0001
- RIGHT_CTRL_PRESSED = 0x0004
- SCROLLLOCK_ON = 0x0040
- SHIFT_PRESSED = 0x0010
-
- VK_TAB = 0x09
- VK_END = 0x23
- VK_HOME = 0x24
- VK_LEFT = 0x25
- VK_UP = 0x26
- VK_RIGHT = 0x27
- VK_DOWN = 0x28
- VK_DELETE = 0x2E
-
- STD_INPUT_HANDLE = -10
- STD_OUTPUT_HANDLE = -11
- FILE_TYPE_PIPE = 0x0003
- FILE_NAME_INFO = 2
- @@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
- @@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
- @@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
- @@GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
- @@SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
- @@GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
- @@FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
- @@ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
- @@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
- @@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
- @@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
- @@ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
- @@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
- @@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
- @@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
- @@SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
-
- @@GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
- @@SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
- @@WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
- ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
-
- private_class_method def self.getconsolemode
- mode = "\000\000\000\000"
- @@GetConsoleMode.call(@@hConsoleHandle, mode)
- mode.unpack1('L')
- end
-
- private_class_method def self.setconsolemode(mode)
- @@SetConsoleMode.call(@@hConsoleHandle, mode)
- end
-
- @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
- #if @@legacy_console
- # setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
- # @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
- #end
-
- @@input_buf = []
- @@output_buf = []
-
- @@output = STDOUT
-
- def self.msys_tty?(io = @@hConsoleInputHandle)
- # check if fd is a pipe
- if @@GetFileType.call(io) != FILE_TYPE_PIPE
- return false
- end
-
- bufsize = 1024
- p_buffer = "\0" * bufsize
- res = @@GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
- return false if res == 0
-
- # get pipe name: p_buffer layout is:
- # struct _FILE_NAME_INFO {
- # DWORD FileNameLength;
- # WCHAR FileName[1];
- # } FILE_NAME_INFO
- len = p_buffer[0, 4].unpack1("L")
- name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
-
- # Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
- # or a cygwin pty pipe ('\cygwin-XXXX-ptyN-XX')
- name =~ /(msys-|cygwin-).*-pty/ ? true : false
- end
-
- KEY_MAP = [
- # It's treated as Meta+Enter on Windows.
- [ { control_keys: :CTRL, virtual_key_code: 0x0D }, "\e\r".bytes ],
- [ { control_keys: :SHIFT, virtual_key_code: 0x0D }, "\e\r".bytes ],
-
- # It's treated as Meta+Space on Windows.
- [ { control_keys: :CTRL, char_code: 0x20 }, "\e ".bytes ],
-
- # Emulate getwch() key sequences.
- [ { control_keys: [], virtual_key_code: VK_UP }, [0, 72] ],
- [ { control_keys: [], virtual_key_code: VK_DOWN }, [0, 80] ],
- [ { control_keys: [], virtual_key_code: VK_RIGHT }, [0, 77] ],
- [ { control_keys: [], virtual_key_code: VK_LEFT }, [0, 75] ],
- [ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
- [ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
- [ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
-
- # Emulate ANSI key sequence.
- [ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
- ]
-
- @@hsg = nil
-
- def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
-
- # high-surrogate
- if 0xD800 <= char_code and char_code <= 0xDBFF
- @@hsg = char_code
- return
- end
- # low-surrogate
- if 0xDC00 <= char_code and char_code <= 0xDFFF
- if @@hsg
- char_code = 0x10000 + (@@hsg - 0xD800) * 0x400 + char_code - 0xDC00
- @@hsg = nil
- else
- # no high-surrogate. ignored.
- return
- end
- else
- # ignore high-surrogate without low-surrogate if there
- @@hsg = nil
- end
-
- key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
-
- match = KEY_MAP.find { |args,| key.matches?(**args) }
- unless match.nil?
- @@output_buf.concat(match.last)
- return
- end
-
- # no char, only control keys
- return if key.char_code == 0 and key.control_keys.any?
-
- @@output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
-
- @@output_buf.concat(key.char.bytes)
- end
-
- def self.check_input_event
- num_of_events = 0.chr * 8
- while @@output_buf.empty?
- Reline.core.line_editor.resize
- if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
- # prevent for background consolemode change
- @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
- next
- end
- next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
- input_records = 0.chr * 20 * 80
- read_event = 0.chr * 4
- if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_records, 80, read_event) != 0
- read_events = read_event.unpack1('L')
- 0.upto(read_events) do |idx|
- input_record = input_records[idx * 20, 20]
- event = input_record[0, 2].unpack1('s*')
- case event
- when WINDOW_BUFFER_SIZE_EVENT
- @@winch_handler.()
- when KEY_EVENT
- key_down = input_record[4, 4].unpack1('l*')
- repeat_count = input_record[8, 2].unpack1('s*')
- virtual_key_code = input_record[10, 2].unpack1('s*')
- virtual_scan_code = input_record[12, 2].unpack1('s*')
- char_code = input_record[14, 2].unpack1('S*')
- control_key_state = input_record[16, 2].unpack1('S*')
- is_key_down = key_down.zero? ? false : true
- if is_key_down
- process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
- end
- end
- end
- end
- end
- end
-
- def self.with_raw_input
- yield
- end
-
- def self.getc
- check_input_event
- @@output_buf.shift
- end
-
- def self.ungetc(c)
- @@output_buf.unshift(c)
- end
-
- def self.in_pasting?
- not self.empty_buffer?
- end
-
- def self.empty_buffer?
- if not @@output_buf.empty?
- false
- elsif @@kbhit.call == 0
- true
- else
- false
- end
- end
-
- def self.get_console_screen_buffer_info
- # CONSOLE_SCREEN_BUFFER_INFO
- # [ 0,2] dwSize.X
- # [ 2,2] dwSize.Y
- # [ 4,2] dwCursorPositions.X
- # [ 6,2] dwCursorPositions.Y
- # [ 8,2] wAttributes
- # [10,2] srWindow.Left
- # [12,2] srWindow.Top
- # [14,2] srWindow.Right
- # [16,2] srWindow.Bottom
- # [18,2] dwMaximumWindowSize.X
- # [20,2] dwMaximumWindowSize.Y
- csbi = 0.chr * 22
- return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0
- csbi
- end
-
- def self.get_screen_size
- unless csbi = get_console_screen_buffer_info
- return [1, 1]
- end
- csbi[0, 4].unpack('SS').reverse
- end
-
- def self.cursor_pos
- unless csbi = get_console_screen_buffer_info
- return Reline::CursorPos.new(0, 0)
- end
- x = csbi[4, 2].unpack1('s')
- y = csbi[6, 2].unpack1('s')
- Reline::CursorPos.new(x, y)
- end
-
- def self.move_cursor_column(val)
- @@SetConsoleCursorPosition.call(@@hConsoleHandle, cursor_pos.y * 65536 + val)
- end
-
- def self.move_cursor_up(val)
- if val > 0
- y = cursor_pos.y - val
- y = 0 if y < 0
- @@SetConsoleCursorPosition.call(@@hConsoleHandle, y * 65536 + cursor_pos.x)
- elsif val < 0
- move_cursor_down(-val)
- end
- end
-
- def self.move_cursor_down(val)
- if val > 0
- return unless csbi = get_console_screen_buffer_info
- screen_height = get_screen_size.first
- y = cursor_pos.y + val
- y = screen_height - 1 if y > (screen_height - 1)
- @@SetConsoleCursorPosition.call(@@hConsoleHandle, (cursor_pos.y + val) * 65536 + cursor_pos.x)
- elsif val < 0
- move_cursor_up(-val)
- end
- end
-
- def self.erase_after_cursor
- return unless csbi = get_console_screen_buffer_info
- attributes = csbi[8, 2].unpack1('S')
- cursor = csbi[4, 4].unpack1('L')
- written = 0.chr * 4
- @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
- @@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
- end
-
- def self.scroll_down(val)
- return if val < 0
- return unless csbi = get_console_screen_buffer_info
- buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s')
- screen_height = window_bottom - window_top + 1
- val = screen_height if val > screen_height
-
- if @@legacy_console || window_left != 0
- # unless ENABLE_VIRTUAL_TERMINAL,
- # if srWindow.Left != 0 then it's conhost.exe hosted console
- # and puts "\n" causes horizontal scroll. its glitch.
- # FYI irb write from culumn 1, so this gives no gain.
- scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4')
- destination_origin = 0 # y * 65536 + x
- fill = [' '.ord, attributes].pack('SS')
- @@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
- else
- origin_x = x + 1
- origin_y = y - window_top + 1
- @@output.write [
- (origin_y != screen_height) ? "\e[#{screen_height};H" : nil,
- "\n" * val,
- (origin_y != screen_height or !x.zero?) ? "\e[#{origin_y};#{origin_x}H" : nil
- ].join
- end
- end
-
- def self.clear_screen
- if @@legacy_console
- return unless csbi = get_console_screen_buffer_info
- buffer_width, _buffer_lines, attributes, window_top, window_bottom = csbi.unpack('ss@8S@12sx2s')
- fill_length = buffer_width * (window_bottom - window_top + 1)
- screen_topleft = window_top * 65536
- written = 0.chr * 4
- @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, fill_length, screen_topleft, written)
- @@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, fill_length, screen_topleft, written)
- @@SetConsoleCursorPosition.call(@@hConsoleHandle, screen_topleft)
- else
- @@output.write "\e[2J" "\e[H"
- end
- end
-
- def self.set_screen_size(rows, columns)
- raise NotImplementedError
- end
-
- def self.hide_cursor
- size = 100
- visible = 0 # 0 means false
- cursor_info = [size, visible].pack('Li')
- @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
- end
-
- def self.show_cursor
- size = 100
- visible = 1 # 1 means true
- cursor_info = [size, visible].pack('Li')
- @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
- end
-
- def self.set_winch_handler(&handler)
- @@winch_handler = handler
- end
-
- def self.prep
- # do nothing
- nil
- end
-
- def self.deprep(otio)
- # do nothing
- end
-
- class KeyEventRecord
-
- attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys
-
- def initialize(virtual_key_code, char_code, control_key_state)
- @virtual_key_code = virtual_key_code
- @char_code = char_code
- @control_key_state = control_key_state
- @enhanced = control_key_state & ENHANCED_KEY != 0
-
- (@control_keys = []).tap do |control_keys|
- # symbols must be sorted to make comparison is easier later on
- control_keys << :ALT if control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0
- control_keys << :CTRL if control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0
- control_keys << :SHIFT if control_key_state & SHIFT_PRESSED != 0
- end.freeze
- end
-
- def char
- @char_code.chr(Encoding::UTF_8)
- end
-
- def enhanced?
- @enhanced
- end
-
- # Verifies if the arguments match with this key event.
- # Nil arguments are ignored, but at least one must be passed as non-nil.
- # To verify that no control keys were pressed, pass an empty array: `control_keys: []`.
- def matches?(control_keys: nil, virtual_key_code: nil, char_code: nil)
- raise ArgumentError, 'No argument was passed to match key event' if control_keys.nil? && virtual_key_code.nil? && char_code.nil?
-
- (control_keys.nil? || [*control_keys].sort == @control_keys) &&
- (virtual_key_code.nil? || @virtual_key_code == virtual_key_code) &&
- (char_code.nil? || char_code == @char_code)
- end
-
- end
-end