mirror of
https://github.com/ruby/ruby.git
synced 2025-08-25 05:55:46 +02:00

be found (https://github.com/ruby/reline/pull/673) Fix https://github.com/ruby/reline/issues/447 https://github.com/ruby/reline/issues/543 This problem occurs when Fiddle can be loaded, curses can be loaded, and TERM is not registered in Terminfo. It should also occur at hardcopy terminals and when Terminfo information is low, but no such reports have been received. Reline should not abort the process because of missing Terminfo. Reline proceeds with `Reline::Terminfo.enabled? == false` when fiddle or curses cannot be loaded. And does the same when Terminfo is present but TERM is not.ebab2875f1/lib/reline/terminfo.rb (L156-L160)
You can check the operation with `TERM=foo bundle exec bin/console`.4ce247ce2b
153 lines
4.3 KiB
Ruby
153 lines
4.3 KiB
Ruby
begin
|
|
require 'fiddle'
|
|
require 'fiddle/import'
|
|
rescue LoadError
|
|
module Reline::Terminfo
|
|
def self.curses_dl
|
|
false
|
|
end
|
|
end
|
|
end
|
|
|
|
module Reline::Terminfo
|
|
extend Fiddle::Importer
|
|
|
|
class TerminfoError < StandardError; end
|
|
|
|
def self.curses_dl_files
|
|
case RUBY_PLATFORM
|
|
when /mingw/, /mswin/
|
|
# aren't supported
|
|
[]
|
|
when /cygwin/
|
|
%w[cygncursesw-10.dll cygncurses-10.dll]
|
|
when /darwin/
|
|
%w[libncursesw.dylib libcursesw.dylib libncurses.dylib libcurses.dylib]
|
|
else
|
|
%w[libncursesw.so libcursesw.so libncurses.so libcurses.so]
|
|
end
|
|
end
|
|
|
|
@curses_dl = false
|
|
def self.curses_dl
|
|
return @curses_dl unless @curses_dl == false
|
|
if Fiddle.const_defined?(:TYPE_VARIADIC)
|
|
curses_dl_files.each do |curses_name|
|
|
result = Fiddle::Handle.new(curses_name)
|
|
rescue Fiddle::DLError
|
|
next
|
|
else
|
|
@curses_dl = result
|
|
break
|
|
end
|
|
end
|
|
@curses_dl = nil if @curses_dl == false
|
|
@curses_dl
|
|
end
|
|
end if not Reline.const_defined?(:Terminfo) or not Reline::Terminfo.respond_to?(:curses_dl)
|
|
|
|
module Reline::Terminfo
|
|
dlload curses_dl
|
|
#extern 'int setupterm(char *term, int fildes, int *errret)'
|
|
@setupterm = Fiddle::Function.new(curses_dl['setupterm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
|
#extern 'char *tigetstr(char *capname)'
|
|
@tigetstr = Fiddle::Function.new(curses_dl['tigetstr'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
|
|
begin
|
|
#extern 'char *tiparm(const char *str, ...)'
|
|
@tiparm = Fiddle::Function.new(curses_dl['tiparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
|
|
rescue Fiddle::DLError
|
|
# OpenBSD lacks tiparm
|
|
#extern 'char *tparm(const char *str, ...)'
|
|
@tiparm = Fiddle::Function.new(curses_dl['tparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
|
|
end
|
|
begin
|
|
#extern 'int tigetflag(char *str)'
|
|
@tigetflag = Fiddle::Function.new(curses_dl['tigetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
|
rescue Fiddle::DLError
|
|
# OpenBSD lacks tigetflag
|
|
#extern 'int tgetflag(char *str)'
|
|
@tigetflag = Fiddle::Function.new(curses_dl['tgetflag'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
|
end
|
|
begin
|
|
#extern 'int tigetnum(char *str)'
|
|
@tigetnum = Fiddle::Function.new(curses_dl['tigetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
|
rescue Fiddle::DLError
|
|
# OpenBSD lacks tigetnum
|
|
#extern 'int tgetnum(char *str)'
|
|
@tigetnum = Fiddle::Function.new(curses_dl['tgetnum'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
|
end
|
|
|
|
def self.setupterm(term, fildes)
|
|
errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
|
|
ret = @setupterm.(term, fildes, errret_int)
|
|
case ret
|
|
when 0 # OK
|
|
@term_supported = true
|
|
when -1 # ERR
|
|
@term_supported = false
|
|
end
|
|
end
|
|
|
|
class StringWithTiparm < String
|
|
def tiparm(*args) # for method chain
|
|
Reline::Terminfo.tiparm(self, *args)
|
|
end
|
|
end
|
|
|
|
def self.tigetstr(capname)
|
|
raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
|
|
capability = @tigetstr.(capname)
|
|
case capability.to_i
|
|
when 0, -1
|
|
raise TerminfoError, "can't find capability: #{capname}"
|
|
end
|
|
StringWithTiparm.new(capability.to_s)
|
|
end
|
|
|
|
def self.tiparm(str, *args)
|
|
new_args = []
|
|
args.each do |a|
|
|
new_args << Fiddle::TYPE_INT << a
|
|
end
|
|
@tiparm.(str, *new_args).to_s
|
|
end
|
|
|
|
def self.tigetflag(capname)
|
|
raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
|
|
flag = @tigetflag.(capname).to_i
|
|
case flag
|
|
when -1
|
|
raise TerminfoError, "not boolean capability: #{capname}"
|
|
when 0
|
|
raise TerminfoError, "can't find capability: #{capname}"
|
|
end
|
|
flag
|
|
end
|
|
|
|
def self.tigetnum(capname)
|
|
raise TerminfoError, "capname is not String: #{capname.inspect}" unless capname.is_a?(String)
|
|
num = @tigetnum.(capname).to_i
|
|
case num
|
|
when -2
|
|
raise TerminfoError, "not numeric capability: #{capname}"
|
|
when -1
|
|
raise TerminfoError, "can't find capability: #{capname}"
|
|
end
|
|
num
|
|
end
|
|
|
|
# NOTE: This means Fiddle and curses are enabled.
|
|
def self.enabled?
|
|
true
|
|
end
|
|
|
|
def self.term_supported?
|
|
@term_supported
|
|
end
|
|
end if Reline::Terminfo.curses_dl
|
|
|
|
module Reline::Terminfo
|
|
def self.enabled?
|
|
false
|
|
end
|
|
end unless Reline::Terminfo.curses_dl
|