reline 0.5.8 → 0.5.10
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 +4 -4
- data/lib/reline/config.rb +40 -43
- data/lib/reline/face.rb +1 -1
- data/lib/reline/{ansi.rb → io/ansi.rb} +95 -85
- data/lib/reline/io/dumb.rb +106 -0
- data/lib/reline/{windows.rb → io/windows.rb} +112 -102
- data/lib/reline/io.rb +41 -0
- data/lib/reline/key_actor/base.rb +22 -6
- data/lib/reline/key_actor/composite.rb +17 -0
- data/lib/reline/key_actor/emacs.rb +2 -2
- data/lib/reline/key_actor/vi_command.rb +2 -2
- data/lib/reline/key_actor/vi_insert.rb +2 -2
- data/lib/reline/key_actor.rb +1 -0
- data/lib/reline/key_stroke.rb +65 -104
- data/lib/reline/line_editor.rb +70 -76
- data/lib/reline/terminfo.rb +6 -1
- data/lib/reline/unicode/east_asian_width.rb +1262 -1191
- data/lib/reline/unicode.rb +14 -39
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +42 -127
- metadata +8 -9
- data/lib/reline/general_io.rb +0 -111
data/lib/reline/unicode.rb
CHANGED
@@ -56,51 +56,26 @@ class Reline::Unicode
|
|
56
56
|
|
57
57
|
require 'reline/unicode/east_asian_width'
|
58
58
|
|
59
|
-
HalfwidthDakutenHandakuten = /[\u{FF9E}\u{FF9F}]/
|
60
|
-
|
61
|
-
MBCharWidthRE = /
|
62
|
-
(?<width_2_1>
|
63
|
-
[#{ EscapedChars.map {|c| "\\x%02x" % c.ord }.join }] (?# ^ + char, such as ^M, ^H, ^[, ...)
|
64
|
-
)
|
65
|
-
| (?<width_3>^\u{2E3B}) (?# THREE-EM DASH)
|
66
|
-
| (?<width_0>^\p{M})
|
67
|
-
| (?<width_2_2>
|
68
|
-
#{ EastAsianWidth::TYPE_F }
|
69
|
-
| #{ EastAsianWidth::TYPE_W }
|
70
|
-
)
|
71
|
-
| (?<width_1>
|
72
|
-
#{ EastAsianWidth::TYPE_H }
|
73
|
-
| #{ EastAsianWidth::TYPE_NA }
|
74
|
-
| #{ EastAsianWidth::TYPE_N }
|
75
|
-
)(?!#{ HalfwidthDakutenHandakuten })
|
76
|
-
| (?<width_2_3>
|
77
|
-
(?: #{ EastAsianWidth::TYPE_H }
|
78
|
-
| #{ EastAsianWidth::TYPE_NA }
|
79
|
-
| #{ EastAsianWidth::TYPE_N })
|
80
|
-
#{ HalfwidthDakutenHandakuten }
|
81
|
-
)
|
82
|
-
| (?<ambiguous_width>
|
83
|
-
#{EastAsianWidth::TYPE_A}
|
84
|
-
)
|
85
|
-
/x
|
86
|
-
|
87
59
|
def self.get_mbchar_width(mbchar)
|
88
60
|
ord = mbchar.ord
|
89
|
-
if
|
61
|
+
if ord <= 0x1F # in EscapedPairs
|
90
62
|
return 2
|
91
|
-
elsif
|
63
|
+
elsif ord <= 0x7E # printable ASCII chars
|
92
64
|
return 1
|
93
65
|
end
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
66
|
+
utf8_mbchar = mbchar.encode(Encoding::UTF_8)
|
67
|
+
ord = utf8_mbchar.ord
|
68
|
+
chunk_index = EastAsianWidth::CHUNK_LAST.bsearch_index { |o| ord <= o }
|
69
|
+
size = EastAsianWidth::CHUNK_WIDTH[chunk_index]
|
70
|
+
if size == -1
|
71
|
+
Reline.ambiguous_width
|
72
|
+
elsif size == 1 && utf8_mbchar.size >= 2
|
73
|
+
second_char_ord = utf8_mbchar[1].ord
|
74
|
+
# Halfwidth Dakuten Handakuten
|
75
|
+
# Only these two character has Letter Modifier category and can be combined in a single grapheme cluster
|
76
|
+
(second_char_ord == 0xFF9E || second_char_ord == 0xFF9F) ? 2 : 1
|
102
77
|
else
|
103
|
-
|
78
|
+
size
|
104
79
|
end
|
105
80
|
end
|
106
81
|
|
data/lib/reline/version.rb
CHANGED
data/lib/reline.rb
CHANGED
@@ -7,6 +7,7 @@ require 'reline/key_stroke'
|
|
7
7
|
require 'reline/line_editor'
|
8
8
|
require 'reline/history'
|
9
9
|
require 'reline/terminfo'
|
10
|
+
require 'reline/io'
|
10
11
|
require 'reline/face'
|
11
12
|
require 'rbconfig'
|
12
13
|
|
@@ -18,20 +19,10 @@ module Reline
|
|
18
19
|
class ConfigEncodingConversionError < StandardError; end
|
19
20
|
|
20
21
|
Key = Struct.new(:char, :combined_char, :with_meta) do
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
(other.char.nil? or char.nil? or char == other.char) and
|
25
|
-
(other.combined_char.nil? or combined_char.nil? or combined_char == other.combined_char) and
|
26
|
-
(other.with_meta.nil? or with_meta.nil? or with_meta == other.with_meta)
|
27
|
-
when Integer, Symbol
|
28
|
-
(combined_char and combined_char == other) or
|
29
|
-
(combined_char.nil? and char and char == other)
|
30
|
-
else
|
31
|
-
false
|
32
|
-
end
|
22
|
+
# For dialog_proc `key.match?(dialog.name)`
|
23
|
+
def match?(sym)
|
24
|
+
combined_char.is_a?(Symbol) && combined_char == sym
|
33
25
|
end
|
34
|
-
alias_method :==, :match?
|
35
26
|
end
|
36
27
|
CursorPos = Struct.new(:x, :y)
|
37
28
|
DialogRenderInfo = Struct.new(
|
@@ -263,7 +254,6 @@ module Reline
|
|
263
254
|
raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
|
264
255
|
end
|
265
256
|
|
266
|
-
Reline.update_iogate
|
267
257
|
io_gate.with_raw_input do
|
268
258
|
inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
|
269
259
|
end
|
@@ -286,7 +276,6 @@ module Reline
|
|
286
276
|
|
287
277
|
def readline(prompt = '', add_hist = false)
|
288
278
|
@mutex.synchronize do
|
289
|
-
Reline.update_iogate
|
290
279
|
io_gate.with_raw_input do
|
291
280
|
inner_readline(prompt, add_hist, false)
|
292
281
|
end
|
@@ -335,14 +324,17 @@ module Reline
|
|
335
324
|
line_editor.prompt_proc = prompt_proc
|
336
325
|
line_editor.auto_indent_proc = auto_indent_proc
|
337
326
|
line_editor.dig_perfect_match_proc = dig_perfect_match_proc
|
327
|
+
|
328
|
+
# Readline calls pre_input_hook just after printing the first prompt.
|
329
|
+
line_editor.print_nomultiline_prompt
|
338
330
|
pre_input_hook&.call
|
339
|
-
|
331
|
+
|
332
|
+
unless Reline::IOGate.dumb?
|
340
333
|
@dialog_proc_list.each_pair do |name_sym, d|
|
341
334
|
line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
|
342
335
|
end
|
343
336
|
end
|
344
337
|
|
345
|
-
line_editor.print_nomultiline_prompt(prompt)
|
346
338
|
line_editor.update_dialogs
|
347
339
|
line_editor.rerender
|
348
340
|
|
@@ -354,7 +346,7 @@ module Reline
|
|
354
346
|
inputs.each do |key|
|
355
347
|
if key.char == :bracketed_paste_start
|
356
348
|
text = io_gate.read_bracketed_paste
|
357
|
-
line_editor.
|
349
|
+
line_editor.insert_multiline_text(text)
|
358
350
|
line_editor.scroll_into_view
|
359
351
|
else
|
360
352
|
line_editor.update(key)
|
@@ -378,92 +370,39 @@ module Reline
|
|
378
370
|
end
|
379
371
|
end
|
380
372
|
|
381
|
-
# GNU Readline
|
382
|
-
#
|
383
|
-
#
|
384
|
-
#
|
385
|
-
#
|
386
|
-
#
|
387
|
-
#
|
388
|
-
# GNU Readline will wait for the 2nd character with "keyseq-timeout"
|
389
|
-
# milli-seconds but wait forever after 3rd characters.
|
373
|
+
# GNU Readline watis for "keyseq-timeout" milliseconds when the input is
|
374
|
+
# ambiguous whether it is matching or matched.
|
375
|
+
# If the next character does not arrive within the specified timeout, input
|
376
|
+
# is considered as matched.
|
377
|
+
# `ESC` is ambiguous because it can be a standalone ESC (matched) or part of
|
378
|
+
# `ESC char` or part of CSI sequence (matching).
|
390
379
|
private def read_io(keyseq_timeout, &block)
|
391
380
|
buffer = []
|
381
|
+
status = KeyStroke::MATCHING
|
392
382
|
loop do
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
expanded = key_stroke.expand(buffer).map{ |expanded_c|
|
403
|
-
Reline::Key.new(expanded_c, expanded_c, false)
|
404
|
-
}
|
405
|
-
block.(expanded)
|
406
|
-
break
|
407
|
-
when :matching
|
408
|
-
if buffer.size == 1
|
409
|
-
case read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
|
410
|
-
when :break then break
|
411
|
-
when :next then next
|
412
|
-
end
|
413
|
-
end
|
414
|
-
when :unmatched
|
415
|
-
if buffer.size == 1 and c == "\e".ord
|
416
|
-
read_escaped_key(keyseq_timeout, c, block)
|
383
|
+
timeout = status == KeyStroke::MATCHING_MATCHED ? keyseq_timeout.fdiv(1000) : Float::INFINITY
|
384
|
+
c = io_gate.getc(timeout)
|
385
|
+
if c.nil? || c == -1
|
386
|
+
if status == KeyStroke::MATCHING_MATCHED
|
387
|
+
status = KeyStroke::MATCHED
|
388
|
+
elsif buffer.empty?
|
389
|
+
# io_gate is closed and reached EOF
|
390
|
+
block.call([Key.new(nil, nil, false)])
|
391
|
+
return
|
417
392
|
else
|
418
|
-
|
419
|
-
Reline::Key.new(expanded_c, expanded_c, false)
|
420
|
-
}
|
421
|
-
block.(expanded)
|
393
|
+
status = KeyStroke::UNMATCHED
|
422
394
|
end
|
423
|
-
|
395
|
+
else
|
396
|
+
buffer << c
|
397
|
+
status = key_stroke.match_status(buffer)
|
424
398
|
end
|
425
|
-
end
|
426
|
-
end
|
427
399
|
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
if c == "\e".ord
|
434
|
-
block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
|
435
|
-
else
|
436
|
-
block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
|
437
|
-
end
|
438
|
-
return :break
|
439
|
-
when :matching
|
440
|
-
io_gate.ungetc(succ_c)
|
441
|
-
return :next
|
442
|
-
when :matched
|
443
|
-
buffer << succ_c
|
444
|
-
expanded = key_stroke.expand(buffer).map{ |expanded_c|
|
445
|
-
Reline::Key.new(expanded_c, expanded_c, false)
|
446
|
-
}
|
447
|
-
block.(expanded)
|
448
|
-
return :break
|
400
|
+
if status == KeyStroke::MATCHED || status == KeyStroke::UNMATCHED
|
401
|
+
expanded, rest_bytes = key_stroke.expand(buffer)
|
402
|
+
rest_bytes.reverse_each { |c| io_gate.ungetc(c) }
|
403
|
+
block.call(expanded)
|
404
|
+
return
|
449
405
|
end
|
450
|
-
else
|
451
|
-
block.([Reline::Key.new(c, c, false)])
|
452
|
-
return :break
|
453
|
-
end
|
454
|
-
end
|
455
|
-
|
456
|
-
private def read_escaped_key(keyseq_timeout, c, block)
|
457
|
-
escaped_c = io_gate.getc(keyseq_timeout.fdiv(1000))
|
458
|
-
|
459
|
-
if escaped_c.nil?
|
460
|
-
block.([Reline::Key.new(c, c, false)])
|
461
|
-
elsif escaped_c >= 128 # maybe, first byte of multi byte
|
462
|
-
block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
|
463
|
-
elsif escaped_c == "\e".ord # escape twice
|
464
|
-
block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
|
465
|
-
else
|
466
|
-
block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
|
467
406
|
end
|
468
407
|
end
|
469
408
|
|
@@ -473,7 +412,7 @@ module Reline
|
|
473
412
|
end
|
474
413
|
|
475
414
|
private def may_req_ambiguous_char_width
|
476
|
-
@ambiguous_width = 2 if io_gate
|
415
|
+
@ambiguous_width = 2 if io_gate.dumb? || !STDIN.tty? || !STDOUT.tty?
|
477
416
|
return if defined? @ambiguous_width
|
478
417
|
io_gate.move_cursor_column(0)
|
479
418
|
begin
|
@@ -521,8 +460,8 @@ module Reline
|
|
521
460
|
def_single_delegator :line_editor, :byte_pointer, :point
|
522
461
|
def_single_delegator :line_editor, :byte_pointer=, :point=
|
523
462
|
|
524
|
-
def self.insert_text(
|
525
|
-
line_editor.
|
463
|
+
def self.insert_text(text)
|
464
|
+
line_editor.insert_multiline_text(text)
|
526
465
|
self
|
527
466
|
end
|
528
467
|
|
@@ -567,37 +506,13 @@ module Reline
|
|
567
506
|
def self.line_editor
|
568
507
|
core.line_editor
|
569
508
|
end
|
509
|
+
end
|
570
510
|
|
571
|
-
def self.update_iogate
|
572
|
-
return if core.config.test_mode
|
573
511
|
|
574
|
-
|
575
|
-
# Example: rails/spring boot the application in non-tty, then run console in tty.
|
576
|
-
if ENV['TERM'] != 'dumb' && core.io_gate == Reline::GeneralIO && $stdout.tty?
|
577
|
-
require 'reline/ansi'
|
578
|
-
remove_const(:IOGate)
|
579
|
-
const_set(:IOGate, Reline::ANSI)
|
580
|
-
end
|
581
|
-
end
|
582
|
-
end
|
512
|
+
Reline::IOGate = Reline::IO.decide_io_gate
|
583
513
|
|
584
|
-
|
585
|
-
|
586
|
-
unless ENV['TERM'] == 'dumb'
|
587
|
-
case RbConfig::CONFIG['host_os']
|
588
|
-
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
589
|
-
require 'reline/windows'
|
590
|
-
tty = (io = Reline::Windows).msys_tty?
|
591
|
-
else
|
592
|
-
tty = $stdout.tty?
|
593
|
-
end
|
594
|
-
end
|
595
|
-
Reline::IOGate = if tty
|
596
|
-
require 'reline/ansi'
|
597
|
-
Reline::ANSI
|
598
|
-
else
|
599
|
-
io
|
600
|
-
end
|
514
|
+
# Deprecated
|
515
|
+
Reline::GeneralIO = Reline::Dumb.new
|
601
516
|
|
602
517
|
Reline::Face.load_initial_configs
|
603
518
|
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date: 2024-05
|
10
|
+
date: 2024-09-05 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: io-console
|
@@ -35,13 +34,16 @@ files:
|
|
35
34
|
- COPYING
|
36
35
|
- README.md
|
37
36
|
- lib/reline.rb
|
38
|
-
- lib/reline/ansi.rb
|
39
37
|
- lib/reline/config.rb
|
40
38
|
- lib/reline/face.rb
|
41
|
-
- lib/reline/general_io.rb
|
42
39
|
- lib/reline/history.rb
|
40
|
+
- lib/reline/io.rb
|
41
|
+
- lib/reline/io/ansi.rb
|
42
|
+
- lib/reline/io/dumb.rb
|
43
|
+
- lib/reline/io/windows.rb
|
43
44
|
- lib/reline/key_actor.rb
|
44
45
|
- lib/reline/key_actor/base.rb
|
46
|
+
- lib/reline/key_actor/composite.rb
|
45
47
|
- lib/reline/key_actor/emacs.rb
|
46
48
|
- lib/reline/key_actor/vi_command.rb
|
47
49
|
- lib/reline/key_actor/vi_insert.rb
|
@@ -52,7 +54,6 @@ files:
|
|
52
54
|
- lib/reline/unicode.rb
|
53
55
|
- lib/reline/unicode/east_asian_width.rb
|
54
56
|
- lib/reline/version.rb
|
55
|
-
- lib/reline/windows.rb
|
56
57
|
- license_of_rb-readline
|
57
58
|
homepage: https://github.com/ruby/reline
|
58
59
|
licenses:
|
@@ -61,7 +62,6 @@ metadata:
|
|
61
62
|
bug_tracker_uri: https://github.com/ruby/reline/issues
|
62
63
|
changelog_uri: https://github.com/ruby/reline/releases
|
63
64
|
source_code_uri: https://github.com/ruby/reline
|
64
|
-
post_install_message:
|
65
65
|
rdoc_options: []
|
66
66
|
require_paths:
|
67
67
|
- lib
|
@@ -76,8 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
78
|
requirements: []
|
79
|
-
rubygems_version: 3.
|
80
|
-
signing_key:
|
79
|
+
rubygems_version: 3.6.0.dev
|
81
80
|
specification_version: 4
|
82
81
|
summary: Alternative GNU Readline or Editline implementation by pure Ruby.
|
83
82
|
test_files: []
|
data/lib/reline/general_io.rb
DELETED
@@ -1,111 +0,0 @@
|
|
1
|
-
require 'io/wait'
|
2
|
-
|
3
|
-
class Reline::GeneralIO
|
4
|
-
RESET_COLOR = '' # Do not send color reset sequence
|
5
|
-
|
6
|
-
def self.reset(encoding: nil)
|
7
|
-
@@pasting = false
|
8
|
-
if encoding
|
9
|
-
@@encoding = encoding
|
10
|
-
elsif defined?(@@encoding)
|
11
|
-
remove_class_variable(:@@encoding)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.encoding
|
16
|
-
if defined?(@@encoding)
|
17
|
-
@@encoding
|
18
|
-
elsif RUBY_PLATFORM =~ /mswin|mingw/
|
19
|
-
Encoding::UTF_8
|
20
|
-
else
|
21
|
-
Encoding::default_external
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.win?
|
26
|
-
false
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.set_default_key_bindings(_)
|
30
|
-
end
|
31
|
-
|
32
|
-
@@buf = []
|
33
|
-
@@input = STDIN
|
34
|
-
|
35
|
-
def self.input=(val)
|
36
|
-
@@input = val
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.with_raw_input
|
40
|
-
yield
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.getc(_timeout_second)
|
44
|
-
unless @@buf.empty?
|
45
|
-
return @@buf.shift
|
46
|
-
end
|
47
|
-
c = nil
|
48
|
-
loop do
|
49
|
-
Reline.core.line_editor.handle_signal
|
50
|
-
result = @@input.wait_readable(0.1)
|
51
|
-
next if result.nil?
|
52
|
-
c = @@input.read(1)
|
53
|
-
break
|
54
|
-
end
|
55
|
-
c&.ord
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.ungetc(c)
|
59
|
-
@@buf.unshift(c)
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.get_screen_size
|
63
|
-
[24, 80]
|
64
|
-
end
|
65
|
-
|
66
|
-
def self.cursor_pos
|
67
|
-
Reline::CursorPos.new(1, 1)
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.hide_cursor
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.show_cursor
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.move_cursor_column(val)
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.move_cursor_up(val)
|
80
|
-
end
|
81
|
-
|
82
|
-
def self.move_cursor_down(val)
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.erase_after_cursor
|
86
|
-
end
|
87
|
-
|
88
|
-
def self.scroll_down(val)
|
89
|
-
end
|
90
|
-
|
91
|
-
def self.clear_screen
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.set_screen_size(rows, columns)
|
95
|
-
end
|
96
|
-
|
97
|
-
def self.set_winch_handler(&handler)
|
98
|
-
end
|
99
|
-
|
100
|
-
@@pasting = false
|
101
|
-
|
102
|
-
def self.in_pasting?
|
103
|
-
@@pasting
|
104
|
-
end
|
105
|
-
|
106
|
-
def self.prep
|
107
|
-
end
|
108
|
-
|
109
|
-
def self.deprep(otio)
|
110
|
-
end
|
111
|
-
end
|