reline 0.0.7 → 0.1.0
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 +20 -5
- data/lib/reline/ansi.rb +12 -15
- data/lib/reline/config.rb +2 -2
- data/lib/reline/history.rb +1 -1
- data/lib/reline/key_actor/emacs.rb +1 -1
- 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 +195 -58
- 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: d28ea6c28099d6ee05888e139f26785b7f524b2d43b97169a262d3039fe4b12d
|
4
|
+
data.tar.gz: c929cedf8040597cdaf6d19ab14aa6724cf4b47dbf4c78b6a1fc2e74637bfc09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9c4c8c540077105e8c326dd7ee0de350dbf8cd7a0aba14ad467f28b2dbb9c52eade5601e56ada651d2ea6f713e2a47891545bccdd9ea11c43d01dfe315fdd27
|
7
|
+
data.tar.gz: 7e8a2c186e0b4c84e3a7ddc62ab08dce768d1ea768ffc91bcf880e0227bb003c2b8fa288e45044cf1ab73144bd7ec46e9ac0faa582721acaf55726fc111706d4
|
data/lib/reline.rb
CHANGED
@@ -32,19 +32,17 @@ module Reline
|
|
32
32
|
dig_perfect_match_proc
|
33
33
|
).each(&method(:attr_reader))
|
34
34
|
|
35
|
-
ATTR_ACCESSOR_NAMES = %i(
|
36
|
-
completion_case_fold
|
37
|
-
).each(&method(:attr_accessor))
|
38
|
-
|
39
35
|
attr_accessor :config
|
40
36
|
attr_accessor :key_stroke
|
41
37
|
attr_accessor :line_editor
|
42
38
|
attr_accessor :ambiguous_width
|
39
|
+
attr_accessor :last_incremental_search
|
43
40
|
attr_reader :output
|
44
41
|
|
45
42
|
def initialize
|
46
43
|
self.output = STDOUT
|
47
44
|
yield self
|
45
|
+
@completion_quote_character = nil
|
48
46
|
end
|
49
47
|
|
50
48
|
def completion_append_character=(val)
|
@@ -83,6 +81,18 @@ module Reline
|
|
83
81
|
@special_prefixes = v.encode(Encoding::default_external)
|
84
82
|
end
|
85
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
|
+
|
86
96
|
def completion_proc=(p)
|
87
97
|
raise ArgumentError unless p.respond_to?(:call)
|
88
98
|
@completion_proc = p
|
@@ -202,6 +212,7 @@ module Reline
|
|
202
212
|
end
|
203
213
|
line_editor.output = output
|
204
214
|
line_editor.completion_proc = completion_proc
|
215
|
+
line_editor.completion_append_character = completion_append_character
|
205
216
|
line_editor.output_modifier_proc = output_modifier_proc
|
206
217
|
line_editor.prompt_proc = prompt_proc
|
207
218
|
line_editor.auto_indent_proc = auto_indent_proc
|
@@ -335,12 +346,14 @@ module Reline
|
|
335
346
|
# Documented API
|
336
347
|
#--------------------------------------------------------
|
337
348
|
|
338
|
-
(Core::ATTR_READER_NAMES
|
349
|
+
(Core::ATTR_READER_NAMES).each { |name|
|
339
350
|
def_single_delegators :core, "#{name}", "#{name}="
|
340
351
|
}
|
341
352
|
def_single_delegators :core, :input=, :output=
|
342
353
|
def_single_delegators :core, :vi_editing_mode, :emacs_editing_mode
|
343
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
|
344
357
|
def_instance_delegators self, :readline
|
345
358
|
private :readline
|
346
359
|
|
@@ -367,6 +380,8 @@ module Reline
|
|
367
380
|
def_single_delegator :line_editor, :rerender, :redisplay
|
368
381
|
def_single_delegators :core, :vi_editing_mode?, :emacs_editing_mode?
|
369
382
|
def_single_delegators :core, :ambiguous_width
|
383
|
+
def_single_delegators :core, :last_incremental_search
|
384
|
+
def_single_delegators :core, :last_incremental_search=
|
370
385
|
|
371
386
|
def_single_delegators :core, :readmultiline
|
372
387
|
def_instance_delegators self, :readmultiline
|
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, # ↑
|
@@ -11,6 +13,8 @@ class Reline::ANSI
|
|
11
13
|
[27, 91, 70] => :ed_move_to_end, # End
|
12
14
|
[27, 32] => :em_set_mark, # M-<space>
|
13
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+←
|
14
18
|
}
|
15
19
|
|
16
20
|
@@input = STDIN
|
@@ -28,7 +32,8 @@ class Reline::ANSI
|
|
28
32
|
unless @@buf.empty?
|
29
33
|
return @@buf.shift
|
30
34
|
end
|
31
|
-
@@input.getbyte
|
35
|
+
c = @@input.raw(intr: true, &:getbyte)
|
36
|
+
(c == 0x16 && @@input.raw(min: 0, tim: 0, &:getbyte)) || c
|
32
37
|
end
|
33
38
|
|
34
39
|
def self.ungetc(c)
|
@@ -60,14 +65,18 @@ class Reline::ANSI
|
|
60
65
|
def self.cursor_pos
|
61
66
|
begin
|
62
67
|
res = ''
|
68
|
+
m = nil
|
63
69
|
@@input.raw do |stdin|
|
64
70
|
@@output << "\e[6n"
|
65
71
|
@@output.flush
|
66
72
|
while (c = stdin.getc) != 'R'
|
67
73
|
res << c if c
|
68
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
|
69
79
|
end
|
70
|
-
m = res.match(/(?<row>\d+);(?<column>\d+)/)
|
71
80
|
column = m[:column].to_i - 1
|
72
81
|
row = m[:row].to_i - 1
|
73
82
|
rescue Errno::ENOTTY
|
@@ -120,24 +129,12 @@ class Reline::ANSI
|
|
120
129
|
def self.prep
|
121
130
|
retrieve_keybuffer
|
122
131
|
int_handle = Signal.trap('INT', 'IGNORE')
|
123
|
-
otio = `stty -g`.chomp
|
124
|
-
setting = ' -echo -icrnl cbreak'
|
125
|
-
stty = `stty -a`
|
126
|
-
if /-parenb\b/ =~ stty
|
127
|
-
setting << ' pass8'
|
128
|
-
end
|
129
|
-
if /\bdsusp *=/ =~ stty
|
130
|
-
setting << ' dsusp undef'
|
131
|
-
end
|
132
|
-
setting << ' -ixoff'
|
133
|
-
`stty #{setting}`
|
134
132
|
Signal.trap('INT', int_handle)
|
135
|
-
|
133
|
+
nil
|
136
134
|
end
|
137
135
|
|
138
136
|
def self.deprep(otio)
|
139
137
|
int_handle = Signal.trap('INT', 'IGNORE')
|
140
|
-
system("stty #{otio}", err: File::NULL)
|
141
138
|
Signal.trap('INT', int_handle)
|
142
139
|
Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
|
143
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
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
|
|
@@ -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
|
@@ -587,20 +602,28 @@ class Reline::LineEditor
|
|
587
602
|
when CompletionState::PERFECT_MATCH
|
588
603
|
@dig_perfect_match_proc&.(@perfect_matched)
|
589
604
|
end
|
590
|
-
is_menu = (@completion_state == CompletionState::MENU)
|
605
|
+
is_menu = (@completion_state == CompletionState::MENU or @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH)
|
591
606
|
result = complete_internal_proc(list, is_menu)
|
607
|
+
if @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH
|
608
|
+
@completion_state = CompletionState::PERFECT_MATCH
|
609
|
+
end
|
592
610
|
return if result.nil?
|
593
611
|
target, preposing, completed, postposing = result
|
594
612
|
return if completed.nil?
|
595
|
-
if target <= completed and (@completion_state == CompletionState::COMPLETION
|
596
|
-
@completion_state = CompletionState::MENU
|
613
|
+
if target <= completed and (@completion_state == CompletionState::COMPLETION)
|
597
614
|
if list.include?(completed)
|
598
|
-
|
615
|
+
if list.one?
|
616
|
+
@completion_state = CompletionState::PERFECT_MATCH
|
617
|
+
else
|
618
|
+
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
|
619
|
+
end
|
599
620
|
@perfect_matched = completed
|
621
|
+
else
|
622
|
+
@completion_state = CompletionState::MENU
|
600
623
|
end
|
601
624
|
if target < completed
|
602
|
-
@line = preposing + completed + postposing
|
603
|
-
line_to_pointer = preposing + completed
|
625
|
+
@line = preposing + completed + completion_append_character.to_s + postposing
|
626
|
+
line_to_pointer = preposing + completed + completion_append_character.to_s
|
604
627
|
@cursor_max = calculate_width(@line)
|
605
628
|
@cursor = calculate_width(line_to_pointer)
|
606
629
|
@byte_pointer = line_to_pointer.bytesize
|
@@ -610,7 +633,8 @@ class Reline::LineEditor
|
|
610
633
|
|
611
634
|
private def move_completed_list(list, direction)
|
612
635
|
case @completion_state
|
613
|
-
when CompletionState::NORMAL, CompletionState::COMPLETION,
|
636
|
+
when CompletionState::NORMAL, CompletionState::COMPLETION,
|
637
|
+
CompletionState::MENU, CompletionState::MENU_WITH_PERFECT_MATCH
|
614
638
|
@completion_state = CompletionState::JOURNEY
|
615
639
|
result = retrieve_completion_block
|
616
640
|
return if result.nil?
|
@@ -776,20 +800,20 @@ class Reline::LineEditor
|
|
776
800
|
@first_char = false
|
777
801
|
completion_occurs = false
|
778
802
|
if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
803
|
+
unless @config.disable_completion
|
804
|
+
result = call_completion_proc
|
805
|
+
if result.is_a?(Array)
|
806
|
+
completion_occurs = true
|
807
|
+
complete(result)
|
808
|
+
end
|
785
809
|
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
|
-
|
810
|
+
elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
|
811
|
+
unless @config.disable_completion
|
812
|
+
result = call_completion_proc
|
813
|
+
if result.is_a?(Array)
|
814
|
+
completion_occurs = true
|
815
|
+
move_completed_list(result, "\C-p".ord == key.char ? :up : :down)
|
816
|
+
end
|
793
817
|
end
|
794
818
|
elsif Symbol === key.char and respond_to?(key.char, true)
|
795
819
|
process_key(key.char, key.char)
|
@@ -804,6 +828,14 @@ class Reline::LineEditor
|
|
804
828
|
end
|
805
829
|
end
|
806
830
|
|
831
|
+
def call_completion_proc
|
832
|
+
result = retrieve_completion_block(true)
|
833
|
+
slice = result[1]
|
834
|
+
result = @completion_proc.(slice) if @completion_proc and slice
|
835
|
+
Reline.core.instance_variable_set(:@completion_quote_character, nil)
|
836
|
+
result
|
837
|
+
end
|
838
|
+
|
807
839
|
private def process_auto_indent
|
808
840
|
return if not @check_new_auto_indent and @previous_line_index # move cursor up or down
|
809
841
|
if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index
|
@@ -815,12 +847,9 @@ class Reline::LineEditor
|
|
815
847
|
@line = ' ' * new_indent + @line.lstrip
|
816
848
|
|
817
849
|
new_indent = nil
|
818
|
-
(new_lines[-2].size + 1)
|
819
|
-
|
820
|
-
|
821
|
-
new_indent = result
|
822
|
-
break
|
823
|
-
end
|
850
|
+
result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[-2].size + 1), false)
|
851
|
+
if result
|
852
|
+
new_indent = result
|
824
853
|
end
|
825
854
|
if new_indent&.>= 0
|
826
855
|
@line = ' ' * new_indent + @line.lstrip
|
@@ -848,7 +877,7 @@ class Reline::LineEditor
|
|
848
877
|
@check_new_auto_indent = false
|
849
878
|
end
|
850
879
|
|
851
|
-
def retrieve_completion_block
|
880
|
+
def retrieve_completion_block(set_completion_quote_character = false)
|
852
881
|
word_break_regexp = /\A[#{Regexp.escape(Reline.completer_word_break_characters)}]/
|
853
882
|
quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/
|
854
883
|
before = @line.byteslice(0, @byte_pointer)
|
@@ -867,14 +896,18 @@ class Reline::LineEditor
|
|
867
896
|
if quote and slice.start_with?(closing_quote)
|
868
897
|
quote = nil
|
869
898
|
i += 1
|
899
|
+
rest = nil
|
900
|
+
break_pointer = nil
|
870
901
|
elsif quote and slice.start_with?(escaped_quote)
|
871
902
|
# skip
|
872
903
|
i += 2
|
873
904
|
elsif slice =~ quote_characters_regexp # find new "
|
905
|
+
rest = $'
|
874
906
|
quote = $&
|
875
907
|
closing_quote = /(?!\\)#{Regexp.escape(quote)}/
|
876
908
|
escaped_quote = /\\#{Regexp.escape(quote)}/
|
877
909
|
i += 1
|
910
|
+
break_pointer = i
|
878
911
|
elsif not quote and slice =~ word_break_regexp
|
879
912
|
rest = $'
|
880
913
|
i += 1
|
@@ -883,15 +916,21 @@ class Reline::LineEditor
|
|
883
916
|
i += 1
|
884
917
|
end
|
885
918
|
end
|
919
|
+
postposing = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
|
886
920
|
if rest
|
887
921
|
preposing = @line.byteslice(0, break_pointer)
|
888
922
|
target = rest
|
923
|
+
if set_completion_quote_character and quote
|
924
|
+
Reline.core.instance_variable_set(:@completion_quote_character, quote)
|
925
|
+
if postposing !~ /(?!\\)#{Regexp.escape(quote)}/ # closing quote
|
926
|
+
insert_text(quote)
|
927
|
+
end
|
928
|
+
end
|
889
929
|
else
|
890
930
|
preposing = ''
|
891
931
|
target = before
|
892
932
|
end
|
893
|
-
|
894
|
-
[preposing, target, postposing]
|
933
|
+
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
|
895
934
|
end
|
896
935
|
|
897
936
|
def confirm_multiline_termination
|
@@ -1144,25 +1183,34 @@ class Reline::LineEditor
|
|
1144
1183
|
end
|
1145
1184
|
alias_method :end_of_line, :ed_move_to_end
|
1146
1185
|
|
1147
|
-
private def
|
1148
|
-
|
1149
|
-
|
1150
|
-
else
|
1151
|
-
@line_backup_in_history = @line
|
1152
|
-
end
|
1153
|
-
searcher = Fiber.new do
|
1186
|
+
private def generate_searcher
|
1187
|
+
Fiber.new do |first_key|
|
1188
|
+
prev_search_key = first_key
|
1154
1189
|
search_word = String.new(encoding: @encoding)
|
1155
1190
|
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
1156
1191
|
last_hit = nil
|
1192
|
+
case first_key
|
1193
|
+
when "\C-r".ord
|
1194
|
+
prompt_name = 'reverse-i-search'
|
1195
|
+
when "\C-s".ord
|
1196
|
+
prompt_name = 'i-search'
|
1197
|
+
end
|
1157
1198
|
loop do
|
1158
1199
|
key = Fiber.yield(search_word)
|
1200
|
+
search_again = false
|
1159
1201
|
case key
|
1160
|
-
when
|
1202
|
+
when -1 # determined
|
1203
|
+
Reline.last_incremental_search = search_word
|
1204
|
+
break
|
1205
|
+
when "\C-h".ord, "\C-?".ord
|
1161
1206
|
grapheme_clusters = search_word.grapheme_clusters
|
1162
1207
|
if grapheme_clusters.size > 0
|
1163
1208
|
grapheme_clusters.pop
|
1164
1209
|
search_word = grapheme_clusters.join
|
1165
1210
|
end
|
1211
|
+
when "\C-r".ord, "\C-s".ord
|
1212
|
+
search_again = true if prev_search_key == key
|
1213
|
+
prev_search_key = key
|
1166
1214
|
else
|
1167
1215
|
multibyte_buf << key
|
1168
1216
|
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
@@ -1171,18 +1219,61 @@ class Reline::LineEditor
|
|
1171
1219
|
end
|
1172
1220
|
end
|
1173
1221
|
hit = nil
|
1174
|
-
if @line_backup_in_history
|
1222
|
+
if not search_word.empty? and @line_backup_in_history&.include?(search_word)
|
1175
1223
|
@history_pointer = nil
|
1176
1224
|
hit = @line_backup_in_history
|
1177
1225
|
else
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1226
|
+
if search_again
|
1227
|
+
if search_word.empty? and Reline.last_incremental_search
|
1228
|
+
search_word = Reline.last_incremental_search
|
1229
|
+
end
|
1230
|
+
if @history_pointer # TODO
|
1231
|
+
case prev_search_key
|
1232
|
+
when "\C-r".ord
|
1233
|
+
history_pointer_base = 0
|
1234
|
+
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
1235
|
+
when "\C-s".ord
|
1236
|
+
history_pointer_base = @history_pointer + 1
|
1237
|
+
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
1238
|
+
end
|
1239
|
+
else
|
1240
|
+
history_pointer_base = 0
|
1241
|
+
history = Reline::HISTORY
|
1242
|
+
end
|
1243
|
+
elsif @history_pointer
|
1244
|
+
case prev_search_key
|
1245
|
+
when "\C-r".ord
|
1246
|
+
history_pointer_base = 0
|
1247
|
+
history = Reline::HISTORY[0..@history_pointer]
|
1248
|
+
when "\C-s".ord
|
1249
|
+
history_pointer_base = @history_pointer
|
1250
|
+
history = Reline::HISTORY[@history_pointer..-1]
|
1251
|
+
end
|
1252
|
+
else
|
1253
|
+
history_pointer_base = 0
|
1254
|
+
history = Reline::HISTORY
|
1255
|
+
end
|
1256
|
+
case prev_search_key
|
1257
|
+
when "\C-r".ord
|
1258
|
+
hit_index = history.rindex { |item|
|
1259
|
+
item.include?(search_word)
|
1260
|
+
}
|
1261
|
+
when "\C-s".ord
|
1262
|
+
hit_index = history.index { |item|
|
1263
|
+
item.include?(search_word)
|
1264
|
+
}
|
1265
|
+
end
|
1181
1266
|
if hit_index
|
1182
|
-
@history_pointer = hit_index
|
1267
|
+
@history_pointer = history_pointer_base + hit_index
|
1183
1268
|
hit = Reline::HISTORY[@history_pointer]
|
1184
1269
|
end
|
1185
1270
|
end
|
1271
|
+
case prev_search_key
|
1272
|
+
when "\C-r".ord
|
1273
|
+
prompt_name = 'reverse-i-search'
|
1274
|
+
when "\C-s".ord
|
1275
|
+
prompt_name = 'i-search'
|
1276
|
+
end
|
1186
1277
|
if hit
|
1187
1278
|
if @is_multiline
|
1188
1279
|
@buffer_of_lines = hit.split("\n")
|
@@ -1190,47 +1281,77 @@ class Reline::LineEditor
|
|
1190
1281
|
@line_index = @buffer_of_lines.size - 1
|
1191
1282
|
@line = @buffer_of_lines.last
|
1192
1283
|
@rerender_all = true
|
1193
|
-
@searching_prompt = "(
|
1284
|
+
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1194
1285
|
else
|
1195
1286
|
@line = hit
|
1196
|
-
@searching_prompt = "(
|
1287
|
+
@searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
|
1197
1288
|
end
|
1198
1289
|
last_hit = hit
|
1199
1290
|
else
|
1200
1291
|
if @is_multiline
|
1201
1292
|
@rerender_all = true
|
1202
|
-
@searching_prompt = "(failed
|
1293
|
+
@searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
|
1203
1294
|
else
|
1204
|
-
@searching_prompt = "(failed
|
1295
|
+
@searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
|
1205
1296
|
end
|
1206
1297
|
end
|
1207
1298
|
end
|
1208
1299
|
end
|
1209
|
-
|
1300
|
+
end
|
1301
|
+
|
1302
|
+
private def search_history(key)
|
1303
|
+
unless @history_pointer
|
1304
|
+
if @is_multiline
|
1305
|
+
@line_backup_in_history = whole_buffer
|
1306
|
+
else
|
1307
|
+
@line_backup_in_history = @line
|
1308
|
+
end
|
1309
|
+
end
|
1310
|
+
searcher = generate_searcher
|
1311
|
+
searcher.resume(key)
|
1210
1312
|
@searching_prompt = "(reverse-i-search)`': "
|
1211
1313
|
@waiting_proc = ->(k) {
|
1212
1314
|
case k
|
1213
|
-
when "\C-j".ord
|
1315
|
+
when "\C-j".ord
|
1214
1316
|
if @history_pointer
|
1215
|
-
|
1317
|
+
buffer = Reline::HISTORY[@history_pointer]
|
1216
1318
|
else
|
1217
|
-
|
1319
|
+
buffer = @line_backup_in_history
|
1320
|
+
end
|
1321
|
+
if @is_multiline
|
1322
|
+
@buffer_of_lines = buffer.split("\n")
|
1323
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1324
|
+
@line_index = @buffer_of_lines.size - 1
|
1325
|
+
@line = @buffer_of_lines.last
|
1326
|
+
@rerender_all = true
|
1327
|
+
else
|
1328
|
+
@line = buffer
|
1218
1329
|
end
|
1219
1330
|
@searching_prompt = nil
|
1220
1331
|
@waiting_proc = nil
|
1221
1332
|
@cursor_max = calculate_width(@line)
|
1222
1333
|
@cursor = @byte_pointer = 0
|
1334
|
+
searcher.resume(-1)
|
1223
1335
|
when "\C-g".ord
|
1224
|
-
|
1336
|
+
if @is_multiline
|
1337
|
+
@buffer_of_lines = @line_backup_in_history.split("\n")
|
1338
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1339
|
+
@line_index = @buffer_of_lines.size - 1
|
1340
|
+
@line = @buffer_of_lines.last
|
1341
|
+
@rerender_all = true
|
1342
|
+
else
|
1343
|
+
@line = @line_backup_in_history
|
1344
|
+
end
|
1225
1345
|
@history_pointer = nil
|
1226
1346
|
@searching_prompt = nil
|
1227
1347
|
@waiting_proc = nil
|
1228
1348
|
@line_backup_in_history = nil
|
1229
1349
|
@cursor_max = calculate_width(@line)
|
1230
1350
|
@cursor = @byte_pointer = 0
|
1351
|
+
@rerender_all = true
|
1231
1352
|
else
|
1232
1353
|
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1233
|
-
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k ==
|
1354
|
+
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
|
1234
1355
|
searcher.resume(k)
|
1235
1356
|
else
|
1236
1357
|
if @history_pointer
|
@@ -1253,13 +1374,21 @@ class Reline::LineEditor
|
|
1253
1374
|
@waiting_proc = nil
|
1254
1375
|
@cursor_max = calculate_width(@line)
|
1255
1376
|
@cursor = @byte_pointer = 0
|
1377
|
+
searcher.resume(-1)
|
1256
1378
|
end
|
1257
1379
|
end
|
1258
1380
|
}
|
1259
1381
|
end
|
1260
1382
|
|
1383
|
+
private def ed_search_prev_history(key)
|
1384
|
+
search_history(key)
|
1385
|
+
end
|
1386
|
+
alias_method :reverse_search_history, :ed_search_prev_history
|
1387
|
+
|
1261
1388
|
private def ed_search_next_history(key)
|
1389
|
+
search_history(key)
|
1262
1390
|
end
|
1391
|
+
alias_method :forward_search_history, :ed_search_next_history
|
1263
1392
|
|
1264
1393
|
private def ed_prev_history(key, arg: 1)
|
1265
1394
|
if @is_multiline and @line_index > 0
|
@@ -1417,6 +1546,14 @@ class Reline::LineEditor
|
|
1417
1546
|
@byte_pointer = @line.bytesize
|
1418
1547
|
@cursor = @cursor_max = calculate_width(@line)
|
1419
1548
|
@kill_ring.append(deleted)
|
1549
|
+
elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1
|
1550
|
+
@cursor = calculate_width(@line)
|
1551
|
+
@byte_pointer = @line.bytesize
|
1552
|
+
@line += @buffer_of_lines.delete_at(@line_index + 1)
|
1553
|
+
@cursor_max = calculate_width(@line)
|
1554
|
+
@buffer_of_lines[@line_index] = @line
|
1555
|
+
@rerender_all = true
|
1556
|
+
@rest_height += 1
|
1420
1557
|
end
|
1421
1558
|
end
|
1422
1559
|
|
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.0
|
4
|
+
version: 0.1.0
|
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-24 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.0.
|
115
|
+
rubygems_version: 3.1.0.pre3
|
102
116
|
signing_key:
|
103
117
|
specification_version: 4
|
104
118
|
summary: Alternative GNU Readline or Editline implementation by pure Ruby.
|