reline 0.5.2 → 0.5.4
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/ansi.rb +1 -1
- data/lib/reline/config.rb +19 -19
- data/lib/reline/line_editor.rb +204 -368
- data/lib/reline/unicode.rb +60 -8
- data/lib/reline/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45922535b3972631020c6b33bc6b88fd400062fb2c0820ab95ab991704c1fc42
|
4
|
+
data.tar.gz: 53f36ad5e7e196ba34a22990c32b38556653b7384bd99108a791d1b4c7cd3b36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb1b50add8dc60baeefd1fecce83abbaf0e134c16c30ca7fd268efe46d364638280bd2a16100e54be6dbf691bc8a9d4220c53210233a06a0278361c07bd5a56f
|
7
|
+
data.tar.gz: 5ed4f57373cd6e9329de58b9361037e4f8e510020c0ba59970de5733a8c8f4b5c004b871d8e21f013ee065daed9b55f433142529b5e4039276a0f0adbc00c4d9
|
data/lib/reline/ansi.rb
CHANGED
@@ -284,7 +284,7 @@ class Reline::ANSI
|
|
284
284
|
buf = @@output.pread(@@output.pos, 0)
|
285
285
|
row = buf.count("\n")
|
286
286
|
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
|
287
|
-
rescue Errno::ESPIPE
|
287
|
+
rescue Errno::ESPIPE, IOError
|
288
288
|
# Just returns column 1 for ambiguous width because this I/O is not
|
289
289
|
# tty and can't seek.
|
290
290
|
row = 0
|
data/lib/reline/config.rb
CHANGED
@@ -53,8 +53,6 @@ class Reline::Config
|
|
53
53
|
@additional_key_bindings[:vi_insert] = {}
|
54
54
|
@additional_key_bindings[:vi_command] = {}
|
55
55
|
@oneshot_key_bindings = {}
|
56
|
-
@skip_section = nil
|
57
|
-
@if_stack = nil
|
58
56
|
@editing_mode_label = :emacs
|
59
57
|
@keymap_label = :emacs
|
60
58
|
@keymap_prefix = []
|
@@ -190,9 +188,7 @@ class Reline::Config
|
|
190
188
|
end
|
191
189
|
end
|
192
190
|
end
|
193
|
-
|
194
|
-
@skip_section = nil
|
195
|
-
@if_stack = []
|
191
|
+
if_stack = []
|
196
192
|
|
197
193
|
lines.each_with_index do |line, no|
|
198
194
|
next if line.match(/\A\s*#/)
|
@@ -201,11 +197,11 @@ class Reline::Config
|
|
201
197
|
|
202
198
|
line = line.chomp.lstrip
|
203
199
|
if line.start_with?('$')
|
204
|
-
handle_directive(line[1..-1], file, no)
|
200
|
+
handle_directive(line[1..-1], file, no, if_stack)
|
205
201
|
next
|
206
202
|
end
|
207
203
|
|
208
|
-
next if
|
204
|
+
next if if_stack.any? { |_no, skip| skip }
|
209
205
|
|
210
206
|
case line
|
211
207
|
when /^set +([^ ]+) +([^ ]+)/i
|
@@ -214,43 +210,47 @@ class Reline::Config
|
|
214
210
|
next
|
215
211
|
when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
|
216
212
|
key, func_name = $1, $2
|
213
|
+
func_name = func_name.split.first
|
217
214
|
keystroke, func = bind_key(key, func_name)
|
218
215
|
next unless keystroke
|
219
216
|
@additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func
|
220
217
|
end
|
221
218
|
end
|
222
|
-
unless
|
223
|
-
raise InvalidInputrc, "#{file}:#{
|
219
|
+
unless if_stack.empty?
|
220
|
+
raise InvalidInputrc, "#{file}:#{if_stack.last[0]}: unclosed if"
|
224
221
|
end
|
225
|
-
ensure
|
226
|
-
@skip_section, @if_stack = conditions
|
227
222
|
end
|
228
223
|
|
229
|
-
def handle_directive(directive, file, no)
|
224
|
+
def handle_directive(directive, file, no, if_stack)
|
230
225
|
directive, args = directive.split(' ')
|
231
226
|
case directive
|
232
227
|
when 'if'
|
233
228
|
condition = false
|
234
229
|
case args
|
235
|
-
when
|
230
|
+
when /^mode=(vi|emacs)$/i
|
231
|
+
mode = $1.downcase
|
232
|
+
# NOTE: mode=vi means vi-insert mode
|
233
|
+
mode = 'vi_insert' if mode == 'vi'
|
234
|
+
if @editing_mode_label == mode.to_sym
|
235
|
+
condition = true
|
236
|
+
end
|
236
237
|
when 'term'
|
237
238
|
when 'version'
|
238
239
|
else # application name
|
239
240
|
condition = true if args == 'Ruby'
|
240
241
|
condition = true if args == 'Reline'
|
241
242
|
end
|
242
|
-
|
243
|
-
@skip_section = !condition
|
243
|
+
if_stack << [no, !condition]
|
244
244
|
when 'else'
|
245
|
-
if
|
245
|
+
if if_stack.empty?
|
246
246
|
raise InvalidInputrc, "#{file}:#{no}: unmatched else"
|
247
247
|
end
|
248
|
-
|
248
|
+
if_stack.last[1] = !if_stack.last[1]
|
249
249
|
when 'endif'
|
250
|
-
if
|
250
|
+
if if_stack.empty?
|
251
251
|
raise InvalidInputrc, "#{file}:#{no}: unmatched endif"
|
252
252
|
end
|
253
|
-
|
253
|
+
if_stack.pop
|
254
254
|
when 'include'
|
255
255
|
read(File.expand_path(args))
|
256
256
|
end
|
data/lib/reline/line_editor.rb
CHANGED
@@ -112,7 +112,11 @@ class Reline::LineEditor
|
|
112
112
|
else
|
113
113
|
prompt = @prompt
|
114
114
|
end
|
115
|
-
if
|
115
|
+
if !@is_multiline
|
116
|
+
mode_string = check_mode_string
|
117
|
+
prompt = mode_string + prompt if mode_string
|
118
|
+
[prompt] + [''] * (buffer.size - 1)
|
119
|
+
elsif @prompt_proc
|
116
120
|
prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
|
117
121
|
prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
|
118
122
|
prompt_list = [prompt] if prompt_list.empty?
|
@@ -291,8 +295,8 @@ class Reline::LineEditor
|
|
291
295
|
end
|
292
296
|
end
|
293
297
|
|
294
|
-
private def split_by_width(str, max_width)
|
295
|
-
Reline::Unicode.split_by_width(str, max_width, @encoding)
|
298
|
+
private def split_by_width(str, max_width, offset: 0)
|
299
|
+
Reline::Unicode.split_by_width(str, max_width, @encoding, offset: offset)
|
296
300
|
end
|
297
301
|
|
298
302
|
def current_byte_pointer_cursor
|
@@ -366,7 +370,7 @@ class Reline::LineEditor
|
|
366
370
|
@scroll_partial_screen
|
367
371
|
end
|
368
372
|
|
369
|
-
def
|
373
|
+
def wrapped_prompt_and_input_lines
|
370
374
|
with_cache(__method__, @buffer_of_lines.size, modified_lines, prompt_list, screen_width) do |n, lines, prompts, width, prev_cache_key, cached_value|
|
371
375
|
prev_n, prev_lines, prev_prompts, prev_width = prev_cache_key
|
372
376
|
cached_wraps = {}
|
@@ -377,9 +381,14 @@ class Reline::LineEditor
|
|
377
381
|
end
|
378
382
|
|
379
383
|
n.times.map do |i|
|
380
|
-
prompt = prompts[i]
|
381
|
-
line = lines[i]
|
382
|
-
cached_wraps[[prompt, line]]
|
384
|
+
prompt = prompts[i] || ''
|
385
|
+
line = lines[i] || ''
|
386
|
+
if (cached = cached_wraps[[prompt, line]])
|
387
|
+
next cached
|
388
|
+
end
|
389
|
+
*wrapped_prompts, code_line_prompt = split_by_width(prompt, width).first.compact
|
390
|
+
wrapped_lines = split_by_width(line, width, offset: calculate_width(code_line_prompt)).first.compact
|
391
|
+
wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
|
383
392
|
end
|
384
393
|
end
|
385
394
|
end
|
@@ -405,8 +414,13 @@ class Reline::LineEditor
|
|
405
414
|
@output.write "#{Reline::IOGate::RESET_COLOR}#{' ' * width}"
|
406
415
|
else
|
407
416
|
x, w, content = new_items[level]
|
408
|
-
|
409
|
-
|
417
|
+
cover_begin = base_x != 0 && new_levels[base_x - 1] == level
|
418
|
+
cover_end = new_levels[base_x + width] == level
|
419
|
+
pos = 0
|
420
|
+
unless x == base_x && w == width
|
421
|
+
content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
|
422
|
+
end
|
423
|
+
Reline::IOGate.move_cursor_column x + pos
|
410
424
|
@output.write "#{Reline::IOGate::RESET_COLOR}#{content}#{Reline::IOGate::RESET_COLOR}"
|
411
425
|
end
|
412
426
|
base_x += width
|
@@ -422,7 +436,7 @@ class Reline::LineEditor
|
|
422
436
|
prompt_width = calculate_width(prompt_list[@line_index], true)
|
423
437
|
line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
|
424
438
|
wrapped_line_before_cursor = split_by_width(' ' * prompt_width + line_before_cursor, screen_width).first.compact
|
425
|
-
wrapped_cursor_y =
|
439
|
+
wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
|
426
440
|
wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
|
427
441
|
[wrapped_cursor_x, wrapped_cursor_y]
|
428
442
|
end
|
@@ -486,8 +500,9 @@ class Reline::LineEditor
|
|
486
500
|
wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
|
487
501
|
|
488
502
|
rendered_lines = @rendered_screen.lines
|
489
|
-
new_lines =
|
490
|
-
|
503
|
+
new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
|
504
|
+
prompt_width = Reline::Unicode.calculate_width(prompt, true)
|
505
|
+
[[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
|
491
506
|
end
|
492
507
|
if @menu_info
|
493
508
|
@menu_info.lines(screen_width).each do |item|
|
@@ -503,7 +518,8 @@ class Reline::LineEditor
|
|
503
518
|
y_range.each do |row|
|
504
519
|
next if row < 0 || row >= screen_height
|
505
520
|
dialog_rows = new_lines[row] ||= []
|
506
|
-
|
521
|
+
# index 0 is for prompt, index 1 is for line, index 2.. is for dialog
|
522
|
+
dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
|
507
523
|
end
|
508
524
|
end
|
509
525
|
|
@@ -688,13 +704,6 @@ class Reline::LineEditor
|
|
688
704
|
|
689
705
|
DIALOG_DEFAULT_HEIGHT = 20
|
690
706
|
|
691
|
-
private def padding_space_with_escape_sequences(str, width)
|
692
|
-
padding_width = width - calculate_width(str, true)
|
693
|
-
# padding_width should be only positive value. But macOS and Alacritty returns negative value.
|
694
|
-
padding_width = 0 if padding_width < 0
|
695
|
-
str + (' ' * padding_width)
|
696
|
-
end
|
697
|
-
|
698
707
|
private def dialog_range(dialog, dialog_y)
|
699
708
|
x_range = dialog.column...dialog.column + dialog.width
|
700
709
|
y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
|
@@ -767,7 +776,7 @@ class Reline::LineEditor
|
|
767
776
|
dialog.contents = contents.map.with_index do |item, i|
|
768
777
|
line_sgr = i == pointer ? enhanced_sgr : default_sgr
|
769
778
|
str_width = dialog.width - (scrollbar_pos.nil? ? 0 : @block_elem_width)
|
770
|
-
str =
|
779
|
+
str, = Reline::Unicode.take_mbchar_range(item, 0, str_width, padding: true)
|
771
780
|
colored_content = "#{line_sgr}#{str}"
|
772
781
|
if scrollbar_pos
|
773
782
|
if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height)
|
@@ -876,10 +885,12 @@ class Reline::LineEditor
|
|
876
885
|
@completion_state = CompletionState::PERFECT_MATCH
|
877
886
|
else
|
878
887
|
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
|
888
|
+
complete(list, true) if @config.show_all_if_ambiguous
|
879
889
|
end
|
880
890
|
@perfect_matched = completed
|
881
891
|
else
|
882
892
|
@completion_state = CompletionState::MENU
|
893
|
+
complete(list, true) if @config.show_all_if_ambiguous
|
883
894
|
end
|
884
895
|
if not just_show_list and target < completed
|
885
896
|
@buffer_of_lines[@line_index] = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
|
@@ -1107,6 +1118,7 @@ class Reline::LineEditor
|
|
1107
1118
|
end
|
1108
1119
|
end
|
1109
1120
|
if key.char.nil?
|
1121
|
+
process_insert(force: true)
|
1110
1122
|
if @first_char
|
1111
1123
|
@eof = true
|
1112
1124
|
end
|
@@ -1220,7 +1232,7 @@ class Reline::LineEditor
|
|
1220
1232
|
end
|
1221
1233
|
|
1222
1234
|
def line()
|
1223
|
-
|
1235
|
+
@buffer_of_lines.join("\n") unless eof?
|
1224
1236
|
end
|
1225
1237
|
|
1226
1238
|
def current_line
|
@@ -1304,14 +1316,12 @@ class Reline::LineEditor
|
|
1304
1316
|
end
|
1305
1317
|
target = before
|
1306
1318
|
end
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
|
1314
|
-
end
|
1319
|
+
lines = whole_lines
|
1320
|
+
if @line_index > 0
|
1321
|
+
preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
|
1322
|
+
end
|
1323
|
+
if (lines.size - 1) > @line_index
|
1324
|
+
postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
|
1315
1325
|
end
|
1316
1326
|
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
|
1317
1327
|
end
|
@@ -1333,20 +1343,16 @@ class Reline::LineEditor
|
|
1333
1343
|
|
1334
1344
|
def delete_text(start = nil, length = nil)
|
1335
1345
|
if start.nil? and length.nil?
|
1336
|
-
if @
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
@byte_pointer = 0
|
1347
|
-
end
|
1348
|
-
else
|
1349
|
-
set_current_line('', 0)
|
1346
|
+
if @buffer_of_lines.size == 1
|
1347
|
+
@buffer_of_lines[@line_index] = ''
|
1348
|
+
@byte_pointer = 0
|
1349
|
+
elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
|
1350
|
+
@buffer_of_lines.pop
|
1351
|
+
@line_index -= 1
|
1352
|
+
@byte_pointer = 0
|
1353
|
+
elsif @line_index < (@buffer_of_lines.size - 1)
|
1354
|
+
@buffer_of_lines.delete_at(@line_index)
|
1355
|
+
@byte_pointer = 0
|
1350
1356
|
end
|
1351
1357
|
elsif not start.nil? and not length.nil?
|
1352
1358
|
if current_line
|
@@ -1502,7 +1508,7 @@ class Reline::LineEditor
|
|
1502
1508
|
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
1503
1509
|
if (@byte_pointer < current_line.bytesize)
|
1504
1510
|
@byte_pointer += byte_size
|
1505
|
-
elsif @
|
1511
|
+
elsif @config.editing_mode_is?(:emacs) and @byte_pointer == current_line.bytesize and @line_index < @buffer_of_lines.size - 1
|
1506
1512
|
@byte_pointer = 0
|
1507
1513
|
@line_index += 1
|
1508
1514
|
end
|
@@ -1515,7 +1521,7 @@ class Reline::LineEditor
|
|
1515
1521
|
if @byte_pointer > 0
|
1516
1522
|
byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
|
1517
1523
|
@byte_pointer -= byte_size
|
1518
|
-
elsif @
|
1524
|
+
elsif @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
|
1519
1525
|
@line_index -= 1
|
1520
1526
|
@byte_pointer = current_line.bytesize
|
1521
1527
|
end
|
@@ -1535,139 +1541,99 @@ class Reline::LineEditor
|
|
1535
1541
|
alias_method :vi_zero, :ed_move_to_beg
|
1536
1542
|
|
1537
1543
|
private def ed_move_to_end(key)
|
1538
|
-
@byte_pointer =
|
1539
|
-
while @byte_pointer < current_line.bytesize
|
1540
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
1541
|
-
@byte_pointer += byte_size
|
1542
|
-
end
|
1544
|
+
@byte_pointer = current_line.bytesize
|
1543
1545
|
end
|
1544
1546
|
alias_method :end_of_line, :ed_move_to_end
|
1545
1547
|
|
1546
|
-
private def generate_searcher
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
case
|
1553
|
-
when "\C-
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1548
|
+
private def generate_searcher(search_key)
|
1549
|
+
search_word = String.new(encoding: @encoding)
|
1550
|
+
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
1551
|
+
hit_pointer = nil
|
1552
|
+
lambda do |key|
|
1553
|
+
search_again = false
|
1554
|
+
case key
|
1555
|
+
when "\C-h".ord, "\C-?".ord
|
1556
|
+
grapheme_clusters = search_word.grapheme_clusters
|
1557
|
+
if grapheme_clusters.size > 0
|
1558
|
+
grapheme_clusters.pop
|
1559
|
+
search_word = grapheme_clusters.join
|
1560
|
+
end
|
1561
|
+
when "\C-r".ord, "\C-s".ord
|
1562
|
+
search_again = true if search_key == key
|
1563
|
+
search_key = key
|
1564
|
+
else
|
1565
|
+
multibyte_buf << key
|
1566
|
+
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
1567
|
+
search_word << multibyte_buf.dup.force_encoding(@encoding)
|
1568
|
+
multibyte_buf.clear
|
1569
|
+
end
|
1557
1570
|
end
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
grapheme_clusters = search_word.grapheme_clusters
|
1567
|
-
if grapheme_clusters.size > 0
|
1568
|
-
grapheme_clusters.pop
|
1569
|
-
search_word = grapheme_clusters.join
|
1570
|
-
end
|
1571
|
-
when "\C-r".ord, "\C-s".ord
|
1572
|
-
search_again = true if prev_search_key == key
|
1573
|
-
prev_search_key = key
|
1574
|
-
else
|
1575
|
-
multibyte_buf << key
|
1576
|
-
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
1577
|
-
search_word << multibyte_buf.dup.force_encoding(@encoding)
|
1578
|
-
multibyte_buf.clear
|
1571
|
+
hit = nil
|
1572
|
+
if not search_word.empty? and @line_backup_in_history&.include?(search_word)
|
1573
|
+
hit_pointer = Reline::HISTORY.size
|
1574
|
+
hit = @line_backup_in_history
|
1575
|
+
else
|
1576
|
+
if search_again
|
1577
|
+
if search_word.empty? and Reline.last_incremental_search
|
1578
|
+
search_word = Reline.last_incremental_search
|
1579
1579
|
end
|
1580
|
-
|
1581
|
-
|
1582
|
-
if not search_word.empty? and @line_backup_in_history&.include?(search_word)
|
1583
|
-
@history_pointer = nil
|
1584
|
-
hit = @line_backup_in_history
|
1585
|
-
else
|
1586
|
-
if search_again
|
1587
|
-
if search_word.empty? and Reline.last_incremental_search
|
1588
|
-
search_word = Reline.last_incremental_search
|
1589
|
-
end
|
1590
|
-
if @history_pointer
|
1591
|
-
case prev_search_key
|
1592
|
-
when "\C-r".ord
|
1593
|
-
history_pointer_base = 0
|
1594
|
-
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
1595
|
-
when "\C-s".ord
|
1596
|
-
history_pointer_base = @history_pointer + 1
|
1597
|
-
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
1598
|
-
end
|
1599
|
-
else
|
1600
|
-
history_pointer_base = 0
|
1601
|
-
history = Reline::HISTORY
|
1602
|
-
end
|
1603
|
-
elsif @history_pointer
|
1604
|
-
case prev_search_key
|
1580
|
+
if @history_pointer
|
1581
|
+
case search_key
|
1605
1582
|
when "\C-r".ord
|
1606
1583
|
history_pointer_base = 0
|
1607
|
-
history = Reline::HISTORY[0
|
1584
|
+
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
1608
1585
|
when "\C-s".ord
|
1609
|
-
history_pointer_base = @history_pointer
|
1610
|
-
history = Reline::HISTORY[@history_pointer..-1]
|
1586
|
+
history_pointer_base = @history_pointer + 1
|
1587
|
+
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
1611
1588
|
end
|
1612
1589
|
else
|
1613
1590
|
history_pointer_base = 0
|
1614
1591
|
history = Reline::HISTORY
|
1615
1592
|
end
|
1616
|
-
|
1593
|
+
elsif @history_pointer
|
1594
|
+
case search_key
|
1617
1595
|
when "\C-r".ord
|
1618
|
-
|
1619
|
-
|
1620
|
-
}
|
1596
|
+
history_pointer_base = 0
|
1597
|
+
history = Reline::HISTORY[0..@history_pointer]
|
1621
1598
|
when "\C-s".ord
|
1622
|
-
|
1623
|
-
|
1624
|
-
}
|
1625
|
-
end
|
1626
|
-
if hit_index
|
1627
|
-
@history_pointer = history_pointer_base + hit_index
|
1628
|
-
hit = Reline::HISTORY[@history_pointer]
|
1599
|
+
history_pointer_base = @history_pointer
|
1600
|
+
history = Reline::HISTORY[@history_pointer..-1]
|
1629
1601
|
end
|
1602
|
+
else
|
1603
|
+
history_pointer_base = 0
|
1604
|
+
history = Reline::HISTORY
|
1630
1605
|
end
|
1631
|
-
case
|
1606
|
+
case search_key
|
1632
1607
|
when "\C-r".ord
|
1633
|
-
|
1608
|
+
hit_index = history.rindex { |item|
|
1609
|
+
item.include?(search_word)
|
1610
|
+
}
|
1634
1611
|
when "\C-s".ord
|
1635
|
-
|
1612
|
+
hit_index = history.index { |item|
|
1613
|
+
item.include?(search_word)
|
1614
|
+
}
|
1636
1615
|
end
|
1637
|
-
if
|
1638
|
-
|
1639
|
-
|
1640
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1641
|
-
@line_index = @buffer_of_lines.size - 1
|
1642
|
-
@byte_pointer = current_line.bytesize
|
1643
|
-
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1644
|
-
else
|
1645
|
-
@buffer_of_lines = [hit]
|
1646
|
-
@byte_pointer = hit.bytesize
|
1647
|
-
@searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
|
1648
|
-
end
|
1649
|
-
last_hit = hit
|
1650
|
-
else
|
1651
|
-
if @is_multiline
|
1652
|
-
@searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
|
1653
|
-
else
|
1654
|
-
@searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
|
1655
|
-
end
|
1616
|
+
if hit_index
|
1617
|
+
hit_pointer = history_pointer_base + hit_index
|
1618
|
+
hit = Reline::HISTORY[hit_pointer]
|
1656
1619
|
end
|
1657
1620
|
end
|
1621
|
+
case search_key
|
1622
|
+
when "\C-r".ord
|
1623
|
+
prompt_name = 'reverse-i-search'
|
1624
|
+
when "\C-s".ord
|
1625
|
+
prompt_name = 'i-search'
|
1626
|
+
end
|
1627
|
+
prompt_name = "failed #{prompt_name}" unless hit
|
1628
|
+
[search_word, prompt_name, hit_pointer]
|
1658
1629
|
end
|
1659
1630
|
end
|
1660
1631
|
|
1661
1632
|
private def incremental_search_history(key)
|
1662
1633
|
unless @history_pointer
|
1663
|
-
|
1664
|
-
@line_backup_in_history = whole_buffer
|
1665
|
-
else
|
1666
|
-
@line_backup_in_history = current_line
|
1667
|
-
end
|
1634
|
+
@line_backup_in_history = whole_buffer
|
1668
1635
|
end
|
1669
|
-
searcher = generate_searcher
|
1670
|
-
searcher.resume(key)
|
1636
|
+
searcher = generate_searcher(key)
|
1671
1637
|
@searching_prompt = "(reverse-i-search)`': "
|
1672
1638
|
termination_keys = ["\C-j".ord]
|
1673
1639
|
termination_keys.concat(@config.isearch_terminators&.chars&.map(&:ord)) if @config.isearch_terminators
|
@@ -1679,53 +1645,41 @@ class Reline::LineEditor
|
|
1679
1645
|
else
|
1680
1646
|
buffer = @line_backup_in_history
|
1681
1647
|
end
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
@line_index = @buffer_of_lines.size - 1
|
1686
|
-
else
|
1687
|
-
@buffer_of_lines = [buffer]
|
1688
|
-
end
|
1648
|
+
@buffer_of_lines = buffer.split("\n")
|
1649
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1650
|
+
@line_index = @buffer_of_lines.size - 1
|
1689
1651
|
@searching_prompt = nil
|
1690
1652
|
@waiting_proc = nil
|
1691
1653
|
@byte_pointer = 0
|
1692
|
-
searcher.resume(-1)
|
1693
1654
|
when "\C-g".ord
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
else
|
1699
|
-
@buffer_of_lines = [@line_backup_in_history]
|
1700
|
-
end
|
1701
|
-
@history_pointer = nil
|
1655
|
+
@buffer_of_lines = @line_backup_in_history.split("\n")
|
1656
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1657
|
+
@line_index = @buffer_of_lines.size - 1
|
1658
|
+
move_history(nil, line: :end, cursor: :end, save_buffer: false)
|
1702
1659
|
@searching_prompt = nil
|
1703
1660
|
@waiting_proc = nil
|
1704
|
-
@line_backup_in_history = nil
|
1705
1661
|
@byte_pointer = 0
|
1706
1662
|
else
|
1707
1663
|
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1708
1664
|
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
|
1709
|
-
searcher.
|
1665
|
+
search_word, prompt_name, hit_pointer = searcher.call(k)
|
1666
|
+
Reline.last_incremental_search = search_word
|
1667
|
+
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1668
|
+
@searching_prompt += ': ' unless @is_multiline
|
1669
|
+
move_history(hit_pointer, line: :end, cursor: :end, save_buffer: false) if hit_pointer
|
1710
1670
|
else
|
1711
1671
|
if @history_pointer
|
1712
1672
|
line = Reline::HISTORY[@history_pointer]
|
1713
1673
|
else
|
1714
1674
|
line = @line_backup_in_history
|
1715
1675
|
end
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
@line_index = @buffer_of_lines.size - 1
|
1721
|
-
else
|
1722
|
-
@line_backup_in_history = current_line
|
1723
|
-
@buffer_of_lines = [line]
|
1724
|
-
end
|
1676
|
+
@line_backup_in_history = whole_buffer
|
1677
|
+
@buffer_of_lines = line.split("\n")
|
1678
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1679
|
+
@line_index = @buffer_of_lines.size - 1
|
1725
1680
|
@searching_prompt = nil
|
1726
1681
|
@waiting_proc = nil
|
1727
1682
|
@byte_pointer = 0
|
1728
|
-
searcher.resume(-1)
|
1729
1683
|
end
|
1730
1684
|
end
|
1731
1685
|
}
|
@@ -1741,191 +1695,95 @@ class Reline::LineEditor
|
|
1741
1695
|
end
|
1742
1696
|
alias_method :forward_search_history, :vi_search_next
|
1743
1697
|
|
1744
|
-
private def
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
return if not current_line.empty? and substr.empty?
|
1751
|
-
history = Reline::HISTORY
|
1752
|
-
elsif @history_pointer.zero?
|
1753
|
-
history = nil
|
1754
|
-
h_pointer = nil
|
1755
|
-
else
|
1756
|
-
history = Reline::HISTORY.slice(0, @history_pointer)
|
1757
|
-
end
|
1758
|
-
return if history.nil?
|
1759
|
-
if @is_multiline
|
1760
|
-
h_pointer = history.rindex { |h|
|
1761
|
-
h.split("\n").each_with_index { |l, i|
|
1762
|
-
if l.start_with?(substr)
|
1763
|
-
line_no = i
|
1764
|
-
break
|
1765
|
-
end
|
1766
|
-
}
|
1767
|
-
not line_no.nil?
|
1768
|
-
}
|
1769
|
-
else
|
1770
|
-
h_pointer = history.rindex { |l|
|
1771
|
-
l.start_with?(substr)
|
1772
|
-
}
|
1773
|
-
end
|
1774
|
-
return if h_pointer.nil?
|
1775
|
-
@history_pointer = h_pointer
|
1776
|
-
cursor = current_byte_pointer_cursor
|
1777
|
-
if @is_multiline
|
1778
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1779
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1780
|
-
@line_index = line_no
|
1781
|
-
calculate_nearest_cursor(cursor)
|
1782
|
-
else
|
1783
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1784
|
-
calculate_nearest_cursor(cursor)
|
1698
|
+
private def search_history(prefix, pointer_range)
|
1699
|
+
pointer_range.each do |pointer|
|
1700
|
+
lines = Reline::HISTORY[pointer].split("\n")
|
1701
|
+
lines.each_with_index do |line, index|
|
1702
|
+
return [pointer, index] if line.start_with?(prefix)
|
1703
|
+
end
|
1785
1704
|
end
|
1705
|
+
nil
|
1706
|
+
end
|
1707
|
+
|
1708
|
+
private def ed_search_prev_history(key, arg: 1)
|
1709
|
+
substr = current_line.byteslice(0, @byte_pointer)
|
1710
|
+
return if @history_pointer == 0
|
1711
|
+
return if @history_pointer.nil? && substr.empty? && !current_line.empty?
|
1712
|
+
|
1713
|
+
history_range = 0...(@history_pointer || Reline::HISTORY.size)
|
1714
|
+
h_pointer, line_index = search_history(substr, history_range.reverse_each)
|
1715
|
+
return unless h_pointer
|
1716
|
+
move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
|
1786
1717
|
arg -= 1
|
1787
1718
|
ed_search_prev_history(key, arg: arg) if arg > 0
|
1788
1719
|
end
|
1789
1720
|
alias_method :history_search_backward, :ed_search_prev_history
|
1790
1721
|
|
1791
1722
|
private def ed_search_next_history(key, arg: 1)
|
1792
|
-
substr = current_line.
|
1793
|
-
if @history_pointer.nil?
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
1797
|
-
end
|
1798
|
-
history = Reline::HISTORY.slice((@history_pointer + 1)..-1)
|
1799
|
-
h_pointer = nil
|
1800
|
-
line_no = nil
|
1801
|
-
if @is_multiline
|
1802
|
-
h_pointer = history.index { |h|
|
1803
|
-
h.split("\n").each_with_index { |l, i|
|
1804
|
-
if l.start_with?(substr)
|
1805
|
-
line_no = i
|
1806
|
-
break
|
1807
|
-
end
|
1808
|
-
}
|
1809
|
-
not line_no.nil?
|
1810
|
-
}
|
1811
|
-
else
|
1812
|
-
h_pointer = history.index { |l|
|
1813
|
-
l.start_with?(substr)
|
1814
|
-
}
|
1815
|
-
end
|
1816
|
-
h_pointer += @history_pointer + 1 if h_pointer and @history_pointer
|
1723
|
+
substr = current_line.byteslice(0, @byte_pointer)
|
1724
|
+
return if @history_pointer.nil?
|
1725
|
+
|
1726
|
+
history_range = @history_pointer + 1...Reline::HISTORY.size
|
1727
|
+
h_pointer, line_index = search_history(substr, history_range)
|
1817
1728
|
return if h_pointer.nil? and not substr.empty?
|
1818
|
-
|
1819
|
-
|
1820
|
-
if @history_pointer.nil? and substr.empty?
|
1821
|
-
@buffer_of_lines = []
|
1822
|
-
@line_index = 0
|
1823
|
-
@byte_pointer = 0
|
1824
|
-
else
|
1825
|
-
cursor = current_byte_pointer_cursor
|
1826
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1827
|
-
@line_index = line_no
|
1828
|
-
calculate_nearest_cursor(cursor)
|
1829
|
-
end
|
1830
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1831
|
-
else
|
1832
|
-
if @history_pointer.nil? and substr.empty?
|
1833
|
-
set_current_line('', 0)
|
1834
|
-
else
|
1835
|
-
set_current_line(Reline::HISTORY[@history_pointer])
|
1836
|
-
end
|
1837
|
-
end
|
1729
|
+
|
1730
|
+
move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
|
1838
1731
|
arg -= 1
|
1839
1732
|
ed_search_next_history(key, arg: arg) if arg > 0
|
1840
1733
|
end
|
1841
1734
|
alias_method :history_search_forward, :ed_search_next_history
|
1842
1735
|
|
1736
|
+
private def move_history(history_pointer, line:, cursor:, save_buffer: true)
|
1737
|
+
history_pointer ||= Reline::HISTORY.size
|
1738
|
+
return if history_pointer < 0 || history_pointer > Reline::HISTORY.size
|
1739
|
+
old_history_pointer = @history_pointer || Reline::HISTORY.size
|
1740
|
+
if old_history_pointer == Reline::HISTORY.size
|
1741
|
+
@line_backup_in_history = save_buffer ? whole_buffer : ''
|
1742
|
+
else
|
1743
|
+
Reline::HISTORY[old_history_pointer] = whole_buffer if save_buffer
|
1744
|
+
end
|
1745
|
+
if history_pointer == Reline::HISTORY.size
|
1746
|
+
buf = @line_backup_in_history
|
1747
|
+
@history_pointer = @line_backup_in_history = nil
|
1748
|
+
else
|
1749
|
+
buf = Reline::HISTORY[history_pointer]
|
1750
|
+
@history_pointer = history_pointer
|
1751
|
+
end
|
1752
|
+
@buffer_of_lines = buf.split("\n")
|
1753
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1754
|
+
@line_index = line == :start ? 0 : line == :end ? @buffer_of_lines.size - 1 : line
|
1755
|
+
@byte_pointer = cursor == :start ? 0 : cursor == :end ? current_line.bytesize : cursor
|
1756
|
+
end
|
1757
|
+
|
1843
1758
|
private def ed_prev_history(key, arg: 1)
|
1844
|
-
if @
|
1759
|
+
if @line_index > 0
|
1845
1760
|
cursor = current_byte_pointer_cursor
|
1846
1761
|
@line_index -= 1
|
1847
1762
|
calculate_nearest_cursor(cursor)
|
1848
1763
|
return
|
1849
1764
|
end
|
1850
|
-
|
1851
|
-
|
1852
|
-
|
1853
|
-
|
1854
|
-
|
1855
|
-
cursor = current_byte_pointer_cursor
|
1856
|
-
if @is_multiline
|
1857
|
-
@line_backup_in_history = whole_buffer
|
1858
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1859
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1860
|
-
@line_index = @buffer_of_lines.size - 1
|
1861
|
-
calculate_nearest_cursor(cursor)
|
1862
|
-
else
|
1863
|
-
@line_backup_in_history = whole_buffer
|
1864
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1865
|
-
calculate_nearest_cursor(cursor)
|
1866
|
-
end
|
1867
|
-
elsif @history_pointer.zero?
|
1868
|
-
return
|
1869
|
-
else
|
1870
|
-
if @is_multiline
|
1871
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1872
|
-
@history_pointer -= 1
|
1873
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1874
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1875
|
-
@line_index = @buffer_of_lines.size - 1
|
1876
|
-
else
|
1877
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1878
|
-
@history_pointer -= 1
|
1879
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1880
|
-
end
|
1881
|
-
end
|
1882
|
-
if @config.editing_mode_is?(:emacs, :vi_insert)
|
1883
|
-
@byte_pointer = current_line.bytesize
|
1884
|
-
elsif @config.editing_mode_is?(:vi_command)
|
1885
|
-
@byte_pointer = 0
|
1886
|
-
end
|
1765
|
+
move_history(
|
1766
|
+
(@history_pointer || Reline::HISTORY.size) - 1,
|
1767
|
+
line: :end,
|
1768
|
+
cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
|
1769
|
+
)
|
1887
1770
|
arg -= 1
|
1888
1771
|
ed_prev_history(key, arg: arg) if arg > 0
|
1889
1772
|
end
|
1890
1773
|
alias_method :previous_history, :ed_prev_history
|
1891
1774
|
|
1892
1775
|
private def ed_next_history(key, arg: 1)
|
1893
|
-
if @
|
1776
|
+
if @line_index < (@buffer_of_lines.size - 1)
|
1894
1777
|
cursor = current_byte_pointer_cursor
|
1895
1778
|
@line_index += 1
|
1896
1779
|
calculate_nearest_cursor(cursor)
|
1897
1780
|
return
|
1898
1781
|
end
|
1899
|
-
|
1900
|
-
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
@buffer_of_lines = @line_backup_in_history.split("\n")
|
1905
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1906
|
-
@line_index = 0
|
1907
|
-
else
|
1908
|
-
@history_pointer = nil
|
1909
|
-
@buffer_of_lines = [@line_backup_in_history]
|
1910
|
-
end
|
1911
|
-
else
|
1912
|
-
if @is_multiline
|
1913
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1914
|
-
@history_pointer += 1
|
1915
|
-
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1916
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1917
|
-
@line_index = 0
|
1918
|
-
else
|
1919
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1920
|
-
@history_pointer += 1
|
1921
|
-
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1922
|
-
end
|
1923
|
-
end
|
1924
|
-
if @config.editing_mode_is?(:emacs, :vi_insert)
|
1925
|
-
@byte_pointer = current_line.bytesize
|
1926
|
-
elsif @config.editing_mode_is?(:vi_command)
|
1927
|
-
@byte_pointer = 0
|
1928
|
-
end
|
1782
|
+
move_history(
|
1783
|
+
(@history_pointer || Reline::HISTORY.size) + 1,
|
1784
|
+
line: :start,
|
1785
|
+
cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
|
1786
|
+
)
|
1929
1787
|
arg -= 1
|
1930
1788
|
ed_next_history(key, arg: arg) if arg > 0
|
1931
1789
|
end
|
@@ -1956,17 +1814,13 @@ class Reline::LineEditor
|
|
1956
1814
|
end
|
1957
1815
|
end
|
1958
1816
|
else
|
1959
|
-
if @history_pointer
|
1960
|
-
Reline::HISTORY[@history_pointer] = whole_buffer
|
1961
|
-
@history_pointer = nil
|
1962
|
-
end
|
1963
1817
|
finish
|
1964
1818
|
end
|
1965
1819
|
end
|
1966
1820
|
|
1967
1821
|
private def em_delete_prev_char(key, arg: 1)
|
1968
1822
|
arg.times do
|
1969
|
-
if @
|
1823
|
+
if @byte_pointer == 0 and @line_index > 0
|
1970
1824
|
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
|
1971
1825
|
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
|
1972
1826
|
@line_index -= 1
|
@@ -1990,7 +1844,7 @@ class Reline::LineEditor
|
|
1990
1844
|
line, deleted = byteslice!(current_line, @byte_pointer, current_line.bytesize - @byte_pointer)
|
1991
1845
|
set_current_line(line, line.bytesize)
|
1992
1846
|
@kill_ring.append(deleted)
|
1993
|
-
elsif @
|
1847
|
+
elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
|
1994
1848
|
set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
|
1995
1849
|
end
|
1996
1850
|
end
|
@@ -2030,7 +1884,7 @@ class Reline::LineEditor
|
|
2030
1884
|
alias_method :kill_whole_line, :em_kill_line
|
2031
1885
|
|
2032
1886
|
private def em_delete(key)
|
2033
|
-
if current_line.empty? and
|
1887
|
+
if current_line.empty? and @buffer_of_lines.size == 1 and key == "\C-d".ord
|
2034
1888
|
@eof = true
|
2035
1889
|
finish
|
2036
1890
|
elsif @byte_pointer < current_line.bytesize
|
@@ -2038,7 +1892,7 @@ class Reline::LineEditor
|
|
2038
1892
|
mbchar = splitted_last.grapheme_clusters.first
|
2039
1893
|
line, = byteslice!(current_line, @byte_pointer, mbchar.bytesize)
|
2040
1894
|
set_current_line(line)
|
2041
|
-
elsif @
|
1895
|
+
elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
|
2042
1896
|
set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
|
2043
1897
|
end
|
2044
1898
|
end
|
@@ -2281,7 +2135,7 @@ class Reline::LineEditor
|
|
2281
2135
|
end
|
2282
2136
|
|
2283
2137
|
private def vi_delete_prev_char(key)
|
2284
|
-
if @
|
2138
|
+
if @byte_pointer == 0 and @line_index > 0
|
2285
2139
|
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
|
2286
2140
|
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
|
2287
2141
|
@line_index -= 1
|
@@ -2378,7 +2232,7 @@ class Reline::LineEditor
|
|
2378
2232
|
end
|
2379
2233
|
|
2380
2234
|
private def vi_list_or_eof(key)
|
2381
|
-
if
|
2235
|
+
if current_line.empty? and @buffer_of_lines.size == 1
|
2382
2236
|
set_current_line('', 0)
|
2383
2237
|
@eof = true
|
2384
2238
|
finish
|
@@ -2409,36 +2263,18 @@ class Reline::LineEditor
|
|
2409
2263
|
if Reline::HISTORY.empty?
|
2410
2264
|
return
|
2411
2265
|
end
|
2412
|
-
|
2413
|
-
@history_pointer = 0
|
2414
|
-
@line_backup_in_history = current_line
|
2415
|
-
set_current_line(Reline::HISTORY[@history_pointer], 0)
|
2416
|
-
elsif @history_pointer.zero?
|
2417
|
-
return
|
2418
|
-
else
|
2419
|
-
Reline::HISTORY[@history_pointer] = current_line
|
2420
|
-
@history_pointer = 0
|
2421
|
-
set_current_line(Reline::HISTORY[@history_pointer], 0)
|
2422
|
-
end
|
2266
|
+
move_history(0, line: :start, cursor: :start)
|
2423
2267
|
end
|
2424
2268
|
|
2425
2269
|
private def vi_histedit(key)
|
2426
2270
|
path = Tempfile.open { |fp|
|
2427
|
-
|
2428
|
-
fp.write whole_lines.join("\n")
|
2429
|
-
else
|
2430
|
-
fp.write current_line
|
2431
|
-
end
|
2271
|
+
fp.write whole_lines.join("\n")
|
2432
2272
|
fp.path
|
2433
2273
|
}
|
2434
2274
|
system("#{ENV['EDITOR']} #{path}")
|
2435
|
-
|
2436
|
-
|
2437
|
-
|
2438
|
-
@line_index = 0
|
2439
|
-
else
|
2440
|
-
@buffer_of_lines = File.read(path).split("\n")
|
2441
|
-
end
|
2275
|
+
@buffer_of_lines = File.read(path).split("\n")
|
2276
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2277
|
+
@line_index = 0
|
2442
2278
|
finish
|
2443
2279
|
end
|
2444
2280
|
|
@@ -2610,7 +2446,7 @@ class Reline::LineEditor
|
|
2610
2446
|
end
|
2611
2447
|
|
2612
2448
|
private def vi_join_lines(key, arg: 1)
|
2613
|
-
if @
|
2449
|
+
if @buffer_of_lines.size > @line_index + 1
|
2614
2450
|
next_line = @buffer_of_lines.delete_at(@line_index + 1).lstrip
|
2615
2451
|
set_current_line(current_line + ' ' + next_line, current_line.bytesize)
|
2616
2452
|
end
|
data/lib/reline/unicode.rb
CHANGED
@@ -128,10 +128,10 @@ class Reline::Unicode
|
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
|
-
def self.split_by_width(str, max_width, encoding = str.encoding)
|
131
|
+
def self.split_by_width(str, max_width, encoding = str.encoding, offset: 0)
|
132
132
|
lines = [String.new(encoding: encoding)]
|
133
133
|
height = 1
|
134
|
-
width =
|
134
|
+
width = offset
|
135
135
|
rest = str.encode(Encoding::UTF_8)
|
136
136
|
in_zero_width = false
|
137
137
|
seq = String.new(encoding: encoding)
|
@@ -145,7 +145,13 @@ class Reline::Unicode
|
|
145
145
|
lines.last << NON_PRINTING_END
|
146
146
|
when csi
|
147
147
|
lines.last << csi
|
148
|
-
|
148
|
+
unless in_zero_width
|
149
|
+
if csi == -"\e[m" || csi == -"\e[0m"
|
150
|
+
seq.clear
|
151
|
+
else
|
152
|
+
seq << csi
|
153
|
+
end
|
154
|
+
end
|
149
155
|
when osc
|
150
156
|
lines.last << osc
|
151
157
|
seq << osc
|
@@ -173,32 +179,78 @@ class Reline::Unicode
|
|
173
179
|
|
174
180
|
# Take a chunk of a String cut by width with escape sequences.
|
175
181
|
def self.take_range(str, start_col, max_width)
|
182
|
+
take_mbchar_range(str, start_col, max_width).first
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.take_mbchar_range(str, start_col, width, cover_begin: false, cover_end: false, padding: false)
|
176
186
|
chunk = String.new(encoding: str.encoding)
|
187
|
+
|
188
|
+
end_col = start_col + width
|
177
189
|
total_width = 0
|
178
190
|
rest = str.encode(Encoding::UTF_8)
|
179
191
|
in_zero_width = false
|
192
|
+
chunk_start_col = nil
|
193
|
+
chunk_end_col = nil
|
194
|
+
has_csi = false
|
180
195
|
rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
|
181
196
|
case
|
182
197
|
when non_printing_start
|
183
198
|
in_zero_width = true
|
199
|
+
chunk << NON_PRINTING_START
|
184
200
|
when non_printing_end
|
185
201
|
in_zero_width = false
|
202
|
+
chunk << NON_PRINTING_END
|
186
203
|
when csi
|
204
|
+
has_csi = true
|
187
205
|
chunk << csi
|
188
206
|
when osc
|
189
207
|
chunk << osc
|
190
208
|
when gc
|
191
209
|
if in_zero_width
|
192
210
|
chunk << gc
|
211
|
+
next
|
212
|
+
end
|
213
|
+
|
214
|
+
mbchar_width = get_mbchar_width(gc)
|
215
|
+
prev_width = total_width
|
216
|
+
total_width += mbchar_width
|
217
|
+
|
218
|
+
if (cover_begin || padding ? total_width <= start_col : prev_width < start_col)
|
219
|
+
# Current character haven't reached start_col yet
|
220
|
+
next
|
221
|
+
elsif padding && !cover_begin && prev_width < start_col && start_col < total_width
|
222
|
+
# Add preceding padding. This padding might have background color.
|
223
|
+
chunk << ' '
|
224
|
+
chunk_start_col ||= start_col
|
225
|
+
chunk_end_col = total_width
|
226
|
+
next
|
227
|
+
elsif (cover_end ? prev_width < end_col : total_width <= end_col)
|
228
|
+
# Current character is in the range
|
229
|
+
chunk << gc
|
230
|
+
chunk_start_col ||= prev_width
|
231
|
+
chunk_end_col = total_width
|
232
|
+
break if total_width >= end_col
|
193
233
|
else
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
234
|
+
# Current character exceeds end_col
|
235
|
+
if padding && end_col < total_width
|
236
|
+
# Add succeeding padding. This padding might have background color.
|
237
|
+
chunk << ' '
|
238
|
+
chunk_start_col ||= prev_width
|
239
|
+
chunk_end_col = end_col
|
240
|
+
end
|
241
|
+
break
|
198
242
|
end
|
199
243
|
end
|
200
244
|
end
|
201
|
-
|
245
|
+
chunk_start_col ||= start_col
|
246
|
+
chunk_end_col ||= start_col
|
247
|
+
if padding && chunk_end_col < end_col
|
248
|
+
# Append padding. This padding should not include background color.
|
249
|
+
chunk << "\e[0m" if has_csi
|
250
|
+
chunk << ' ' * (end_col - chunk_end_col)
|
251
|
+
chunk_end_col = end_col
|
252
|
+
end
|
253
|
+
[chunk, chunk_start_col, chunk_end_col - chunk_start_col]
|
202
254
|
end
|
203
255
|
|
204
256
|
def self.get_next_mbchar_size(line, byte_pointer)
|
data/lib/reline/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: io-console
|