reline 0.3.6 → 0.3.8

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: 3075f4003cf263e4652fc0dec716c71b55b597e6cbdc8cdb5297181b72780b57
4
- data.tar.gz: 78eb2e13f17bc0c7ae34b425effe29bf40a30b355af7d0efd271823c2cdde521
3
+ metadata.gz: 709b8943f16732f771d45da031e9676dc01c8b75f0410134a8b1fa8ab590d294
4
+ data.tar.gz: 04aa52c6ea6a8939402a1554b42bce891bd65a13be6b76cbfd3f4859df1455d4
5
5
  SHA512:
6
- metadata.gz: 9fd55d135c7b1aaffaff575f930bdb6365c202a1d15b5943d3dd9f678f416ba312b21c836ef8b78d11ee9942c4e0f0ac50d395633196bd649bd23a2fa6096456
7
- data.tar.gz: 43fe692b243560a81da41a48f4cb5cdf05514f85788bbc6b54bba72aef4d5e7258e73c2a84622c80e51adf36345cd9e7595455f8301e09c1f299f7b2ec147ff2
6
+ metadata.gz: ab8a124f732cfa4b8522f397a546fc89ea93f188ca9f44f7f560ea2afb00abbe3b95486c17a20b826d360a8bb064ca441bd357acffe1eb4ec371fbf6380cd37d
7
+ data.tar.gz: e756e58d4ae8929045998b8278fcee48ba1867741cc4d47bd72beb3e3a74902938d4c8a9dcd4c0452f20b25f5b4fe05eb96929bc39c28f326dc88c9bdf7be458
data/lib/reline/ansi.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'io/console'
2
2
  require 'io/wait'
3
- require 'timeout'
4
3
  require_relative 'terminfo'
5
4
 
6
5
  class Reline::ANSI
@@ -14,10 +13,21 @@ class Reline::ANSI
14
13
  'kcud1' => :ed_next_history,
15
14
  'kcuf1' => :ed_next_char,
16
15
  'kcub1' => :ed_prev_char,
17
- 'cuu' => :ed_prev_history,
18
- 'cud' => :ed_next_history,
19
- 'cuf' => :ed_next_char,
20
- 'cub' => :ed_prev_char,
16
+ }
17
+
18
+ ANSI_CURSOR_KEY_BINDINGS = {
19
+ # Up
20
+ 'A' => [:ed_prev_history, {}],
21
+ # Down
22
+ 'B' => [:ed_next_history, {}],
23
+ # Right
24
+ 'C' => [:ed_next_char, { ctrl: :em_next_word, meta: :em_next_word }],
25
+ # Left
26
+ 'D' => [:ed_prev_char, { ctrl: :ed_prev_word, meta: :ed_prev_word }],
27
+ # End
28
+ 'F' => [:ed_move_to_end, {}],
29
+ # Home
30
+ 'H' => [:ed_move_to_beg, {}],
21
31
  }
22
32
 
23
33
  if Reline::Terminfo.enabled?
@@ -33,22 +43,12 @@ class Reline::ANSI
33
43
  end
34
44
 
35
45
  def self.set_default_key_bindings(config, allow_terminfo: true)
46
+ set_default_key_bindings_ansi_cursor(config)
36
47
  if allow_terminfo && Reline::Terminfo.enabled?
37
48
  set_default_key_bindings_terminfo(config)
38
49
  else
39
50
  set_default_key_bindings_comprehensive_list(config)
40
51
  end
41
- {
42
- # extended entries of terminfo
43
- [27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→, extended entry
44
- [27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←, extended entry
45
- [27, 91, 49, 59, 51, 67] => :em_next_word, # Meta+→, extended entry
46
- [27, 91, 49, 59, 51, 68] => :ed_prev_word, # Meta+←, extended entry
47
- }.each_pair do |key, func|
48
- config.add_default_key_binding_by_keymap(:emacs, key, func)
49
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
50
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
51
- end
52
52
  {
53
53
  [27, 91, 90] => :completion_journey_up, # S-Tab
54
54
  }.each_pair do |key, func|
@@ -64,18 +64,33 @@ class Reline::ANSI
64
64
  end
65
65
  end
66
66
 
67
+ def self.set_default_key_bindings_ansi_cursor(config)
68
+ ANSI_CURSOR_KEY_BINDINGS.each do |char, (default_func, modifiers)|
69
+ bindings = [["\e[#{char}", default_func]] # CSI + char
70
+ if modifiers[:ctrl]
71
+ # CSI + ctrl_key_modifier + char
72
+ bindings << ["\e[1;5#{char}", modifiers[:ctrl]]
73
+ end
74
+ if modifiers[:meta]
75
+ # CSI + meta_key_modifier + char
76
+ bindings << ["\e[1;3#{char}", modifiers[:meta]]
77
+ # Meta(ESC) + CSI + char
78
+ bindings << ["\e\e[#{char}", modifiers[:meta]]
79
+ end
80
+ bindings.each do |sequence, func|
81
+ key = sequence.bytes
82
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
83
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
84
+ config.add_default_key_binding_by_keymap(:vi_command, key, func)
85
+ end
86
+ end
87
+ end
88
+
67
89
  def self.set_default_key_bindings_terminfo(config)
68
90
  key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
69
91
  begin
70
92
  key_code = Reline::Terminfo.tigetstr(capname)
71
- case capname
72
- # Escape sequences that omit the move distance and are set to defaults
73
- # value 1 may be sometimes sent by pressing the arrow-key.
74
- when 'cuu', 'cud', 'cuf', 'cub'
75
- [ key_code.sub(/%p1%d/, '').bytes, key_binding ]
76
- else
77
- [ key_code.bytes, key_binding ]
78
- end
93
+ [ key_code.bytes, key_binding ]
79
94
  rescue Reline::Terminfo::TerminfoError
80
95
  # capname is undefined
81
96
  end
@@ -94,14 +109,8 @@ class Reline::ANSI
94
109
  [27, 91, 49, 126] => :ed_move_to_beg, # Home
95
110
  [27, 91, 52, 126] => :ed_move_to_end, # End
96
111
  [27, 91, 51, 126] => :key_delete, # Del
97
- [27, 91, 65] => :ed_prev_history, # ↑
98
- [27, 91, 66] => :ed_next_history, # ↓
99
- [27, 91, 67] => :ed_next_char, # →
100
- [27, 91, 68] => :ed_prev_char, # ←
101
112
 
102
113
  # KDE
103
- [27, 91, 72] => :ed_move_to_beg, # Home
104
- [27, 91, 70] => :ed_move_to_end, # End
105
114
  # Del is 0x08
106
115
  [27, 71, 65] => :ed_prev_history, # ↑
107
116
  [27, 71, 66] => :ed_next_history, # ↓
@@ -118,12 +127,6 @@ class Reline::ANSI
118
127
  # Del is 0x08
119
128
  # Arrow keys are the same of KDE
120
129
 
121
- # iTerm2
122
- [27, 27, 91, 67] => :em_next_word, # Option+→, extended entry
123
- [27, 27, 91, 68] => :ed_prev_word, # Option+←, extended entry
124
- [195, 166] => :em_next_word, # Option+f
125
- [195, 162] => :ed_prev_word, # Option+b
126
-
127
130
  [27, 79, 65] => :ed_prev_history, # ↑
128
131
  [27, 79, 66] => :ed_next_history, # ↓
129
132
  [27, 79, 67] => :ed_next_char, # →
@@ -150,11 +153,13 @@ class Reline::ANSI
150
153
  end
151
154
 
152
155
  @@buf = []
153
- def self.inner_getc
156
+ def self.inner_getc(timeout_second)
154
157
  unless @@buf.empty?
155
158
  return @@buf.shift
156
159
  end
157
160
  until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
161
+ timeout_second -= 0.1
162
+ return nil if timeout_second <= 0
158
163
  Reline.core.line_editor.resize
159
164
  end
160
165
  (c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
@@ -168,40 +173,38 @@ class Reline::ANSI
168
173
  @@in_bracketed_paste_mode = false
169
174
  START_BRACKETED_PASTE = String.new("\e[200~,", encoding: Encoding::ASCII_8BIT)
170
175
  END_BRACKETED_PASTE = String.new("\e[200~.", encoding: Encoding::ASCII_8BIT)
171
- def self.getc_with_bracketed_paste
176
+ def self.getc_with_bracketed_paste(timeout_second)
172
177
  buffer = String.new(encoding: Encoding::ASCII_8BIT)
173
- buffer << inner_getc
178
+ buffer << inner_getc(timeout_second)
174
179
  while START_BRACKETED_PASTE.start_with?(buffer) or END_BRACKETED_PASTE.start_with?(buffer) do
175
180
  if START_BRACKETED_PASTE == buffer
176
181
  @@in_bracketed_paste_mode = true
177
- return inner_getc
182
+ return inner_getc(timeout_second)
178
183
  elsif END_BRACKETED_PASTE == buffer
179
184
  @@in_bracketed_paste_mode = false
180
185
  ungetc(-1)
181
- return inner_getc
186
+ return inner_getc(timeout_second)
182
187
  end
183
- begin
184
- succ_c = nil
185
- Timeout.timeout(Reline.core.config.keyseq_timeout * 100) {
186
- succ_c = inner_getc
187
- }
188
- rescue Timeout::Error
189
- break
190
- else
188
+ succ_c = inner_getc(Reline.core.config.keyseq_timeout)
189
+
190
+ if succ_c
191
191
  buffer << succ_c
192
+ else
193
+ break
192
194
  end
193
195
  end
194
196
  buffer.bytes.reverse_each do |ch|
195
197
  ungetc ch
196
198
  end
197
- inner_getc
199
+ inner_getc(timeout_second)
198
200
  end
199
201
 
200
- def self.getc
202
+ # if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
203
+ def self.getc(timeout_second)
201
204
  if Reline.core.config.enable_bracketed_paste
202
- getc_with_bracketed_paste
205
+ getc_with_bracketed_paste(timeout_second)
203
206
  else
204
- inner_getc
207
+ inner_getc(timeout_second)
205
208
  end
206
209
  end
207
210
 
@@ -331,9 +334,12 @@ class Reline::ANSI
331
334
  @@output.write "\e[K"
332
335
  end
333
336
 
337
+ # This only works when the cursor is at the bottom of the scroll range
338
+ # For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623
334
339
  def self.scroll_down(x)
335
340
  return if x.zero?
336
- @@output.write "\e[#{x}S"
341
+ # We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576
342
+ @@output.write "\n" * x
337
343
  end
338
344
 
339
345
  def self.clear_screen
@@ -1,4 +1,3 @@
1
- require 'timeout'
2
1
  require 'io/wait'
3
2
 
4
3
  class Reline::GeneralIO
@@ -35,7 +34,7 @@ class Reline::GeneralIO
35
34
  yield
36
35
  end
37
36
 
38
- def self.getc
37
+ def self.getc(_timeout_second)
39
38
  unless @@buf.empty?
40
39
  return @@buf.shift
41
40
  end
@@ -1605,7 +1605,7 @@ class Reline::LineEditor
1605
1605
  else
1606
1606
  @just_cursor_moving = false
1607
1607
  end
1608
- if @is_multiline and @auto_indent_proc and not simplified_rendering?
1608
+ if @is_multiline and @auto_indent_proc and not simplified_rendering? and @line
1609
1609
  process_auto_indent
1610
1610
  end
1611
1611
  end
@@ -2696,6 +2696,7 @@ class Reline::LineEditor
2696
2696
  @cursor_max -= width
2697
2697
  end
2698
2698
  end
2699
+ alias_method :kill_word, :em_delete_next_word
2699
2700
 
2700
2701
  private def ed_delete_prev_word(key)
2701
2702
  if @byte_pointer > 0
@@ -2707,6 +2708,7 @@ class Reline::LineEditor
2707
2708
  @cursor_max -= width
2708
2709
  end
2709
2710
  end
2711
+ alias_method :backward_kill_word, :ed_delete_prev_word
2710
2712
 
2711
2713
  private def ed_transpose_chars(key)
2712
2714
  if @byte_pointer > 0
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.3.6'
2
+ VERSION = '0.3.8'
3
3
  end
@@ -295,7 +295,7 @@ class Reline::Windows
295
295
  yield
296
296
  end
297
297
 
298
- def self.getc
298
+ def self.getc(_timeout_second)
299
299
  check_input_event
300
300
  @@output_buf.shift
301
301
  end
data/lib/reline.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'io/console'
2
- require 'timeout'
3
2
  require 'forwardable'
4
3
  require 'reline/version'
5
4
  require 'reline/config'
@@ -397,7 +396,7 @@ module Reline
397
396
  private def read_io(keyseq_timeout, &block)
398
397
  buffer = []
399
398
  loop do
400
- c = io_gate.getc
399
+ c = io_gate.getc(Float::INFINITY)
401
400
  if c == -1
402
401
  result = :unmatched
403
402
  @bracketed_paste_finished = true
@@ -434,15 +433,8 @@ module Reline
434
433
  end
435
434
 
436
435
  private def read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
437
- begin
438
- succ_c = nil
439
- Timeout.timeout(keyseq_timeout / 1000.0) {
440
- succ_c = io_gate.getc
441
- }
442
- rescue Timeout::Error # cancel matching only when first byte
443
- block.([Reline::Key.new(c, c, false)])
444
- return :break
445
- else
436
+ succ_c = io_gate.getc(keyseq_timeout.fdiv(1000))
437
+ if succ_c
446
438
  case key_stroke.match_status(buffer.dup.push(succ_c))
447
439
  when :unmatched
448
440
  if c == "\e".ord
@@ -462,27 +454,23 @@ module Reline
462
454
  block.(expanded)
463
455
  return :break
464
456
  end
457
+ else
458
+ block.([Reline::Key.new(c, c, false)])
459
+ return :break
465
460
  end
466
461
  end
467
462
 
468
463
  private def read_escaped_key(keyseq_timeout, c, block)
469
- begin
470
- escaped_c = nil
471
- Timeout.timeout(keyseq_timeout / 1000.0) {
472
- escaped_c = io_gate.getc
473
- }
474
- rescue Timeout::Error # independent ESC
464
+ escaped_c = io_gate.getc(keyseq_timeout.fdiv(1000))
465
+
466
+ if escaped_c.nil?
475
467
  block.([Reline::Key.new(c, c, false)])
468
+ elsif escaped_c >= 128 # maybe, first byte of multi byte
469
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
470
+ elsif escaped_c == "\e".ord # escape twice
471
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
476
472
  else
477
- if escaped_c.nil?
478
- block.([Reline::Key.new(c, c, false)])
479
- elsif escaped_c >= 128 # maybe, first byte of multi byte
480
- block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
481
- elsif escaped_c == "\e".ord # escape twice
482
- block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
483
- else
484
- block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
485
- end
473
+ block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
486
474
  end
487
475
  end
488
476
 
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.3.6
4
+ version: 0.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-08 00:00:00.000000000 Z
11
+ date: 2023-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -72,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
72
  - !ruby/object:Gem::Version
73
73
  version: '0'
74
74
  requirements: []
75
- rubygems_version: 3.4.13
75
+ rubygems_version: 3.4.10
76
76
  signing_key:
77
77
  specification_version: 4
78
78
  summary: Alternative GNU Readline or Editline implementation by pure Ruby.