Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
if: ${{ startsWith(github.repository, 'ruby/') || github.event_name != 'schedule' }}
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
with:
engine: cruby
engine: all
min_version: 2.6 # from `required_ruby_version` in io-console.gemspec

test:
Expand All @@ -25,9 +25,15 @@ jobs:
include:
- ruby: mswin
os: windows-latest
- ruby: jruby-head
os: macos-15-intel
exclude:
- ruby: jruby
os: windows-latest
- ruby: jruby-head
os: windows-latest
- ruby: truffleruby
os: windows-latest
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
steps:
- name: git config
Expand Down
4 changes: 2 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ task :test => ffi_version_file if RUBY_ENGINE == "jruby"
Rake::TestTask.new(:test) do |t|
if extask
t.libs = [extask.lib_dir.chomp("/"+File.dirname(name))]
elsif RUBY_ENGINE == "jruby"
t.libs.unshift "lib/ffi"
end
t.libs.unshift "lib/ffi" if RUBY_ENGINE == "jruby"
t.libs << "test/lib"
t.ruby_opts << "-rhelper"
t.options = "--ignore-name=TestIO_Console#test_bad_keyword" if RUBY_ENGINE == "jruby"
t.test_files = FileList["test/**/test_*.rb"]
end

Expand Down
56 changes: 48 additions & 8 deletions lib/ffi/io/console/stty_console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,44 @@ module IO::Console
STTY = %w[/usr/bin/stty /bin/stty].find {|path| File.executable?(path)}
end

unless IO::Console::STTY &&
system(IO::Console::STTY, out: File::NULL, err: %i[child out])
raise "stty command returned nonzero exit status"
end
raise LoadError, "stty command not found" unless IO::Console::STTY

warn "io/console on JRuby shells out to stty for most operations" if $VERBOSE

class IO::Console::Mode
def initialize(saved)
@saved = saved
@args = []
end

def initialize_copy(mode)
super
@saved = mode.__send__(:saved).dup
@args = mode.__send__(:args).dup
end

def echo=(echo)
@args << (echo ? 'echo' : '-echo')
echo
end

def raw(min: 1, time: nil, intr: nil)
dup.raw!(min:, time:, intr:)
end

def raw!(min: 1, time: nil, intr: nil)
@args << 'raw'
@args.push('min', min.to_s) if min >= 0
@args.push('time', ((time || 0) * 10).to_i.to_s)
@args.concat(%w[brkint isig opost]) if intr
self
end

private

attr_reader :saved, :args
end

# Non-Windows assumes stty command is available
class IO
private def _io_console_stty(*args)
Expand All @@ -34,11 +65,11 @@ class IO
end

def raw(*, min: 1, time: nil, intr: nil)
saved = _io_console_stty('-g')
_io_console_stty('raw')
saved = console_mode
self.console_mode = saved.raw(min:, time:, intr:)
yield self
ensure
_io_console_stty(saved) if saved
self.console_mode = saved if saved
end

def raw!(*)
Expand Down Expand Up @@ -73,6 +104,15 @@ def noecho
_io_console_stty(saved) if saved
end

def console_mode
Console::Mode.new(_io_console_stty('-g').chomp)
end

def console_mode=(mode)
_io_console_stty(mode.__send__(:saved), *mode.__send__(:args))
mode
end

# Not all systems return same format of stty -a output
IEEE_STD_1003_2 = '(?<rows>\d+) rows; (?<columns>\d+) columns'
UBUNTU = 'rows (?<rows>\d+); columns (?<columns>\d+)'
Expand All @@ -96,7 +136,7 @@ def winsize=(size)

row, col, _, _ = size

_io_console_stty("rows #{row} cols #{col}")
_io_console_stty('rows', row.to_s, 'cols', col.to_s)
end

def iflush
Expand Down
4 changes: 4 additions & 0 deletions test/io/console/test_io_console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,8 @@ def test_getpass
end

def test_iflush
pend "stty cannot flush terminal queues" if IO.private_method_defined?(:_io_console_stty)

helper {|m, s|
m.print "a"
s.iflush
Expand All @@ -390,6 +392,8 @@ def test_oflush
end

def test_ioflush
pend "stty cannot flush terminal queues" if IO.private_method_defined?(:_io_console_stty)

helper {|m, s|
m.print "a"
s.ioflush
Expand Down
Loading