Skip to content

Commit

Permalink
Split namespace of env-dependent I/O classes
Browse files Browse the repository at this point in the history
  • Loading branch information
aycabta committed May 12, 2019
1 parent 11476e9 commit 0f45bd0
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 58 deletions.
35 changes: 20 additions & 15 deletions lib/reline.rb
Expand Up @@ -82,12 +82,6 @@ def self.delete_text(start = nil, length = nil)
raise NotImplementedError
end

if IS_WINDOWS
require 'reline/windows'
else
require 'reline/ansi'
end

def retrieve_completion_block(line, byte_pointer)
break_regexp = /[#{Regexp.escape(@@basic_word_break_characters)}]/
before_pointer = line.byteslice(0, byte_pointer)
Expand Down Expand Up @@ -132,10 +126,11 @@ def readline(prompt = '', add_hist = false)
end

def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
otio = prep
@@config.read
otio = Reline::IO.prep

may_req_ambiguous_char_width
@@line_editor.reset(prompt)
if multiline
@@line_editor.multiline_on
if block_given?
Expand Down Expand Up @@ -171,7 +166,7 @@ def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)

key_stroke = Reline::KeyStroke.new(config)
begin
while c = getc
while c = Reline::IO.getc
key_stroke.input_to!(c)&.then { |inputs|
inputs.each { |c|
@@line_editor.input_key(c)
Expand All @@ -180,25 +175,35 @@ def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
}
break if @@line_editor.finished?
end
Reline.move_cursor_column(0)
Reline::IO.move_cursor_column(0)
rescue StandardError => e
deprep(otio)
Reline::IO.deprep(otio)
raise e
end

deprep(otio)
Reline::IO.deprep(otio)
end

def may_req_ambiguous_char_width
@@ambiguous_width = 2 if Reline::IO == Reline::GeneralIO or STDOUT.is_a?(File)
return if @@ambiguous_width
Reline.move_cursor_column(0)
Reline::IO.move_cursor_column(0)
print "\u{25bd}"
@@ambiguous_width = Reline.cursor_pos.x
Reline.move_cursor_column(0)
Reline.erase_after_cursor
@@ambiguous_width = Reline::IO.cursor_pos.x
Reline::IO.move_cursor_column(0)
Reline::IO.erase_after_cursor
end

def self.ambiguous_width
@@ambiguous_width
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'
16 changes: 8 additions & 8 deletions lib/reline/ansi.rb
@@ -1,13 +1,13 @@
module Reline
def getc
class Reline::ANSI
def self.getc
c = nil
until c
return nil if @line_editor.finished?
loop do
result = select([$stdin], [], [], 0.1)
next if result.nil?
c = $stdin.read(1)
break
end
c.ord
c&.ord
end

def self.get_screen_size
Expand All @@ -29,7 +29,7 @@ def self.cursor_pos
end
end
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

def self.move_cursor_column(x)
Expand Down Expand Up @@ -66,7 +66,7 @@ def self.clear_screen
print "\e[1;1H"
end

def prep
def self.prep
int_handle = Signal.trap('INT', 'IGNORE')
otio = `stty -g`.chomp
setting = ' -echo -icrnl cbreak'
Expand All @@ -79,7 +79,7 @@ def prep
otio
end

def deprep(otio)
def self.deprep(otio)
int_handle = Signal.trap('INT', 'IGNORE')
`stty #{otio}`
Signal.trap('INT', int_handle)
Expand Down
55 changes: 55 additions & 0 deletions lib/reline/general_io.rb
@@ -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
65 changes: 36 additions & 29 deletions lib/reline/line_editor.rb
Expand Up @@ -76,41 +76,48 @@ module CompletionState
CompletionJourneyData = Struct.new('CompletionJourneyData', :preposing, :postposing, :list, :pointer)
MenuInfo = Struct.new('MenuInfo', :target, :list)

def initialize(config, prompt = '', encoding = Encoding.default_external)
def initialize(config)
@config = config
reset
end

def reset(prompt = '', encoding = Encoding.default_external)
@prompt = prompt
@prompt_width = calculate_width(@prompt)
@cursor = 0
@cursor_max = 0
@byte_pointer = 0
@encoding = encoding
@buffer_of_lines = [String.new(encoding: @encoding)]
@line_index = 0
@previous_line_index = nil
@line = @buffer_of_lines[0]
@prompt_width = calculate_width(@prompt)
@is_multiline = false
@finished = false
@cleared = false
@rerender_all = false
@is_confirm_multiline_termination = false
@history_pointer = nil
@line_backup_in_history = nil
@kill_ring = Reline::KillRing.new
@vi_clipboard = ''
@vi_arg = nil
@multibyte_buffer = String.new(encoding: 'ASCII-8BIT')
@meta_prefix = false
@waiting_proc = nil
@waiting_operator_proc = nil
@completion_journey_data = nil
@completion_state = CompletionState::NORMAL
@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
@move_up = 0
@started_from = 0
@highest_in_this = 1
@highest_in_all = 1
@menu_info = nil
@line_backup_in_history = nil
@multibyte_buffer = String.new(encoding: 'ASCII-8BIT')
end

def multiline_on
Expand Down Expand Up @@ -158,18 +165,18 @@ def multiline_off

private def scroll_down(val)
if val <= @rest_height
Reline.move_cursor_down(val)
Reline::IO.move_cursor_down(val)
@rest_height -= val
else
Reline.move_cursor_down(@rest_height)
Reline.scroll_down(val - @rest_height)
Reline::IO.move_cursor_down(@rest_height)
Reline::IO.scroll_down(val - @rest_height)
@rest_height = 0
end
end

private def move_cursor_up(val)
if val > 0
Reline.move_cursor_up(val)
Reline::IO.move_cursor_up(val)
@rest_height += val
elsif val < 0
move_cursor_down(-val)
Expand All @@ -178,7 +185,7 @@ def multiline_off

private def move_cursor_down(val)
if val > 0
Reline.move_cursor_down(val)
Reline::IO.move_cursor_down(val)
@rest_height -= val
@rest_height = 0 if @rest_height < 0
elsif val < 0
Expand Down Expand Up @@ -210,8 +217,8 @@ def multiline_off
end

def rerender # TODO: support physical and logical lines
@rest_height ||= (Reline.get_screen_size.first - 1) - Reline.cursor_pos.y
@screen_size ||= Reline.get_screen_size
@rest_height ||= (Reline::IO.get_screen_size.first - 1) - Reline::IO.cursor_pos.y
@screen_size ||= Reline::IO.get_screen_size
if @menu_info
puts
@menu_info.list.each do |item|
Expand All @@ -228,7 +235,7 @@ def rerender # TODO: support physical and logical lines
prompt_width = @prompt_width
end
if @cleared
Reline.clear_screen
Reline::IO.clear_screen
@cleared = false
back = 0
@buffer_of_lines.each_with_index do |line, index|
Expand All @@ -241,7 +248,7 @@ def rerender # TODO: support physical and logical lines
end
move_cursor_up(back)
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
end
# FIXME: end of logical line sometimes breaks
Expand Down Expand Up @@ -285,7 +292,7 @@ def rerender # TODO: support physical and logical lines
@previous_line_index = nil
elsif @rerender_all
move_cursor_up(@first_line_started_from + @started_from)
Reline.move_cursor_column(0)
Reline::IO.move_cursor_column(0)
back = 0
@buffer_of_lines.each do |line|
width = prompt_width + calculate_width(line)
Expand All @@ -297,10 +304,10 @@ def rerender # TODO: support physical and logical lines
move_cursor_up(back)
elsif back < @highest_in_all
scroll_down(back)
Reline.erase_after_cursor
Reline::IO.erase_after_cursor
(@highest_in_all - back).times do
scroll_down(1)
Reline.erase_after_cursor
Reline::IO.erase_after_cursor
end
move_cursor_up(@highest_in_all)
end
Expand All @@ -327,8 +334,8 @@ def rerender # TODO: support physical and logical lines
render_partial(prompt, prompt_width, @line) if !@is_multiline or !finished?
if @is_multiline and finished?
scroll_down(1) unless @buffer_of_lines.last.empty?
Reline.move_cursor_column(0)
Reline.erase_after_cursor
Reline::IO.move_cursor_column(0)
Reline::IO.erase_after_cursor
end
end

Expand All @@ -347,17 +354,17 @@ def rerender # TODO: support physical and logical lines
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
end
visual_lines.each_with_index do |line, index|
Reline.move_cursor_column(0)
Reline::IO.move_cursor_column(0)
escaped_print line
Reline.erase_after_cursor
Reline::IO.erase_after_cursor
move_cursor_down(1) if index < (visual_lines.size - 1)
end
if with_control
if finished?
puts
else
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
visual_lines.size
Expand Down

0 comments on commit 0f45bd0

Please sign in to comment.