reline 0.2.6 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.