reline 0.5.9 → 0.5.11
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/config.rb +41 -50
- data/lib/reline/face.rb +1 -1
- data/lib/reline/history.rb +3 -3
- data/lib/reline/io/ansi.rb +33 -49
- data/lib/reline/io/dumb.rb +2 -2
- data/lib/reline/io/windows.rb +83 -66
- data/lib/reline/line_editor.rb +114 -135
- data/lib/reline/terminfo.rb +1 -1
- data/lib/reline/unicode/east_asian_width.rb +1262 -1191
- data/lib/reline/unicode.rb +34 -43
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +11 -8
- metadata +3 -6
data/lib/reline/line_editor.rb
CHANGED
@@ -72,17 +72,21 @@ class Reline::LineEditor
|
|
72
72
|
|
73
73
|
MINIMUM_SCROLLBAR_HEIGHT = 1
|
74
74
|
|
75
|
-
def initialize(config
|
75
|
+
def initialize(config)
|
76
76
|
@config = config
|
77
77
|
@completion_append_character = ''
|
78
78
|
@screen_size = [0, 0] # Should be initialized with actual winsize in LineEditor#reset
|
79
|
-
reset_variables
|
79
|
+
reset_variables
|
80
80
|
end
|
81
81
|
|
82
82
|
def io_gate
|
83
83
|
Reline::IOGate
|
84
84
|
end
|
85
85
|
|
86
|
+
def encoding
|
87
|
+
io_gate.encoding
|
88
|
+
end
|
89
|
+
|
86
90
|
def set_pasting_state(in_pasting)
|
87
91
|
# While pasting, text to be inserted is stored to @continuous_insertion_buffer.
|
88
92
|
# After pasting, this buffer should be force inserted.
|
@@ -136,9 +140,9 @@ class Reline::LineEditor
|
|
136
140
|
end
|
137
141
|
end
|
138
142
|
|
139
|
-
def reset(prompt = ''
|
143
|
+
def reset(prompt = '')
|
140
144
|
@screen_size = Reline::IOGate.get_screen_size
|
141
|
-
reset_variables(prompt
|
145
|
+
reset_variables(prompt)
|
142
146
|
@rendered_screen.base_y = Reline::IOGate.cursor_pos.y
|
143
147
|
if ENV.key?('RELINE_ALT_SCROLLBAR')
|
144
148
|
@full_block = '::'
|
@@ -150,7 +154,7 @@ class Reline::LineEditor
|
|
150
154
|
@upper_half_block = '▀'
|
151
155
|
@lower_half_block = '▄'
|
152
156
|
@block_elem_width = 1
|
153
|
-
elsif
|
157
|
+
elsif encoding == Encoding::UTF_8
|
154
158
|
@full_block = '█'
|
155
159
|
@upper_half_block = '▀'
|
156
160
|
@lower_half_block = '▄'
|
@@ -176,9 +180,8 @@ class Reline::LineEditor
|
|
176
180
|
scroll_into_view
|
177
181
|
Reline::IOGate.move_cursor_up @rendered_screen.cursor_y
|
178
182
|
@rendered_screen.base_y = Reline::IOGate.cursor_pos.y
|
179
|
-
|
180
|
-
|
181
|
-
render_differential
|
183
|
+
clear_rendered_screen_cache
|
184
|
+
render
|
182
185
|
end
|
183
186
|
|
184
187
|
private def handle_interrupted
|
@@ -186,11 +189,11 @@ class Reline::LineEditor
|
|
186
189
|
|
187
190
|
@interrupted = false
|
188
191
|
clear_dialogs
|
189
|
-
|
190
|
-
|
192
|
+
render
|
193
|
+
cursor_to_bottom_offset = @rendered_screen.lines.size - @rendered_screen.cursor_y
|
194
|
+
Reline::IOGate.scroll_down cursor_to_bottom_offset
|
191
195
|
Reline::IOGate.move_cursor_column 0
|
192
|
-
|
193
|
-
@rendered_screen.cursor_y = 0
|
196
|
+
clear_rendered_screen_cache
|
194
197
|
case @old_trap
|
195
198
|
when 'DEFAULT', 'SYSTEM_DEFAULT'
|
196
199
|
raise Interrupt
|
@@ -220,10 +223,9 @@ class Reline::LineEditor
|
|
220
223
|
@eof
|
221
224
|
end
|
222
225
|
|
223
|
-
def reset_variables(prompt = ''
|
226
|
+
def reset_variables(prompt = '')
|
224
227
|
@prompt = prompt.gsub("\n", "\\n")
|
225
228
|
@mark_pointer = nil
|
226
|
-
@encoding = encoding
|
227
229
|
@is_multiline = false
|
228
230
|
@finished = false
|
229
231
|
@history_pointer = nil
|
@@ -240,7 +242,7 @@ class Reline::LineEditor
|
|
240
242
|
@searching_prompt = nil
|
241
243
|
@just_cursor_moving = false
|
242
244
|
@eof = false
|
243
|
-
@continuous_insertion_buffer = String.new(encoding:
|
245
|
+
@continuous_insertion_buffer = String.new(encoding: encoding)
|
244
246
|
@scroll_partial_screen = 0
|
245
247
|
@drop_terminate_spaces = false
|
246
248
|
@in_pasting = false
|
@@ -260,7 +262,7 @@ class Reline::LineEditor
|
|
260
262
|
|
261
263
|
def reset_line
|
262
264
|
@byte_pointer = 0
|
263
|
-
@buffer_of_lines = [String.new(encoding:
|
265
|
+
@buffer_of_lines = [String.new(encoding: encoding)]
|
264
266
|
@line_index = 0
|
265
267
|
@cache.clear
|
266
268
|
@line_backup_in_history = nil
|
@@ -276,7 +278,7 @@ class Reline::LineEditor
|
|
276
278
|
end
|
277
279
|
|
278
280
|
private def insert_new_line(cursor_line, next_line)
|
279
|
-
@buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding:
|
281
|
+
@buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding: encoding))
|
280
282
|
@buffer_of_lines[@line_index] = cursor_line
|
281
283
|
@line_index += 1
|
282
284
|
@byte_pointer = 0
|
@@ -299,7 +301,7 @@ class Reline::LineEditor
|
|
299
301
|
end
|
300
302
|
|
301
303
|
private def split_by_width(str, max_width, offset: 0)
|
302
|
-
Reline::Unicode.split_by_width(str, max_width,
|
304
|
+
Reline::Unicode.split_by_width(str, max_width, encoding, offset: offset)
|
303
305
|
end
|
304
306
|
|
305
307
|
def current_byte_pointer_cursor
|
@@ -460,49 +462,25 @@ class Reline::LineEditor
|
|
460
462
|
end
|
461
463
|
|
462
464
|
def render_finished
|
463
|
-
|
464
|
-
render_full_content
|
465
|
-
end
|
466
|
-
|
467
|
-
def clear_rendered_lines
|
468
|
-
Reline::IOGate.move_cursor_up @rendered_screen.cursor_y
|
469
|
-
Reline::IOGate.move_cursor_column 0
|
470
|
-
|
471
|
-
num_lines = @rendered_screen.lines.size
|
472
|
-
return unless num_lines && num_lines >= 1
|
473
|
-
|
474
|
-
Reline::IOGate.move_cursor_down num_lines - 1
|
475
|
-
(num_lines - 1).times do
|
476
|
-
Reline::IOGate.erase_after_cursor
|
477
|
-
Reline::IOGate.move_cursor_up 1
|
478
|
-
end
|
479
|
-
Reline::IOGate.erase_after_cursor
|
480
|
-
@rendered_screen.lines = []
|
481
|
-
@rendered_screen.cursor_y = 0
|
482
|
-
end
|
483
|
-
|
484
|
-
def render_full_content
|
465
|
+
render_differential([], 0, 0)
|
485
466
|
lines = @buffer_of_lines.size.times.map do |i|
|
486
|
-
line = prompt_list[i] + modified_lines[i]
|
467
|
+
line = Reline::Unicode.strip_non_printing_start_end(prompt_list[i]) + modified_lines[i]
|
487
468
|
wrapped_lines, = split_by_width(line, screen_width)
|
488
469
|
wrapped_lines.last.empty? ? "#{line} " : line
|
489
470
|
end
|
490
471
|
@output.puts lines.map { |l| "#{l}\r\n" }.join
|
491
472
|
end
|
492
473
|
|
493
|
-
def print_nomultiline_prompt
|
494
|
-
|
495
|
-
|
474
|
+
def print_nomultiline_prompt
|
475
|
+
Reline::IOGate.disable_auto_linewrap(true) if Reline::IOGate.win?
|
496
476
|
# Readline's test `TestRelineAsReadline#test_readline` requires first output to be prompt, not cursor reset escape sequence.
|
497
|
-
@
|
498
|
-
|
499
|
-
|
477
|
+
@output.write Reline::Unicode.strip_non_printing_start_end(@prompt) if @prompt && !@is_multiline
|
478
|
+
ensure
|
479
|
+
Reline::IOGate.disable_auto_linewrap(false) if Reline::IOGate.win?
|
500
480
|
end
|
501
481
|
|
502
|
-
def
|
482
|
+
def render
|
503
483
|
wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
|
504
|
-
|
505
|
-
rendered_lines = @rendered_screen.lines
|
506
484
|
new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
|
507
485
|
prompt_width = Reline::Unicode.calculate_width(prompt, true)
|
508
486
|
[[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
|
@@ -520,12 +498,22 @@ class Reline::LineEditor
|
|
520
498
|
x_range, y_range = dialog_range dialog, wrapped_cursor_y - screen_scroll_top
|
521
499
|
y_range.each do |row|
|
522
500
|
next if row < 0 || row >= screen_height
|
501
|
+
|
523
502
|
dialog_rows = new_lines[row] ||= []
|
524
503
|
# index 0 is for prompt, index 1 is for line, index 2.. is for dialog
|
525
504
|
dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
|
526
505
|
end
|
527
506
|
end
|
528
507
|
|
508
|
+
render_differential new_lines, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top
|
509
|
+
end
|
510
|
+
|
511
|
+
# Reflects lines to be rendered and new cursor position to the screen
|
512
|
+
# by calculating the difference from the previous render.
|
513
|
+
|
514
|
+
private def render_differential(new_lines, new_cursor_x, new_cursor_y)
|
515
|
+
Reline::IOGate.disable_auto_linewrap(true) if Reline::IOGate.win?
|
516
|
+
rendered_lines = @rendered_screen.lines
|
529
517
|
cursor_y = @rendered_screen.cursor_y
|
530
518
|
if new_lines != rendered_lines
|
531
519
|
# Hide cursor while rendering to avoid cursor flickering.
|
@@ -552,11 +540,16 @@ class Reline::LineEditor
|
|
552
540
|
@rendered_screen.lines = new_lines
|
553
541
|
Reline::IOGate.show_cursor
|
554
542
|
end
|
555
|
-
|
556
|
-
Reline::IOGate.
|
557
|
-
|
558
|
-
|
559
|
-
|
543
|
+
Reline::IOGate.move_cursor_column new_cursor_x
|
544
|
+
Reline::IOGate.move_cursor_down new_cursor_y - cursor_y
|
545
|
+
@rendered_screen.cursor_y = new_cursor_y
|
546
|
+
ensure
|
547
|
+
Reline::IOGate.disable_auto_linewrap(false) if Reline::IOGate.win?
|
548
|
+
end
|
549
|
+
|
550
|
+
private def clear_rendered_screen_cache
|
551
|
+
@rendered_screen.lines = []
|
552
|
+
@rendered_screen.cursor_y = 0
|
560
553
|
end
|
561
554
|
|
562
555
|
def upper_space_height(wrapped_cursor_y)
|
@@ -568,7 +561,7 @@ class Reline::LineEditor
|
|
568
561
|
end
|
569
562
|
|
570
563
|
def rerender
|
571
|
-
|
564
|
+
render unless @in_pasting
|
572
565
|
end
|
573
566
|
|
574
567
|
class DialogProcScope
|
@@ -813,7 +806,7 @@ class Reline::LineEditor
|
|
813
806
|
|
814
807
|
private def complete_internal_proc(list, is_menu)
|
815
808
|
preposing, target, postposing = retrieve_completion_block
|
816
|
-
|
809
|
+
candidates = list.select { |i|
|
817
810
|
if i and not Encoding.compatible?(target.encoding, i.encoding)
|
818
811
|
raise Encoding::CompatibilityError, "#{target.encoding.name} is not compatible with #{i.encoding.name}"
|
819
812
|
end
|
@@ -824,10 +817,10 @@ class Reline::LineEditor
|
|
824
817
|
end
|
825
818
|
}.uniq
|
826
819
|
if is_menu
|
827
|
-
menu(target,
|
820
|
+
menu(target, candidates)
|
828
821
|
return nil
|
829
822
|
end
|
830
|
-
completed =
|
823
|
+
completed = candidates.inject { |memo, item|
|
831
824
|
begin
|
832
825
|
memo_mbchars = memo.unicode_normalize.grapheme_clusters
|
833
826
|
item_mbchars = item.unicode_normalize.grapheme_clusters
|
@@ -854,7 +847,8 @@ class Reline::LineEditor
|
|
854
847
|
end
|
855
848
|
result
|
856
849
|
}
|
857
|
-
|
850
|
+
|
851
|
+
[target, preposing, completed, postposing, candidates]
|
858
852
|
end
|
859
853
|
|
860
854
|
private def perform_completion(list, just_show_list)
|
@@ -862,7 +856,11 @@ class Reline::LineEditor
|
|
862
856
|
when CompletionState::NORMAL
|
863
857
|
@completion_state = CompletionState::COMPLETION
|
864
858
|
when CompletionState::PERFECT_MATCH
|
865
|
-
@dig_perfect_match_proc
|
859
|
+
if @dig_perfect_match_proc
|
860
|
+
@dig_perfect_match_proc.(@perfect_matched)
|
861
|
+
else
|
862
|
+
@completion_state = CompletionState::COMPLETION
|
863
|
+
end
|
866
864
|
end
|
867
865
|
if just_show_list
|
868
866
|
is_menu = true
|
@@ -878,24 +876,26 @@ class Reline::LineEditor
|
|
878
876
|
@completion_state = CompletionState::PERFECT_MATCH
|
879
877
|
end
|
880
878
|
return if result.nil?
|
881
|
-
target, preposing, completed, postposing = result
|
879
|
+
target, preposing, completed, postposing, candidates = result
|
882
880
|
return if completed.nil?
|
883
881
|
if target <= completed and (@completion_state == CompletionState::COMPLETION)
|
884
|
-
|
885
|
-
|
882
|
+
append_character = ''
|
883
|
+
if candidates.include?(completed)
|
884
|
+
if candidates.one?
|
885
|
+
append_character = completion_append_character.to_s
|
886
886
|
@completion_state = CompletionState::PERFECT_MATCH
|
887
887
|
else
|
888
888
|
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
|
889
|
-
perform_completion(
|
889
|
+
perform_completion(candidates, true) if @config.show_all_if_ambiguous
|
890
890
|
end
|
891
891
|
@perfect_matched = completed
|
892
892
|
else
|
893
893
|
@completion_state = CompletionState::MENU
|
894
|
-
perform_completion(
|
894
|
+
perform_completion(candidates, true) if @config.show_all_if_ambiguous
|
895
895
|
end
|
896
|
-
|
897
|
-
@buffer_of_lines[@line_index] = (preposing + completed +
|
898
|
-
line_to_pointer = (preposing + completed +
|
896
|
+
unless just_show_list
|
897
|
+
@buffer_of_lines[@line_index] = (preposing + completed + append_character + postposing).split("\n")[@line_index] || String.new(encoding: encoding)
|
898
|
+
line_to_pointer = (preposing + completed + append_character).split("\n")[@line_index] || String.new(encoding: encoding)
|
899
899
|
@byte_pointer = line_to_pointer.bytesize
|
900
900
|
end
|
901
901
|
end
|
@@ -1070,8 +1070,8 @@ class Reline::LineEditor
|
|
1070
1070
|
private def normal_char(key)
|
1071
1071
|
@multibyte_buffer << key.combined_char
|
1072
1072
|
if @multibyte_buffer.size > 1
|
1073
|
-
if @multibyte_buffer.dup.force_encoding(
|
1074
|
-
process_key(@multibyte_buffer.dup.force_encoding(
|
1073
|
+
if @multibyte_buffer.dup.force_encoding(encoding).valid_encoding?
|
1074
|
+
process_key(@multibyte_buffer.dup.force_encoding(encoding), nil)
|
1075
1075
|
@multibyte_buffer.clear
|
1076
1076
|
else
|
1077
1077
|
# invalid
|
@@ -1329,7 +1329,7 @@ class Reline::LineEditor
|
|
1329
1329
|
if (lines.size - 1) > @line_index
|
1330
1330
|
postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
|
1331
1331
|
end
|
1332
|
-
[preposing.encode(
|
1332
|
+
[preposing.encode(encoding), target.encode(encoding), postposing.encode(encoding)]
|
1333
1333
|
end
|
1334
1334
|
|
1335
1335
|
def confirm_multiline_termination
|
@@ -1337,11 +1337,11 @@ class Reline::LineEditor
|
|
1337
1337
|
@confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
|
1338
1338
|
end
|
1339
1339
|
|
1340
|
-
def
|
1340
|
+
def insert_multiline_text(text)
|
1341
1341
|
save_old_buffer
|
1342
1342
|
pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
|
1343
1343
|
post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
|
1344
|
-
lines = (pre + text.gsub(/\r\n?/, "\n") + post).split("\n", -1)
|
1344
|
+
lines = (pre + Reline::Unicode.safe_encode(text, encoding).gsub(/\r\n?/, "\n") + post).split("\n", -1)
|
1345
1345
|
lines << '' if lines.empty?
|
1346
1346
|
@buffer_of_lines[@line_index, 1] = lines
|
1347
1347
|
@line_index += lines.size - 1
|
@@ -1386,7 +1386,7 @@ class Reline::LineEditor
|
|
1386
1386
|
last += current_line.bytesize if last < 0
|
1387
1387
|
first += current_line.bytesize if first < 0
|
1388
1388
|
range = range.exclude_end? ? first...last : first..last
|
1389
|
-
line = current_line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(
|
1389
|
+
line = current_line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(encoding)
|
1390
1390
|
set_current_line(line)
|
1391
1391
|
else
|
1392
1392
|
set_current_line(current_line.byteslice(0, start))
|
@@ -1597,7 +1597,7 @@ class Reline::LineEditor
|
|
1597
1597
|
alias_method :end_of_line, :ed_move_to_end
|
1598
1598
|
|
1599
1599
|
private def generate_searcher(search_key)
|
1600
|
-
search_word = String.new(encoding:
|
1600
|
+
search_word = String.new(encoding: encoding)
|
1601
1601
|
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
1602
1602
|
hit_pointer = nil
|
1603
1603
|
lambda do |key|
|
@@ -1614,8 +1614,8 @@ class Reline::LineEditor
|
|
1614
1614
|
search_key = key
|
1615
1615
|
else
|
1616
1616
|
multibyte_buf << key
|
1617
|
-
if multibyte_buf.dup.force_encoding(
|
1618
|
-
search_word << multibyte_buf.dup.force_encoding(
|
1617
|
+
if multibyte_buf.dup.force_encoding(encoding).valid_encoding?
|
1618
|
+
search_word << multibyte_buf.dup.force_encoding(encoding)
|
1619
1619
|
multibyte_buf.clear
|
1620
1620
|
end
|
1621
1621
|
end
|
@@ -1681,57 +1681,29 @@ class Reline::LineEditor
|
|
1681
1681
|
end
|
1682
1682
|
|
1683
1683
|
private def incremental_search_history(key)
|
1684
|
-
|
1685
|
-
@line_backup_in_history = whole_buffer
|
1686
|
-
end
|
1684
|
+
backup = @buffer_of_lines.dup, @line_index, @byte_pointer, @history_pointer, @line_backup_in_history
|
1687
1685
|
searcher = generate_searcher(key)
|
1688
1686
|
@searching_prompt = "(reverse-i-search)`': "
|
1689
1687
|
termination_keys = ["\C-j".ord]
|
1690
|
-
termination_keys.concat(@config.isearch_terminators
|
1688
|
+
termination_keys.concat(@config.isearch_terminators.chars.map(&:ord)) if @config.isearch_terminators
|
1691
1689
|
@waiting_proc = ->(k) {
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
else
|
1697
|
-
buffer = @line_backup_in_history
|
1698
|
-
end
|
1699
|
-
@buffer_of_lines = buffer.split("\n")
|
1700
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1701
|
-
@line_index = @buffer_of_lines.size - 1
|
1690
|
+
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1691
|
+
if k == "\C-g".ord
|
1692
|
+
# cancel search and restore buffer
|
1693
|
+
@buffer_of_lines, @line_index, @byte_pointer, @history_pointer, @line_backup_in_history = backup
|
1702
1694
|
@searching_prompt = nil
|
1703
1695
|
@waiting_proc = nil
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
@
|
1708
|
-
@
|
1709
|
-
move_history(
|
1696
|
+
elsif !termination_keys.include?(k) && (chr.match?(/[[:print:]]/) || k == "\C-h".ord || k == "\C-?".ord || k == "\C-r".ord || k == "\C-s".ord)
|
1697
|
+
search_word, prompt_name, hit_pointer = searcher.call(k)
|
1698
|
+
Reline.last_incremental_search = search_word
|
1699
|
+
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1700
|
+
@searching_prompt += ': ' unless @is_multiline
|
1701
|
+
move_history(hit_pointer, line: :end, cursor: :end) if hit_pointer
|
1702
|
+
else
|
1703
|
+
# terminaton_keys and other keys will terminalte
|
1704
|
+
move_history(@history_pointer, line: :end, cursor: :start)
|
1710
1705
|
@searching_prompt = nil
|
1711
1706
|
@waiting_proc = nil
|
1712
|
-
@byte_pointer = 0
|
1713
|
-
else
|
1714
|
-
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1715
|
-
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
|
1716
|
-
search_word, prompt_name, hit_pointer = searcher.call(k)
|
1717
|
-
Reline.last_incremental_search = search_word
|
1718
|
-
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
1719
|
-
@searching_prompt += ': ' unless @is_multiline
|
1720
|
-
move_history(hit_pointer, line: :end, cursor: :end, save_buffer: false) if hit_pointer
|
1721
|
-
else
|
1722
|
-
if @history_pointer
|
1723
|
-
line = Reline::HISTORY[@history_pointer]
|
1724
|
-
else
|
1725
|
-
line = @line_backup_in_history
|
1726
|
-
end
|
1727
|
-
@line_backup_in_history = whole_buffer
|
1728
|
-
@buffer_of_lines = line.split("\n")
|
1729
|
-
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1730
|
-
@line_index = @buffer_of_lines.size - 1
|
1731
|
-
@searching_prompt = nil
|
1732
|
-
@waiting_proc = nil
|
1733
|
-
@byte_pointer = 0
|
1734
|
-
end
|
1735
1707
|
end
|
1736
1708
|
}
|
1737
1709
|
end
|
@@ -1786,14 +1758,14 @@ class Reline::LineEditor
|
|
1786
1758
|
end
|
1787
1759
|
alias_method :history_search_forward, :ed_search_next_history
|
1788
1760
|
|
1789
|
-
private def move_history(history_pointer, line:, cursor
|
1761
|
+
private def move_history(history_pointer, line:, cursor:)
|
1790
1762
|
history_pointer ||= Reline::HISTORY.size
|
1791
1763
|
return if history_pointer < 0 || history_pointer > Reline::HISTORY.size
|
1792
1764
|
old_history_pointer = @history_pointer || Reline::HISTORY.size
|
1793
1765
|
if old_history_pointer == Reline::HISTORY.size
|
1794
|
-
@line_backup_in_history =
|
1766
|
+
@line_backup_in_history = whole_buffer
|
1795
1767
|
else
|
1796
|
-
Reline::HISTORY[old_history_pointer] = whole_buffer
|
1768
|
+
Reline::HISTORY[old_history_pointer] = whole_buffer
|
1797
1769
|
end
|
1798
1770
|
if history_pointer == Reline::HISTORY.size
|
1799
1771
|
buf = @line_backup_in_history
|
@@ -1803,7 +1775,7 @@ class Reline::LineEditor
|
|
1803
1775
|
@history_pointer = history_pointer
|
1804
1776
|
end
|
1805
1777
|
@buffer_of_lines = buf.split("\n")
|
1806
|
-
@buffer_of_lines = [String.new(encoding:
|
1778
|
+
@buffer_of_lines = [String.new(encoding: encoding)] if @buffer_of_lines.empty?
|
1807
1779
|
@line_index = line == :start ? 0 : line == :end ? @buffer_of_lines.size - 1 : line
|
1808
1780
|
@byte_pointer = cursor == :start ? 0 : cursor == :end ? current_line.bytesize : cursor
|
1809
1781
|
end
|
@@ -1982,9 +1954,8 @@ class Reline::LineEditor
|
|
1982
1954
|
private def ed_clear_screen(key)
|
1983
1955
|
Reline::IOGate.clear_screen
|
1984
1956
|
@screen_size = Reline::IOGate.get_screen_size
|
1985
|
-
@rendered_screen.lines = []
|
1986
1957
|
@rendered_screen.base_y = 0
|
1987
|
-
|
1958
|
+
clear_rendered_screen_cache
|
1988
1959
|
end
|
1989
1960
|
alias_method :clear_screen, :ed_clear_screen
|
1990
1961
|
|
@@ -2259,9 +2230,11 @@ class Reline::LineEditor
|
|
2259
2230
|
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
2260
2231
|
elsif byte_pointer_diff < 0
|
2261
2232
|
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2233
|
+
else
|
2234
|
+
return
|
2262
2235
|
end
|
2263
2236
|
copy_for_vi(cut)
|
2264
|
-
set_current_line(line
|
2237
|
+
set_current_line(line, @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
|
2265
2238
|
end
|
2266
2239
|
|
2267
2240
|
private def vi_yank(key, arg: nil)
|
@@ -2280,6 +2253,8 @@ class Reline::LineEditor
|
|
2280
2253
|
cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
|
2281
2254
|
elsif byte_pointer_diff < 0
|
2282
2255
|
cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2256
|
+
else
|
2257
|
+
return
|
2283
2258
|
end
|
2284
2259
|
copy_for_vi(cut)
|
2285
2260
|
end
|
@@ -2325,7 +2300,7 @@ class Reline::LineEditor
|
|
2325
2300
|
}
|
2326
2301
|
system("#{ENV['EDITOR']} #{path}")
|
2327
2302
|
@buffer_of_lines = File.read(path).split("\n")
|
2328
|
-
@buffer_of_lines = [String.new(encoding:
|
2303
|
+
@buffer_of_lines = [String.new(encoding: encoding)] if @buffer_of_lines.empty?
|
2329
2304
|
@line_index = 0
|
2330
2305
|
finish
|
2331
2306
|
end
|
@@ -2409,9 +2384,9 @@ class Reline::LineEditor
|
|
2409
2384
|
|
2410
2385
|
private def search_next_char(key, arg, need_prev_char: false, inclusive: false)
|
2411
2386
|
if key.instance_of?(String)
|
2412
|
-
|
2387
|
+
inputted_char = key
|
2413
2388
|
else
|
2414
|
-
|
2389
|
+
inputted_char = key.chr
|
2415
2390
|
end
|
2416
2391
|
prev_total = nil
|
2417
2392
|
total = nil
|
@@ -2423,7 +2398,7 @@ class Reline::LineEditor
|
|
2423
2398
|
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2424
2399
|
total = [mbchar.bytesize, width]
|
2425
2400
|
else
|
2426
|
-
if
|
2401
|
+
if inputted_char == mbchar
|
2427
2402
|
arg -= 1
|
2428
2403
|
if arg.zero?
|
2429
2404
|
found = true
|
@@ -2461,9 +2436,9 @@ class Reline::LineEditor
|
|
2461
2436
|
|
2462
2437
|
private def search_prev_char(key, arg, need_next_char = false)
|
2463
2438
|
if key.instance_of?(String)
|
2464
|
-
|
2439
|
+
inputted_char = key
|
2465
2440
|
else
|
2466
|
-
|
2441
|
+
inputted_char = key.chr
|
2467
2442
|
end
|
2468
2443
|
prev_total = nil
|
2469
2444
|
total = nil
|
@@ -2475,7 +2450,7 @@ class Reline::LineEditor
|
|
2475
2450
|
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2476
2451
|
total = [mbchar.bytesize, width]
|
2477
2452
|
else
|
2478
|
-
if
|
2453
|
+
if inputted_char == mbchar
|
2479
2454
|
arg -= 1
|
2480
2455
|
if arg.zero?
|
2481
2456
|
found = true
|
@@ -2554,4 +2529,8 @@ class Reline::LineEditor
|
|
2554
2529
|
private def set_next_action_state(type, value)
|
2555
2530
|
@next_action_state = [type, value]
|
2556
2531
|
end
|
2532
|
+
|
2533
|
+
private def re_read_init_file(_key)
|
2534
|
+
@config.reload
|
2535
|
+
end
|
2557
2536
|
end
|
data/lib/reline/terminfo.rb
CHANGED
@@ -83,7 +83,7 @@ module Reline::Terminfo
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def self.setupterm(term, fildes)
|
86
|
-
errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
|
86
|
+
errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE)
|
87
87
|
ret = @setupterm.(term, fildes, errret_int)
|
88
88
|
case ret
|
89
89
|
when 0 # OK
|