[ruby/reline] Add a timeout to cursor_pos
(https://github.com/ruby/reline/pull/750) https://github.com/ruby/reline/commit/dd4a654e5d
This commit is contained in:
parent
9f47f0eb3c
commit
8f4277f405
@ -412,7 +412,7 @@ module Reline
|
||||
end
|
||||
|
||||
private def may_req_ambiguous_char_width
|
||||
@ambiguous_width = 2 if io_gate.dumb? || !STDIN.tty? || !STDOUT.tty?
|
||||
@ambiguous_width = 1 if io_gate.dumb? || !STDIN.tty? || !STDOUT.tty?
|
||||
return if defined? @ambiguous_width
|
||||
io_gate.move_cursor_column(0)
|
||||
begin
|
||||
@ -421,7 +421,7 @@ module Reline
|
||||
# LANG=C
|
||||
@ambiguous_width = 1
|
||||
else
|
||||
@ambiguous_width = io_gate.cursor_pos.x
|
||||
@ambiguous_width = io_gate.cursor_pos.x == 2 ? 2 : 1
|
||||
end
|
||||
io_gate.move_cursor_column(0)
|
||||
io_gate.erase_after_cursor
|
||||
|
@ -245,39 +245,30 @@ class Reline::ANSI < Reline::IO
|
||||
self
|
||||
end
|
||||
|
||||
def cursor_pos
|
||||
if both_tty?
|
||||
res = +''
|
||||
m = nil
|
||||
@input.raw do |stdin|
|
||||
@output << "\e[6n"
|
||||
@output.flush
|
||||
loop do
|
||||
c = stdin.getc
|
||||
next if c.nil?
|
||||
res << c
|
||||
m = res.match(/\e\[(?<row>\d+);(?<column>\d+)R/)
|
||||
break if m
|
||||
end
|
||||
(m.pre_match + m.post_match).chars.reverse_each do |ch|
|
||||
stdin.ungetc ch
|
||||
private def cursor_pos_internal(timeout:)
|
||||
match = nil
|
||||
@input.raw do |stdin|
|
||||
@output << "\e[6n"
|
||||
@output.flush
|
||||
timeout_at = Time.now + timeout
|
||||
buf = +''
|
||||
while (wait = timeout_at - Time.now) > 0 && stdin.wait_readable(wait)
|
||||
buf << stdin.readpartial(1024)
|
||||
if (match = buf.match(/\e\[(?<row>\d+);(?<column>\d+)R/))
|
||||
buf = match.pre_match + match.post_match
|
||||
break
|
||||
end
|
||||
end
|
||||
column = m[:column].to_i - 1
|
||||
row = m[:row].to_i - 1
|
||||
else
|
||||
begin
|
||||
buf = @output.pread(@output.pos, 0)
|
||||
row = buf.count("\n")
|
||||
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
|
||||
rescue Errno::ESPIPE, IOError
|
||||
# Just returns column 1 for ambiguous width because this I/O is not
|
||||
# tty and can't seek.
|
||||
row = 0
|
||||
column = 1
|
||||
buf.chars.reverse_each do |ch|
|
||||
stdin.ungetc ch
|
||||
end
|
||||
end
|
||||
Reline::CursorPos.new(column, row)
|
||||
[match[:column].to_i - 1, match[:row].to_i - 1] if match
|
||||
end
|
||||
|
||||
def cursor_pos
|
||||
col, row = cursor_pos_internal(timeout: 0.5) if both_tty?
|
||||
Reline::CursorPos.new(col || 0, row || 0)
|
||||
end
|
||||
|
||||
def both_tty?
|
||||
|
@ -60,7 +60,7 @@ class Reline::Dumb < Reline::IO
|
||||
end
|
||||
|
||||
def cursor_pos
|
||||
Reline::CursorPos.new(1, 1)
|
||||
Reline::CursorPos.new(0, 0)
|
||||
end
|
||||
|
||||
def hide_cursor
|
||||
|
@ -1,6 +1,10 @@
|
||||
require_relative 'helper'
|
||||
require 'reline'
|
||||
require 'stringio'
|
||||
begin
|
||||
require "pty"
|
||||
rescue LoadError # some platforms don't support PTY
|
||||
end
|
||||
|
||||
class Reline::Test < Reline::TestCase
|
||||
class DummyCallbackObject
|
||||
@ -432,6 +436,37 @@ class Reline::Test < Reline::TestCase
|
||||
/mswin|mingw/.match?(RUBY_PLATFORM)
|
||||
end
|
||||
|
||||
def test_tty_amibuous_width
|
||||
omit unless defined?(PTY)
|
||||
ruby_file = Tempfile.create('rubyfile')
|
||||
ruby_file.write(<<~RUBY)
|
||||
require 'reline'
|
||||
Thread.new { sleep 2; puts 'timeout'; exit }
|
||||
p [Reline.ambiguous_width, gets.chomp]
|
||||
RUBY
|
||||
ruby_file.close
|
||||
lib = File.expand_path('../../lib', __dir__)
|
||||
cmd = [{ 'TERM' => 'xterm' }, 'ruby', '-I', lib, ruby_file.to_path]
|
||||
|
||||
# Calculate ambiguous width from cursor position
|
||||
[1, 2].each do |ambiguous_width|
|
||||
PTY.spawn(*cmd) do |r, w, pid|
|
||||
loop { break if r.readpartial(1024).include?("\e[6n") }
|
||||
w.puts "hello\e[10;#{ambiguous_width + 1}Rworld"
|
||||
assert_include(r.gets, [ambiguous_width, 'helloworld'].inspect)
|
||||
Process.waitpid pid
|
||||
end
|
||||
end
|
||||
|
||||
# Ambiguous width = 1 when cursor pos timed out
|
||||
PTY.spawn(*cmd) do |r, w, pid|
|
||||
loop { break if r.readpartial(1024).include?("\e[6n") }
|
||||
w.puts "hello\e[10;2Sworld"
|
||||
assert_include(r.gets, [1, "hello\e[10;2Sworld"].inspect)
|
||||
Process.waitpid pid
|
||||
end
|
||||
end
|
||||
|
||||
def get_reline_encoding
|
||||
if encoding = Reline.core.encoding
|
||||
encoding
|
||||
|
@ -15,7 +15,7 @@ class Reline::Unicode::Test < Reline::TestCase
|
||||
end
|
||||
|
||||
def test_ambiguous_width
|
||||
assert_equal 2, Reline::Unicode.calculate_width('√', true)
|
||||
assert_equal 1, Reline::Unicode.calculate_width('√', true)
|
||||
end
|
||||
|
||||
def test_csi_regexp
|
||||
|
Loading…
x
Reference in New Issue
Block a user