mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
[ruby/reline] Add terminfo support
https://github.com/ruby/reline/commit/74a7ffaa2f
This commit is contained in:
parent
1b543dc226
commit
46c813969b
2 changed files with 132 additions and 14 deletions
|
@ -1,7 +1,12 @@
|
|||
require 'io/console'
|
||||
require 'timeout'
|
||||
require_relative 'terminfo'
|
||||
|
||||
class Reline::ANSI
|
||||
if Reline::Terminfo.enabled?
|
||||
Reline::Terminfo.setupterm(0, 2)
|
||||
end
|
||||
|
||||
def self.encoding
|
||||
Encoding.default_external
|
||||
end
|
||||
|
@ -11,6 +16,51 @@ class Reline::ANSI
|
|||
end
|
||||
|
||||
def self.set_default_key_bindings(config)
|
||||
if Reline::Terminfo.enabled?
|
||||
set_default_key_bindings_terminfo(config)
|
||||
else
|
||||
set_default_key_bindings_comprehensive_list(config)
|
||||
end
|
||||
{
|
||||
# extended entries of terminfo
|
||||
[27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→, extended entry
|
||||
[27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←, extended entry
|
||||
}.each_pair do |key, func|
|
||||
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
||||
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
||||
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
||||
end
|
||||
{
|
||||
# default bindings
|
||||
[27, 32] => :em_set_mark, # M-<space>
|
||||
[24, 24] => :em_exchange_mark, # C-x C-x TODO also add Windows
|
||||
}.each_pair do |key, func|
|
||||
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
||||
end
|
||||
end
|
||||
|
||||
def self.set_default_key_bindings_terminfo(config)
|
||||
{
|
||||
Reline::Terminfo.tigetstr('khome').to_s.bytes => :ed_move_to_beg,
|
||||
Reline::Terminfo.tigetstr('kend').to_s.bytes => :ed_move_to_end,
|
||||
Reline::Terminfo.tigetstr('kcuu1').to_s.bytes => :ed_prev_history,
|
||||
Reline::Terminfo.tigetstr('kcud1').to_s.bytes => :ed_next_history,
|
||||
Reline::Terminfo.tigetstr('kcuf1').to_s.bytes => :ed_next_char,
|
||||
Reline::Terminfo.tigetstr('kcub1').to_s.bytes => :ed_prev_char,
|
||||
# Escape sequences that omit the move distance and are set to defaults
|
||||
# value 1 may be sometimes sent by pressing the arrow-key.
|
||||
Reline::Terminfo.tigetstr('cuu').to_s.sub(/%p1%d/, '').bytes => :ed_prev_history,
|
||||
Reline::Terminfo.tigetstr('cud').to_s.sub(/%p1%d/, '').bytes => :ed_next_history,
|
||||
Reline::Terminfo.tigetstr('cuf').to_s.sub(/%p1%d/, '').bytes => :ed_next_char,
|
||||
Reline::Terminfo.tigetstr('cub').to_s.sub(/%p1%d/, '').bytes => :ed_prev_char,
|
||||
}.each_pair do |key, func|
|
||||
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
||||
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
||||
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
||||
end
|
||||
end
|
||||
|
||||
def self.set_default_key_bindings_comprehensive_list(config)
|
||||
{
|
||||
# Console (80x25)
|
||||
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
||||
|
@ -41,15 +91,11 @@ class Reline::ANSI
|
|||
# Arrow keys are the same of KDE
|
||||
|
||||
# iTerm2
|
||||
[27, 27, 91, 67] => :em_next_word, # Option+→
|
||||
[27, 27, 91, 68] => :ed_prev_word, # Option+←
|
||||
[27, 27, 91, 67] => :em_next_word, # Option+→, extended entry
|
||||
[27, 27, 91, 68] => :ed_prev_word, # Option+←, extended entry
|
||||
[195, 166] => :em_next_word, # Option+f
|
||||
[195, 162] => :ed_prev_word, # Option+b
|
||||
|
||||
# others
|
||||
[27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→
|
||||
[27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←
|
||||
|
||||
[27, 79, 65] => :ed_prev_history, # ↑
|
||||
[27, 79, 66] => :ed_next_history, # ↓
|
||||
[27, 79, 67] => :ed_next_char, # →
|
||||
|
@ -59,14 +105,6 @@ class Reline::ANSI
|
|||
config.add_default_key_binding_by_keymap(:vi_insert, key, func)
|
||||
config.add_default_key_binding_by_keymap(:vi_command, key, func)
|
||||
end
|
||||
|
||||
{
|
||||
# others
|
||||
[27, 32] => :em_set_mark, # M-<space>
|
||||
[24, 24] => :em_exchange_mark, # C-x C-x TODO also add Windows
|
||||
}.each_pair do |key, func|
|
||||
config.add_default_key_binding_by_keymap(:emacs, key, func)
|
||||
end
|
||||
end
|
||||
|
||||
@@input = STDIN
|
||||
|
|
80
lib/reline/terminfo.rb
Normal file
80
lib/reline/terminfo.rb
Normal file
|
@ -0,0 +1,80 @@
|
|||
require 'fiddle'
|
||||
require 'fiddle/import'
|
||||
|
||||
module Reline::Terminfo
|
||||
extend Fiddle::Importer
|
||||
|
||||
class TerminfoError < StandardError; end
|
||||
|
||||
@curses_dl = nil
|
||||
def self.curses_dl
|
||||
return @curses_dl if @curses_dl
|
||||
if Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
|
||||
# Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
|
||||
%w[libncursesw.so libcursesw.so libncurses.so libcurses.so].each do |curses_name|
|
||||
result = Fiddle::Handle.new(curses_name)
|
||||
rescue Fiddle::DLError
|
||||
next
|
||||
else
|
||||
@curses_dl = result
|
||||
break
|
||||
end
|
||||
end
|
||||
@curses_dl
|
||||
end
|
||||
end
|
||||
|
||||
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)
|
||||
#extern 'char *tiparm(const char *str, ...)'
|
||||
@tiparm = Fiddle::Function.new(curses_dl['tiparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
|
||||
|
||||
def self.setupterm(term, fildes)
|
||||
errret_int = String.new("\x00" * 8, encoding: 'ASCII-8BIT')
|
||||
ret = @setupterm.(term, fildes, errret_int)
|
||||
errret = errret_int.unpack('i')[0]
|
||||
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
|
||||
|
||||
def self.tigetstr(capname)
|
||||
@tigetstr.(capname)
|
||||
end
|
||||
|
||||
def self.tiparm(str, *args)
|
||||
new_args = []
|
||||
args.each do |a|
|
||||
new_args << Fiddle::TYPE_INT << a
|
||||
end
|
||||
@tiparm.(str, *new_args)
|
||||
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
|
Loading…
Add table
Reference in a new issue