summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHiroshi SHIBATA <hsbt@ruby-lang.org>2024-09-06 09:55:34 +0900
committerGitHub <noreply@github.com>2024-09-05 17:55:34 -0700
commitc3f7041ab19fbf0e937126dc1b7397b97f768b9a (patch)
tree741575c32037cd78586588ced0dd7cbaaa0f8cad /lib
parent4eb51dfc9e67683a1a03fdf302d5ddd95cad716a (diff)
Merge reline-0.5.10 (#11558)
* Merge reline-0.5.8 * Merge reline-0.5.9 * Merge reline-0.5.10
Diffstat (limited to 'lib')
-rw-r--r--lib/reline.rb169
-rw-r--r--lib/reline/config.rb100
-rw-r--r--lib/reline/face.rb2
-rw-r--r--lib/reline/general_io.rb111
-rw-r--r--lib/reline/io.rb41
-rw-r--r--lib/reline/io/ansi.rb (renamed from lib/reline/ansi.rb)182
-rw-r--r--lib/reline/io/dumb.rb106
-rw-r--r--lib/reline/io/windows.rb (renamed from lib/reline/windows.rb)214
-rw-r--r--lib/reline/key_actor.rb1
-rw-r--r--lib/reline/key_actor/base.rb28
-rw-r--r--lib/reline/key_actor/composite.rb17
-rw-r--r--lib/reline/key_actor/emacs.rb6
-rw-r--r--lib/reline/key_actor/vi_command.rb4
-rw-r--r--lib/reline/key_actor/vi_insert.rb4
-rw-r--r--lib/reline/key_stroke.rb169
-rw-r--r--lib/reline/line_editor.rb193
-rw-r--r--lib/reline/terminfo.rb7
-rw-r--r--lib/reline/unicode.rb53
-rw-r--r--lib/reline/unicode/east_asian_width.rb2453
-rw-r--r--lib/reline/version.rb2
20 files changed, 1942 insertions, 1920 deletions
diff --git a/lib/reline.rb b/lib/reline.rb
index fb00b96531..ddb0224180 100644
--- a/lib/reline.rb
+++ b/lib/reline.rb
@@ -7,6 +7,7 @@ require 'reline/key_stroke'
require 'reline/line_editor'
require 'reline/history'
require 'reline/terminfo'
+require 'reline/io'
require 'reline/face'
require 'rbconfig'
@@ -18,20 +19,10 @@ module Reline
class ConfigEncodingConversionError < StandardError; end
Key = Struct.new(:char, :combined_char, :with_meta) do
- def match?(other)
- case other
- when Reline::Key
- (other.char.nil? or char.nil? or char == other.char) and
- (other.combined_char.nil? or combined_char.nil? or combined_char == other.combined_char) and
- (other.with_meta.nil? or with_meta.nil? or with_meta == other.with_meta)
- when Integer, Symbol
- (combined_char and combined_char == other) or
- (combined_char.nil? and char and char == other)
- else
- false
- end
+ # For dialog_proc `key.match?(dialog.name)`
+ def match?(sym)
+ combined_char.is_a?(Symbol) && combined_char == sym
end
- alias_method :==, :match?
end
CursorPos = Struct.new(:x, :y)
DialogRenderInfo = Struct.new(
@@ -263,7 +254,6 @@ module Reline
raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
end
- Reline.update_iogate
io_gate.with_raw_input do
inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
end
@@ -286,7 +276,6 @@ module Reline
def readline(prompt = '', add_hist = false)
@mutex.synchronize do
- Reline.update_iogate
io_gate.with_raw_input do
inner_readline(prompt, add_hist, false)
end
@@ -335,14 +324,17 @@ module Reline
line_editor.prompt_proc = prompt_proc
line_editor.auto_indent_proc = auto_indent_proc
line_editor.dig_perfect_match_proc = dig_perfect_match_proc
+
+ # Readline calls pre_input_hook just after printing the first prompt.
+ line_editor.print_nomultiline_prompt
pre_input_hook&.call
- unless Reline::IOGate == Reline::GeneralIO
+
+ unless Reline::IOGate.dumb?
@dialog_proc_list.each_pair do |name_sym, d|
line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
end
end
- line_editor.print_nomultiline_prompt(prompt)
line_editor.update_dialogs
line_editor.rerender
@@ -354,7 +346,7 @@ module Reline
inputs.each do |key|
if key.char == :bracketed_paste_start
text = io_gate.read_bracketed_paste
- line_editor.insert_pasted_text(text)
+ line_editor.insert_multiline_text(text)
line_editor.scroll_into_view
else
line_editor.update(key)
@@ -378,92 +370,39 @@ module Reline
end
end
- # GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
- # is followed by a character, and times out and treats it as a standalone
- # ESC if the second character does not arrive. If the second character
- # comes before timed out, it is treated as a modifier key with the
- # meta-property of meta-key, so that it can be distinguished from
- # multibyte characters with the 8th bit turned on.
- #
- # GNU Readline will wait for the 2nd character with "keyseq-timeout"
- # milli-seconds but wait forever after 3rd characters.
+ # GNU Readline watis for "keyseq-timeout" milliseconds when the input is
+ # ambiguous whether it is matching or matched.
+ # If the next character does not arrive within the specified timeout, input
+ # is considered as matched.
+ # `ESC` is ambiguous because it can be a standalone ESC (matched) or part of
+ # `ESC char` or part of CSI sequence (matching).
private def read_io(keyseq_timeout, &block)
buffer = []
+ status = KeyStroke::MATCHING
loop do
- c = io_gate.getc(Float::INFINITY)
- if c == -1
- result = :unmatched
- else
- buffer << c
- result = key_stroke.match_status(buffer)
- end
- case result
- when :matched
- expanded = key_stroke.expand(buffer).map{ |expanded_c|
- Reline::Key.new(expanded_c, expanded_c, false)
- }
- block.(expanded)
- break
- when :matching
- if buffer.size == 1
- case read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
- when :break then break
- when :next then next
- end
- end
- when :unmatched
- if buffer.size == 1 and c == "\e".ord
- read_escaped_key(keyseq_timeout, c, block)
+ timeout = status == KeyStroke::MATCHING_MATCHED ? keyseq_timeout.fdiv(1000) : Float::INFINITY
+ c = io_gate.getc(timeout)
+ if c.nil? || c == -1
+ if status == KeyStroke::MATCHING_MATCHED
+ status = KeyStroke::MATCHED
+ elsif buffer.empty?
+ # io_gate is closed and reached EOF
+ block.call([Key.new(nil, nil, false)])
+ return
else
- expanded = buffer.map{ |expanded_c|
- Reline::Key.new(expanded_c, expanded_c, false)
- }
- block.(expanded)
+ status = KeyStroke::UNMATCHED
end
- break
+ else
+ buffer << c
+ status = key_stroke.match_status(buffer)
end
- end
- end
- private def read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
- succ_c = io_gate.getc(keyseq_timeout.fdiv(1000))
- if succ_c
- case key_stroke.match_status(buffer.dup.push(succ_c))
- when :unmatched
- if c == "\e".ord
- block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
- else
- block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
- end
- return :break
- when :matching
- io_gate.ungetc(succ_c)
- return :next
- when :matched
- buffer << succ_c
- expanded = key_stroke.expand(buffer).map{ |expanded_c|
- Reline::Key.new(expanded_c, expanded_c, false)
- }
- block.(expanded)
- return :break
+ if status == KeyStroke::MATCHED || status == KeyStroke::UNMATCHED
+ expanded, rest_bytes = key_stroke.expand(buffer)
+ rest_bytes.reverse_each { |c| io_gate.ungetc(c) }
+ block.call(expanded)
+ return
end
- else
- block.([Reline::Key.new(c, c, false)])
- return :break
- end
- end
-
- private def read_escaped_key(keyseq_timeout, c, block)
- escaped_c = io_gate.getc(keyseq_timeout.fdiv(1000))
-
- if escaped_c.nil?
- block.([Reline::Key.new(c, c, false)])
- elsif escaped_c >= 128 # maybe, first byte of multi byte
- block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
- elsif escaped_c == "\e".ord # escape twice
- block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
- else
- block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
end
end
@@ -473,7 +412,7 @@ module Reline
end
private def may_req_ambiguous_char_width
- @ambiguous_width = 2 if io_gate == Reline::GeneralIO or !STDOUT.tty?
+ @ambiguous_width = 2 if io_gate.dumb? || !STDIN.tty? || !STDOUT.tty?
return if defined? @ambiguous_width
io_gate.move_cursor_column(0)
begin
@@ -521,8 +460,8 @@ module Reline
def_single_delegator :line_editor, :byte_pointer, :point
def_single_delegator :line_editor, :byte_pointer=, :point=
- def self.insert_text(*args, &block)
- line_editor.insert_text(*args, &block)
+ def self.insert_text(text)
+ line_editor.insert_multiline_text(text)
self
end
@@ -567,37 +506,13 @@ module Reline
def self.line_editor
core.line_editor
end
+end
- def self.update_iogate
- return if core.config.test_mode
- # Need to change IOGate when `$stdout.tty?` change from false to true by `$stdout.reopen`
- # Example: rails/spring boot the application in non-tty, then run console in tty.
- if ENV['TERM'] != 'dumb' && core.io_gate == Reline::GeneralIO && $stdout.tty?
- require 'reline/ansi'
- remove_const(:IOGate)
- const_set(:IOGate, Reline::ANSI)
- end
- end
-end
+Reline::IOGate = Reline::IO.decide_io_gate
-require 'reline/general_io'
-io = Reline::GeneralIO
-unless ENV['TERM'] == 'dumb'
- case RbConfig::CONFIG['host_os']
- when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
- require 'reline/windows'
- tty = (io = Reline::Windows).msys_tty?
- else
- tty = $stdout.tty?
- end
-end
-Reline::IOGate = if tty
- require 'reline/ansi'
- Reline::ANSI
-else
- io
-end
+# Deprecated
+Reline::GeneralIO = Reline::Dumb.new
Reline::Face.load_initial_configs
diff --git a/lib/reline/config.rb b/lib/reline/config.rb
index d44c2675ab..6aa6ba8d94 100644
--- a/lib/reline/config.rb
+++ b/lib/reline/config.rb
@@ -29,18 +29,31 @@ class Reline::Config
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 = {}
+ reset_variables
+ end
+
+ def reset
+ if editing_mode_is?(:vi_command)
+ @editing_mode_label = :vi_insert
+ end
+ @oneshot_key_bindings.clear
+ end
+
+ def reset_variables
+ @additional_key_bindings = { # from inputrc
+ emacs: Reline::KeyActor::Base.new,
+ vi_insert: Reline::KeyActor::Base.new,
+ vi_command: Reline::KeyActor::Base.new
+ }
+ @oneshot_key_bindings = Reline::KeyActor::Base.new
@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
+ @default_key_bindings = {
+ emacs: Reline::KeyActor::Base.new(Reline::KeyActor::EMACS_MAPPING),
+ vi_insert: Reline::KeyActor::Base.new(Reline::KeyActor::VI_INSERT_MAPPING),
+ vi_command: Reline::KeyActor::Base.new(Reline::KeyActor::VI_COMMAND_MAPPING)
+ }
@vi_cmd_mode_string = '(cmd)'
@vi_ins_mode_string = '(ins)'
@emacs_mode_string = '@'
@@ -49,20 +62,15 @@ class Reline::Config
@keyseq_timeout = 500
@test_mode = false
@autocompletion = false
- @convert_meta = true if seven_bit_encoding?(Reline::IOGate.encoding)
+ @convert_meta = seven_bit_encoding?(Reline::IOGate.encoding)
@loaded = false
@enable_bracketed_paste = true
- end
-
- def reset
- if editing_mode_is?(:vi_command)
- @editing_mode_label = :vi_insert
- end
- @oneshot_key_bindings.clear
+ @show_mode_in_prompt = false
+ @default_inputrc_path = nil
end
def editing_mode
- @key_actors[@editing_mode_label]
+ @default_key_bindings[@editing_mode_label]
end
def editing_mode=(val)
@@ -74,7 +82,7 @@ class Reline::Config
end
def keymap
- @key_actors[@keymap_label]
+ @default_key_bindings[@keymap_label]
end
def loaded?
@@ -133,14 +141,14 @@ class Reline::Config
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
+ Reline::KeyActor::Composite.new([@oneshot_key_bindings, @additional_key_bindings[@editing_mode_label], @default_key_bindings[@editing_mode_label]])
end
def add_oneshot_key_binding(keystroke, target)
- @oneshot_key_bindings[keystroke] = target
+ # IRB sets invalid keystroke [Reline::Key]. We should ignore it.
+ return unless keystroke.all? { |c| c.is_a?(Integer) }
+
+ @oneshot_key_bindings.add(keystroke, target)
end
def reset_oneshot_key_bindings
@@ -148,11 +156,11 @@ class Reline::Config
end
def add_default_key_binding_by_keymap(keymap, keystroke, target)
- @key_actors[keymap].default_key_bindings[keystroke] = target
+ @default_key_bindings[keymap].add(keystroke, target)
end
def add_default_key_binding(keystroke, target)
- @key_actors[@keymap_label].default_key_bindings[keystroke] = target
+ add_default_key_binding_by_keymap(@keymap_label, keystroke, target)
end
def read_lines(lines, file = nil)
@@ -182,16 +190,17 @@ class Reline::Config
next if if_stack.any? { |_no, skip| skip }
case line
- when /^set +([^ ]+) +([^ ]+)/i
- var, value = $1.downcase, $2
- bind_variable(var, value)
+ when /^set +([^ ]+) +(.+)/i
+ # value ignores everything after a space, raw_value does not.
+ var, value, raw_value = $1.downcase, $2.partition(' ').first, $2
+ bind_variable(var, value, raw_value)
next
when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
key, func_name = $1, $2
func_name = func_name.split.first
keystroke, func = bind_key(key, func_name)
next unless keystroke
- @additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func
+ @additional_key_bindings[@keymap_label].add(@keymap_prefix + keystroke, func)
end
end
unless if_stack.empty?
@@ -234,7 +243,7 @@ class Reline::Config
end
end
- def bind_variable(name, value)
+ def bind_variable(name, value, raw_value)
case name
when 'history-size'
begin
@@ -242,24 +251,8 @@ class Reline::Config
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)
+ @isearch_terminators = retrieve_string(raw_value)
when 'editing-mode'
case value
when 'emacs'
@@ -301,11 +294,11 @@ class Reline::Config
@show_mode_in_prompt = false
end
when 'vi-cmd-mode-string'
- @vi_cmd_mode_string = retrieve_string(value)
+ @vi_cmd_mode_string = retrieve_string(raw_value)
when 'vi-ins-mode-string'
- @vi_ins_mode_string = retrieve_string(value)
+ @vi_ins_mode_string = retrieve_string(raw_value)
when 'emacs-mode-string'
- @emacs_mode_string = retrieve_string(value)
+ @emacs_mode_string = retrieve_string(raw_value)
when *VARIABLE_NAMES then
variable_name = :"@#{name.tr(?-, ?_)}"
instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
@@ -373,6 +366,11 @@ class Reline::Config
ret
end
+ def reload
+ reset_variables
+ read
+ end
+
private def seven_bit_encoding?(encoding)
encoding == Encoding::US_ASCII
end
diff --git a/lib/reline/face.rb b/lib/reline/face.rb
index d07196e2e7..5b4464a623 100644
--- a/lib/reline/face.rb
+++ b/lib/reline/face.rb
@@ -107,7 +107,7 @@ class Reline::Face
def sgr_rgb_256color(key, value)
# 256 colors are
- # 0..15: standard colors, hight intensity colors
+ # 0..15: standard colors, high intensity colors
# 16..232: 216 colors (R, G, B each 6 steps)
# 233..255: grayscale colors (24 steps)
# This methods converts rgb_expression to 216 colors
diff --git a/lib/reline/general_io.rb b/lib/reline/general_io.rb
deleted file mode 100644
index d52151ad3c..0000000000
--- a/lib/reline/general_io.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-require 'io/wait'
-
-class Reline::GeneralIO
- RESET_COLOR = '' # Do not send color reset sequence
-
- def self.reset(encoding: nil)
- @@pasting = false
- if encoding
- @@encoding = encoding
- elsif defined?(@@encoding)
- remove_class_variable(:@@encoding)
- end
- 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(_timeout_second)
- unless @@buf.empty?
- return @@buf.shift
- end
- c = nil
- loop do
- Reline.core.line_editor.handle_signal
- 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
- [24, 80]
- 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.prep
- end
-
- def self.deprep(otio)
- end
-end
diff --git a/lib/reline/io.rb b/lib/reline/io.rb
new file mode 100644
index 0000000000..c1dd1a56c8
--- /dev/null
+++ b/lib/reline/io.rb
@@ -0,0 +1,41 @@
+
+module Reline
+ class IO
+ RESET_COLOR = "\e[0m"
+
+ def self.decide_io_gate
+ if ENV['TERM'] == 'dumb'
+ Reline::Dumb.new
+ else
+ require 'reline/io/ansi'
+
+ case RbConfig::CONFIG['host_os']
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
+ require 'reline/io/windows'
+ io = Reline::Windows.new
+ if io.msys_tty?
+ Reline::ANSI.new
+ else
+ io
+ end
+ else
+ Reline::ANSI.new
+ end
+ end
+ end
+
+ def dumb?
+ false
+ end
+
+ def win?
+ false
+ end
+
+ def reset_color_sequence
+ self.class::RESET_COLOR
+ end
+ end
+end
+
+require 'reline/io/dumb'
diff --git a/lib/reline/ansi.rb b/lib/reline/io/ansi.rb
index 45a475a787..a730a953f7 100644
--- a/lib/reline/ansi.rb
+++ b/lib/reline/io/ansi.rb
@@ -1,10 +1,7 @@
require 'io/console'
require 'io/wait'
-require_relative 'terminfo'
-
-class Reline::ANSI
- RESET_COLOR = "\e[0m"
+class Reline::ANSI < Reline::IO
CAPNAME_KEY_BINDINGS = {
'khome' => :ed_move_to_beg,
'kend' => :ed_move_to_end,
@@ -36,15 +33,18 @@ class Reline::ANSI
Reline::Terminfo.setupterm(0, 2)
end
- def self.encoding
- Encoding.default_external
+ def initialize
+ @input = STDIN
+ @output = STDOUT
+ @buf = []
+ @old_winch_handler = nil
end
- def self.win?
- false
+ def encoding
+ Encoding.default_external
end
- def self.set_default_key_bindings(config, allow_terminfo: true)
+ def set_default_key_bindings(config, allow_terminfo: true)
set_bracketed_paste_key_bindings(config)
set_default_key_bindings_ansi_cursor(config)
if allow_terminfo && Reline::Terminfo.enabled?
@@ -67,13 +67,13 @@ class Reline::ANSI
end
end
- def self.set_bracketed_paste_key_bindings(config)
+ def set_bracketed_paste_key_bindings(config)
[:emacs, :vi_insert, :vi_command].each do |keymap|
config.add_default_key_binding_by_keymap(keymap, START_BRACKETED_PASTE.bytes, :bracketed_paste_start)
end
end
- def self.set_default_key_bindings_ansi_cursor(config)
+ def set_default_key_bindings_ansi_cursor(config)
ANSI_CURSOR_KEY_BINDINGS.each do |char, (default_func, modifiers)|
bindings = [["\e[#{char}", default_func]] # CSI + char
if modifiers[:ctrl]
@@ -95,7 +95,7 @@ class Reline::ANSI
end
end
- def self.set_default_key_bindings_terminfo(config)
+ def set_default_key_bindings_terminfo(config)
key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
begin
key_code = Reline::Terminfo.tigetstr(capname)
@@ -112,12 +112,16 @@ class Reline::ANSI
end
end
- def self.set_default_key_bindings_comprehensive_list(config)
+ def set_default_key_bindings_comprehensive_list(config)
{
+ # xterm
+ [27, 91, 51, 126] => :key_delete, # kdch1
+ [27, 91, 53, 126] => :ed_search_prev_history, # kpp
+ [27, 91, 54, 126] => :ed_search_next_history, # knp
+
# 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
# KDE
# Del is 0x08
@@ -147,47 +151,42 @@ class Reline::ANSI
end
end
- @@input = STDIN
- def self.input=(val)
- @@input = val
+ def input=(val)
+ @input = val
end
- @@output = STDOUT
- def self.output=(val)
- @@output = val
+ def output=(val)
+ @output = val
end
- def self.with_raw_input
- if @@input.tty?
- @@input.raw(intr: true) { yield }
+ def with_raw_input
+ if @input.tty?
+ @input.raw(intr: true) { yield }
else
yield
end
end
- @@buf = []
- def self.inner_getc(timeout_second)
- unless @@buf.empty?
- return @@buf.shift
+ def inner_getc(timeout_second)
+ unless @buf.empty?
+ return @buf.shift
end
- until @@input.wait_readable(0.01)
+ until @input.wait_readable(0.01)
timeout_second -= 0.01
return nil if timeout_second <= 0
Reline.core.line_editor.handle_signal
end
- c = @@input.getbyte
- (c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
+ c = @input.getbyte
+ (c == 0x16 && @input.tty? && @input.raw(min: 0, time: 0, &:getbyte)) || c
rescue Errno::EIO
# Maybe the I/O has been closed.
nil
- rescue Errno::ENOTTY
- nil
end
START_BRACKETED_PASTE = String.new("\e[200~", encoding: Encoding::ASCII_8BIT)
END_BRACKETED_PASTE = String.new("\e[201~", encoding: Encoding::ASCII_8BIT)
- def self.read_bracketed_paste
+ def read_bracketed_paste
buffer = String.new(encoding: Encoding::ASCII_8BIT)
until buffer.end_with?(END_BRACKETED_PASTE)
c = inner_getc(Float::INFINITY)
@@ -199,60 +198,60 @@ class Reline::ANSI
end
# if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
- def self.getc(timeout_second)
+ def getc(timeout_second)
inner_getc(timeout_second)
end
- def self.in_pasting?
+ def in_pasting?
not empty_buffer?
end
- def self.empty_buffer?
- unless @@buf.empty?
+ def empty_buffer?
+ unless @buf.empty?
return false
end
- !@@input.wait_readable(0)
+ !@input.wait_readable(0)
end
- def self.ungetc(c)
- @@buf.unshift(c)
+ def ungetc(c)
+ @buf.unshift(c)
end
- def self.retrieve_keybuffer
+ def retrieve_keybuffer
begin
- return unless @@input.wait_readable(0.001)
- str = @@input.read_nonblock(1024)
+ return unless @input.wait_readable(0.001)
+ str = @input.read_nonblock(1024)
str.bytes.each do |c|
- @@buf.push(c)
+ @buf.push(c)
end
rescue EOFError
end
end
- def self.get_screen_size
- s = @@input.winsize
+ def 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
+ rescue Errno::ENOTTY, Errno::ENODEV
[24, 80]
end
- def self.set_screen_size(rows, columns)
- @@input.winsize = [rows, columns]
+ def set_screen_size(rows, columns)
+ @input.winsize = [rows, columns]
self
- rescue Errno::ENOTTY
+ rescue Errno::ENOTTY, Errno::ENODEV
self
end
- def self.cursor_pos
- begin
+ def cursor_pos
+ if both_tty?
res = +''
m = nil
- @@input.raw do |stdin|
- @@output << "\e[6n"
- @@output.flush
+ @input.raw do |stdin|
+ @output << "\e[6n"
+ @output.flush
loop do
c = stdin.getc
next if c.nil?
@@ -266,9 +265,9 @@ class Reline::ANSI
end
column = m[:column].to_i - 1
row = m[:row].to_i - 1
- rescue Errno::ENOTTY
+ else
begin
- buf = @@output.pread(@@output.pos, 0)
+ buf = @output.pread(@output.pos, 0)
row = buf.count("\n")
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
rescue Errno::ESPIPE, IOError
@@ -281,82 +280,93 @@ class Reline::ANSI
Reline::CursorPos.new(column, row)
end
- def self.move_cursor_column(x)
- @@output.write "\e[#{x + 1}G"
+ def both_tty?
+ @input.tty? && @output.tty?
+ end
+
+ def move_cursor_column(x)
+ @output.write "\e[#{x + 1}G"
end
- def self.move_cursor_up(x)
+ def move_cursor_up(x)
if x > 0
- @@output.write "\e[#{x}A"
+ @output.write "\e[#{x}A"
elsif x < 0
move_cursor_down(-x)
end
end
- def self.move_cursor_down(x)
+ def move_cursor_down(x)
if x > 0
- @@output.write "\e[#{x}B"
+ @output.write "\e[#{x}B"
elsif x < 0
move_cursor_up(-x)
end
end
- def self.hide_cursor
+ def hide_cursor
+ seq = "\e[?25l"
if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
begin
- @@output.write Reline::Terminfo.tigetstr('civis')
+ seq = Reline::Terminfo.tigetstr('civis')
rescue Reline::Terminfo::TerminfoError
# civis is undefined
end
- else
- # ignored
end
+ @output.write seq
end
- def self.show_cursor
+ def show_cursor
+ seq = "\e[?25h"
if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
begin
- @@output.write Reline::Terminfo.tigetstr('cnorm')
+ seq = Reline::Terminfo.tigetstr('cnorm')
rescue Reline::Terminfo::TerminfoError
# cnorm is undefined
end
- else
- # ignored
end
+ @output.write seq
end
- def self.erase_after_cursor
- @@output.write "\e[K"
+ def erase_after_cursor
+ @output.write "\e[K"
end
# This only works when the cursor is at the bottom of the scroll range
# For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623
- def self.scroll_down(x)
+ def scroll_down(x)
return if x.zero?
# We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576
- @@output.write "\n" * x
+ @output.write "\n" * x
end
- def self.clear_screen
- @@output.write "\e[2J"
- @@output.write "\e[1;1H"
+ def 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)
+ def set_winch_handler(&handler)
+ @old_winch_handler = Signal.trap('WINCH', &handler)
+ @old_cont_handler = Signal.trap('CONT') do
+ @input.raw!(intr: true) if @input.tty?
+ # Rerender the screen. Note that screen size might be changed while suspended.
+ handler.call
+ end
+ rescue ArgumentError
+ # Signal.trap may raise an ArgumentError if the platform doesn't support the signal.
end
- def self.prep
+ def prep
# Enable bracketed paste
- @@output.write "\e[?2004h" if Reline.core.config.enable_bracketed_paste
+ @output.write "\e[?2004h" if Reline.core.config.enable_bracketed_paste && both_tty?
retrieve_keybuffer
nil
end
- def self.deprep(otio)
+ def deprep(otio)
# Disable bracketed paste
- @@output.write "\e[?2004l" if Reline.core.config.enable_bracketed_paste
- Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
+ @output.write "\e[?2004l" if Reline.core.config.enable_bracketed_paste && both_tty?
+ Signal.trap('WINCH', @old_winch_handler) if @old_winch_handler
+ Signal.trap('CONT', @old_cont_handler) if @old_cont_handler
end
end
diff --git a/lib/reline/io/dumb.rb b/lib/reline/io/dumb.rb
new file mode 100644
index 0000000000..6ed69ffdfa
--- /dev/null
+++ b/lib/reline/io/dumb.rb
@@ -0,0 +1,106 @@
+require 'io/wait'
+
+class Reline::Dumb < Reline::IO
+ RESET_COLOR = '' # Do not send color reset sequence
+
+ def initialize(encoding: nil)
+ @input = STDIN
+ @buf = []
+ @pasting = false
+ @encoding = encoding
+ @screen_size = [24, 80]
+ end
+
+ def dumb?
+ true
+ end
+
+ def encoding
+ if @encoding
+ @encoding
+ elsif RUBY_PLATFORM =~ /mswin|mingw/
+ Encoding::UTF_8
+ else
+ Encoding::default_external
+ end
+ end
+
+ def set_default_key_bindings(_)
+ end
+
+ def input=(val)
+ @input = val
+ end
+
+ def with_raw_input
+ yield
+ end
+
+ def getc(_timeout_second)
+ unless @buf.empty?
+ return @buf.shift
+ end
+ c = nil
+ loop do
+ Reline.core.line_editor.handle_signal
+ result = @input.wait_readable(0.1)
+ next if result.nil?
+ c = @input.read(1)
+ break
+ end
+ c&.ord
+ end
+
+ def ungetc(c)
+ @buf.unshift(c)
+ end
+
+ def get_screen_size
+ @screen_size
+ end
+
+ def cursor_pos
+ Reline::CursorPos.new(1, 1)
+ end
+
+ def hide_cursor
+ end
+
+ def show_cursor
+ end
+
+ def move_cursor_column(val)
+ end
+
+ def move_cursor_up(val)
+ end
+
+ def move_cursor_down(val)
+ end
+
+ def erase_after_cursor
+ end
+
+ def scroll_down(val)
+ end
+
+ def clear_screen
+ end
+
+ def set_screen_size(rows, columns)
+ @screen_size = [rows, columns]
+ end
+
+ def set_winch_handler(&handler)
+ end
+
+ def in_pasting?
+ @pasting
+ end
+
+ def prep
+ end
+
+ def deprep(otio)
+ end
+end
diff --git a/lib/reline/windows.rb b/lib/reline/io/windows.rb
index ee3f73e383..40025db504 100644
--- a/lib/reline/windows.rb
+++ b/lib/reline/io/windows.rb
@@ -1,21 +1,49 @@
require 'fiddle/import'
-class Reline::Windows
- RESET_COLOR = "\e[0m"
+class Reline::Windows < Reline::IO
+ def initialize
+ @input_buf = []
+ @output_buf = []
+
+ @output = STDOUT
+ @hsg = nil
+ @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')
+
+ @legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
+ end
- def self.encoding
+ def encoding
Encoding::UTF_8
end
- def self.win?
+ def win?
true
end
- def self.win_legacy_console?
- @@legacy_console
+ def win_legacy_console?
+ @legacy_console
end
- def self.set_default_key_bindings(config)
+ def set_default_key_bindings(config)
{
[224, 72] => :ed_prev_history, # ↑
[224, 80] => :ed_next_history, # ↓
@@ -129,58 +157,42 @@ class Reline::Windows
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
+ # Calling Win32API with console handle is reported to fail after executing some external command.
+ # We need to refresh console handle and retry the call again.
+ private def call_with_console_handle(win32func, *args)
+ val = win32func.call(@hConsoleHandle, *args)
+ return val if val != 0
+
+ @hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
+ win32func.call(@hConsoleHandle, *args)
+ end
+
+ private def getconsolemode
mode = "\000\000\000\000"
- @@GetConsoleMode.call(@@hConsoleHandle, mode)
+ call_with_console_handle(@GetConsoleMode, mode)
mode.unpack1('L')
end
- private_class_method def self.setconsolemode(mode)
- @@SetConsoleMode.call(@@hConsoleHandle, mode)
+ private def setconsolemode(mode)
+ call_with_console_handle(@SetConsoleMode, mode)
end
- @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
- #if @@legacy_console
+ #if @legacy_console
# setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
- # @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
+ # @legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
#end
- @@input_buf = []
- @@output_buf = []
-
- @@output = STDOUT
-
- def self.msys_tty?(io = @@hConsoleInputHandle)
+ def msys_tty?(io = @hConsoleInputHandle)
# check if fd is a pipe
- if @@GetFileType.call(io) != FILE_TYPE_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)
+ res = @GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
return false if res == 0
# get pipe name: p_buffer layout is:
@@ -217,65 +229,63 @@ class Reline::Windows
[ { 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)
+ def 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
+ @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
+ 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
+ @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)
+ @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.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
- @@output_buf.concat(key.char.bytes)
+ @output_buf.concat(key.char.bytes)
end
- def self.check_input_event
+ def check_input_event
num_of_events = 0.chr * 8
- while @@output_buf.empty?
+ while @output_buf.empty?
Reline.core.line_editor.handle_signal
- if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
+ if @WaitForSingleObject.(@hConsoleInputHandle, 100) != 0 # max 0.1 sec
# prevent for background consolemode change
- @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
+ @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
+ 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
+ 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.()
+ @winch_handler.()
when KEY_EVENT
key_down = input_record[4, 4].unpack1('l*')
repeat_count = input_record[8, 2].unpack1('s*')
@@ -293,34 +303,34 @@ class Reline::Windows
end
end
- def self.with_raw_input
+ def with_raw_input
yield
end
- def self.getc(_timeout_second)
+ def getc(_timeout_second)
check_input_event
- @@output_buf.shift
+ @output_buf.shift
end
- def self.ungetc(c)
- @@output_buf.unshift(c)
+ def ungetc(c)
+ @output_buf.unshift(c)
end
- def self.in_pasting?
- not self.empty_buffer?
+ def in_pasting?
+ not empty_buffer?
end
- def self.empty_buffer?
- if not @@output_buf.empty?
+ def empty_buffer?
+ if not @output_buf.empty?
false
- elsif @@kbhit.call == 0
+ elsif @kbhit.call == 0
true
else
false
end
end
- def self.get_console_screen_buffer_info
+ def get_console_screen_buffer_info
# CONSOLE_SCREEN_BUFFER_INFO
# [ 0,2] dwSize.X
# [ 2,2] dwSize.Y
@@ -334,18 +344,18 @@ class Reline::Windows
# [18,2] dwMaximumWindowSize.X
# [20,2] dwMaximumWindowSize.Y
csbi = 0.chr * 22
- return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0
+ return if call_with_console_handle(@GetConsoleScreenBufferInfo, csbi) == 0
csbi
end
- def self.get_screen_size
+ def 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
+ def cursor_pos
unless csbi = get_console_screen_buffer_info
return Reline::CursorPos.new(0, 0)
end
@@ -354,49 +364,49 @@ class Reline::Windows
Reline::CursorPos.new(x, y)
end
- def self.move_cursor_column(val)
- @@SetConsoleCursorPosition.call(@@hConsoleHandle, cursor_pos.y * 65536 + val)
+ def move_cursor_column(val)
+ call_with_console_handle(@SetConsoleCursorPosition, cursor_pos.y * 65536 + val)
end
- def self.move_cursor_up(val)
+ def 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)
+ call_with_console_handle(@SetConsoleCursorPosition, y * 65536 + cursor_pos.x)
elsif val < 0
move_cursor_down(-val)
end
end
- def self.move_cursor_down(val)
+ def 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)
+ call_with_console_handle(@SetConsoleCursorPosition, (cursor_pos.y + val) * 65536 + cursor_pos.x)
elsif val < 0
move_cursor_up(-val)
end
end
- def self.erase_after_cursor
+ def 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)
+ call_with_console_handle(@FillConsoleOutputCharacter, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
+ call_with_console_handle(@FillConsoleOutputAttribute, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
end
- def self.scroll_down(val)
+ def 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
+ 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.
@@ -404,11 +414,11 @@ class Reline::Windows
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)
+ call_with_console_handle(@ScrollConsoleScreenBuffer, scroll_rectangle, nil, destination_origin, fill)
else
origin_x = x + 1
origin_y = y - window_top + 1
- @@output.write [
+ @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
@@ -416,49 +426,49 @@ class Reline::Windows
end
end
- def self.clear_screen
- if @@legacy_console
+ def 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)
+ call_with_console_handle(@FillConsoleOutputCharacter, 0x20, fill_length, screen_topleft, written)
+ call_with_console_handle(@FillConsoleOutputAttribute, attributes, fill_length, screen_topleft, written)
+ call_with_console_handle(@SetConsoleCursorPosition, screen_topleft)
else
- @@output.write "\e[2J" "\e[H"
+ @output.write "\e[2J" "\e[H"
end
end
- def self.set_screen_size(rows, columns)
+ def set_screen_size(rows, columns)
raise NotImplementedError
end
- def self.hide_cursor
+ def hide_cursor
size = 100
visible = 0 # 0 means false
cursor_info = [size, visible].pack('Li')
- @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
+ call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
end
- def self.show_cursor
+ def show_cursor
size = 100
visible = 1 # 1 means true
cursor_info = [size, visible].pack('Li')
- @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
+ call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
end
- def self.set_winch_handler(&handler)
- @@winch_handler = handler
+ def set_winch_handler(&handler)
+ @winch_handler = handler
end
- def self.prep
+ def prep
# do nothing
nil
end
- def self.deprep(otio)
+ def deprep(otio)
# do nothing
end
diff --git a/lib/reline/key_actor.rb b/lib/reline/key_actor.rb
index ebe09d2009..0ac7604556 100644
--- a/lib/reline/key_actor.rb
+++ b/lib/reline/key_actor.rb
@@ -2,6 +2,7 @@ module Reline::KeyActor
end
require 'reline/key_actor/base'
+require 'reline/key_actor/composite'
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
index 194e98938c..ee28c7681e 100644
--- a/lib/reline/key_actor/base.rb
+++ b/lib/reline/key_actor/base.rb
@@ -1,15 +1,31 @@
class Reline::KeyActor::Base
- MAPPING = Array.new(256)
+ def initialize(mapping = [])
+ @mapping = mapping
+ @matching_bytes = {}
+ @key_bindings = {}
+ end
def get_method(key)
- self.class::MAPPING[key]
+ @mapping[key]
+ end
+
+ def add(key, func)
+ (1...key.size).each do |size|
+ @matching_bytes[key.take(size)] = true
+ end
+ @key_bindings[key] = func
+ end
+
+ def matching?(key)
+ @matching_bytes[key]
end
- def initialize
- @default_key_bindings = {}
+ def get(key)
+ @key_bindings[key]
end
- def default_key_bindings
- @default_key_bindings
+ def clear
+ @matching_bytes.clear
+ @key_bindings.clear
end
end
diff --git a/lib/reline/key_actor/composite.rb b/lib/reline/key_actor/composite.rb
new file mode 100644
index 0000000000..37e94ce6cf
--- /dev/null
+++ b/lib/reline/key_actor/composite.rb
@@ -0,0 +1,17 @@
+class Reline::KeyActor::Composite
+ def initialize(key_actors)
+ @key_actors = key_actors
+ end
+
+ def matching?(key)
+ @key_actors.any? { |key_actor| key_actor.matching?(key) }
+ end
+
+ def get(key)
+ @key_actors.each do |key_actor|
+ func = key_actor.get(key)
+ return func if func
+ end
+ nil
+ end
+end
diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb
index edd88289a3..ad84ee1d99 100644
--- a/lib/reline/key_actor/emacs.rb
+++ b/lib/reline/key_actor/emacs.rb
@@ -1,5 +1,5 @@
-class Reline::KeyActor::Emacs < Reline::KeyActor::Base
- MAPPING = [
+module Reline::KeyActor
+ EMACS_MAPPING = [
# 0 ^@
:em_set_mark,
# 1 ^A
@@ -319,7 +319,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
# 158 M-^^
:ed_unassigned,
# 159 M-^_
- :ed_unassigned,
+ :redo,
# 160 M-SPACE
:em_set_mark,
# 161 M-!
diff --git a/lib/reline/key_actor/vi_command.rb b/lib/reline/key_actor/vi_command.rb
index 06bb0ba8e4..d972c5e67f 100644
--- a/lib/reline/key_actor/vi_command.rb
+++ b/lib/reline/key_actor/vi_command.rb
@@ -1,5 +1,5 @@
-class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
- MAPPING = [
+module Reline::KeyActor
+ VI_COMMAND_MAPPING = [
# 0 ^@
:ed_unassigned,
# 1 ^A
diff --git a/lib/reline/key_actor/vi_insert.rb b/lib/reline/key_actor/vi_insert.rb
index f8ccf468c6..312df1646b 100644
--- a/lib/reline/key_actor/vi_insert.rb
+++ b/lib/reline/key_actor/vi_insert.rb
@@ -1,5 +1,5 @@
-class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
- MAPPING = [
+module Reline::KeyActor
+ VI_INSERT_MAPPING = [
# 0 ^@
:ed_unassigned,
# 1 ^A
diff --git a/lib/reline/key_stroke.rb b/lib/reline/key_stroke.rb
index bceffbb53f..ba40899685 100644
--- a/lib/reline/key_stroke.rb
+++ b/lib/reline/key_stroke.rb
@@ -7,138 +7,99 @@ class Reline::KeyStroke
@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
+ # Input exactly matches to a key sequence
+ MATCHING = :matching
+ # Input partially matches to a key sequence
+ MATCHED = :matched
+ # Input matches to a key sequence and the key sequence is a prefix of another key sequence
+ MATCHING_MATCHED = :matching_matched
+ # Input does not match to any key sequence
+ UNMATCHED = :unmatched
- 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 match_status(input)
+ matching = key_mapping.matching?(input)
+ matched = key_mapping.get(input)
- 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
+ # FIXME: Workaround for single byte. remove this after MAPPING is merged into KeyActor.
+ matched ||= input.size == 1
+ matching ||= input == [ESC_BYTE]
- 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
- }
- if key_mapping.keys.any? { |lhs| start_with?(input, lhs) }
- :matched
+ if matching && matched
+ MATCHING_MATCHED
+ elsif matching
+ MATCHING
+ elsif matched
+ MATCHED
+ elsif input[0] == ESC_BYTE
+ match_unknown_escape_sequence(input, vi_mode: @config.editing_mode_is?(:vi_insert, :vi_command))
+ elsif input.size == 1
+ MATCHED
else
- match_unknown_escape_sequence(input).first
+ UNMATCHED
end
end
def expand(input)
- lhs = key_mapping.keys.select { |item| start_with?(input, item) }.sort_by(&:size).last
- unless lhs
- status, size = match_unknown_escape_sequence(input)
- case status
- when :matched
- return [:ed_unassigned] + expand(input.drop(size))
- when :matching
- return [:ed_unassigned]
- else
- return input
- end
+ matched_bytes = nil
+ (1..input.size).each do |i|
+ bytes = input.take(i)
+ status = match_status(bytes)
+ matched_bytes = bytes if status == MATCHED || status == MATCHING_MATCHED
end
- rhs = key_mapping[lhs]
+ return [[], []] unless matched_bytes
- 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
+ func = key_mapping.get(matched_bytes)
+ if func.is_a?(Array)
+ keys = func.map { |c| Reline::Key.new(c, c, false) }
+ elsif func
+ keys = [Reline::Key.new(func, func, false)]
+ elsif matched_bytes.size == 1
+ keys = [Reline::Key.new(matched_bytes.first, matched_bytes.first, false)]
+ elsif matched_bytes.size == 2 && matched_bytes[0] == ESC_BYTE
+ keys = [Reline::Key.new(matched_bytes[1], matched_bytes[1] | 0b10000000, true)]
+ else
+ keys = []
end
+
+ [keys, input.drop(matched_bytes.size)]
end
private
# returns match status of CSI/SS3 sequence and matched length
- def match_unknown_escape_sequence(input)
+ def match_unknown_escape_sequence(input, vi_mode: false)
idx = 0
- return [:unmatched, nil] unless input[idx] == ESC_BYTE
+ return UNMATCHED unless input[idx] == ESC_BYTE
idx += 1
idx += 1 if input[idx] == ESC_BYTE
case input[idx]
when nil
- return [:matching, nil]
+ if idx == 1 # `ESC`
+ return MATCHING_MATCHED
+ else # `ESC ESC`
+ return MATCHING
+ end
when 91 # == '['.ord
- # CSI sequence
+ # CSI sequence `ESC [ ... char`
idx += 1
idx += 1 while idx < input.size && CSI_PARAMETER_BYTES_RANGE.cover?(input[idx])
idx += 1 while idx < input.size && CSI_INTERMEDIATE_BYTES_RANGE.cover?(input[idx])
- input[idx] ? [:matched, idx + 1] : [:matching, nil]
when 79 # == 'O'.ord
- # SS3 sequence
- input[idx + 1] ? [:matched, idx + 2] : [:matching, nil]
+ # SS3 sequence `ESC O char`
+ idx += 1
else
- if idx == 1
- # `ESC char`, make it :unmatched so that it will be handled correctly in `read_2nd_character_of_key_sequence`
- [:unmatched, nil]
- else
- # `ESC ESC char`
- [:matched, idx + 1]
- end
+ # `ESC char` or `ESC ESC char`
+ return UNMATCHED if vi_mode
+ end
+
+ case input.size
+ when idx
+ MATCHING
+ when idx + 1
+ MATCHED
+ else
+ UNMATCHED
end
end
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index 23ece60220..c71a5f79ee 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -45,6 +45,7 @@ class Reline::LineEditor
RenderedScreen = Struct.new(:base_y, :lines, :cursor_y, keyword_init: true)
CompletionJourneyState = Struct.new(:line_index, :pre, :target, :post, :list, :pointer)
+ NullActionState = [nil, nil].freeze
class MenuInfo
attr_reader :list
@@ -175,9 +176,8 @@ class Reline::LineEditor
scroll_into_view
Reline::IOGate.move_cursor_up @rendered_screen.cursor_y
@rendered_screen.base_y = Reline::IOGate.cursor_pos.y
- @rendered_screen.lines = []
- @rendered_screen.cursor_y = 0
- render_differential
+ clear_rendered_screen_cache
+ render
end
private def handle_interrupted
@@ -185,11 +185,11 @@ class Reline::LineEditor
@interrupted = false
clear_dialogs
- scrolldown = render_differential
- Reline::IOGate.scroll_down scrolldown
+ render
+ cursor_to_bottom_offset = @rendered_screen.lines.size - @rendered_screen.cursor_y
+ Reline::IOGate.scroll_down cursor_to_bottom_offset
Reline::IOGate.move_cursor_column 0
- @rendered_screen.lines = []
- @rendered_screen.cursor_y = 0
+ clear_rendered_screen_cache
case @old_trap
when 'DEFAULT', 'SYSTEM_DEFAULT'
raise Interrupt
@@ -237,7 +237,6 @@ class Reline::LineEditor
@perfect_matched = nil
@menu_info = nil
@searching_prompt = nil
- @first_char = true
@just_cursor_moving = false
@eof = false
@continuous_insertion_buffer = String.new(encoding: @encoding)
@@ -250,8 +249,11 @@ class Reline::LineEditor
@resized = false
@cache = {}
@rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
- @past_lines = []
+ @input_lines = [[[""], 0, 0]]
+ @input_lines_position = 0
@undoing = false
+ @prev_action_state = NullActionState
+ @next_action_state = NullActionState
reset_line
end
@@ -411,7 +413,7 @@ class Reline::LineEditor
# do nothing
elsif level == :blank
Reline::IOGate.move_cursor_column base_x
- @output.write "#{Reline::IOGate::RESET_COLOR}#{' ' * width}"
+ @output.write "#{Reline::IOGate.reset_color_sequence}#{' ' * width}"
else
x, w, content = new_items[level]
cover_begin = base_x != 0 && new_levels[base_x - 1] == level
@@ -421,7 +423,7 @@ class Reline::LineEditor
content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
end
Reline::IOGate.move_cursor_column x + pos
- @output.write "#{Reline::IOGate::RESET_COLOR}#{content}#{Reline::IOGate::RESET_COLOR}"
+ @output.write "#{Reline::IOGate.reset_color_sequence}#{content}#{Reline::IOGate.reset_color_sequence}"
end
base_x += width
end
@@ -457,28 +459,7 @@ class Reline::LineEditor
end
def render_finished
- clear_rendered_lines
- render_full_content
- end
-
- def clear_rendered_lines
- Reline::IOGate.move_cursor_up @rendered_screen.cursor_y
- Reline::IOGate.move_cursor_column 0
-
- num_lines = @rendered_screen.lines.size
- return unless num_lines && num_lines >= 1
-
- Reline::IOGate.move_cursor_down num_lines - 1
- (num_lines - 1).times do
- Reline::IOGate.erase_after_cursor
- Reline::IOGate.move_cursor_up 1
- end
- Reline::IOGate.erase_after_cursor
- @rendered_screen.lines = []
- @rendered_screen.cursor_y = 0
- end
-
- def render_full_content
+ render_differential([], 0, 0)
lines = @buffer_of_lines.size.times.map do |i|
line = prompt_list[i] + modified_lines[i]
wrapped_lines, = split_by_width(line, screen_width)
@@ -487,19 +468,13 @@ class Reline::LineEditor
@output.puts lines.map { |l| "#{l}\r\n" }.join
end
- def print_nomultiline_prompt(prompt)
- return unless prompt && !@is_multiline
-
+ def print_nomultiline_prompt
# Readline's test `TestRelineAsReadline#test_readline` requires first output to be prompt, not cursor reset escape sequence.
- @rendered_screen.lines = [[[0, Reline::Unicode.calculate_width(prompt, true), prompt]]]
- @rendered_screen.cursor_y = 0
- @output.write prompt
+ @output.write @prompt if @prompt && !@is_multiline
end
- def render_differential
+ def render
wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
-
- rendered_lines = @rendered_screen.lines
new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
prompt_width = Reline::Unicode.calculate_width(prompt, true)
[[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
@@ -517,12 +492,21 @@ class Reline::LineEditor
x_range, y_range = dialog_range dialog, wrapped_cursor_y - screen_scroll_top
y_range.each do |row|
next if row < 0 || row >= screen_height
+
dialog_rows = new_lines[row] ||= []
# index 0 is for prompt, index 1 is for line, index 2.. is for dialog
dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
end
end
+ render_differential new_lines, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top
+ end
+
+ # Reflects lines to be rendered and new cursor position to the screen
+ # by calculating the difference from the previous render.
+
+ private def render_differential(new_lines, new_cursor_x, new_cursor_y)
+ rendered_lines = @rendered_screen.lines
cursor_y = @rendered_screen.cursor_y
if new_lines != rendered_lines
# Hide cursor while rendering to avoid cursor flickering.
@@ -549,11 +533,14 @@ class Reline::LineEditor
@rendered_screen.lines = new_lines
Reline::IOGate.show_cursor
end
- y = wrapped_cursor_y - screen_scroll_top
- Reline::IOGate.move_cursor_column wrapped_cursor_x
- Reline::IOGate.move_cursor_down y - cursor_y
- @rendered_screen.cursor_y = y
- new_lines.size - y
+ Reline::IOGate.move_cursor_column new_cursor_x
+ Reline::IOGate.move_cursor_down new_cursor_y - cursor_y
+ @rendered_screen.cursor_y = new_cursor_y
+ end
+
+ private def clear_rendered_screen_cache
+ @rendered_screen.lines = []
+ @rendered_screen.cursor_y = 0
end
def upper_space_height(wrapped_cursor_y)
@@ -565,7 +552,7 @@ class Reline::LineEditor
end
def rerender
- render_differential unless @in_pasting
+ render unless @in_pasting
end
class DialogProcScope
@@ -683,10 +670,8 @@ class Reline::LineEditor
@trap_key.each do |t|
@config.add_oneshot_key_binding(t, @name)
end
- elsif @trap_key.is_a?(Array)
+ else
@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
@@ -1079,17 +1064,7 @@ class Reline::LineEditor
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
- if @config.editing_mode_is?(:vi_command, :vi_insert)
- # split ESC + key in vi mode
- 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)
- end
- else
- process_key(key.combined_char, method_symbol)
- end
+ process_key(key.combined_char, method_symbol)
@multibyte_buffer.clear
end
if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
@@ -1118,13 +1093,10 @@ class Reline::LineEditor
end
if key.char.nil?
process_insert(force: true)
- if @first_char
- @eof = true
- end
+ @eof = buffer_empty?
finish
return
end
- @first_char = false
@completion_occurs = false
if key.char.is_a?(Symbol)
@@ -1132,12 +1104,15 @@ class Reline::LineEditor
else
normal_char(key)
end
+
+ @prev_action_state, @next_action_state = @next_action_state, NullActionState
+
unless @completion_occurs
@completion_state = CompletionState::NORMAL
@completion_journey_state = nil
end
- push_past_lines unless @undoing
+ push_input_lines unless @undoing
@undoing = false
if @in_pasting
@@ -1156,21 +1131,24 @@ class Reline::LineEditor
def save_old_buffer
@old_buffer_of_lines = @buffer_of_lines.dup
- @old_byte_pointer = @byte_pointer.dup
- @old_line_index = @line_index.dup
end
- def push_past_lines
- if @old_buffer_of_lines != @buffer_of_lines
- @past_lines.push([@old_buffer_of_lines, @old_byte_pointer, @old_line_index])
+ def push_input_lines
+ if @old_buffer_of_lines == @buffer_of_lines
+ @input_lines[@input_lines_position] = [@buffer_of_lines.dup, @byte_pointer, @line_index]
+ else
+ @input_lines = @input_lines[0..@input_lines_position]
+ @input_lines_position += 1
+ @input_lines.push([@buffer_of_lines.dup, @byte_pointer, @line_index])
end
- trim_past_lines
+ trim_input_lines
end
- MAX_PAST_LINES = 100
- def trim_past_lines
- if @past_lines.size > MAX_PAST_LINES
- @past_lines.shift
+ MAX_INPUT_LINES = 100
+ def trim_input_lines
+ if @input_lines.size > MAX_INPUT_LINES
+ @input_lines.shift
+ @input_lines_position -= 1
end
end
@@ -1343,7 +1321,7 @@ class Reline::LineEditor
@confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
end
- def insert_pasted_text(text)
+ def insert_multiline_text(text)
save_old_buffer
pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
@@ -1352,7 +1330,7 @@ class Reline::LineEditor
@buffer_of_lines[@line_index, 1] = lines
@line_index += lines.size - 1
@byte_pointer = @buffer_of_lines[@line_index].bytesize - post.bytesize
- push_past_lines
+ push_input_lines
end
def insert_text(text)
@@ -1411,6 +1389,10 @@ class Reline::LineEditor
whole_lines.join("\n")
end
+ private def buffer_empty?
+ current_line.empty? and @buffer_of_lines.size == 1
+ end
+
def finished?
@finished
end
@@ -1759,29 +1741,31 @@ class Reline::LineEditor
end
private def ed_search_prev_history(key, arg: 1)
- substr = current_line.byteslice(0, @byte_pointer)
+ substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
return if @history_pointer == 0
return if @history_pointer.nil? && substr.empty? && !current_line.empty?
history_range = 0...(@history_pointer || Reline::HISTORY.size)
h_pointer, line_index = search_history(substr, history_range.reverse_each)
return unless h_pointer
- move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
+ move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
arg -= 1
+ set_next_action_state(:search_history, :empty) if substr.empty?
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 = current_line.byteslice(0, @byte_pointer)
+ substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
return if @history_pointer.nil?
history_range = @history_pointer + 1...Reline::HISTORY.size
h_pointer, line_index = search_history(substr, history_range)
return if h_pointer.nil? and not substr.empty?
- move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
+ move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
arg -= 1
+ set_next_action_state(:search_history, :empty) if substr.empty?
ed_search_next_history(key, arg: arg) if arg > 0
end
alias_method :history_search_forward, :ed_search_next_history
@@ -1937,7 +1921,7 @@ class Reline::LineEditor
alias_method :kill_whole_line, :em_kill_line
private def em_delete(key)
- if current_line.empty? and @buffer_of_lines.size == 1 and key == "\C-d".ord
+ if buffer_empty? and key == "\C-d".ord
@eof = true
finish
elsif @byte_pointer < current_line.bytesize
@@ -1982,9 +1966,8 @@ class Reline::LineEditor
private def ed_clear_screen(key)
Reline::IOGate.clear_screen
@screen_size = Reline::IOGate.get_screen_size
- @rendered_screen.lines = []
@rendered_screen.base_y = 0
- @rendered_screen.cursor_y = 0
+ clear_rendered_screen_cache
end
alias_method :clear_screen, :ed_clear_screen
@@ -2259,9 +2242,11 @@ class Reline::LineEditor
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
elsif byte_pointer_diff < 0
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
+ else
+ return
end
copy_for_vi(cut)
- set_current_line(line || '', @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
+ set_current_line(line, @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
end
private def vi_yank(key, arg: nil)
@@ -2280,13 +2265,14 @@ class Reline::LineEditor
cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
elsif byte_pointer_diff < 0
cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
+ else
+ return
end
copy_for_vi(cut)
end
private def vi_list_or_eof(key)
- if current_line.empty? and @buffer_of_lines.size == 1
- set_current_line('', 0)
+ if buffer_empty?
@eof = true
finish
else
@@ -2529,13 +2515,34 @@ class Reline::LineEditor
end
private def undo(_key)
- return if @past_lines.empty?
+ @undoing = true
+
+ return if @input_lines_position <= 0
+
+ @input_lines_position -= 1
+ target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
+ set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
+ end
+ private def redo(_key)
@undoing = true
- target_lines, target_cursor_x, target_cursor_y = @past_lines.last
- set_current_lines(target_lines, target_cursor_x, target_cursor_y)
+ return if @input_lines_position >= @input_lines.size - 1
+
+ @input_lines_position += 1
+ target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
+ set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
+ end
+
+ private def prev_action_state_value(type)
+ @prev_action_state[0] == type ? @prev_action_state[1] : nil
+ end
+
+ private def set_next_action_state(type, value)
+ @next_action_state = [type, value]
+ end
- @past_lines.pop
+ private def re_read_init_file(_key)
+ @config.reload
end
end
diff --git a/lib/reline/terminfo.rb b/lib/reline/terminfo.rb
index 6885a0c6be..c2b1f681b4 100644
--- a/lib/reline/terminfo.rb
+++ b/lib/reline/terminfo.rb
@@ -1,4 +1,7 @@
begin
+ # Ignore warning `Add fiddle to your Gemfile or gemspec` in Ruby 3.4.
+ # terminfo.rb and ansi.rb supports fiddle unavailable environment.
+ verbose, $VERBOSE = $VERBOSE, nil
require 'fiddle'
require 'fiddle/import'
rescue LoadError
@@ -7,6 +10,8 @@ rescue LoadError
false
end
end
+ensure
+ $VERBOSE = verbose
end
module Reline::Terminfo
@@ -78,7 +83,7 @@ module Reline::Terminfo
end
def self.setupterm(term, fildes)
- errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
+ errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE)
ret = @setupterm.(term, fildes, errret_int)
case ret
when 0 # OK
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb
index d7460d6d4a..ef239d5e9e 100644
--- a/lib/reline/unicode.rb
+++ b/lib/reline/unicode.rb
@@ -56,51 +56,26 @@ class Reline::Unicode
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
+ if ord <= 0x1F # in EscapedPairs
return 2
- elsif (0x20 <= ord and ord <= 0x7E) # printable ASCII chars
+ elsif 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
+ utf8_mbchar = mbchar.encode(Encoding::UTF_8)
+ ord = utf8_mbchar.ord
+ chunk_index = EastAsianWidth::CHUNK_LAST.bsearch_index { |o| ord <= o }
+ size = EastAsianWidth::CHUNK_WIDTH[chunk_index]
+ if size == -1
+ Reline.ambiguous_width
+ elsif size == 1 && utf8_mbchar.size >= 2
+ second_char_ord = utf8_mbchar[1].ord
+ # Halfwidth Dakuten Handakuten
+ # Only these two character has Letter Modifier category and can be combined in a single grapheme cluster
+ (second_char_ord == 0xFF9E || second_char_ord == 0xFF9F) ? 2 : 1
else
- nil
+ size
end
end
diff --git a/lib/reline/unicode/east_asian_width.rb b/lib/reline/unicode/east_asian_width.rb
index fa16a1bb56..106ca4881a 100644
--- a/lib/reline/unicode/east_asian_width.rb
+++ b/lib/reline/unicode/east_asian_width.rb
@@ -2,1195 +2,1266 @@ class Reline::Unicode::EastAsianWidth
# This is based on EastAsianWidth.txt
# UNICODE_VERSION = '15.1.0'
- # 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{2FFF}
- \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{31EF}-\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 }]/
+ CHUNK_LAST, CHUNK_WIDTH = [
+ [0x1f, 2],
+ [0x7e, 1],
+ [0x7f, 2],
+ [0xa0, 1],
+ [0xa1, -1],
+ [0xa3, 1],
+ [0xa4, -1],
+ [0xa6, 1],
+ [0xa8, -1],
+ [0xa9, 1],
+ [0xaa, -1],
+ [0xac, 1],
+ [0xae, -1],
+ [0xaf, 1],
+ [0xb4, -1],
+ [0xb5, 1],
+ [0xba, -1],
+ [0xbb, 1],
+ [0xbf, -1],
+ [0xc5, 1],
+ [0xc6, -1],
+ [0xcf, 1],
+ [0xd0, -1],
+ [0xd6, 1],
+ [0xd8, -1],
+ [0xdd, 1],
+ [0xe1, -1],
+ [0xe5, 1],
+ [0xe6, -1],
+ [0xe7, 1],
+ [0xea, -1],
+ [0xeb, 1],
+ [0xed, -1],
+ [0xef, 1],
+ [0xf0, -1],
+ [0xf1, 1],
+ [0xf3, -1],
+ [0xf6, 1],
+ [0xfa, -1],
+ [0xfb, 1],
+ [0xfc, -1],
+ [0xfd, 1],
+ [0xfe, -1],
+ [0x100, 1],
+ [0x101, -1],
+ [0x110, 1],
+ [0x111, -1],
+ [0x112, 1],
+ [0x113, -1],
+ [0x11a, 1],
+ [0x11b, -1],
+ [0x125, 1],
+ [0x127, -1],
+ [0x12a, 1],
+ [0x12b, -1],
+ [0x130, 1],
+ [0x133, -1],
+ [0x137, 1],
+ [0x138, -1],
+ [0x13e, 1],
+ [0x142, -1],
+ [0x143, 1],
+ [0x144, -1],
+ [0x147, 1],
+ [0x14b, -1],
+ [0x14c, 1],
+ [0x14d, -1],
+ [0x151, 1],
+ [0x153, -1],
+ [0x165, 1],
+ [0x167, -1],
+ [0x16a, 1],
+ [0x16b, -1],
+ [0x1cd, 1],
+ [0x1ce, -1],
+ [0x1cf, 1],
+ [0x1d0, -1],
+ [0x1d1, 1],
+ [0x1d2, -1],
+ [0x1d3, 1],
+ [0x1d4, -1],
+ [0x1d5, 1],
+ [0x1d6, -1],
+ [0x1d7, 1],
+ [0x1d8, -1],
+ [0x1d9, 1],
+ [0x1da, -1],
+ [0x1db, 1],
+ [0x1dc, -1],
+ [0x250, 1],
+ [0x251, -1],
+ [0x260, 1],
+ [0x261, -1],
+ [0x2c3, 1],
+ [0x2c4, -1],
+ [0x2c6, 1],
+ [0x2c7, -1],
+ [0x2c8, 1],
+ [0x2cb, -1],
+ [0x2cc, 1],
+ [0x2cd, -1],
+ [0x2cf, 1],
+ [0x2d0, -1],
+ [0x2d7, 1],
+ [0x2db, -1],
+ [0x2dc, 1],
+ [0x2dd, -1],
+ [0x2de, 1],
+ [0x2df, -1],
+ [0x2ff, 1],
+ [0x36f, 0],
+ [0x390, 1],
+ [0x3a1, -1],
+ [0x3a2, 1],
+ [0x3a9, -1],
+ [0x3b0, 1],
+ [0x3c1, -1],
+ [0x3c2, 1],
+ [0x3c9, -1],
+ [0x400, 1],
+ [0x401, -1],
+ [0x40f, 1],
+ [0x44f, -1],
+ [0x450, 1],
+ [0x451, -1],
+ [0x482, 1],
+ [0x487, 0],
+ [0x590, 1],
+ [0x5bd, 0],
+ [0x5be, 1],
+ [0x5bf, 0],
+ [0x5c0, 1],
+ [0x5c2, 0],
+ [0x5c3, 1],
+ [0x5c5, 0],
+ [0x5c6, 1],
+ [0x5c7, 0],
+ [0x60f, 1],
+ [0x61a, 0],
+ [0x64a, 1],
+ [0x65f, 0],
+ [0x66f, 1],
+ [0x670, 0],
+ [0x6d5, 1],
+ [0x6dc, 0],
+ [0x6de, 1],
+ [0x6e4, 0],
+ [0x6e6, 1],
+ [0x6e8, 0],
+ [0x6e9, 1],
+ [0x6ed, 0],
+ [0x710, 1],
+ [0x711, 0],
+ [0x72f, 1],
+ [0x74a, 0],
+ [0x7a5, 1],
+ [0x7b0, 0],
+ [0x7ea, 1],
+ [0x7f3, 0],
+ [0x7fc, 1],
+ [0x7fd, 0],
+ [0x815, 1],
+ [0x819, 0],
+ [0x81a, 1],
+ [0x823, 0],
+ [0x824, 1],
+ [0x827, 0],
+ [0x828, 1],
+ [0x82d, 0],
+ [0x858, 1],
+ [0x85b, 0],
+ [0x897, 1],
+ [0x89f, 0],
+ [0x8c9, 1],
+ [0x8e1, 0],
+ [0x8e2, 1],
+ [0x902, 0],
+ [0x939, 1],
+ [0x93a, 0],
+ [0x93b, 1],
+ [0x93c, 0],
+ [0x940, 1],
+ [0x948, 0],
+ [0x94c, 1],
+ [0x94d, 0],
+ [0x950, 1],
+ [0x957, 0],
+ [0x961, 1],
+ [0x963, 0],
+ [0x980, 1],
+ [0x981, 0],
+ [0x9bb, 1],
+ [0x9bc, 0],
+ [0x9c0, 1],
+ [0x9c4, 0],
+ [0x9cc, 1],
+ [0x9cd, 0],
+ [0x9e1, 1],
+ [0x9e3, 0],
+ [0x9fd, 1],
+ [0x9fe, 0],
+ [0xa00, 1],
+ [0xa02, 0],
+ [0xa3b, 1],
+ [0xa3c, 0],
+ [0xa40, 1],
+ [0xa42, 0],
+ [0xa46, 1],
+ [0xa48, 0],
+ [0xa4a, 1],
+ [0xa4d, 0],
+ [0xa50, 1],
+ [0xa51, 0],
+ [0xa6f, 1],
+ [0xa71, 0],
+ [0xa74, 1],
+ [0xa75, 0],
+ [0xa80, 1],
+ [0xa82, 0],
+ [0xabb, 1],
+ [0xabc, 0],
+ [0xac0, 1],
+ [0xac5, 0],
+ [0xac6, 1],
+ [0xac8, 0],
+ [0xacc, 1],
+ [0xacd, 0],
+ [0xae1, 1],
+ [0xae3, 0],
+ [0xaf9, 1],
+ [0xaff, 0],
+ [0xb00, 1],
+ [0xb01, 0],
+ [0xb3b, 1],
+ [0xb3c, 0],
+ [0xb3e, 1],
+ [0xb3f, 0],
+ [0xb40, 1],
+ [0xb44, 0],
+ [0xb4c, 1],
+ [0xb4d, 0],
+ [0xb54, 1],
+ [0xb56, 0],
+ [0xb61, 1],
+ [0xb63, 0],
+ [0xb81, 1],
+ [0xb82, 0],
+ [0xbbf, 1],
+ [0xbc0, 0],
+ [0xbcc, 1],
+ [0xbcd, 0],
+ [0xbff, 1],
+ [0xc00, 0],
+ [0xc03, 1],
+ [0xc04, 0],
+ [0xc3b, 1],
+ [0xc3c, 0],
+ [0xc3d, 1],
+ [0xc40, 0],
+ [0xc45, 1],
+ [0xc48, 0],
+ [0xc49, 1],
+ [0xc4d, 0],
+ [0xc54, 1],
+ [0xc56, 0],
+ [0xc61, 1],
+ [0xc63, 0],
+ [0xc80, 1],
+ [0xc81, 0],
+ [0xcbb, 1],
+ [0xcbc, 0],
+ [0xcbe, 1],
+ [0xcbf, 0],
+ [0xcc5, 1],
+ [0xcc6, 0],
+ [0xccb, 1],
+ [0xccd, 0],
+ [0xce1, 1],
+ [0xce3, 0],
+ [0xcff, 1],
+ [0xd01, 0],
+ [0xd3a, 1],
+ [0xd3c, 0],
+ [0xd40, 1],
+ [0xd44, 0],
+ [0xd4c, 1],
+ [0xd4d, 0],
+ [0xd61, 1],
+ [0xd63, 0],
+ [0xd80, 1],
+ [0xd81, 0],
+ [0xdc9, 1],
+ [0xdca, 0],
+ [0xdd1, 1],
+ [0xdd4, 0],
+ [0xdd5, 1],
+ [0xdd6, 0],
+ [0xe30, 1],
+ [0xe31, 0],
+ [0xe33, 1],
+ [0xe3a, 0],
+ [0xe46, 1],
+ [0xe4e, 0],
+ [0xeb0, 1],
+ [0xeb1, 0],
+ [0xeb3, 1],
+ [0xebc, 0],
+ [0xec7, 1],
+ [0xece, 0],
+ [0xf17, 1],
+ [0xf19, 0],
+ [0xf34, 1],
+ [0xf35, 0],
+ [0xf36, 1],
+ [0xf37, 0],
+ [0xf38, 1],
+ [0xf39, 0],
+ [0xf70, 1],
+ [0xf7e, 0],
+ [0xf7f, 1],
+ [0xf84, 0],
+ [0xf85, 1],
+ [0xf87, 0],
+ [0xf8c, 1],
+ [0xf97, 0],
+ [0xf98, 1],
+ [0xfbc, 0],
+ [0xfc5, 1],
+ [0xfc6, 0],
+ [0x102c, 1],
+ [0x1030, 0],
+ [0x1031, 1],
+ [0x1037, 0],
+ [0x1038, 1],
+ [0x103a, 0],
+ [0x103c, 1],
+ [0x103e, 0],
+ [0x1057, 1],
+ [0x1059, 0],
+ [0x105d, 1],
+ [0x1060, 0],
+ [0x1070, 1],
+ [0x1074, 0],
+ [0x1081, 1],
+ [0x1082, 0],
+ [0x1084, 1],
+ [0x1086, 0],
+ [0x108c, 1],
+ [0x108d, 0],
+ [0x109c, 1],
+ [0x109d, 0],
+ [0x10ff, 1],
+ [0x115f, 2],
+ [0x135c, 1],
+ [0x135f, 0],
+ [0x1711, 1],
+ [0x1714, 0],
+ [0x1731, 1],
+ [0x1733, 0],
+ [0x1751, 1],
+ [0x1753, 0],
+ [0x1771, 1],
+ [0x1773, 0],
+ [0x17b3, 1],
+ [0x17b5, 0],
+ [0x17b6, 1],
+ [0x17bd, 0],
+ [0x17c5, 1],
+ [0x17c6, 0],
+ [0x17c8, 1],
+ [0x17d3, 0],
+ [0x17dc, 1],
+ [0x17dd, 0],
+ [0x180a, 1],
+ [0x180d, 0],
+ [0x180e, 1],
+ [0x180f, 0],
+ [0x1884, 1],
+ [0x1886, 0],
+ [0x18a8, 1],
+ [0x18a9, 0],
+ [0x191f, 1],
+ [0x1922, 0],
+ [0x1926, 1],
+ [0x1928, 0],
+ [0x1931, 1],
+ [0x1932, 0],
+ [0x1938, 1],
+ [0x193b, 0],
+ [0x1a16, 1],
+ [0x1a18, 0],
+ [0x1a1a, 1],
+ [0x1a1b, 0],
+ [0x1a55, 1],
+ [0x1a56, 0],
+ [0x1a57, 1],
+ [0x1a5e, 0],
+ [0x1a5f, 1],
+ [0x1a60, 0],
+ [0x1a61, 1],
+ [0x1a62, 0],
+ [0x1a64, 1],
+ [0x1a6c, 0],
+ [0x1a72, 1],
+ [0x1a7c, 0],
+ [0x1a7e, 1],
+ [0x1a7f, 0],
+ [0x1aaf, 1],
+ [0x1abd, 0],
+ [0x1abe, 1],
+ [0x1ace, 0],
+ [0x1aff, 1],
+ [0x1b03, 0],
+ [0x1b33, 1],
+ [0x1b34, 0],
+ [0x1b35, 1],
+ [0x1b3a, 0],
+ [0x1b3b, 1],
+ [0x1b3c, 0],
+ [0x1b41, 1],
+ [0x1b42, 0],
+ [0x1b6a, 1],
+ [0x1b73, 0],
+ [0x1b7f, 1],
+ [0x1b81, 0],
+ [0x1ba1, 1],
+ [0x1ba5, 0],
+ [0x1ba7, 1],
+ [0x1ba9, 0],
+ [0x1baa, 1],
+ [0x1bad, 0],
+ [0x1be5, 1],
+ [0x1be6, 0],
+ [0x1be7, 1],
+ [0x1be9, 0],
+ [0x1bec, 1],
+ [0x1bed, 0],
+ [0x1bee, 1],
+ [0x1bf1, 0],
+ [0x1c2b, 1],
+ [0x1c33, 0],
+ [0x1c35, 1],
+ [0x1c37, 0],
+ [0x1ccf, 1],
+ [0x1cd2, 0],
+ [0x1cd3, 1],
+ [0x1ce0, 0],
+ [0x1ce1, 1],
+ [0x1ce8, 0],
+ [0x1cec, 1],
+ [0x1ced, 0],
+ [0x1cf3, 1],
+ [0x1cf4, 0],
+ [0x1cf7, 1],
+ [0x1cf9, 0],
+ [0x1dbf, 1],
+ [0x1dff, 0],
+ [0x200f, 1],
+ [0x2010, -1],
+ [0x2012, 1],
+ [0x2016, -1],
+ [0x2017, 1],
+ [0x2019, -1],
+ [0x201b, 1],
+ [0x201d, -1],
+ [0x201f, 1],
+ [0x2022, -1],
+ [0x2023, 1],
+ [0x2027, -1],
+ [0x202f, 1],
+ [0x2030, -1],
+ [0x2031, 1],
+ [0x2033, -1],
+ [0x2034, 1],
+ [0x2035, -1],
+ [0x203a, 1],
+ [0x203b, -1],
+ [0x203d, 1],
+ [0x203e, -1],
+ [0x2073, 1],
+ [0x2074, -1],
+ [0x207e, 1],
+ [0x207f, -1],
+ [0x2080, 1],
+ [0x2084, -1],
+ [0x20ab, 1],
+ [0x20ac, -1],
+ [0x20cf, 1],
+ [0x20dc, 0],
+ [0x20e0, 1],
+ [0x20e1, 0],
+ [0x20e4, 1],
+ [0x20f0, 0],
+ [0x2102, 1],
+ [0x2103, -1],
+ [0x2104, 1],
+ [0x2105, -1],
+ [0x2108, 1],
+ [0x2109, -1],
+ [0x2112, 1],
+ [0x2113, -1],
+ [0x2115, 1],
+ [0x2116, -1],
+ [0x2120, 1],
+ [0x2122, -1],
+ [0x2125, 1],
+ [0x2126, -1],
+ [0x212a, 1],
+ [0x212b, -1],
+ [0x2152, 1],
+ [0x2154, -1],
+ [0x215a, 1],
+ [0x215e, -1],
+ [0x215f, 1],
+ [0x216b, -1],
+ [0x216f, 1],
+ [0x2179, -1],
+ [0x2188, 1],
+ [0x2189, -1],
+ [0x218f, 1],
+ [0x2199, -1],
+ [0x21b7, 1],
+ [0x21b9, -1],
+ [0x21d1, 1],
+ [0x21d2, -1],
+ [0x21d3, 1],
+ [0x21d4, -1],
+ [0x21e6, 1],
+ [0x21e7, -1],
+ [0x21ff, 1],
+ [0x2200, -1],
+ [0x2201, 1],
+ [0x2203, -1],
+ [0x2206, 1],
+ [0x2208, -1],
+ [0x220a, 1],
+ [0x220b, -1],
+ [0x220e, 1],
+ [0x220f, -1],
+ [0x2210, 1],
+ [0x2211, -1],
+ [0x2214, 1],
+ [0x2215, -1],
+ [0x2219, 1],
+ [0x221a, -1],
+ [0x221c, 1],
+ [0x2220, -1],
+ [0x2222, 1],
+ [0x2223, -1],
+ [0x2224, 1],
+ [0x2225, -1],
+ [0x2226, 1],
+ [0x222c, -1],
+ [0x222d, 1],
+ [0x222e, -1],
+ [0x2233, 1],
+ [0x2237, -1],
+ [0x223b, 1],
+ [0x223d, -1],
+ [0x2247, 1],
+ [0x2248, -1],
+ [0x224b, 1],
+ [0x224c, -1],
+ [0x2251, 1],
+ [0x2252, -1],
+ [0x225f, 1],
+ [0x2261, -1],
+ [0x2263, 1],
+ [0x2267, -1],
+ [0x2269, 1],
+ [0x226b, -1],
+ [0x226d, 1],
+ [0x226f, -1],
+ [0x2281, 1],
+ [0x2283, -1],
+ [0x2285, 1],
+ [0x2287, -1],
+ [0x2294, 1],
+ [0x2295, -1],
+ [0x2298, 1],
+ [0x2299, -1],
+ [0x22a4, 1],
+ [0x22a5, -1],
+ [0x22be, 1],
+ [0x22bf, -1],
+ [0x2311, 1],
+ [0x2312, -1],
+ [0x2319, 1],
+ [0x231b, 2],
+ [0x2328, 1],
+ [0x232a, 2],
+ [0x23e8, 1],
+ [0x23ec, 2],
+ [0x23ef, 1],
+ [0x23f0, 2],
+ [0x23f2, 1],
+ [0x23f3, 2],
+ [0x245f, 1],
+ [0x24e9, -1],
+ [0x24ea, 1],
+ [0x254b, -1],
+ [0x254f, 1],
+ [0x2573, -1],
+ [0x257f, 1],
+ [0x258f, -1],
+ [0x2591, 1],
+ [0x2595, -1],
+ [0x259f, 1],
+ [0x25a1, -1],
+ [0x25a2, 1],
+ [0x25a9, -1],
+ [0x25b1, 1],
+ [0x25b3, -1],
+ [0x25b5, 1],
+ [0x25b7, -1],
+ [0x25bb, 1],
+ [0x25bd, -1],
+ [0x25bf, 1],
+ [0x25c1, -1],
+ [0x25c5, 1],
+ [0x25c8, -1],
+ [0x25ca, 1],
+ [0x25cb, -1],
+ [0x25cd, 1],
+ [0x25d1, -1],
+ [0x25e1, 1],
+ [0x25e5, -1],
+ [0x25ee, 1],
+ [0x25ef, -1],
+ [0x25fc, 1],
+ [0x25fe, 2],
+ [0x2604, 1],
+ [0x2606, -1],
+ [0x2608, 1],
+ [0x2609, -1],
+ [0x260d, 1],
+ [0x260f, -1],
+ [0x2613, 1],
+ [0x2615, 2],
+ [0x261b, 1],
+ [0x261c, -1],
+ [0x261d, 1],
+ [0x261e, -1],
+ [0x263f, 1],
+ [0x2640, -1],
+ [0x2641, 1],
+ [0x2642, -1],
+ [0x2647, 1],
+ [0x2653, 2],
+ [0x265f, 1],
+ [0x2661, -1],
+ [0x2662, 1],
+ [0x2665, -1],
+ [0x2666, 1],
+ [0x266a, -1],
+ [0x266b, 1],
+ [0x266d, -1],
+ [0x266e, 1],
+ [0x266f, -1],
+ [0x267e, 1],
+ [0x267f, 2],
+ [0x2692, 1],
+ [0x2693, 2],
+ [0x269d, 1],
+ [0x269f, -1],
+ [0x26a0, 1],
+ [0x26a1, 2],
+ [0x26a9, 1],
+ [0x26ab, 2],
+ [0x26bc, 1],
+ [0x26be, 2],
+ [0x26bf, -1],
+ [0x26c3, 1],
+ [0x26c5, 2],
+ [0x26cd, -1],
+ [0x26ce, 2],
+ [0x26d3, -1],
+ [0x26d4, 2],
+ [0x26e1, -1],
+ [0x26e2, 1],
+ [0x26e3, -1],
+ [0x26e7, 1],
+ [0x26e9, -1],
+ [0x26ea, 2],
+ [0x26f1, -1],
+ [0x26f3, 2],
+ [0x26f4, -1],
+ [0x26f5, 2],
+ [0x26f9, -1],
+ [0x26fa, 2],
+ [0x26fc, -1],
+ [0x26fd, 2],
+ [0x26ff, -1],
+ [0x2704, 1],
+ [0x2705, 2],
+ [0x2709, 1],
+ [0x270b, 2],
+ [0x2727, 1],
+ [0x2728, 2],
+ [0x273c, 1],
+ [0x273d, -1],
+ [0x274b, 1],
+ [0x274c, 2],
+ [0x274d, 1],
+ [0x274e, 2],
+ [0x2752, 1],
+ [0x2755, 2],
+ [0x2756, 1],
+ [0x2757, 2],
+ [0x2775, 1],
+ [0x277f, -1],
+ [0x2794, 1],
+ [0x2797, 2],
+ [0x27af, 1],
+ [0x27b0, 2],
+ [0x27be, 1],
+ [0x27bf, 2],
+ [0x2b1a, 1],
+ [0x2b1c, 2],
+ [0x2b4f, 1],
+ [0x2b50, 2],
+ [0x2b54, 1],
+ [0x2b55, 2],
+ [0x2b59, -1],
+ [0x2cee, 1],
+ [0x2cf1, 0],
+ [0x2d7e, 1],
+ [0x2d7f, 0],
+ [0x2ddf, 1],
+ [0x2dff, 0],
+ [0x2e7f, 1],
+ [0x2e99, 2],
+ [0x2e9a, 1],
+ [0x2ef3, 2],
+ [0x2eff, 1],
+ [0x2fd5, 2],
+ [0x2fef, 1],
+ [0x3029, 2],
+ [0x302d, 0],
+ [0x303e, 2],
+ [0x3040, 1],
+ [0x3096, 2],
+ [0x3098, 1],
+ [0x309a, 0],
+ [0x30ff, 2],
+ [0x3104, 1],
+ [0x312f, 2],
+ [0x3130, 1],
+ [0x318e, 2],
+ [0x318f, 1],
+ [0x31e3, 2],
+ [0x31ee, 1],
+ [0x321e, 2],
+ [0x321f, 1],
+ [0x3247, 2],
+ [0x324f, -1],
+ [0x4dbf, 2],
+ [0x4dff, 1],
+ [0xa48c, 2],
+ [0xa48f, 1],
+ [0xa4c6, 2],
+ [0xa66e, 1],
+ [0xa66f, 0],
+ [0xa673, 1],
+ [0xa67d, 0],
+ [0xa69d, 1],
+ [0xa69f, 0],
+ [0xa6ef, 1],
+ [0xa6f1, 0],
+ [0xa801, 1],
+ [0xa802, 0],
+ [0xa805, 1],
+ [0xa806, 0],
+ [0xa80a, 1],
+ [0xa80b, 0],
+ [0xa824, 1],
+ [0xa826, 0],
+ [0xa82b, 1],
+ [0xa82c, 0],
+ [0xa8c3, 1],
+ [0xa8c5, 0],
+ [0xa8df, 1],
+ [0xa8f1, 0],
+ [0xa8fe, 1],
+ [0xa8ff, 0],
+ [0xa925, 1],
+ [0xa92d, 0],
+ [0xa946, 1],
+ [0xa951, 0],
+ [0xa95f, 1],
+ [0xa97c, 2],
+ [0xa97f, 1],
+ [0xa982, 0],
+ [0xa9b2, 1],
+ [0xa9b3, 0],
+ [0xa9b5, 1],
+ [0xa9b9, 0],
+ [0xa9bb, 1],
+ [0xa9bd, 0],
+ [0xa9e4, 1],
+ [0xa9e5, 0],
+ [0xaa28, 1],
+ [0xaa2e, 0],
+ [0xaa30, 1],
+ [0xaa32, 0],
+ [0xaa34, 1],
+ [0xaa36, 0],
+ [0xaa42, 1],
+ [0xaa43, 0],
+ [0xaa4b, 1],
+ [0xaa4c, 0],
+ [0xaa7b, 1],
+ [0xaa7c, 0],
+ [0xaaaf, 1],
+ [0xaab0, 0],
+ [0xaab1, 1],
+ [0xaab4, 0],
+ [0xaab6, 1],
+ [0xaab8, 0],
+ [0xaabd, 1],
+ [0xaabf, 0],
+ [0xaac0, 1],
+ [0xaac1, 0],
+ [0xaaeb, 1],
+ [0xaaed, 0],
+ [0xaaf5, 1],
+ [0xaaf6, 0],
+ [0xabe4, 1],
+ [0xabe5, 0],
+ [0xabe7, 1],
+ [0xabe8, 0],
+ [0xabec, 1],
+ [0xabed, 0],
+ [0xabff, 1],
+ [0xd7a3, 2],
+ [0xdfff, 1],
+ [0xf8ff, -1],
+ [0xfaff, 2],
+ [0xfb1d, 1],
+ [0xfb1e, 0],
+ [0xfdff, 1],
+ [0xfe0f, 0],
+ [0xfe19, 2],
+ [0xfe1f, 1],
+ [0xfe2f, 0],
+ [0xfe52, 2],
+ [0xfe53, 1],
+ [0xfe66, 2],
+ [0xfe67, 1],
+ [0xfe6b, 2],
+ [0xff00, 1],
+ [0xff60, 2],
+ [0xffdf, 1],
+ [0xffe6, 2],
+ [0xfffc, 1],
+ [0xfffd, -1],
+ [0x101fc, 1],
+ [0x101fd, 0],
+ [0x102df, 1],
+ [0x102e0, 0],
+ [0x10375, 1],
+ [0x1037a, 0],
+ [0x10a00, 1],
+ [0x10a03, 0],
+ [0x10a04, 1],
+ [0x10a06, 0],
+ [0x10a0b, 1],
+ [0x10a0f, 0],
+ [0x10a37, 1],
+ [0x10a3a, 0],
+ [0x10a3e, 1],
+ [0x10a3f, 0],
+ [0x10ae4, 1],
+ [0x10ae6, 0],
+ [0x10d23, 1],
+ [0x10d27, 0],
+ [0x10eaa, 1],
+ [0x10eac, 0],
+ [0x10efc, 1],
+ [0x10eff, 0],
+ [0x10f45, 1],
+ [0x10f50, 0],
+ [0x10f81, 1],
+ [0x10f85, 0],
+ [0x11000, 1],
+ [0x11001, 0],
+ [0x11037, 1],
+ [0x11046, 0],
+ [0x1106f, 1],
+ [0x11070, 0],
+ [0x11072, 1],
+ [0x11074, 0],
+ [0x1107e, 1],
+ [0x11081, 0],
+ [0x110b2, 1],
+ [0x110b6, 0],
+ [0x110b8, 1],
+ [0x110ba, 0],
+ [0x110c1, 1],
+ [0x110c2, 0],
+ [0x110ff, 1],
+ [0x11102, 0],
+ [0x11126, 1],
+ [0x1112b, 0],
+ [0x1112c, 1],
+ [0x11134, 0],
+ [0x11172, 1],
+ [0x11173, 0],
+ [0x1117f, 1],
+ [0x11181, 0],
+ [0x111b5, 1],
+ [0x111be, 0],
+ [0x111c8, 1],
+ [0x111cc, 0],
+ [0x111ce, 1],
+ [0x111cf, 0],
+ [0x1122e, 1],
+ [0x11231, 0],
+ [0x11233, 1],
+ [0x11234, 0],
+ [0x11235, 1],
+ [0x11237, 0],
+ [0x1123d, 1],
+ [0x1123e, 0],
+ [0x11240, 1],
+ [0x11241, 0],
+ [0x112de, 1],
+ [0x112df, 0],
+ [0x112e2, 1],
+ [0x112ea, 0],
+ [0x112ff, 1],
+ [0x11301, 0],
+ [0x1133a, 1],
+ [0x1133c, 0],
+ [0x1133f, 1],
+ [0x11340, 0],
+ [0x11365, 1],
+ [0x1136c, 0],
+ [0x1136f, 1],
+ [0x11374, 0],
+ [0x11437, 1],
+ [0x1143f, 0],
+ [0x11441, 1],
+ [0x11444, 0],
+ [0x11445, 1],
+ [0x11446, 0],
+ [0x1145d, 1],
+ [0x1145e, 0],
+ [0x114b2, 1],
+ [0x114b8, 0],
+ [0x114b9, 1],
+ [0x114ba, 0],
+ [0x114be, 1],
+ [0x114c0, 0],
+ [0x114c1, 1],
+ [0x114c3, 0],
+ [0x115b1, 1],
+ [0x115b5, 0],
+ [0x115bb, 1],
+ [0x115bd, 0],
+ [0x115be, 1],
+ [0x115c0, 0],
+ [0x115db, 1],
+ [0x115dd, 0],
+ [0x11632, 1],
+ [0x1163a, 0],
+ [0x1163c, 1],
+ [0x1163d, 0],
+ [0x1163e, 1],
+ [0x11640, 0],
+ [0x116aa, 1],
+ [0x116ab, 0],
+ [0x116ac, 1],
+ [0x116ad, 0],
+ [0x116af, 1],
+ [0x116b5, 0],
+ [0x116b6, 1],
+ [0x116b7, 0],
+ [0x1171c, 1],
+ [0x1171f, 0],
+ [0x11721, 1],
+ [0x11725, 0],
+ [0x11726, 1],
+ [0x1172b, 0],
+ [0x1182e, 1],
+ [0x11837, 0],
+ [0x11838, 1],
+ [0x1183a, 0],
+ [0x1193a, 1],
+ [0x1193c, 0],
+ [0x1193d, 1],
+ [0x1193e, 0],
+ [0x11942, 1],
+ [0x11943, 0],
+ [0x119d3, 1],
+ [0x119d7, 0],
+ [0x119d9, 1],
+ [0x119db, 0],
+ [0x119df, 1],
+ [0x119e0, 0],
+ [0x11a00, 1],
+ [0x11a0a, 0],
+ [0x11a32, 1],
+ [0x11a38, 0],
+ [0x11a3a, 1],
+ [0x11a3e, 0],
+ [0x11a46, 1],
+ [0x11a47, 0],
+ [0x11a50, 1],
+ [0x11a56, 0],
+ [0x11a58, 1],
+ [0x11a5b, 0],
+ [0x11a89, 1],
+ [0x11a96, 0],
+ [0x11a97, 1],
+ [0x11a99, 0],
+ [0x11c2f, 1],
+ [0x11c36, 0],
+ [0x11c37, 1],
+ [0x11c3d, 0],
+ [0x11c3e, 1],
+ [0x11c3f, 0],
+ [0x11c91, 1],
+ [0x11ca7, 0],
+ [0x11ca9, 1],
+ [0x11cb0, 0],
+ [0x11cb1, 1],
+ [0x11cb3, 0],
+ [0x11cb4, 1],
+ [0x11cb6, 0],
+ [0x11d30, 1],
+ [0x11d36, 0],
+ [0x11d39, 1],
+ [0x11d3a, 0],
+ [0x11d3b, 1],
+ [0x11d3d, 0],
+ [0x11d3e, 1],
+ [0x11d45, 0],
+ [0x11d46, 1],
+ [0x11d47, 0],
+ [0x11d8f, 1],
+ [0x11d91, 0],
+ [0x11d94, 1],
+ [0x11d95, 0],
+ [0x11d96, 1],
+ [0x11d97, 0],
+ [0x11ef2, 1],
+ [0x11ef4, 0],
+ [0x11eff, 1],
+ [0x11f01, 0],
+ [0x11f35, 1],
+ [0x11f3a, 0],
+ [0x11f3f, 1],
+ [0x11f40, 0],
+ [0x11f41, 1],
+ [0x11f42, 0],
+ [0x1343f, 1],
+ [0x13440, 0],
+ [0x13446, 1],
+ [0x13455, 0],
+ [0x16aef, 1],
+ [0x16af4, 0],
+ [0x16b2f, 1],
+ [0x16b36, 0],
+ [0x16f4e, 1],
+ [0x16f4f, 0],
+ [0x16f8e, 1],
+ [0x16f92, 0],
+ [0x16fdf, 1],
+ [0x16fe3, 2],
+ [0x16fe4, 0],
+ [0x16fef, 1],
+ [0x16ff1, 2],
+ [0x16fff, 1],
+ [0x187f7, 2],
+ [0x187ff, 1],
+ [0x18cd5, 2],
+ [0x18cff, 1],
+ [0x18d08, 2],
+ [0x1afef, 1],
+ [0x1aff3, 2],
+ [0x1aff4, 1],
+ [0x1affb, 2],
+ [0x1affc, 1],
+ [0x1affe, 2],
+ [0x1afff, 1],
+ [0x1b122, 2],
+ [0x1b131, 1],
+ [0x1b132, 2],
+ [0x1b14f, 1],
+ [0x1b152, 2],
+ [0x1b154, 1],
+ [0x1b155, 2],
+ [0x1b163, 1],
+ [0x1b167, 2],
+ [0x1b16f, 1],
+ [0x1b2fb, 2],
+ [0x1bc9c, 1],
+ [0x1bc9e, 0],
+ [0x1ceff, 1],
+ [0x1cf2d, 0],
+ [0x1cf2f, 1],
+ [0x1cf46, 0],
+ [0x1d166, 1],
+ [0x1d169, 0],
+ [0x1d17a, 1],
+ [0x1d182, 0],
+ [0x1d184, 1],
+ [0x1d18b, 0],
+ [0x1d1a9, 1],
+ [0x1d1ad, 0],
+ [0x1d241, 1],
+ [0x1d244, 0],
+ [0x1d9ff, 1],
+ [0x1da36, 0],
+ [0x1da3a, 1],
+ [0x1da6c, 0],
+ [0x1da74, 1],
+ [0x1da75, 0],
+ [0x1da83, 1],
+ [0x1da84, 0],
+ [0x1da9a, 1],
+ [0x1da9f, 0],
+ [0x1daa0, 1],
+ [0x1daaf, 0],
+ [0x1dfff, 1],
+ [0x1e006, 0],
+ [0x1e007, 1],
+ [0x1e018, 0],
+ [0x1e01a, 1],
+ [0x1e021, 0],
+ [0x1e022, 1],
+ [0x1e024, 0],
+ [0x1e025, 1],
+ [0x1e02a, 0],
+ [0x1e08e, 1],
+ [0x1e08f, 0],
+ [0x1e12f, 1],
+ [0x1e136, 0],
+ [0x1e2ad, 1],
+ [0x1e2ae, 0],
+ [0x1e2eb, 1],
+ [0x1e2ef, 0],
+ [0x1e4eb, 1],
+ [0x1e4ef, 0],
+ [0x1e8cf, 1],
+ [0x1e8d6, 0],
+ [0x1e943, 1],
+ [0x1e94a, 0],
+ [0x1f003, 1],
+ [0x1f004, 2],
+ [0x1f0ce, 1],
+ [0x1f0cf, 2],
+ [0x1f0ff, 1],
+ [0x1f10a, -1],
+ [0x1f10f, 1],
+ [0x1f12d, -1],
+ [0x1f12f, 1],
+ [0x1f169, -1],
+ [0x1f16f, 1],
+ [0x1f18d, -1],
+ [0x1f18e, 2],
+ [0x1f190, -1],
+ [0x1f19a, 2],
+ [0x1f1ac, -1],
+ [0x1f1ff, 1],
+ [0x1f202, 2],
+ [0x1f20f, 1],
+ [0x1f23b, 2],
+ [0x1f23f, 1],
+ [0x1f248, 2],
+ [0x1f24f, 1],
+ [0x1f251, 2],
+ [0x1f25f, 1],
+ [0x1f265, 2],
+ [0x1f2ff, 1],
+ [0x1f320, 2],
+ [0x1f32c, 1],
+ [0x1f335, 2],
+ [0x1f336, 1],
+ [0x1f37c, 2],
+ [0x1f37d, 1],
+ [0x1f393, 2],
+ [0x1f39f, 1],
+ [0x1f3ca, 2],
+ [0x1f3ce, 1],
+ [0x1f3d3, 2],
+ [0x1f3df, 1],
+ [0x1f3f0, 2],
+ [0x1f3f3, 1],
+ [0x1f3f4, 2],
+ [0x1f3f7, 1],
+ [0x1f43e, 2],
+ [0x1f43f, 1],
+ [0x1f440, 2],
+ [0x1f441, 1],
+ [0x1f4fc, 2],
+ [0x1f4fe, 1],
+ [0x1f53d, 2],
+ [0x1f54a, 1],
+ [0x1f54e, 2],
+ [0x1f54f, 1],
+ [0x1f567, 2],
+ [0x1f579, 1],
+ [0x1f57a, 2],
+ [0x1f594, 1],
+ [0x1f596, 2],
+ [0x1f5a3, 1],
+ [0x1f5a4, 2],
+ [0x1f5fa, 1],
+ [0x1f64f, 2],
+ [0x1f67f, 1],
+ [0x1f6c5, 2],
+ [0x1f6cb, 1],
+ [0x1f6cc, 2],
+ [0x1f6cf, 1],
+ [0x1f6d2, 2],
+ [0x1f6d4, 1],
+ [0x1f6d7, 2],
+ [0x1f6db, 1],
+ [0x1f6df, 2],
+ [0x1f6ea, 1],
+ [0x1f6ec, 2],
+ [0x1f6f3, 1],
+ [0x1f6fc, 2],
+ [0x1f7df, 1],
+ [0x1f7eb, 2],
+ [0x1f7ef, 1],
+ [0x1f7f0, 2],
+ [0x1f90b, 1],
+ [0x1f93a, 2],
+ [0x1f93b, 1],
+ [0x1f945, 2],
+ [0x1f946, 1],
+ [0x1f9ff, 2],
+ [0x1fa6f, 1],
+ [0x1fa7c, 2],
+ [0x1fa7f, 1],
+ [0x1fa88, 2],
+ [0x1fa8f, 1],
+ [0x1fabd, 2],
+ [0x1fabe, 1],
+ [0x1fac5, 2],
+ [0x1facd, 1],
+ [0x1fadb, 2],
+ [0x1fadf, 1],
+ [0x1fae8, 2],
+ [0x1faef, 1],
+ [0x1faf8, 2],
+ [0x1ffff, 1],
+ [0x2fffd, 2],
+ [0x2ffff, 1],
+ [0x3fffd, 2],
+ [0xe00ff, 1],
+ [0xe01ef, 0],
+ [0xeffff, 1],
+ [0xffffd, -1],
+ [0xfffff, 1],
+ [0x10fffd, -1],
+ [0x7fffffff, 1]
+ ].transpose.map(&:freeze)
end
diff --git a/lib/reline/version.rb b/lib/reline/version.rb
index 46613a5952..b75d874adb 100644
--- a/lib/reline/version.rb
+++ b/lib/reline/version.rb
@@ -1,3 +1,3 @@
module Reline
- VERSION = '0.5.7'
+ VERSION = '0.5.10'
end