mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Split namespace of env-dependent I/O classes
This commit is contained in:
parent
11476e9902
commit
0f45bd0584
5 changed files with 125 additions and 58 deletions
|
@ -82,12 +82,6 @@ module Reline
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
if IS_WINDOWS
|
|
||||||
require 'reline/windows'
|
|
||||||
else
|
|
||||||
require 'reline/ansi'
|
|
||||||
end
|
|
||||||
|
|
||||||
def retrieve_completion_block(line, byte_pointer)
|
def retrieve_completion_block(line, byte_pointer)
|
||||||
break_regexp = /[#{Regexp.escape(@@basic_word_break_characters)}]/
|
break_regexp = /[#{Regexp.escape(@@basic_word_break_characters)}]/
|
||||||
before_pointer = line.byteslice(0, byte_pointer)
|
before_pointer = line.byteslice(0, byte_pointer)
|
||||||
|
@ -132,10 +126,11 @@ module Reline
|
||||||
end
|
end
|
||||||
|
|
||||||
def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
|
def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
|
||||||
otio = prep
|
|
||||||
@@config.read
|
@@config.read
|
||||||
|
otio = Reline::IO.prep
|
||||||
|
|
||||||
may_req_ambiguous_char_width
|
may_req_ambiguous_char_width
|
||||||
|
@@line_editor.reset(prompt)
|
||||||
if multiline
|
if multiline
|
||||||
@@line_editor.multiline_on
|
@@line_editor.multiline_on
|
||||||
if block_given?
|
if block_given?
|
||||||
|
@ -171,7 +166,7 @@ module Reline
|
||||||
|
|
||||||
key_stroke = Reline::KeyStroke.new(config)
|
key_stroke = Reline::KeyStroke.new(config)
|
||||||
begin
|
begin
|
||||||
while c = getc
|
while c = Reline::IO.getc
|
||||||
key_stroke.input_to!(c)&.then { |inputs|
|
key_stroke.input_to!(c)&.then { |inputs|
|
||||||
inputs.each { |c|
|
inputs.each { |c|
|
||||||
@@line_editor.input_key(c)
|
@@line_editor.input_key(c)
|
||||||
|
@ -180,25 +175,35 @@ module Reline
|
||||||
}
|
}
|
||||||
break if @@line_editor.finished?
|
break if @@line_editor.finished?
|
||||||
end
|
end
|
||||||
Reline.move_cursor_column(0)
|
Reline::IO.move_cursor_column(0)
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
deprep(otio)
|
Reline::IO.deprep(otio)
|
||||||
raise e
|
raise e
|
||||||
end
|
end
|
||||||
|
|
||||||
deprep(otio)
|
Reline::IO.deprep(otio)
|
||||||
end
|
end
|
||||||
|
|
||||||
def may_req_ambiguous_char_width
|
def may_req_ambiguous_char_width
|
||||||
|
@@ambiguous_width = 2 if Reline::IO == Reline::GeneralIO or STDOUT.is_a?(File)
|
||||||
return if @@ambiguous_width
|
return if @@ambiguous_width
|
||||||
Reline.move_cursor_column(0)
|
Reline::IO.move_cursor_column(0)
|
||||||
print "\u{25bd}"
|
print "\u{25bd}"
|
||||||
@@ambiguous_width = Reline.cursor_pos.x
|
@@ambiguous_width = Reline::IO.cursor_pos.x
|
||||||
Reline.move_cursor_column(0)
|
Reline::IO.move_cursor_column(0)
|
||||||
Reline.erase_after_cursor
|
Reline::IO.erase_after_cursor
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.ambiguous_width
|
def self.ambiguous_width
|
||||||
@@ambiguous_width
|
@@ambiguous_width
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Reline::IS_WINDOWS
|
||||||
|
require 'reline/windows'
|
||||||
|
Reline::IO = Reline::Windows
|
||||||
|
else
|
||||||
|
require 'reline/ansi'
|
||||||
|
Reline::IO = Reline::ANSI
|
||||||
|
end
|
||||||
|
require 'reline/general_io'
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
module Reline
|
class Reline::ANSI
|
||||||
def getc
|
def self.getc
|
||||||
c = nil
|
c = nil
|
||||||
until c
|
loop do
|
||||||
return nil if @line_editor.finished?
|
|
||||||
result = select([$stdin], [], [], 0.1)
|
result = select([$stdin], [], [], 0.1)
|
||||||
next if result.nil?
|
next if result.nil?
|
||||||
c = $stdin.read(1)
|
c = $stdin.read(1)
|
||||||
|
break
|
||||||
end
|
end
|
||||||
c.ord
|
c&.ord
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get_screen_size
|
def self.get_screen_size
|
||||||
|
@ -29,7 +29,7 @@ module Reline
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
m = res.match(/(?<row>\d+);(?<column>\d+)/)
|
m = res.match(/(?<row>\d+);(?<column>\d+)/)
|
||||||
CursorPos.new(m[:column].to_i - 1, m[:row].to_i - 1)
|
Reline::CursorPos.new(m[:column].to_i - 1, m[:row].to_i - 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.move_cursor_column(x)
|
def self.move_cursor_column(x)
|
||||||
|
@ -66,7 +66,7 @@ module Reline
|
||||||
print "\e[1;1H"
|
print "\e[1;1H"
|
||||||
end
|
end
|
||||||
|
|
||||||
def prep
|
def self.prep
|
||||||
int_handle = Signal.trap('INT', 'IGNORE')
|
int_handle = Signal.trap('INT', 'IGNORE')
|
||||||
otio = `stty -g`.chomp
|
otio = `stty -g`.chomp
|
||||||
setting = ' -echo -icrnl cbreak'
|
setting = ' -echo -icrnl cbreak'
|
||||||
|
@ -79,7 +79,7 @@ module Reline
|
||||||
otio
|
otio
|
||||||
end
|
end
|
||||||
|
|
||||||
def deprep(otio)
|
def self.deprep(otio)
|
||||||
int_handle = Signal.trap('INT', 'IGNORE')
|
int_handle = Signal.trap('INT', 'IGNORE')
|
||||||
`stty #{otio}`
|
`stty #{otio}`
|
||||||
Signal.trap('INT', int_handle)
|
Signal.trap('INT', int_handle)
|
||||||
|
|
55
lib/reline/general_io.rb
Normal file
55
lib/reline/general_io.rb
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
require 'timeout'
|
||||||
|
|
||||||
|
class Reline::GeneralIO
|
||||||
|
@@buf = []
|
||||||
|
|
||||||
|
def self.input=(val)
|
||||||
|
@@input = val
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.getc
|
||||||
|
c = nil
|
||||||
|
loop do
|
||||||
|
result = select([@@input], [], [], 0.1)
|
||||||
|
next if result.nil?
|
||||||
|
c = @@input.read(1)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
c&.ord
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.get_screen_size
|
||||||
|
[1, 1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.cursor_pos
|
||||||
|
Reline::CursorPos.new(1, 1)
|
||||||
|
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.prep
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.deprep(otio)
|
||||||
|
end
|
||||||
|
end
|
|
@ -76,41 +76,48 @@ class Reline::LineEditor
|
||||||
CompletionJourneyData = Struct.new('CompletionJourneyData', :preposing, :postposing, :list, :pointer)
|
CompletionJourneyData = Struct.new('CompletionJourneyData', :preposing, :postposing, :list, :pointer)
|
||||||
MenuInfo = Struct.new('MenuInfo', :target, :list)
|
MenuInfo = Struct.new('MenuInfo', :target, :list)
|
||||||
|
|
||||||
def initialize(config, prompt = '', encoding = Encoding.default_external)
|
def initialize(config)
|
||||||
@config = config
|
@config = config
|
||||||
|
reset
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset(prompt = '', encoding = Encoding.default_external)
|
||||||
@prompt = prompt
|
@prompt = prompt
|
||||||
@prompt_width = calculate_width(@prompt)
|
|
||||||
@cursor = 0
|
|
||||||
@cursor_max = 0
|
|
||||||
@byte_pointer = 0
|
|
||||||
@encoding = encoding
|
@encoding = encoding
|
||||||
@buffer_of_lines = [String.new(encoding: @encoding)]
|
@prompt_width = calculate_width(@prompt)
|
||||||
@line_index = 0
|
|
||||||
@previous_line_index = nil
|
|
||||||
@line = @buffer_of_lines[0]
|
|
||||||
@is_multiline = false
|
@is_multiline = false
|
||||||
@finished = false
|
@finished = false
|
||||||
@cleared = false
|
@cleared = false
|
||||||
@rerender_all = false
|
@rerender_all = false
|
||||||
@is_confirm_multiline_termination = false
|
@is_confirm_multiline_termination = false
|
||||||
@history_pointer = nil
|
@history_pointer = nil
|
||||||
@line_backup_in_history = nil
|
|
||||||
@kill_ring = Reline::KillRing.new
|
@kill_ring = Reline::KillRing.new
|
||||||
@vi_clipboard = ''
|
@vi_clipboard = ''
|
||||||
@vi_arg = nil
|
@vi_arg = nil
|
||||||
@multibyte_buffer = String.new(encoding: 'ASCII-8BIT')
|
|
||||||
@meta_prefix = false
|
@meta_prefix = false
|
||||||
@waiting_proc = nil
|
@waiting_proc = nil
|
||||||
@waiting_operator_proc = nil
|
@waiting_operator_proc = nil
|
||||||
@completion_journey_data = nil
|
@completion_journey_data = nil
|
||||||
@completion_state = CompletionState::NORMAL
|
@completion_state = CompletionState::NORMAL
|
||||||
@perfect_matched = nil
|
@perfect_matched = nil
|
||||||
|
@menu_info = nil
|
||||||
|
@first_prompt = true
|
||||||
|
@searching_prompt = nil
|
||||||
|
@first_char = true
|
||||||
|
@cursor = 0
|
||||||
|
@cursor_max = 0
|
||||||
|
@byte_pointer = 0
|
||||||
|
@buffer_of_lines = [String.new(encoding: @encoding)]
|
||||||
|
@line_index = 0
|
||||||
|
@previous_line_index = nil
|
||||||
|
@line = @buffer_of_lines[0]
|
||||||
@first_line_started_from = 0
|
@first_line_started_from = 0
|
||||||
@move_up = 0
|
@move_up = 0
|
||||||
@started_from = 0
|
@started_from = 0
|
||||||
@highest_in_this = 1
|
@highest_in_this = 1
|
||||||
@highest_in_all = 1
|
@highest_in_all = 1
|
||||||
@menu_info = nil
|
@line_backup_in_history = nil
|
||||||
|
@multibyte_buffer = String.new(encoding: 'ASCII-8BIT')
|
||||||
end
|
end
|
||||||
|
|
||||||
def multiline_on
|
def multiline_on
|
||||||
|
@ -158,18 +165,18 @@ class Reline::LineEditor
|
||||||
|
|
||||||
private def scroll_down(val)
|
private def scroll_down(val)
|
||||||
if val <= @rest_height
|
if val <= @rest_height
|
||||||
Reline.move_cursor_down(val)
|
Reline::IO.move_cursor_down(val)
|
||||||
@rest_height -= val
|
@rest_height -= val
|
||||||
else
|
else
|
||||||
Reline.move_cursor_down(@rest_height)
|
Reline::IO.move_cursor_down(@rest_height)
|
||||||
Reline.scroll_down(val - @rest_height)
|
Reline::IO.scroll_down(val - @rest_height)
|
||||||
@rest_height = 0
|
@rest_height = 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def move_cursor_up(val)
|
private def move_cursor_up(val)
|
||||||
if val > 0
|
if val > 0
|
||||||
Reline.move_cursor_up(val)
|
Reline::IO.move_cursor_up(val)
|
||||||
@rest_height += val
|
@rest_height += val
|
||||||
elsif val < 0
|
elsif val < 0
|
||||||
move_cursor_down(-val)
|
move_cursor_down(-val)
|
||||||
|
@ -178,7 +185,7 @@ class Reline::LineEditor
|
||||||
|
|
||||||
private def move_cursor_down(val)
|
private def move_cursor_down(val)
|
||||||
if val > 0
|
if val > 0
|
||||||
Reline.move_cursor_down(val)
|
Reline::IO.move_cursor_down(val)
|
||||||
@rest_height -= val
|
@rest_height -= val
|
||||||
@rest_height = 0 if @rest_height < 0
|
@rest_height = 0 if @rest_height < 0
|
||||||
elsif val < 0
|
elsif val < 0
|
||||||
|
@ -210,8 +217,8 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
|
|
||||||
def rerender # TODO: support physical and logical lines
|
def rerender # TODO: support physical and logical lines
|
||||||
@rest_height ||= (Reline.get_screen_size.first - 1) - Reline.cursor_pos.y
|
@rest_height ||= (Reline::IO.get_screen_size.first - 1) - Reline::IO.cursor_pos.y
|
||||||
@screen_size ||= Reline.get_screen_size
|
@screen_size ||= Reline::IO.get_screen_size
|
||||||
if @menu_info
|
if @menu_info
|
||||||
puts
|
puts
|
||||||
@menu_info.list.each do |item|
|
@menu_info.list.each do |item|
|
||||||
|
@ -228,7 +235,7 @@ class Reline::LineEditor
|
||||||
prompt_width = @prompt_width
|
prompt_width = @prompt_width
|
||||||
end
|
end
|
||||||
if @cleared
|
if @cleared
|
||||||
Reline.clear_screen
|
Reline::IO.clear_screen
|
||||||
@cleared = false
|
@cleared = false
|
||||||
back = 0
|
back = 0
|
||||||
@buffer_of_lines.each_with_index do |line, index|
|
@buffer_of_lines.each_with_index do |line, index|
|
||||||
|
@ -241,7 +248,7 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
move_cursor_up(back)
|
move_cursor_up(back)
|
||||||
move_cursor_down(@first_line_started_from + @started_from)
|
move_cursor_down(@first_line_started_from + @started_from)
|
||||||
Reline.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
Reline::IO.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
# FIXME: end of logical line sometimes breaks
|
# FIXME: end of logical line sometimes breaks
|
||||||
|
@ -285,7 +292,7 @@ class Reline::LineEditor
|
||||||
@previous_line_index = nil
|
@previous_line_index = nil
|
||||||
elsif @rerender_all
|
elsif @rerender_all
|
||||||
move_cursor_up(@first_line_started_from + @started_from)
|
move_cursor_up(@first_line_started_from + @started_from)
|
||||||
Reline.move_cursor_column(0)
|
Reline::IO.move_cursor_column(0)
|
||||||
back = 0
|
back = 0
|
||||||
@buffer_of_lines.each do |line|
|
@buffer_of_lines.each do |line|
|
||||||
width = prompt_width + calculate_width(line)
|
width = prompt_width + calculate_width(line)
|
||||||
|
@ -297,10 +304,10 @@ class Reline::LineEditor
|
||||||
move_cursor_up(back)
|
move_cursor_up(back)
|
||||||
elsif back < @highest_in_all
|
elsif back < @highest_in_all
|
||||||
scroll_down(back)
|
scroll_down(back)
|
||||||
Reline.erase_after_cursor
|
Reline::IO.erase_after_cursor
|
||||||
(@highest_in_all - back).times do
|
(@highest_in_all - back).times do
|
||||||
scroll_down(1)
|
scroll_down(1)
|
||||||
Reline.erase_after_cursor
|
Reline::IO.erase_after_cursor
|
||||||
end
|
end
|
||||||
move_cursor_up(@highest_in_all)
|
move_cursor_up(@highest_in_all)
|
||||||
end
|
end
|
||||||
|
@ -327,8 +334,8 @@ class Reline::LineEditor
|
||||||
render_partial(prompt, prompt_width, @line) if !@is_multiline or !finished?
|
render_partial(prompt, prompt_width, @line) if !@is_multiline or !finished?
|
||||||
if @is_multiline and finished?
|
if @is_multiline and finished?
|
||||||
scroll_down(1) unless @buffer_of_lines.last.empty?
|
scroll_down(1) unless @buffer_of_lines.last.empty?
|
||||||
Reline.move_cursor_column(0)
|
Reline::IO.move_cursor_column(0)
|
||||||
Reline.erase_after_cursor
|
Reline::IO.erase_after_cursor
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -347,9 +354,9 @@ class Reline::LineEditor
|
||||||
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
||||||
end
|
end
|
||||||
visual_lines.each_with_index do |line, index|
|
visual_lines.each_with_index do |line, index|
|
||||||
Reline.move_cursor_column(0)
|
Reline::IO.move_cursor_column(0)
|
||||||
escaped_print line
|
escaped_print line
|
||||||
Reline.erase_after_cursor
|
Reline::IO.erase_after_cursor
|
||||||
move_cursor_down(1) if index < (visual_lines.size - 1)
|
move_cursor_down(1) if index < (visual_lines.size - 1)
|
||||||
end
|
end
|
||||||
if with_control
|
if with_control
|
||||||
|
@ -357,7 +364,7 @@ class Reline::LineEditor
|
||||||
puts
|
puts
|
||||||
else
|
else
|
||||||
move_cursor_up((visual_lines.size - 1) - @started_from)
|
move_cursor_up((visual_lines.size - 1) - @started_from)
|
||||||
Reline.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
Reline::IO.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
visual_lines.size
|
visual_lines.size
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
require 'fiddle/import'
|
require 'fiddle/import'
|
||||||
|
|
||||||
module Reline
|
class Reline::Windows
|
||||||
class Win32API
|
class Win32API
|
||||||
DLL = {}
|
DLL = {}
|
||||||
TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
|
TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
|
||||||
|
@ -52,7 +52,7 @@ module Reline
|
||||||
@@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
|
@@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
|
||||||
@@buf = []
|
@@buf = []
|
||||||
|
|
||||||
def getwch
|
def self.getwch
|
||||||
while @@kbhit.call == 0
|
while @@kbhit.call == 0
|
||||||
sleep(0.001)
|
sleep(0.001)
|
||||||
end
|
end
|
||||||
|
@ -69,7 +69,7 @@ module Reline
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def getc
|
def self.getc
|
||||||
unless @@buf.empty?
|
unless @@buf.empty?
|
||||||
return @@buf.shift
|
return @@buf.shift
|
||||||
end
|
end
|
||||||
|
@ -112,7 +112,7 @@ module Reline
|
||||||
@@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
|
@@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi)
|
||||||
x = csbi[4, 2].unpack('s*').first
|
x = csbi[4, 2].unpack('s*').first
|
||||||
y = csbi[6, 4].unpack('s*').first
|
y = csbi[6, 4].unpack('s*').first
|
||||||
CursorPos.new(x, y)
|
Reline::CursorPos.new(x, y)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.move_cursor_column(val)
|
def self.move_cursor_column(val)
|
||||||
|
@ -161,12 +161,12 @@ module Reline
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
def prep
|
def self.prep
|
||||||
# do nothing
|
# do nothing
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def deprep(otio)
|
def self.deprep(otio)
|
||||||
# do nothing
|
# do nothing
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue