reline 0.0.5 → 0.1.2
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.rb +33 -18
- data/lib/reline/ansi.rb +14 -15
- data/lib/reline/config.rb +2 -2
- data/lib/reline/history.rb +1 -1
- data/lib/reline/key_actor/emacs.rb +2 -2
- data/lib/reline/key_actor/vi_command.rb +1 -1
- data/lib/reline/key_actor/vi_insert.rb +1 -1
- data/lib/reline/line_editor.rb +239 -71
- data/lib/reline/version.rb +1 -1
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7612855f90bdd7b5602c7d9e7b2b4de200d6986c45ff64b5a356380c1211b83e
|
4
|
+
data.tar.gz: 58406022787d706f400e828e31fde79b3e90c09a106b82a84218e5b748725db4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dcd02ec0e09c6dafa6cf3e9e1dbbeab9befabe033a1ae581628ff01fb4435fce3bb4cbe4cccb5890761e1a58a6637379a5f154ed67f28edaf46a71ba6a00d5c1
|
7
|
+
data.tar.gz: 55a61bcab1c41d35002462c80f11d4406426a815bc84ddb680f73c023139fea95e89bc5cc3d1a9e25f1b77ed0986923e5152cfdd489b9e484bd2e459a6602256
|
data/lib/reline.rb
CHANGED
@@ -16,12 +16,6 @@ module Reline
|
|
16
16
|
CursorPos = Struct.new(:x, :y)
|
17
17
|
|
18
18
|
class Core
|
19
|
-
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
20
|
-
IS_WINDOWS = true
|
21
|
-
else
|
22
|
-
IS_WINDOWS = false
|
23
|
-
end
|
24
|
-
|
25
19
|
ATTR_READER_NAMES = %i(
|
26
20
|
completion_append_character
|
27
21
|
basic_word_break_characters
|
@@ -38,19 +32,17 @@ module Reline
|
|
38
32
|
dig_perfect_match_proc
|
39
33
|
).each(&method(:attr_reader))
|
40
34
|
|
41
|
-
ATTR_ACCESSOR_NAMES = %i(
|
42
|
-
completion_case_fold
|
43
|
-
).each(&method(:attr_accessor))
|
44
|
-
|
45
35
|
attr_accessor :config
|
46
36
|
attr_accessor :key_stroke
|
47
37
|
attr_accessor :line_editor
|
48
38
|
attr_accessor :ambiguous_width
|
39
|
+
attr_accessor :last_incremental_search
|
49
40
|
attr_reader :output
|
50
41
|
|
51
42
|
def initialize
|
52
43
|
self.output = STDOUT
|
53
44
|
yield self
|
45
|
+
@completion_quote_character = nil
|
54
46
|
end
|
55
47
|
|
56
48
|
def completion_append_character=(val)
|
@@ -89,23 +81,35 @@ module Reline
|
|
89
81
|
@special_prefixes = v.encode(Encoding::default_external)
|
90
82
|
end
|
91
83
|
|
84
|
+
def completion_case_fold=(v)
|
85
|
+
@config.completion_ignore_case = v
|
86
|
+
end
|
87
|
+
|
88
|
+
def completion_case_fold
|
89
|
+
@config.completion_ignore_case
|
90
|
+
end
|
91
|
+
|
92
|
+
def completion_quote_character
|
93
|
+
@completion_quote_character
|
94
|
+
end
|
95
|
+
|
92
96
|
def completion_proc=(p)
|
93
|
-
raise ArgumentError unless p.
|
97
|
+
raise ArgumentError unless p.respond_to?(:call)
|
94
98
|
@completion_proc = p
|
95
99
|
end
|
96
100
|
|
97
101
|
def output_modifier_proc=(p)
|
98
|
-
raise ArgumentError unless p.
|
102
|
+
raise ArgumentError unless p.respond_to?(:call)
|
99
103
|
@output_modifier_proc = p
|
100
104
|
end
|
101
105
|
|
102
106
|
def prompt_proc=(p)
|
103
|
-
raise ArgumentError unless p.
|
107
|
+
raise ArgumentError unless p.respond_to?(:call)
|
104
108
|
@prompt_proc = p
|
105
109
|
end
|
106
110
|
|
107
111
|
def auto_indent_proc=(p)
|
108
|
-
raise ArgumentError unless p.
|
112
|
+
raise ArgumentError unless p.respond_to?(:call)
|
109
113
|
@auto_indent_proc = p
|
110
114
|
end
|
111
115
|
|
@@ -114,7 +118,7 @@ module Reline
|
|
114
118
|
end
|
115
119
|
|
116
120
|
def dig_perfect_match_proc=(p)
|
117
|
-
raise ArgumentError unless p.
|
121
|
+
raise ArgumentError unless p.respond_to?(:call)
|
118
122
|
@dig_perfect_match_proc = p
|
119
123
|
end
|
120
124
|
|
@@ -208,6 +212,7 @@ module Reline
|
|
208
212
|
end
|
209
213
|
line_editor.output = output
|
210
214
|
line_editor.completion_proc = completion_proc
|
215
|
+
line_editor.completion_append_character = completion_append_character
|
211
216
|
line_editor.output_modifier_proc = output_modifier_proc
|
212
217
|
line_editor.prompt_proc = prompt_proc
|
213
218
|
line_editor.auto_indent_proc = auto_indent_proc
|
@@ -341,12 +346,14 @@ module Reline
|
|
341
346
|
# Documented API
|
342
347
|
#--------------------------------------------------------
|
343
348
|
|
344
|
-
(Core::ATTR_READER_NAMES
|
349
|
+
(Core::ATTR_READER_NAMES).each { |name|
|
345
350
|
def_single_delegators :core, "#{name}", "#{name}="
|
346
351
|
}
|
347
352
|
def_single_delegators :core, :input=, :output=
|
348
353
|
def_single_delegators :core, :vi_editing_mode, :emacs_editing_mode
|
349
354
|
def_single_delegators :core, :readline
|
355
|
+
def_single_delegators :core, :completion_case_fold, :completion_case_fold=
|
356
|
+
def_single_delegators :core, :completion_quote_character
|
350
357
|
def_instance_delegators self, :readline
|
351
358
|
private :readline
|
352
359
|
|
@@ -373,6 +380,8 @@ module Reline
|
|
373
380
|
def_single_delegator :line_editor, :rerender, :redisplay
|
374
381
|
def_single_delegators :core, :vi_editing_mode?, :emacs_editing_mode?
|
375
382
|
def_single_delegators :core, :ambiguous_width
|
383
|
+
def_single_delegators :core, :last_incremental_search
|
384
|
+
def_single_delegators :core, :last_incremental_search=
|
376
385
|
|
377
386
|
def_single_delegators :core, :readmultiline
|
378
387
|
def_instance_delegators self, :readmultiline
|
@@ -400,9 +409,15 @@ module Reline
|
|
400
409
|
HISTORY = History.new(core.config)
|
401
410
|
end
|
402
411
|
|
403
|
-
if
|
412
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
404
413
|
require 'reline/windows'
|
405
|
-
Reline::
|
414
|
+
if Reline::Windows.get_screen_size == [0, 0]
|
415
|
+
# Maybe Mintty on Cygwin
|
416
|
+
require 'reline/ansi'
|
417
|
+
Reline::IOGate = Reline::ANSI
|
418
|
+
else
|
419
|
+
Reline::IOGate = Reline::Windows
|
420
|
+
end
|
406
421
|
else
|
407
422
|
require 'reline/ansi'
|
408
423
|
Reline::IOGate = Reline::ANSI
|
data/lib/reline/ansi.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'io/console'
|
2
|
+
|
1
3
|
class Reline::ANSI
|
2
4
|
RAW_KEYSTROKE_CONFIG = {
|
3
5
|
[27, 91, 65] => :ed_prev_history, # ↑
|
@@ -7,8 +9,12 @@ class Reline::ANSI
|
|
7
9
|
[27, 91, 51, 126] => :key_delete, # Del
|
8
10
|
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
9
11
|
[27, 91, 52, 126] => :ed_move_to_end, # End
|
12
|
+
[27, 91, 72] => :ed_move_to_beg, # Home
|
13
|
+
[27, 91, 70] => :ed_move_to_end, # End
|
10
14
|
[27, 32] => :em_set_mark, # M-<space>
|
11
15
|
[24, 24] => :em_exchange_mark, # C-x C-x TODO also add Windows
|
16
|
+
[27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→
|
17
|
+
[27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←
|
12
18
|
}
|
13
19
|
|
14
20
|
@@input = STDIN
|
@@ -26,7 +32,8 @@ class Reline::ANSI
|
|
26
32
|
unless @@buf.empty?
|
27
33
|
return @@buf.shift
|
28
34
|
end
|
29
|
-
@@input.getbyte
|
35
|
+
c = @@input.raw(intr: true, &:getbyte)
|
36
|
+
(c == 0x16 && @@input.raw(min: 0, tim: 0, &:getbyte)) || c
|
30
37
|
end
|
31
38
|
|
32
39
|
def self.ungetc(c)
|
@@ -58,14 +65,18 @@ class Reline::ANSI
|
|
58
65
|
def self.cursor_pos
|
59
66
|
begin
|
60
67
|
res = ''
|
68
|
+
m = nil
|
61
69
|
@@input.raw do |stdin|
|
62
70
|
@@output << "\e[6n"
|
63
71
|
@@output.flush
|
64
72
|
while (c = stdin.getc) != 'R'
|
65
73
|
res << c if c
|
66
74
|
end
|
75
|
+
m = res.match(/\e\[(?<row>\d+);(?<column>\d+)/)
|
76
|
+
(m.pre_match + m.post_match).chars.reverse_each do |ch|
|
77
|
+
stdin.ungetc ch
|
78
|
+
end
|
67
79
|
end
|
68
|
-
m = res.match(/(?<row>\d+);(?<column>\d+)/)
|
69
80
|
column = m[:column].to_i - 1
|
70
81
|
row = m[:row].to_i - 1
|
71
82
|
rescue Errno::ENOTTY
|
@@ -118,24 +129,12 @@ class Reline::ANSI
|
|
118
129
|
def self.prep
|
119
130
|
retrieve_keybuffer
|
120
131
|
int_handle = Signal.trap('INT', 'IGNORE')
|
121
|
-
otio = `stty -g`.chomp
|
122
|
-
setting = ' -echo -icrnl cbreak'
|
123
|
-
stty = `stty -a`
|
124
|
-
if /-parenb\b/ =~ stty
|
125
|
-
setting << ' pass8'
|
126
|
-
end
|
127
|
-
if /\bdsusp *=/ =~ stty
|
128
|
-
setting << ' dsusp undef'
|
129
|
-
end
|
130
|
-
setting << ' -ixoff'
|
131
|
-
`stty #{setting}`
|
132
132
|
Signal.trap('INT', int_handle)
|
133
|
-
|
133
|
+
nil
|
134
134
|
end
|
135
135
|
|
136
136
|
def self.deprep(otio)
|
137
137
|
int_handle = Signal.trap('INT', 'IGNORE')
|
138
|
-
`stty #{otio}`
|
139
138
|
Signal.trap('INT', int_handle)
|
140
139
|
Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
|
141
140
|
end
|
data/lib/reline/config.rb
CHANGED
@@ -157,7 +157,7 @@ class Reline::Config
|
|
157
157
|
case directive
|
158
158
|
when 'if'
|
159
159
|
condition = false
|
160
|
-
case args
|
160
|
+
case args
|
161
161
|
when 'mode'
|
162
162
|
when 'term'
|
163
163
|
when 'version'
|
@@ -184,7 +184,7 @@ class Reline::Config
|
|
184
184
|
|
185
185
|
def bind_variable(name, value)
|
186
186
|
case name
|
187
|
-
when VARIABLE_NAMES then
|
187
|
+
when *VARIABLE_NAMES then
|
188
188
|
variable_name = :"@#{name.tr(?-, ?_)}"
|
189
189
|
instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
|
190
190
|
when 'bell-style'
|
data/lib/reline/history.rb
CHANGED
@@ -9,7 +9,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
|
9
9
|
# 3 ^C
|
10
10
|
:ed_ignore,
|
11
11
|
# 4 ^D
|
12
|
-
:
|
12
|
+
:em_delete,
|
13
13
|
# 5 ^E
|
14
14
|
:ed_move_to_end,
|
15
15
|
# 6 ^F
|
@@ -39,7 +39,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
|
39
39
|
# 18 ^R
|
40
40
|
:ed_search_prev_history,
|
41
41
|
# 19 ^S
|
42
|
-
:
|
42
|
+
:ed_search_next_history,
|
43
43
|
# 20 ^T
|
44
44
|
:ed_transpose_chars,
|
45
45
|
# 21 ^U
|
data/lib/reline/line_editor.rb
CHANGED
@@ -10,6 +10,7 @@ class Reline::LineEditor
|
|
10
10
|
attr_reader :byte_pointer
|
11
11
|
attr_accessor :confirm_multiline_termination_proc
|
12
12
|
attr_accessor :completion_proc
|
13
|
+
attr_accessor :completion_append_character
|
13
14
|
attr_accessor :output_modifier_proc
|
14
15
|
attr_accessor :prompt_proc
|
15
16
|
attr_accessor :auto_indent_proc
|
@@ -43,6 +44,7 @@ class Reline::LineEditor
|
|
43
44
|
COMPLETION = :completion
|
44
45
|
MENU = :menu
|
45
46
|
JOURNEY = :journey
|
47
|
+
MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
|
46
48
|
PERFECT_MATCH = :perfect_match
|
47
49
|
end
|
48
50
|
|
@@ -57,6 +59,7 @@ class Reline::LineEditor
|
|
57
59
|
|
58
60
|
def initialize(config)
|
59
61
|
@config = config
|
62
|
+
@completion_append_character = ''
|
60
63
|
reset_variables
|
61
64
|
end
|
62
65
|
|
@@ -192,7 +195,7 @@ class Reline::LineEditor
|
|
192
195
|
lines.each_with_index { |line, i|
|
193
196
|
prompt = ''
|
194
197
|
prompt = prompt_list[i] if prompt_list and prompt_list[i]
|
195
|
-
result += calculate_height_by_width(calculate_width(prompt + line))
|
198
|
+
result += calculate_height_by_width(calculate_width(prompt, true) + calculate_width(line))
|
196
199
|
}
|
197
200
|
result
|
198
201
|
end
|
@@ -549,10 +552,14 @@ class Reline::LineEditor
|
|
549
552
|
private def complete_internal_proc(list, is_menu)
|
550
553
|
preposing, target, postposing = retrieve_completion_block
|
551
554
|
list = list.select { |i|
|
552
|
-
if i and
|
553
|
-
raise Encoding::CompatibilityError
|
555
|
+
if i and not Encoding.compatible?(target.encoding, i.encoding)
|
556
|
+
raise Encoding::CompatibilityError, "#{target.encoding.name} is not compatible with #{i.encoding.name}"
|
557
|
+
end
|
558
|
+
if @config.completion_ignore_case
|
559
|
+
i&.downcase&.start_with?(target.downcase)
|
560
|
+
else
|
561
|
+
i&.start_with?(target)
|
554
562
|
end
|
555
|
-
i&.start_with?(target)
|
556
563
|
}
|
557
564
|
if is_menu
|
558
565
|
menu(target, list)
|
@@ -569,10 +576,18 @@ class Reline::LineEditor
|
|
569
576
|
size = [memo_mbchars.size, item_mbchars.size].min
|
570
577
|
result = ''
|
571
578
|
size.times do |i|
|
572
|
-
if
|
573
|
-
|
579
|
+
if @config.completion_ignore_case
|
580
|
+
if memo_mbchars[i].casecmp?(item_mbchars[i])
|
581
|
+
result << memo_mbchars[i]
|
582
|
+
else
|
583
|
+
break
|
584
|
+
end
|
574
585
|
else
|
575
|
-
|
586
|
+
if memo_mbchars[i] == item_mbchars[i]
|
587
|
+
result << memo_mbchars[i]
|
588
|
+
else
|
589
|
+
break
|
590
|
+
end
|
576
591
|
end
|
577
592
|
end
|
578
593
|
result
|
@@ -580,27 +595,43 @@ class Reline::LineEditor
|
|
580
595
|
[target, preposing, completed, postposing]
|
581
596
|
end
|
582
597
|
|
583
|
-
private def complete(list)
|
598
|
+
private def complete(list, just_show_list = false)
|
584
599
|
case @completion_state
|
585
600
|
when CompletionState::NORMAL, CompletionState::JOURNEY
|
586
601
|
@completion_state = CompletionState::COMPLETION
|
587
602
|
when CompletionState::PERFECT_MATCH
|
588
603
|
@dig_perfect_match_proc&.(@perfect_matched)
|
589
604
|
end
|
590
|
-
|
605
|
+
if just_show_list
|
606
|
+
is_menu = true
|
607
|
+
elsif @completion_state == CompletionState::MENU
|
608
|
+
is_menu = true
|
609
|
+
elsif @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH
|
610
|
+
is_menu = true
|
611
|
+
else
|
612
|
+
is_menu = false
|
613
|
+
end
|
591
614
|
result = complete_internal_proc(list, is_menu)
|
615
|
+
if @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH
|
616
|
+
@completion_state = CompletionState::PERFECT_MATCH
|
617
|
+
end
|
592
618
|
return if result.nil?
|
593
619
|
target, preposing, completed, postposing = result
|
594
620
|
return if completed.nil?
|
595
|
-
if target <= completed and (@completion_state == CompletionState::COMPLETION
|
596
|
-
@completion_state = CompletionState::MENU
|
621
|
+
if target <= completed and (@completion_state == CompletionState::COMPLETION)
|
597
622
|
if list.include?(completed)
|
598
|
-
|
623
|
+
if list.one?
|
624
|
+
@completion_state = CompletionState::PERFECT_MATCH
|
625
|
+
else
|
626
|
+
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
|
627
|
+
end
|
599
628
|
@perfect_matched = completed
|
629
|
+
else
|
630
|
+
@completion_state = CompletionState::MENU
|
600
631
|
end
|
601
|
-
if target < completed
|
602
|
-
@line = preposing + completed + postposing
|
603
|
-
line_to_pointer = preposing + completed
|
632
|
+
if not just_show_list and target < completed
|
633
|
+
@line = preposing + completed + completion_append_character.to_s + postposing
|
634
|
+
line_to_pointer = preposing + completed + completion_append_character.to_s
|
604
635
|
@cursor_max = calculate_width(@line)
|
605
636
|
@cursor = calculate_width(line_to_pointer)
|
606
637
|
@byte_pointer = line_to_pointer.bytesize
|
@@ -610,7 +641,8 @@ class Reline::LineEditor
|
|
610
641
|
|
611
642
|
private def move_completed_list(list, direction)
|
612
643
|
case @completion_state
|
613
|
-
when CompletionState::NORMAL, CompletionState::COMPLETION,
|
644
|
+
when CompletionState::NORMAL, CompletionState::COMPLETION,
|
645
|
+
CompletionState::MENU, CompletionState::MENU_WITH_PERFECT_MATCH
|
614
646
|
@completion_state = CompletionState::JOURNEY
|
615
647
|
result = retrieve_completion_block
|
616
648
|
return if result.nil?
|
@@ -766,7 +798,7 @@ class Reline::LineEditor
|
|
766
798
|
end
|
767
799
|
|
768
800
|
def input_key(key)
|
769
|
-
if key.
|
801
|
+
if key.char.nil?
|
770
802
|
if @first_char
|
771
803
|
@line = nil
|
772
804
|
end
|
@@ -776,20 +808,20 @@ class Reline::LineEditor
|
|
776
808
|
@first_char = false
|
777
809
|
completion_occurs = false
|
778
810
|
if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
811
|
+
unless @config.disable_completion
|
812
|
+
result = call_completion_proc
|
813
|
+
if result.is_a?(Array)
|
814
|
+
completion_occurs = true
|
815
|
+
complete(result)
|
816
|
+
end
|
785
817
|
end
|
786
|
-
elsif @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
818
|
+
elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
819
|
+
unless @config.disable_completion
|
820
|
+
result = call_completion_proc
|
821
|
+
if result.is_a?(Array)
|
822
|
+
completion_occurs = true
|
823
|
+
move_completed_list(result, "\C-p".ord == key.char ? :up : :down)
|
824
|
+
end
|
793
825
|
end
|
794
826
|
elsif Symbol === key.char and respond_to?(key.char, true)
|
795
827
|
process_key(key.char, key.char)
|
@@ -804,8 +836,33 @@ class Reline::LineEditor
|
|
804
836
|
end
|
805
837
|
end
|
806
838
|
|
839
|
+
def call_completion_proc
|
840
|
+
result = retrieve_completion_block(true)
|
841
|
+
slice = result[1]
|
842
|
+
result = @completion_proc.(slice) if @completion_proc and slice
|
843
|
+
Reline.core.instance_variable_set(:@completion_quote_character, nil)
|
844
|
+
result
|
845
|
+
end
|
846
|
+
|
807
847
|
private def process_auto_indent
|
808
848
|
return if not @check_new_auto_indent and @previous_line_index # move cursor up or down
|
849
|
+
if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index
|
850
|
+
# Fix indent of a line when a newline is inserted to the next
|
851
|
+
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
852
|
+
new_indent = @auto_indent_proc.(new_lines[0..-3].push(''), @line_index - 1, 0, true)
|
853
|
+
md = @line.match(/\A */)
|
854
|
+
prev_indent = md[0].count(' ')
|
855
|
+
@line = ' ' * new_indent + @line.lstrip
|
856
|
+
|
857
|
+
new_indent = nil
|
858
|
+
result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[-2].size + 1), false)
|
859
|
+
if result
|
860
|
+
new_indent = result
|
861
|
+
end
|
862
|
+
if new_indent&.>= 0
|
863
|
+
@line = ' ' * new_indent + @line.lstrip
|
864
|
+
end
|
865
|
+
end
|
809
866
|
if @previous_line_index
|
810
867
|
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
811
868
|
else
|
@@ -828,7 +885,7 @@ class Reline::LineEditor
|
|
828
885
|
@check_new_auto_indent = false
|
829
886
|
end
|
830
887
|
|
831
|
-
def retrieve_completion_block
|
888
|
+
def retrieve_completion_block(set_completion_quote_character = false)
|
832
889
|
word_break_regexp = /\A[#{Regexp.escape(Reline.completer_word_break_characters)}]/
|
833
890
|
quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/
|
834
891
|
before = @line.byteslice(0, @byte_pointer)
|
@@ -847,31 +904,42 @@ class Reline::LineEditor
|
|
847
904
|
if quote and slice.start_with?(closing_quote)
|
848
905
|
quote = nil
|
849
906
|
i += 1
|
907
|
+
rest = nil
|
908
|
+
break_pointer = nil
|
850
909
|
elsif quote and slice.start_with?(escaped_quote)
|
851
910
|
# skip
|
852
911
|
i += 2
|
853
912
|
elsif slice =~ quote_characters_regexp # find new "
|
913
|
+
rest = $'
|
854
914
|
quote = $&
|
855
915
|
closing_quote = /(?!\\)#{Regexp.escape(quote)}/
|
856
916
|
escaped_quote = /\\#{Regexp.escape(quote)}/
|
857
917
|
i += 1
|
918
|
+
break_pointer = i
|
858
919
|
elsif not quote and slice =~ word_break_regexp
|
859
920
|
rest = $'
|
860
921
|
i += 1
|
922
|
+
before = @line.byteslice(i, @byte_pointer - i)
|
861
923
|
break_pointer = i
|
862
924
|
else
|
863
925
|
i += 1
|
864
926
|
end
|
865
927
|
end
|
928
|
+
postposing = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
|
866
929
|
if rest
|
867
930
|
preposing = @line.byteslice(0, break_pointer)
|
868
931
|
target = rest
|
932
|
+
if set_completion_quote_character and quote
|
933
|
+
Reline.core.instance_variable_set(:@completion_quote_character, quote)
|
934
|
+
if postposing !~ /(?!\\)#{Regexp.escape(quote)}/ # closing quote
|
935
|
+
insert_text(quote)
|
936
|
+
end
|
937
|
+
end
|
869
938
|
else
|
870
939
|
preposing = ''
|
871
940
|
target = before
|
872
941
|
end
|
873
|
-
|
874
|
-
[preposing, target, postposing]
|
942
|
+
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
|
875
943
|
end
|
876
944
|
|
877
945
|
def confirm_multiline_termination
|
@@ -1124,25 +1192,34 @@ class Reline::LineEditor
|
|
1124
1192
|
end
|
1125
1193
|
alias_method :end_of_line, :ed_move_to_end
|
1126
1194
|
|
1127
|
-
private def
|
1128
|
-
|
1129
|
-
|
1130
|
-
else
|
1131
|
-
@line_backup_in_history = @line
|
1132
|
-
end
|
1133
|
-
searcher = Fiber.new do
|
1195
|
+
private def generate_searcher
|
1196
|
+
Fiber.new do |first_key|
|
1197
|
+
prev_search_key = first_key
|
1134
1198
|
search_word = String.new(encoding: @encoding)
|
1135
1199
|
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
1136
1200
|
last_hit = nil
|
1201
|
+
case first_key
|
1202
|
+
when "\C-r".ord
|
1203
|
+
prompt_name = 'reverse-i-search'
|
1204
|
+
when "\C-s".ord
|
1205
|
+
prompt_name = 'i-search'
|
1206
|
+
end
|
1137
1207
|
loop do
|
1138
1208
|
key = Fiber.yield(search_word)
|
1209
|
+
search_again = false
|
1139
1210
|
case key
|
1140
|
-
when
|
1211
|
+
when -1 # determined
|
1212
|
+
Reline.last_incremental_search = search_word
|
1213
|
+
break
|
1214
|
+
when "\C-h".ord, "\C-?".ord
|
1141
1215
|
grapheme_clusters = search_word.grapheme_clusters
|
1142
1216
|
if grapheme_clusters.size > 0
|
1143
1217
|
grapheme_clusters.pop
|
1144
1218
|
search_word = grapheme_clusters.join
|
1145
1219
|
end
|
1220
|
+
when "\C-r".ord, "\C-s".ord
|
1221
|
+
search_again = true if prev_search_key == key
|
1222
|
+
prev_search_key = key
|
1146
1223
|
else
|
1147
1224
|
multibyte_buf << key
|
1148
1225
|
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
@@ -1151,18 +1228,61 @@ class Reline::LineEditor
|
|
1151
1228
|
end
|
1152
1229
|
end
|
1153
1230
|
hit = nil
|
1154
|
-
if @line_backup_in_history
|
1231
|
+
if not search_word.empty? and @line_backup_in_history&.include?(search_word)
|
1155
1232
|
@history_pointer = nil
|
1156
1233
|
hit = @line_backup_in_history
|
1157
1234
|
else
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1235
|
+
if search_again
|
1236
|
+
if search_word.empty? and Reline.last_incremental_search
|
1237
|
+
search_word = Reline.last_incremental_search
|
1238
|
+
end
|
1239
|
+
if @history_pointer # TODO
|
1240
|
+
case prev_search_key
|
1241
|
+
when "\C-r".ord
|
1242
|
+
history_pointer_base = 0
|
1243
|
+
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
1244
|
+
when "\C-s".ord
|
1245
|
+
history_pointer_base = @history_pointer + 1
|
1246
|
+
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
1247
|
+
end
|
1248
|
+
else
|
1249
|
+
history_pointer_base = 0
|
1250
|
+
history = Reline::HISTORY
|
1251
|
+
end
|
1252
|
+
elsif @history_pointer
|
1253
|
+
case prev_search_key
|
1254
|
+
when "\C-r".ord
|
1255
|
+
history_pointer_base = 0
|
1256
|
+
history = Reline::HISTORY[0..@history_pointer]
|
1257
|
+
when "\C-s".ord
|
1258
|
+
history_pointer_base = @history_pointer
|
1259
|
+
history = Reline::HISTORY[@history_pointer..-1]
|
1260
|
+
end
|
1261
|
+
else
|
1262
|
+
history_pointer_base = 0
|
1263
|
+
history = Reline::HISTORY
|
1264
|
+
end
|
1265
|
+
case prev_search_key
|
1266
|
+
when "\C-r".ord
|
1267
|
+
hit_index = history.rindex { |item|
|
1268
|
+
item.include?(search_word)
|
1269
|
+
}
|
1270
|
+
when "\C-s".ord
|
1271
|
+
hit_index = history.index { |item|
|
1272
|
+
item.include?(search_word)
|
1273
|
+
}
|
1274
|
+
end
|
1161
1275
|
if hit_index
|
1162
|
-
@history_pointer = hit_index
|
1276
|
+
@history_pointer = history_pointer_base + hit_index
|
1163
1277
|
hit = Reline::HISTORY[@history_pointer]
|
1164
1278
|
end
|
1165
1279
|
end
|
1280
|
+
case prev_search_key
|
1281
|
+
when "\C-r".ord
|
1282
|
+
prompt_name = 'reverse-i-search'
|
1283
|
+
when "\C-s".ord
|
1284
|
+
prompt_name = 'i-search'
|
1285
|
+
end
|
1166
1286
|
if hit
|
1167
1287
|
if @is_multiline
|
1168
1288
|
@buffer_of_lines = hit.split("\n")
|
@@ -1170,47 +1290,77 @@ class Reline::LineEditor
|
|
1170
1290
|
@line_index = @buffer_of_lines.size - 1
|
1171
1291
|
@line = @buffer_of_lines.last
|
1172
1292
|
@rerender_all = true
|
1173
|
-
@searching_prompt = "(
|
1293
|
+
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1174
1294
|
else
|
1175
1295
|
@line = hit
|
1176
|
-
@searching_prompt = "(
|
1296
|
+
@searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
|
1177
1297
|
end
|
1178
1298
|
last_hit = hit
|
1179
1299
|
else
|
1180
1300
|
if @is_multiline
|
1181
1301
|
@rerender_all = true
|
1182
|
-
@searching_prompt = "(failed
|
1302
|
+
@searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
|
1183
1303
|
else
|
1184
|
-
@searching_prompt = "(failed
|
1304
|
+
@searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
|
1185
1305
|
end
|
1186
1306
|
end
|
1187
1307
|
end
|
1188
1308
|
end
|
1189
|
-
|
1309
|
+
end
|
1310
|
+
|
1311
|
+
private def search_history(key)
|
1312
|
+
unless @history_pointer
|
1313
|
+
if @is_multiline
|
1314
|
+
@line_backup_in_history = whole_buffer
|
1315
|
+
else
|
1316
|
+
@line_backup_in_history = @line
|
1317
|
+
end
|
1318
|
+
end
|
1319
|
+
searcher = generate_searcher
|
1320
|
+
searcher.resume(key)
|
1190
1321
|
@searching_prompt = "(reverse-i-search)`': "
|
1191
1322
|
@waiting_proc = ->(k) {
|
1192
1323
|
case k
|
1193
|
-
when "\C-j".ord
|
1324
|
+
when "\C-j".ord
|
1194
1325
|
if @history_pointer
|
1195
|
-
|
1326
|
+
buffer = Reline::HISTORY[@history_pointer]
|
1196
1327
|
else
|
1197
|
-
|
1328
|
+
buffer = @line_backup_in_history
|
1329
|
+
end
|
1330
|
+
if @is_multiline
|
1331
|
+
@buffer_of_lines = buffer.split("\n")
|
1332
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1333
|
+
@line_index = @buffer_of_lines.size - 1
|
1334
|
+
@line = @buffer_of_lines.last
|
1335
|
+
@rerender_all = true
|
1336
|
+
else
|
1337
|
+
@line = buffer
|
1198
1338
|
end
|
1199
1339
|
@searching_prompt = nil
|
1200
1340
|
@waiting_proc = nil
|
1201
1341
|
@cursor_max = calculate_width(@line)
|
1202
1342
|
@cursor = @byte_pointer = 0
|
1343
|
+
searcher.resume(-1)
|
1203
1344
|
when "\C-g".ord
|
1204
|
-
|
1345
|
+
if @is_multiline
|
1346
|
+
@buffer_of_lines = @line_backup_in_history.split("\n")
|
1347
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1348
|
+
@line_index = @buffer_of_lines.size - 1
|
1349
|
+
@line = @buffer_of_lines.last
|
1350
|
+
@rerender_all = true
|
1351
|
+
else
|
1352
|
+
@line = @line_backup_in_history
|
1353
|
+
end
|
1205
1354
|
@history_pointer = nil
|
1206
1355
|
@searching_prompt = nil
|
1207
1356
|
@waiting_proc = nil
|
1208
1357
|
@line_backup_in_history = nil
|
1209
1358
|
@cursor_max = calculate_width(@line)
|
1210
1359
|
@cursor = @byte_pointer = 0
|
1360
|
+
@rerender_all = true
|
1211
1361
|
else
|
1212
1362
|
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1213
|
-
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k ==
|
1363
|
+
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
|
1214
1364
|
searcher.resume(k)
|
1215
1365
|
else
|
1216
1366
|
if @history_pointer
|
@@ -1233,13 +1383,21 @@ class Reline::LineEditor
|
|
1233
1383
|
@waiting_proc = nil
|
1234
1384
|
@cursor_max = calculate_width(@line)
|
1235
1385
|
@cursor = @byte_pointer = 0
|
1386
|
+
searcher.resume(-1)
|
1236
1387
|
end
|
1237
1388
|
end
|
1238
1389
|
}
|
1239
1390
|
end
|
1240
1391
|
|
1392
|
+
private def ed_search_prev_history(key)
|
1393
|
+
search_history(key)
|
1394
|
+
end
|
1395
|
+
alias_method :reverse_search_history, :ed_search_prev_history
|
1396
|
+
|
1241
1397
|
private def ed_search_next_history(key)
|
1398
|
+
search_history(key)
|
1242
1399
|
end
|
1400
|
+
alias_method :forward_search_history, :ed_search_next_history
|
1243
1401
|
|
1244
1402
|
private def ed_prev_history(key, arg: 1)
|
1245
1403
|
if @is_multiline and @line_index > 0
|
@@ -1397,6 +1555,14 @@ class Reline::LineEditor
|
|
1397
1555
|
@byte_pointer = @line.bytesize
|
1398
1556
|
@cursor = @cursor_max = calculate_width(@line)
|
1399
1557
|
@kill_ring.append(deleted)
|
1558
|
+
elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1
|
1559
|
+
@cursor = calculate_width(@line)
|
1560
|
+
@byte_pointer = @line.bytesize
|
1561
|
+
@line += @buffer_of_lines.delete_at(@line_index + 1)
|
1562
|
+
@cursor_max = calculate_width(@line)
|
1563
|
+
@buffer_of_lines[@line_index] = @line
|
1564
|
+
@rerender_all = true
|
1565
|
+
@rest_height += 1
|
1400
1566
|
end
|
1401
1567
|
end
|
1402
1568
|
|
@@ -1410,7 +1576,7 @@ class Reline::LineEditor
|
|
1410
1576
|
end
|
1411
1577
|
end
|
1412
1578
|
|
1413
|
-
private def
|
1579
|
+
private def em_delete(key)
|
1414
1580
|
if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
|
1415
1581
|
@line = nil
|
1416
1582
|
if @buffer_of_lines.size > 1
|
@@ -1435,7 +1601,19 @@ class Reline::LineEditor
|
|
1435
1601
|
@rest_height += 1
|
1436
1602
|
end
|
1437
1603
|
end
|
1438
|
-
alias_method :delete_char, :
|
1604
|
+
alias_method :delete_char, :em_delete
|
1605
|
+
|
1606
|
+
private def em_delete_or_list(key)
|
1607
|
+
if @line.empty? or @byte_pointer < @line.bytesize
|
1608
|
+
em_delete(key)
|
1609
|
+
else # show completed list
|
1610
|
+
result = call_completion_proc
|
1611
|
+
if result.is_a?(Array)
|
1612
|
+
complete(result, true)
|
1613
|
+
end
|
1614
|
+
end
|
1615
|
+
end
|
1616
|
+
alias_method :delete_char_or_list, :em_delete_or_list
|
1439
1617
|
|
1440
1618
|
private def em_yank(key)
|
1441
1619
|
yanked = @kill_ring.yank
|
@@ -1739,18 +1917,6 @@ class Reline::LineEditor
|
|
1739
1917
|
private def vi_yank(key)
|
1740
1918
|
end
|
1741
1919
|
|
1742
|
-
private def vi_end_of_transmission(key)
|
1743
|
-
if @line.empty?
|
1744
|
-
@line = nil
|
1745
|
-
if @buffer_of_lines.size > 1
|
1746
|
-
scroll_down(@highest_in_all - @first_line_started_from)
|
1747
|
-
end
|
1748
|
-
Reline::IOGate.move_cursor_column(0)
|
1749
|
-
@eof = true
|
1750
|
-
finish
|
1751
|
-
end
|
1752
|
-
end
|
1753
|
-
|
1754
1920
|
private def vi_list_or_eof(key)
|
1755
1921
|
if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
|
1756
1922
|
@line = nil
|
@@ -1761,9 +1927,11 @@ class Reline::LineEditor
|
|
1761
1927
|
@eof = true
|
1762
1928
|
finish
|
1763
1929
|
else
|
1764
|
-
|
1930
|
+
ed_newline(key)
|
1765
1931
|
end
|
1766
1932
|
end
|
1933
|
+
alias_method :vi_end_of_transmission, :vi_list_or_eof
|
1934
|
+
alias_method :vi_eof_maybe, :vi_list_or_eof
|
1767
1935
|
|
1768
1936
|
private def ed_delete_next_char(key, arg: 1)
|
1769
1937
|
byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
|
data/lib/reline/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: io-console
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.5'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,14 +105,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
91
105
|
requirements:
|
92
106
|
- - ">="
|
93
107
|
- !ruby/object:Gem::Version
|
94
|
-
version: '
|
108
|
+
version: '2.5'
|
95
109
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
110
|
requirements:
|
97
111
|
- - ">="
|
98
112
|
- !ruby/object:Gem::Version
|
99
113
|
version: '0'
|
100
114
|
requirements: []
|
101
|
-
rubygems_version: 3.
|
115
|
+
rubygems_version: 3.1.2
|
102
116
|
signing_key:
|
103
117
|
specification_version: 4
|
104
118
|
summary: Alternative GNU Readline or Editline implementation by pure Ruby.
|