2021-10-11 08:24:19 -04:00
|
|
|
begin
|
|
|
|
require 'fiddle'
|
|
|
|
require 'fiddle/import'
|
|
|
|
rescue LoadError
|
|
|
|
module Reline::Terminfo
|
|
|
|
def self.curses_dl
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2021-05-18 08:46:16 -04:00
|
|
|
|
|
|
|
module Reline::Terminfo
|
|
|
|
extend Fiddle::Importer
|
|
|
|
|
|
|
|
class TerminfoError < StandardError; end
|
|
|
|
|
2021-07-05 02:54:12 -04:00
|
|
|
def self.curses_dl_files
|
|
|
|
case RUBY_PLATFORM
|
|
|
|
when /mingw/, /mswin/
|
|
|
|
# aren't supported
|
|
|
|
[]
|
2021-07-06 10:03:09 -04:00
|
|
|
when /cygwin/
|
|
|
|
%w[cygncursesw-10.dll cygncurses-10.dll]
|
|
|
|
when /darwin/
|
|
|
|
%w[libncursesw.dylib libcursesw.dylib libncurses.dylib libcurses.dylib]
|
2021-07-05 02:54:12 -04:00
|
|
|
else
|
|
|
|
%w[libncursesw.so libcursesw.so libncurses.so libcurses.so]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-08-06 00:33:47 -04:00
|
|
|
@curses_dl = false
|
2021-05-18 08:46:16 -04:00
|
|
|
def self.curses_dl
|
2021-08-06 00:33:47 -04:00
|
|
|
return @curses_dl unless @curses_dl == false
|
2021-06-21 05:44:10 -04:00
|
|
|
if RUBY_VERSION >= '3.0.0'
|
|
|
|
# Gem module isn't defined in test-all of the Ruby repository, and
|
|
|
|
# Fiddle in Ruby 3.0.0 or later supports Fiddle::TYPE_VARIADIC.
|
|
|
|
fiddle_supports_variadic = true
|
|
|
|
elsif Fiddle.const_defined?(:VERSION) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
|
2021-05-18 08:46:16 -04:00
|
|
|
# Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
|
2021-06-21 05:44:10 -04:00
|
|
|
fiddle_supports_variadic = true
|
|
|
|
else
|
|
|
|
fiddle_supports_variadic = false
|
|
|
|
end
|
2021-08-05 13:51:10 -04:00
|
|
|
if fiddle_supports_variadic and not Fiddle.const_defined?(:TYPE_VARIADIC)
|
2021-07-28 10:26:41 -04:00
|
|
|
# If the libffi version is not 3.0.5 or higher, there isn't TYPE_VARIADIC.
|
|
|
|
fiddle_supports_variadic = false
|
|
|
|
end
|
2021-06-21 05:44:10 -04:00
|
|
|
if fiddle_supports_variadic
|
2021-07-05 02:54:12 -04:00
|
|
|
curses_dl_files.each do |curses_name|
|
2021-05-18 08:46:16 -04:00
|
|
|
result = Fiddle::Handle.new(curses_name)
|
|
|
|
rescue Fiddle::DLError
|
|
|
|
next
|
|
|
|
else
|
|
|
|
@curses_dl = result
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
2021-08-06 00:33:47 -04:00
|
|
|
@curses_dl = nil if @curses_dl == false
|
2021-05-18 08:46:16 -04:00
|
|
|
@curses_dl
|
|
|
|
end
|
2021-10-11 08:24:19 -04:00
|
|
|
end if not Reline.const_defined?(:Terminfo) or not Reline::Terminfo.respond_to?(:curses_dl)
|
2021-05-18 08:46:16 -04:00
|
|
|
|
|
|
|
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)
|
2021-07-24 01:46:54 -04:00
|
|
|
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
|
2021-07-23 16:43:28 -04:00
|
|
|
# OpenBSD lacks tiparm
|
2021-07-24 01:46:54 -04:00
|
|
|
#extern 'char *tparm(const char *str, ...)'
|
|
|
|
@tiparm = Fiddle::Function.new(curses_dl['tparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
|
2021-07-23 16:43:28 -04:00
|
|
|
end
|
2021-06-25 07:01:02 -04:00
|
|
|
# TODO: add int tigetflag(char *capname) and int tigetnum(char *capname)
|
2021-05-18 08:46:16 -04:00
|
|
|
|
|
|
|
def self.setupterm(term, fildes)
|
|
|
|
errret_int = String.new("\x00" * 8, encoding: 'ASCII-8BIT')
|
|
|
|
ret = @setupterm.(term, fildes, errret_int)
|
2021-09-22 05:14:13 -04:00
|
|
|
errret = errret_int.unpack1('i')
|
2021-05-18 08:46:16 -04:00
|
|
|
case ret
|
|
|
|
when 0 # OK
|
|
|
|
0
|
|
|
|
when -1 # ERR
|
|
|
|
case errret
|
|
|
|
when 1
|
|
|
|
raise TerminfoError.new('The terminal is hardcopy, cannot be used for curses applications.')
|
|
|
|
when 0
|
|
|
|
raise TerminfoError.new('The terminal could not be found, or that it is a generic type, having too little information for curses applications to run.')
|
|
|
|
when -1
|
|
|
|
raise TerminfoError.new('The terminfo database could not be found.')
|
|
|
|
else # unknown
|
|
|
|
-1
|
|
|
|
end
|
|
|
|
else # unknown
|
|
|
|
-2
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-06-24 05:04:02 -04:00
|
|
|
class StringWithTiparm < String
|
|
|
|
def tiparm(*args) # for method chain
|
2021-05-19 04:57:30 -04:00
|
|
|
Reline::Terminfo.tiparm(self, *args)
|
|
|
|
end
|
2021-06-24 05:04:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.tigetstr(capname)
|
2021-08-06 00:34:25 -04:00
|
|
|
capability = @tigetstr.(capname)
|
|
|
|
case capability.to_i
|
|
|
|
when 0, -1
|
|
|
|
raise TerminfoError, "can't find capability: #{capname}"
|
|
|
|
end
|
|
|
|
StringWithTiparm.new(capability.to_s)
|
2021-05-18 08:46:16 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.tiparm(str, *args)
|
|
|
|
new_args = []
|
|
|
|
args.each do |a|
|
|
|
|
new_args << Fiddle::TYPE_INT << a
|
|
|
|
end
|
2021-05-19 04:53:17 -04:00
|
|
|
@tiparm.(str, *new_args).to_s
|
2021-05-18 08:46:16 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.enabled?
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end if Reline::Terminfo.curses_dl
|
|
|
|
|
|
|
|
module Reline::Terminfo
|
|
|
|
def self.enabled?
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end unless Reline::Terminfo.curses_dl
|