reline 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc0f6fb7c331a37907554b292249a75b218646aa14298586790cc09d6c174894
4
- data.tar.gz: 79fd7b502a7ab601f6642964bb0987dae5d0a62bc8cfda016d8806c8b76bb723
3
+ metadata.gz: 1bb2255429504a1beb1a5a9f863f7cba5c4c65781b7cd8b2aa843b0df639fb26
4
+ data.tar.gz: c9372db87ad831e06d0e99d20981cb14a08e8b15ca3011f4b6df2a05aaeef7b3
5
5
  SHA512:
6
- metadata.gz: 2b4300db4d7bef4ab3ddc8f45db07e20e37b371d89e7a21f343dd3c7096209d0c19028def435d584c7bc1f0a9f18d0d6c783b47d28967eb3d34e4d0eaa613490
7
- data.tar.gz: '081a683b1980b9c8d27822e62dcdc776024cc408e3f93b0c999f8da2c6b2fef92c4eded142f7bee8f95fcd7a18fc8431a87f2cd19d1c1064fa677f7de606dcf0'
6
+ metadata.gz: 63e8b6f4a9de8a69a8f22c979b6fee92026143be658b9e928da43dddb868fb6b641b5f140de436c1dd5ed1f3cdbc3c42c7c41084fcc1d811cd713c684aedda8e
7
+ data.tar.gz: 7a459412f528f43d5e65f4c7c6a5c74055e2c5334f21a65411bc4f187b55b649c15fd612ed27f2dc0032f7fdc5973c7fa57b674b0a323ac2d9537b23fff19664
data/lib/reline.rb CHANGED
@@ -7,12 +7,15 @@ require 'reline/key_actor'
7
7
  require 'reline/key_stroke'
8
8
  require 'reline/line_editor'
9
9
  require 'reline/history'
10
+ require 'reline/terminfo'
10
11
  require 'rbconfig'
11
12
 
12
13
  module Reline
13
14
  FILENAME_COMPLETION_PROC = nil
14
15
  USERNAME_COMPLETION_PROC = nil
15
16
 
17
+ class ConfigEncodingConversionError < StandardError; end
18
+
16
19
  Key = Struct.new('Key', :char, :combined_char, :with_meta)
17
20
  CursorPos = Struct.new(:x, :y)
18
21
 
data/lib/reline/ansi.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'io/console'
2
+ require 'io/wait'
2
3
  require 'timeout'
3
4
  require_relative 'terminfo'
4
5
 
@@ -183,12 +184,7 @@ class Reline::ANSI
183
184
  unless @@buf.empty?
184
185
  return false
185
186
  end
186
- rs, = IO.select([@@input], [], [], 0.00001)
187
- if rs and rs[0]
188
- false
189
- else
190
- true
191
- end
187
+ !@@input.wait_readable(0)
192
188
  end
193
189
 
194
190
  def self.ungetc(c)
@@ -197,8 +193,7 @@ class Reline::ANSI
197
193
 
198
194
  def self.retrieve_keybuffer
199
195
  begin
200
- result = select([@@input], [], [], 0.001)
201
- return if result.nil?
196
+ return unless @@input.wait_readable(0.001)
202
197
  str = @@input.read_nonblock(1024)
203
198
  str.bytes.each do |c|
204
199
  @@buf.push(c)
data/lib/reline/config.rb CHANGED
@@ -74,6 +74,7 @@ class Reline::Config
74
74
  @additional_key_bindings.keys.each do |key|
75
75
  @additional_key_bindings[key].clear
76
76
  end
77
+ reset_default_key_bindings
77
78
  end
78
79
 
79
80
  def editing_mode
@@ -157,8 +158,15 @@ class Reline::Config
157
158
  end
158
159
 
159
160
  def read_lines(lines, file = nil)
160
- if lines.first.encoding != Reline.encoding_system_needs
161
- lines = lines.map { |l| l.encode(Reline.encoding_system_needs) }
161
+ if not lines.empty? and lines.first.encoding != Reline.encoding_system_needs
162
+ begin
163
+ lines = lines.map do |l|
164
+ l.encode(Reline.encoding_system_needs)
165
+ rescue Encoding::UndefinedConversionError
166
+ mes = "The inputrc encoded in #{lines.first.encoding.name} can't be converted to the locale #{Reline.encoding_system_needs.name}."
167
+ raise Reline::ConfigEncodingConversionError.new(mes)
168
+ end
169
+ end
162
170
  end
163
171
  conditions = [@skip_section, @if_stack]
164
172
  @skip_section = nil
@@ -150,7 +150,7 @@ class Reline::LineEditor
150
150
  @screen_size = Reline::IOGate.get_screen_size
151
151
  @screen_height = @screen_size.first
152
152
  reset_variables(prompt, encoding: encoding)
153
- @old_trap = Signal.trap('SIGINT') {
153
+ @old_trap = Signal.trap(:INT) {
154
154
  if @scroll_partial_screen
155
155
  move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1)
156
156
  else
@@ -158,8 +158,16 @@ class Reline::LineEditor
158
158
  end
159
159
  Reline::IOGate.move_cursor_column(0)
160
160
  scroll_down(1)
161
- @old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
162
- raise Interrupt
161
+ case @old_trap
162
+ when 'DEFAULT', 'SYSTEM_DEFAULT'
163
+ raise Interrupt
164
+ when 'IGNORE'
165
+ # Do nothing
166
+ when 'EXIT'
167
+ exit
168
+ else
169
+ @old_trap.call
170
+ end
163
171
  }
164
172
  Reline::IOGate.set_winch_handler do
165
173
  @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
@@ -6,12 +6,39 @@ module Reline::Terminfo
6
6
 
7
7
  class TerminfoError < StandardError; end
8
8
 
9
- @curses_dl = nil
9
+ def self.curses_dl_files
10
+ case RUBY_PLATFORM
11
+ when /mingw/, /mswin/
12
+ # aren't supported
13
+ []
14
+ when /cygwin/
15
+ %w[cygncursesw-10.dll cygncurses-10.dll]
16
+ when /darwin/
17
+ %w[libncursesw.dylib libcursesw.dylib libncurses.dylib libcurses.dylib]
18
+ else
19
+ %w[libncursesw.so libcursesw.so libncurses.so libcurses.so]
20
+ end
21
+ end
22
+
23
+ @curses_dl = false
10
24
  def self.curses_dl
11
- return @curses_dl if @curses_dl
12
- if Fiddle.const_defined?(:VERSION) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
25
+ return @curses_dl unless @curses_dl == false
26
+ if RUBY_VERSION >= '3.0.0'
27
+ # Gem module isn't defined in test-all of the Ruby repository, and
28
+ # Fiddle in Ruby 3.0.0 or later supports Fiddle::TYPE_VARIADIC.
29
+ fiddle_supports_variadic = true
30
+ elsif Fiddle.const_defined?(:VERSION) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
13
31
  # Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
14
- %w[libncursesw.so libcursesw.so libncurses.so libcurses.so].each do |curses_name|
32
+ fiddle_supports_variadic = true
33
+ else
34
+ fiddle_supports_variadic = false
35
+ end
36
+ if fiddle_supports_variadic and not Fiddle.const_defined?(:TYPE_VARIADIC)
37
+ # If the libffi version is not 3.0.5 or higher, there isn't TYPE_VARIADIC.
38
+ fiddle_supports_variadic = false
39
+ end
40
+ if fiddle_supports_variadic
41
+ curses_dl_files.each do |curses_name|
15
42
  result = Fiddle::Handle.new(curses_name)
16
43
  rescue Fiddle::DLError
17
44
  next
@@ -20,6 +47,7 @@ module Reline::Terminfo
20
47
  break
21
48
  end
22
49
  end
50
+ @curses_dl = nil if @curses_dl == false
23
51
  @curses_dl
24
52
  end
25
53
  end
@@ -30,8 +58,15 @@ module Reline::Terminfo
30
58
  @setupterm = Fiddle::Function.new(curses_dl['setupterm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
31
59
  #extern 'char *tigetstr(char *capname)'
32
60
  @tigetstr = Fiddle::Function.new(curses_dl['tigetstr'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
33
- #extern 'char *tiparm(const char *str, ...)'
34
- @tiparm = Fiddle::Function.new(curses_dl['tiparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
61
+ begin
62
+ #extern 'char *tiparm(const char *str, ...)'
63
+ @tiparm = Fiddle::Function.new(curses_dl['tiparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
64
+ rescue Fiddle::DLError
65
+ # OpenBSD lacks tiparm
66
+ #extern 'char *tparm(const char *str, ...)'
67
+ @tiparm = Fiddle::Function.new(curses_dl['tparm'], [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_VOIDP)
68
+ end
69
+ # TODO: add int tigetflag(char *capname) and int tigetnum(char *capname)
35
70
 
36
71
  def self.setupterm(term, fildes)
37
72
  errret_int = String.new("\x00" * 8, encoding: 'ASCII-8BIT')
@@ -56,12 +91,19 @@ module Reline::Terminfo
56
91
  end
57
92
  end
58
93
 
59
- def self.tigetstr(capname)
60
- result = @tigetstr.(capname).to_s
61
- def result.tiparm(*args) # for method chain
94
+ class StringWithTiparm < String
95
+ def tiparm(*args) # for method chain
62
96
  Reline::Terminfo.tiparm(self, *args)
63
97
  end
64
- result
98
+ end
99
+
100
+ def self.tigetstr(capname)
101
+ capability = @tigetstr.(capname)
102
+ case capability.to_i
103
+ when 0, -1
104
+ raise TerminfoError, "can't find capability: #{capname}"
105
+ end
106
+ StringWithTiparm.new(capability.to_s)
65
107
  end
66
108
 
67
109
  def self.tiparm(str, *args)
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.2.6'
2
+ VERSION = '0.2.7'
3
3
  end
@@ -91,6 +91,7 @@ class Reline::Windows
91
91
  VK_LMENU = 0xA4
92
92
  VK_CONTROL = 0x11
93
93
  VK_SHIFT = 0x10
94
+ VK_DIVIDE = 0x6F
94
95
 
95
96
  KEY_EVENT = 0x01
96
97
  WINDOW_BUFFER_SIZE_EVENT = 0x04
@@ -180,46 +181,38 @@ class Reline::Windows
180
181
  name =~ /(msys-|cygwin-).*-pty/ ? true : false
181
182
  end
182
183
 
184
+ KEY_MAP = [
185
+ # It's treated as Meta+Enter on Windows.
186
+ [ { control_keys: :CTRL, virtual_key_code: 0x0D }, "\e\r".bytes ],
187
+ [ { control_keys: :SHIFT, virtual_key_code: 0x0D }, "\e\r".bytes ],
188
+
189
+ # It's treated as Meta+Space on Windows.
190
+ [ { control_keys: :CTRL, char_code: 0x20 }, "\e ".bytes ],
191
+
192
+ # Emulate getwch() key sequences.
193
+ [ { control_keys: [], virtual_key_code: VK_UP }, [0, 72] ],
194
+ [ { control_keys: [], virtual_key_code: VK_DOWN }, [0, 80] ],
195
+ [ { control_keys: [], virtual_key_code: VK_RIGHT }, [0, 77] ],
196
+ [ { control_keys: [], virtual_key_code: VK_LEFT }, [0, 75] ],
197
+ [ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
198
+ [ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
199
+ [ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
200
+ ]
201
+
183
202
  def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
184
- char = char_code.chr(Encoding::UTF_8)
185
- if char_code == 0x0D and control_key_state.anybits?(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED | SHIFT_PRESSED)
186
- # It's treated as Meta+Enter on Windows.
187
- @@output_buf.push("\e".ord)
188
- @@output_buf.push(char_code)
189
- elsif char_code == 0x20 and control_key_state.anybits?(LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
190
- # It's treated as Meta+Space on Windows.
191
- @@output_buf.push("\e".ord)
192
- @@output_buf.push(char_code)
193
- elsif control_key_state.anybits?(LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)
194
- @@output_buf.push("\e".ord)
195
- @@output_buf.concat(char.bytes)
196
- elsif control_key_state.anybits?(ENHANCED_KEY)
197
- case virtual_key_code # Emulate getwch() key sequences.
198
- when VK_END
199
- @@output_buf.push(0, 79)
200
- when VK_HOME
201
- @@output_buf.push(0, 71)
202
- when VK_LEFT
203
- @@output_buf.push(0, 75)
204
- when VK_UP
205
- @@output_buf.push(0, 72)
206
- when VK_RIGHT
207
- @@output_buf.push(0, 77)
208
- when VK_DOWN
209
- @@output_buf.push(0, 80)
210
- when VK_DELETE
211
- @@output_buf.push(0, 83)
212
- end
213
- elsif char_code == 0 and control_key_state != 0
214
- # unknown
215
- else
216
- case virtual_key_code
217
- when VK_RETURN
218
- @@output_buf.push("\n".ord)
219
- else
220
- @@output_buf.concat(char.bytes)
221
- end
203
+
204
+ key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
205
+
206
+ match = KEY_MAP.find { |args,| key.matches?(**args) }
207
+ unless match.nil?
208
+ @@output_buf.concat(match.last)
209
+ return
222
210
  end
211
+
212
+ # no char, only control keys
213
+ return if key.char_code == 0 and key.control_keys.any?
214
+
215
+ @@output_buf.concat(key.char.bytes)
223
216
  end
224
217
 
225
218
  def self.check_input_event
@@ -360,4 +353,43 @@ class Reline::Windows
360
353
  def self.deprep(otio)
361
354
  # do nothing
362
355
  end
356
+
357
+ class KeyEventRecord
358
+
359
+ attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys
360
+
361
+ def initialize(virtual_key_code, char_code, control_key_state)
362
+ @virtual_key_code = virtual_key_code
363
+ @char_code = char_code
364
+ @control_key_state = control_key_state
365
+ @enhanced = control_key_state & ENHANCED_KEY != 0
366
+
367
+ (@control_keys = []).tap do |control_keys|
368
+ # symbols must be sorted to make comparison is easier later on
369
+ control_keys << :ALT if control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0
370
+ control_keys << :CTRL if control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0
371
+ control_keys << :SHIFT if control_key_state & SHIFT_PRESSED != 0
372
+ end.freeze
373
+ end
374
+
375
+ def char
376
+ @char_code.chr(Encoding::UTF_8)
377
+ end
378
+
379
+ def enhanced?
380
+ @enhanced
381
+ end
382
+
383
+ # Verifies if the arguments match with this key event.
384
+ # Nil arguments are ignored, but at least one must be passed as non-nil.
385
+ # To verify that no control keys were pressed, pass an empty array: `control_keys: []`.
386
+ def matches?(control_keys: nil, virtual_key_code: nil, char_code: nil)
387
+ raise ArgumentError, 'No argument was passed to match key event' if control_keys.nil? && virtual_key_code.nil? && char_code.nil?
388
+
389
+ (control_keys.nil? || [*control_keys].sort == @control_keys) &&
390
+ (virtual_key_code.nil? || @virtual_key_code == virtual_key_code) &&
391
+ (char_code.nil? || char_code == @char_code)
392
+ end
393
+
394
+ end
363
395
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-21 00:00:00.000000000 Z
11
+ date: 2021-08-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -73,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  requirements: []
76
- rubygems_version: 3.2.17
76
+ rubygems_version: 3.2.22
77
77
  signing_key:
78
78
  specification_version: 4
79
79
  summary: Alternative GNU Readline or Editline implementation by pure Ruby.