reline 0.5.8 → 0.5.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|