reline 0.0.1 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/lib/reline.rb +329 -334
- data/lib/reline/ansi.rb +28 -11
- data/lib/reline/config.rb +4 -5
- data/lib/reline/general_io.rb +4 -1
- data/lib/reline/key_actor/vi_command.rb +1 -1
- data/lib/reline/key_actor/vi_insert.rb +1 -1
- data/lib/reline/key_stroke.rb +1 -1
- data/lib/reline/line_editor.rb +181 -76
- data/lib/reline/unicode/east_asian_width.rb +1 -1
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +109 -65
- metadata +4 -4
data/lib/reline/ansi.rb
CHANGED
@@ -7,7 +7,11 @@ class Reline::ANSI
|
|
7
7
|
[27, 91, 51, 126] => :key_delete, # Del
|
8
8
|
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
9
9
|
[27, 91, 52, 126] => :ed_move_to_end, # End
|
10
|
-
|
10
|
+
[27, 91, 72] => :ed_move_to_beg, # Home
|
11
|
+
[27, 91, 70] => :ed_move_to_end, # End
|
12
|
+
[27, 32] => :em_set_mark, # M-<space>
|
13
|
+
[24, 24] => :em_exchange_mark, # C-x C-x TODO also add Windows
|
14
|
+
}
|
11
15
|
|
12
16
|
@@input = STDIN
|
13
17
|
def self.input=(val)
|
@@ -24,20 +28,22 @@ class Reline::ANSI
|
|
24
28
|
unless @@buf.empty?
|
25
29
|
return @@buf.shift
|
26
30
|
end
|
27
|
-
|
28
|
-
loop do
|
29
|
-
result = select([@@input], [], [], 0.1)
|
30
|
-
next if result.nil?
|
31
|
-
c = @@input.read(1)
|
32
|
-
break
|
33
|
-
end
|
34
|
-
c&.ord
|
31
|
+
@@input.getbyte
|
35
32
|
end
|
36
33
|
|
37
34
|
def self.ungetc(c)
|
38
35
|
@@buf.unshift(c)
|
39
36
|
end
|
40
37
|
|
38
|
+
def self.retrieve_keybuffer
|
39
|
+
result = select([@@input], [], [], 0.001)
|
40
|
+
return if result.nil?
|
41
|
+
str = @@input.read_nonblock(1024)
|
42
|
+
str.bytes.each do |c|
|
43
|
+
@@buf.push(c)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
41
47
|
def self.get_screen_size
|
42
48
|
@@input.winsize
|
43
49
|
rescue Errno::ENOTTY
|
@@ -106,13 +112,23 @@ class Reline::ANSI
|
|
106
112
|
print "\e[1;1H"
|
107
113
|
end
|
108
114
|
|
115
|
+
@@old_winch_handler = nil
|
116
|
+
def self.set_winch_handler(&handler)
|
117
|
+
@@old_winch_handler = Signal.trap('WINCH', &handler)
|
118
|
+
end
|
119
|
+
|
109
120
|
def self.prep
|
121
|
+
retrieve_keybuffer
|
110
122
|
int_handle = Signal.trap('INT', 'IGNORE')
|
111
123
|
otio = `stty -g`.chomp
|
112
124
|
setting = ' -echo -icrnl cbreak'
|
113
|
-
|
125
|
+
stty = `stty -a`
|
126
|
+
if /-parenb\b/ =~ stty
|
114
127
|
setting << ' pass8'
|
115
128
|
end
|
129
|
+
if /\bdsusp *=/ =~ stty
|
130
|
+
setting << ' dsusp undef'
|
131
|
+
end
|
116
132
|
setting << ' -ixoff'
|
117
133
|
`stty #{setting}`
|
118
134
|
Signal.trap('INT', int_handle)
|
@@ -121,7 +137,8 @@ class Reline::ANSI
|
|
121
137
|
|
122
138
|
def self.deprep(otio)
|
123
139
|
int_handle = Signal.trap('INT', 'IGNORE')
|
124
|
-
|
140
|
+
system("stty #{otio}", err: File::NULL)
|
125
141
|
Signal.trap('INT', int_handle)
|
142
|
+
Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
|
126
143
|
end
|
127
144
|
end
|
data/lib/reline/config.rb
CHANGED
@@ -126,20 +126,19 @@ class Reline::Config
|
|
126
126
|
no += 1
|
127
127
|
|
128
128
|
line = line.chomp.lstrip
|
129
|
-
if line
|
129
|
+
if line.start_with?('$')
|
130
130
|
handle_directive(line[1..-1], file, no)
|
131
131
|
next
|
132
132
|
end
|
133
133
|
|
134
134
|
next if @skip_section
|
135
135
|
|
136
|
-
|
136
|
+
case line
|
137
|
+
when /^set +([^ ]+) +([^ ]+)/i
|
137
138
|
var, value = $1.downcase, $2.downcase
|
138
139
|
bind_variable(var, value)
|
139
140
|
next
|
140
|
-
|
141
|
-
|
142
|
-
if line =~ /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/
|
141
|
+
when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
|
143
142
|
key, func_name = $1, $2
|
144
143
|
keystroke, func = bind_key(key, func_name)
|
145
144
|
next unless keystroke
|
data/lib/reline/general_io.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'timeout'
|
2
2
|
|
3
3
|
class Reline::GeneralIO
|
4
|
-
RAW_KEYSTROKE_CONFIG = {}
|
4
|
+
RAW_KEYSTROKE_CONFIG = {}
|
5
5
|
|
6
6
|
@@buf = []
|
7
7
|
|
@@ -56,6 +56,9 @@ class Reline::GeneralIO
|
|
56
56
|
def self.set_screen_size(rows, columns)
|
57
57
|
end
|
58
58
|
|
59
|
+
def self.set_winch_handler(&handler)
|
60
|
+
end
|
61
|
+
|
59
62
|
def self.prep
|
60
63
|
end
|
61
64
|
|
data/lib/reline/key_stroke.rb
CHANGED
@@ -32,7 +32,7 @@ class Reline::KeyStroke
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def expand(input)
|
35
|
-
lhs = key_mapping.keys.select { |
|
35
|
+
lhs = key_mapping.keys.select { |item| input.start_with? item }.sort_by(&:size).reverse.first
|
36
36
|
return input unless lhs
|
37
37
|
rhs = key_mapping[lhs]
|
38
38
|
|
data/lib/reline/line_editor.rb
CHANGED
@@ -60,15 +60,72 @@ class Reline::LineEditor
|
|
60
60
|
reset_variables
|
61
61
|
end
|
62
62
|
|
63
|
+
private def check_multiline_prompt(buffer, prompt)
|
64
|
+
if @vi_arg
|
65
|
+
prompt = "(arg: #{@vi_arg}) "
|
66
|
+
@rerender_all = true
|
67
|
+
elsif @searching_prompt
|
68
|
+
prompt = @searching_prompt
|
69
|
+
@rerender_all = true
|
70
|
+
else
|
71
|
+
prompt = @prompt
|
72
|
+
end
|
73
|
+
if @prompt_proc
|
74
|
+
prompt_list = @prompt_proc.(buffer)
|
75
|
+
prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
|
76
|
+
prompt = prompt_list[@line_index]
|
77
|
+
prompt_width = calculate_width(prompt, true)
|
78
|
+
[prompt, prompt_width, prompt_list]
|
79
|
+
else
|
80
|
+
prompt_width = calculate_width(prompt, true)
|
81
|
+
[prompt, prompt_width, nil]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
63
85
|
def reset(prompt = '', encoding = Encoding.default_external)
|
64
86
|
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
65
87
|
@screen_size = Reline::IOGate.get_screen_size
|
66
88
|
reset_variables(prompt, encoding)
|
67
89
|
@old_trap = Signal.trap('SIGINT') {
|
68
|
-
scroll_down(@highest_in_all - @first_line_started_from)
|
69
|
-
Reline::IOGate.move_cursor_column(0)
|
70
90
|
@old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
|
91
|
+
raise Interrupt
|
71
92
|
}
|
93
|
+
Reline::IOGate.set_winch_handler do
|
94
|
+
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
95
|
+
old_screen_size = @screen_size
|
96
|
+
@screen_size = Reline::IOGate.get_screen_size
|
97
|
+
if old_screen_size.last < @screen_size.last # columns increase
|
98
|
+
@rerender_all = true
|
99
|
+
rerender
|
100
|
+
else
|
101
|
+
back = 0
|
102
|
+
new_buffer = whole_lines
|
103
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer, prompt)
|
104
|
+
new_buffer.each_with_index do |line, index|
|
105
|
+
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
106
|
+
width = prompt_width + calculate_width(line)
|
107
|
+
height = calculate_height_by_width(width)
|
108
|
+
back += height
|
109
|
+
end
|
110
|
+
@highest_in_all = back
|
111
|
+
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
112
|
+
@first_line_started_from =
|
113
|
+
if @line_index.zero?
|
114
|
+
0
|
115
|
+
else
|
116
|
+
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list)
|
117
|
+
end
|
118
|
+
if @prompt_proc
|
119
|
+
prompt = prompt_list[@line_index]
|
120
|
+
prompt_width = calculate_width(prompt, true)
|
121
|
+
end
|
122
|
+
calculate_nearest_cursor
|
123
|
+
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
124
|
+
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
125
|
+
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
126
|
+
@rerender_all = true
|
127
|
+
end
|
128
|
+
end
|
72
129
|
end
|
73
130
|
|
74
131
|
def finalize
|
@@ -81,6 +138,7 @@ class Reline::LineEditor
|
|
81
138
|
|
82
139
|
def reset_variables(prompt = '', encoding = Encoding.default_external)
|
83
140
|
@prompt = prompt
|
141
|
+
@mark_pointer = nil
|
84
142
|
@encoding = encoding
|
85
143
|
@is_multiline = false
|
86
144
|
@finished = false
|
@@ -129,6 +187,16 @@ class Reline::LineEditor
|
|
129
187
|
@is_multiline = false
|
130
188
|
end
|
131
189
|
|
190
|
+
private def calculate_height_by_lines(lines, prompt_list)
|
191
|
+
result = 0
|
192
|
+
lines.each_with_index { |line, i|
|
193
|
+
prompt = ''
|
194
|
+
prompt = prompt_list[i] if prompt_list and prompt_list[i]
|
195
|
+
result += calculate_height_by_width(calculate_width(prompt + line))
|
196
|
+
}
|
197
|
+
result
|
198
|
+
end
|
199
|
+
|
132
200
|
private def insert_new_line(cursor_line, next_line)
|
133
201
|
@line = cursor_line
|
134
202
|
@buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding: @encoding))
|
@@ -241,7 +309,7 @@ class Reline::LineEditor
|
|
241
309
|
@byte_pointer = new_byte_pointer
|
242
310
|
end
|
243
311
|
|
244
|
-
def rerender
|
312
|
+
def rerender
|
245
313
|
return if @line.nil?
|
246
314
|
if @menu_info
|
247
315
|
scroll_down(@highest_in_all - @first_line_started_from)
|
@@ -249,32 +317,18 @@ class Reline::LineEditor
|
|
249
317
|
@menu_info.list.each do |item|
|
250
318
|
Reline::IOGate.move_cursor_column(0)
|
251
319
|
@output.print item
|
320
|
+
@output.flush
|
252
321
|
scroll_down(1)
|
253
322
|
end
|
254
323
|
scroll_down(@highest_in_all - 1)
|
255
324
|
move_cursor_up(@highest_in_all - 1 - @first_line_started_from)
|
256
325
|
@menu_info = nil
|
257
326
|
end
|
258
|
-
|
259
|
-
prompt = "(arg: #{@vi_arg}) "
|
260
|
-
prompt_width = calculate_width(prompt)
|
261
|
-
elsif @searching_prompt
|
262
|
-
prompt = @searching_prompt
|
263
|
-
prompt_width = calculate_width(prompt)
|
264
|
-
else
|
265
|
-
prompt = @prompt
|
266
|
-
prompt_width = calculate_width(prompt, true)
|
267
|
-
end
|
327
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
|
268
328
|
if @cleared
|
269
329
|
Reline::IOGate.clear_screen
|
270
330
|
@cleared = false
|
271
331
|
back = 0
|
272
|
-
prompt_list = nil
|
273
|
-
if @prompt_proc
|
274
|
-
prompt_list = @prompt_proc.(whole_lines)
|
275
|
-
prompt = prompt_list[@line_index]
|
276
|
-
prompt_width = calculate_width(prompt, true)
|
277
|
-
end
|
278
332
|
modify_lines(whole_lines).each_with_index do |line, index|
|
279
333
|
if @prompt_proc
|
280
334
|
pr = prompt_list[index]
|
@@ -300,15 +354,8 @@ class Reline::LineEditor
|
|
300
354
|
else
|
301
355
|
new_lines = whole_lines
|
302
356
|
end
|
303
|
-
prompt_list =
|
304
|
-
|
305
|
-
prompt_list = @prompt_proc.(new_lines)
|
306
|
-
prompt = prompt_list[@line_index]
|
307
|
-
prompt_width = calculate_width(prompt, true)
|
308
|
-
end
|
309
|
-
all_height = new_lines.inject(0) { |result, line|
|
310
|
-
result + calculate_height_by_width(prompt_width + calculate_width(line)) # TODO prompt_list
|
311
|
-
}
|
357
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines, prompt)
|
358
|
+
all_height = calculate_height_by_lines(new_lines, prompt_list)
|
312
359
|
diff = all_height - @highest_in_all
|
313
360
|
move_cursor_down(@highest_in_all - @first_line_started_from - @started_from - 1)
|
314
361
|
if diff > 0
|
@@ -348,9 +395,7 @@ class Reline::LineEditor
|
|
348
395
|
if @line_index.zero?
|
349
396
|
0
|
350
397
|
else
|
351
|
-
@buffer_of_lines[0..(@line_index - 1)]
|
352
|
-
result + calculate_height_by_width(prompt_width + calculate_width(line)) # TODO prompt_list
|
353
|
-
}
|
398
|
+
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list)
|
354
399
|
end
|
355
400
|
if @prompt_proc
|
356
401
|
prompt = prompt_list[@line_index]
|
@@ -369,12 +414,7 @@ class Reline::LineEditor
|
|
369
414
|
Reline::IOGate.move_cursor_column(0)
|
370
415
|
back = 0
|
371
416
|
new_buffer = whole_lines
|
372
|
-
prompt_list =
|
373
|
-
if @prompt_proc
|
374
|
-
prompt_list = @prompt_proc.(new_buffer)
|
375
|
-
prompt = prompt_list[@line_index]
|
376
|
-
prompt_width = calculate_width(prompt, true)
|
377
|
-
end
|
417
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer, prompt)
|
378
418
|
new_buffer.each_with_index do |line, index|
|
379
419
|
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
380
420
|
width = prompt_width + calculate_width(line)
|
@@ -414,9 +454,7 @@ class Reline::LineEditor
|
|
414
454
|
if @line_index.zero?
|
415
455
|
0
|
416
456
|
else
|
417
|
-
new_buffer[0..(@line_index - 1)]
|
418
|
-
result + calculate_height_by_width(prompt_width + calculate_width(line)) # TODO prompt_list
|
419
|
-
}
|
457
|
+
calculate_height_by_lines(new_buffer[0..(@line_index - 1)], prompt_list)
|
420
458
|
end
|
421
459
|
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
422
460
|
move_cursor_down(@first_line_started_from + @started_from)
|
@@ -426,12 +464,7 @@ class Reline::LineEditor
|
|
426
464
|
end
|
427
465
|
line = modify_lines(whole_lines)[@line_index]
|
428
466
|
if @is_multiline
|
429
|
-
prompt_list =
|
430
|
-
if @prompt_proc
|
431
|
-
prompt_list = @prompt_proc.(whole_lines)
|
432
|
-
prompt = prompt_list[@line_index]
|
433
|
-
prompt_width = calculate_width(prompt, true)
|
434
|
-
end
|
467
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
|
435
468
|
if finished?
|
436
469
|
# Always rerender on finish because output_modifier_proc may return a different output.
|
437
470
|
render_partial(prompt, prompt_width, line)
|
@@ -477,6 +510,7 @@ class Reline::LineEditor
|
|
477
510
|
next
|
478
511
|
end
|
479
512
|
@output.print line
|
513
|
+
@output.flush
|
480
514
|
if @first_prompt
|
481
515
|
@first_prompt = false
|
482
516
|
@pre_input_hook&.call
|
@@ -619,9 +653,9 @@ class Reline::LineEditor
|
|
619
653
|
else
|
620
654
|
old_waiting_proc = @waiting_proc
|
621
655
|
old_waiting_operator_proc = @waiting_operator_proc
|
622
|
-
@waiting_proc = proc { |
|
656
|
+
@waiting_proc = proc { |k|
|
623
657
|
old_cursor, old_byte_pointer = @cursor, @byte_pointer
|
624
|
-
old_waiting_proc.(
|
658
|
+
old_waiting_proc.(k)
|
625
659
|
cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer
|
626
660
|
@cursor, @byte_pointer = old_cursor, old_byte_pointer
|
627
661
|
@waiting_operator_proc.(cursor_diff, byte_pointer_diff)
|
@@ -732,7 +766,7 @@ class Reline::LineEditor
|
|
732
766
|
end
|
733
767
|
|
734
768
|
def input_key(key)
|
735
|
-
if key.
|
769
|
+
if key.char.nil?
|
736
770
|
if @first_char
|
737
771
|
@line = nil
|
738
772
|
end
|
@@ -772,6 +806,26 @@ class Reline::LineEditor
|
|
772
806
|
|
773
807
|
private def process_auto_indent
|
774
808
|
return if not @check_new_auto_indent and @previous_line_index # move cursor up or down
|
809
|
+
if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index
|
810
|
+
# Fix indent of a line when a newline is inserted to the next
|
811
|
+
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
812
|
+
new_indent = @auto_indent_proc.(new_lines[0..-3].push(''), @line_index - 1, 0, true)
|
813
|
+
md = @line.match(/\A */)
|
814
|
+
prev_indent = md[0].count(' ')
|
815
|
+
@line = ' ' * new_indent + @line.lstrip
|
816
|
+
|
817
|
+
new_indent = nil
|
818
|
+
(new_lines[-2].size + 1).times do |n|
|
819
|
+
result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, n, false)
|
820
|
+
if result
|
821
|
+
new_indent = result
|
822
|
+
break
|
823
|
+
end
|
824
|
+
end
|
825
|
+
if new_indent&.>= 0
|
826
|
+
@line = ' ' * new_indent + @line.lstrip
|
827
|
+
end
|
828
|
+
end
|
775
829
|
if @previous_line_index
|
776
830
|
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
777
831
|
else
|
@@ -801,17 +855,25 @@ class Reline::LineEditor
|
|
801
855
|
rest = nil
|
802
856
|
break_pointer = nil
|
803
857
|
quote = nil
|
858
|
+
closing_quote = nil
|
859
|
+
escaped_quote = nil
|
804
860
|
i = 0
|
805
861
|
while i < @byte_pointer do
|
806
862
|
slice = @line.byteslice(i, @byte_pointer - i)
|
807
|
-
|
863
|
+
unless slice.valid_encoding?
|
864
|
+
i += 1
|
865
|
+
next
|
866
|
+
end
|
867
|
+
if quote and slice.start_with?(closing_quote)
|
808
868
|
quote = nil
|
809
869
|
i += 1
|
810
|
-
elsif quote and slice.start_with?(
|
870
|
+
elsif quote and slice.start_with?(escaped_quote)
|
811
871
|
# skip
|
812
872
|
i += 2
|
813
873
|
elsif slice =~ quote_characters_regexp # find new "
|
814
874
|
quote = $&
|
875
|
+
closing_quote = /(?!\\)#{Regexp.escape(quote)}/
|
876
|
+
escaped_quote = /\\#{Regexp.escape(quote)}/
|
815
877
|
i += 1
|
816
878
|
elsif not quote and slice =~ word_break_regexp
|
817
879
|
rest = $'
|
@@ -839,11 +901,7 @@ class Reline::LineEditor
|
|
839
901
|
else
|
840
902
|
temp_buffer[@line_index] = @line
|
841
903
|
end
|
842
|
-
|
843
|
-
@confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
|
844
|
-
else
|
845
|
-
false
|
846
|
-
end
|
904
|
+
@confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
|
847
905
|
end
|
848
906
|
|
849
907
|
def insert_text(text)
|
@@ -959,8 +1017,8 @@ class Reline::LineEditor
|
|
959
1017
|
end
|
960
1018
|
width
|
961
1019
|
else
|
962
|
-
str.encode(Encoding::UTF_8).grapheme_clusters.inject(0) { |
|
963
|
-
|
1020
|
+
str.encode(Encoding::UTF_8).grapheme_clusters.inject(0) { |w, gc|
|
1021
|
+
w + Reline::Unicode.get_mbchar_width(gc)
|
964
1022
|
}
|
965
1023
|
end
|
966
1024
|
end
|
@@ -981,6 +1039,8 @@ class Reline::LineEditor
|
|
981
1039
|
end
|
982
1040
|
end
|
983
1041
|
|
1042
|
+
private def ed_unassigned(key) end # do nothing
|
1043
|
+
|
984
1044
|
private def ed_insert(key)
|
985
1045
|
if key.instance_of?(String)
|
986
1046
|
width = Reline::Unicode.get_mbchar_width(key)
|
@@ -1085,7 +1145,11 @@ class Reline::LineEditor
|
|
1085
1145
|
alias_method :end_of_line, :ed_move_to_end
|
1086
1146
|
|
1087
1147
|
private def ed_search_prev_history(key)
|
1088
|
-
|
1148
|
+
if @is_multiline
|
1149
|
+
@line_backup_in_history = whole_buffer
|
1150
|
+
else
|
1151
|
+
@line_backup_in_history = @line
|
1152
|
+
end
|
1089
1153
|
searcher = Fiber.new do
|
1090
1154
|
search_word = String.new(encoding: @encoding)
|
1091
1155
|
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
@@ -1120,18 +1184,32 @@ class Reline::LineEditor
|
|
1120
1184
|
end
|
1121
1185
|
end
|
1122
1186
|
if hit
|
1123
|
-
@
|
1124
|
-
|
1187
|
+
if @is_multiline
|
1188
|
+
@buffer_of_lines = hit.split("\n")
|
1189
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1190
|
+
@line_index = @buffer_of_lines.size - 1
|
1191
|
+
@line = @buffer_of_lines.last
|
1192
|
+
@rerender_all = true
|
1193
|
+
@searching_prompt = "(reverse-i-search)`%s'" % [search_word]
|
1194
|
+
else
|
1195
|
+
@line = hit
|
1196
|
+
@searching_prompt = "(reverse-i-search)`%s': %s" % [search_word, hit]
|
1197
|
+
end
|
1125
1198
|
last_hit = hit
|
1126
1199
|
else
|
1127
|
-
@
|
1200
|
+
if @is_multiline
|
1201
|
+
@rerender_all = true
|
1202
|
+
@searching_prompt = "(failed reverse-i-search)`%s'" % [search_word]
|
1203
|
+
else
|
1204
|
+
@searching_prompt = "(failed reverse-i-search)`%s': %s" % [search_word, last_hit]
|
1205
|
+
end
|
1128
1206
|
end
|
1129
1207
|
end
|
1130
1208
|
end
|
1131
1209
|
searcher.resume
|
1132
1210
|
@searching_prompt = "(reverse-i-search)`': "
|
1133
|
-
@waiting_proc = ->(
|
1134
|
-
case
|
1211
|
+
@waiting_proc = ->(k) {
|
1212
|
+
case k
|
1135
1213
|
when "\C-j".ord, "\C-?".ord
|
1136
1214
|
if @history_pointer
|
1137
1215
|
@line = Reline::HISTORY[@history_pointer]
|
@@ -1151,14 +1229,25 @@ class Reline::LineEditor
|
|
1151
1229
|
@cursor_max = calculate_width(@line)
|
1152
1230
|
@cursor = @byte_pointer = 0
|
1153
1231
|
else
|
1154
|
-
chr =
|
1155
|
-
if chr.match?(/[[:print:]]/)
|
1156
|
-
searcher.resume(
|
1232
|
+
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1233
|
+
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == 127
|
1234
|
+
searcher.resume(k)
|
1157
1235
|
else
|
1158
1236
|
if @history_pointer
|
1159
|
-
|
1237
|
+
line = Reline::HISTORY[@history_pointer]
|
1238
|
+
else
|
1239
|
+
line = @line_backup_in_history
|
1240
|
+
end
|
1241
|
+
if @is_multiline
|
1242
|
+
@line_backup_in_history = whole_buffer
|
1243
|
+
@buffer_of_lines = line.split("\n")
|
1244
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1245
|
+
@line_index = @buffer_of_lines.size - 1
|
1246
|
+
@line = @buffer_of_lines.last
|
1247
|
+
@rerender_all = true
|
1160
1248
|
else
|
1161
|
-
@
|
1249
|
+
@line_backup_in_history = @line
|
1250
|
+
@line = line
|
1162
1251
|
end
|
1163
1252
|
@searching_prompt = nil
|
1164
1253
|
@waiting_proc = nil
|
@@ -1211,7 +1300,7 @@ class Reline::LineEditor
|
|
1211
1300
|
@line = Reline::HISTORY[@history_pointer]
|
1212
1301
|
end
|
1213
1302
|
end
|
1214
|
-
if @config.editing_mode_is?(:emacs)
|
1303
|
+
if @config.editing_mode_is?(:emacs, :vi_insert)
|
1215
1304
|
@cursor_max = @cursor = calculate_width(@line)
|
1216
1305
|
@byte_pointer = @line.bytesize
|
1217
1306
|
elsif @config.editing_mode_is?(:vi_command)
|
@@ -1258,7 +1347,7 @@ class Reline::LineEditor
|
|
1258
1347
|
end
|
1259
1348
|
end
|
1260
1349
|
@line = '' unless @line
|
1261
|
-
if @config.editing_mode_is?(:emacs)
|
1350
|
+
if @config.editing_mode_is?(:emacs, :vi_insert)
|
1262
1351
|
@cursor_max = @cursor = calculate_width(@line)
|
1263
1352
|
@byte_pointer = @line.bytesize
|
1264
1353
|
elsif @config.editing_mode_is?(:vi_command)
|
@@ -1697,8 +1786,8 @@ class Reline::LineEditor
|
|
1697
1786
|
end
|
1698
1787
|
|
1699
1788
|
private def ed_delete_next_char(key, arg: 1)
|
1700
|
-
|
1701
|
-
|
1789
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
|
1790
|
+
unless @line.empty? || byte_size == 0
|
1702
1791
|
@line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
|
1703
1792
|
copy_for_vi(mbchar)
|
1704
1793
|
width = Reline::Unicode.get_mbchar_width(mbchar)
|
@@ -1795,13 +1884,13 @@ class Reline::LineEditor
|
|
1795
1884
|
end
|
1796
1885
|
|
1797
1886
|
private def vi_replace_char(key, arg: 1)
|
1798
|
-
@waiting_proc = ->(
|
1887
|
+
@waiting_proc = ->(k) {
|
1799
1888
|
if arg == 1
|
1800
1889
|
byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
|
1801
1890
|
before = @line.byteslice(0, @byte_pointer)
|
1802
1891
|
remaining_point = @byte_pointer + byte_size
|
1803
1892
|
after = @line.byteslice(remaining_point, @line.size - remaining_point)
|
1804
|
-
@line = before +
|
1893
|
+
@line = before + k.chr + after
|
1805
1894
|
@cursor_max = calculate_width(@line)
|
1806
1895
|
@waiting_proc = nil
|
1807
1896
|
elsif arg > 1
|
@@ -1812,7 +1901,7 @@ class Reline::LineEditor
|
|
1812
1901
|
before = @line.byteslice(0, @byte_pointer)
|
1813
1902
|
remaining_point = @byte_pointer + byte_size
|
1814
1903
|
after = @line.byteslice(remaining_point, @line.size - remaining_point)
|
1815
|
-
replaced =
|
1904
|
+
replaced = k.chr * arg
|
1816
1905
|
@line = before + replaced + after
|
1817
1906
|
@byte_pointer += replaced.bytesize
|
1818
1907
|
@cursor += calculate_width(replaced)
|
@@ -1873,4 +1962,20 @@ class Reline::LineEditor
|
|
1873
1962
|
arg -= 1
|
1874
1963
|
vi_join_lines(key, arg: arg) if arg > 0
|
1875
1964
|
end
|
1965
|
+
|
1966
|
+
private def em_set_mark(key)
|
1967
|
+
@mark_pointer = [@byte_pointer, @line_index]
|
1968
|
+
end
|
1969
|
+
alias_method :set_mark, :em_set_mark
|
1970
|
+
|
1971
|
+
private def em_exchange_mark(key)
|
1972
|
+
new_pointer = [@byte_pointer, @line_index]
|
1973
|
+
@previous_line_index = @line_index
|
1974
|
+
@byte_pointer, @line_index = @mark_pointer
|
1975
|
+
@byte_pointer, @line_index = @mark_pointer
|
1976
|
+
@cursor = calculate_width(@line.byteslice(0, @byte_pointer))
|
1977
|
+
@cursor_max = calculate_width(@line)
|
1978
|
+
@mark_pointer = new_pointer
|
1979
|
+
end
|
1980
|
+
alias_method :exchange_point_and_mark, :em_exchange_mark
|
1876
1981
|
end
|