reline 0.2.0 → 0.2.5
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/README.md +4 -0
- data/lib/reline.rb +6 -0
- data/lib/reline/config.rb +6 -6
- data/lib/reline/line_editor.rb +193 -52
- data/lib/reline/unicode.rb +1 -0
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +25 -0
- data/license_of_rb-readline +25 -0
- metadata +4 -4
- data/lib/reline/line_editor.rb.orig +0 -2606
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1da0f8ec80f16c720589413fbc14c02ac199dcfc0b0344270a61edbad4aec966
|
4
|
+
data.tar.gz: d214e02ad3500323e98d97d57677b7bbc94ea4c09df0b529d5b21ea66374a6a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d218a92032ad8b02218e44bda7fe7d7404845f6cc9cceb9aade01d3c49bc33a0396b02857de417ecee59b5d65c0cb787eecec8dea60180ae3b5457df6c89ebd
|
7
|
+
data.tar.gz: 12c4b8d00608e1f9f16a1c5e530ae86c7530f39ddb1c0f6100b1d4ae87a6dbd53def15d9f387941062aafdb57360fd499dc5850a5bd60d07776daf60e057acfe
|
data/README.md
CHANGED
@@ -11,3 +11,7 @@ Reline is compatible with the API of Ruby's stdlib 'readline', GNU Readline and
|
|
11
11
|
## License
|
12
12
|
|
13
13
|
The gem is available as open source under the terms of the [Ruby License](https://www.ruby-lang.org/en/about/license.txt).
|
14
|
+
|
15
|
+
## Acknowledgments for [rb-readline](https://github.com/ConnorAtherton/rb-readline)
|
16
|
+
|
17
|
+
In developing Reline, we have used some of the rb-readline implementation, so this library includes [copyright notice, list of conditions and the disclaimer](license_of_rb-readline) under the 3-Clause BSD License. Reline would never have been developed without rb-readline. Thank you for the tremendous accomplishments.
|
data/lib/reline.rb
CHANGED
@@ -243,6 +243,7 @@ module Reline
|
|
243
243
|
loop do
|
244
244
|
prev_pasting_state = Reline::IOGate.in_pasting?
|
245
245
|
read_io(config.keyseq_timeout) { |inputs|
|
246
|
+
line_editor.set_pasting_state(Reline::IOGate.in_pasting?)
|
246
247
|
inputs.each { |c|
|
247
248
|
line_editor.input_key(c)
|
248
249
|
line_editor.rerender
|
@@ -253,6 +254,7 @@ module Reline
|
|
253
254
|
end
|
254
255
|
}
|
255
256
|
if prev_pasting_state == true and not Reline::IOGate.in_pasting? and not line_editor.finished?
|
257
|
+
line_editor.set_pasting_state(false)
|
256
258
|
prev_pasting_state = false
|
257
259
|
line_editor.rerender_all
|
258
260
|
end
|
@@ -444,6 +446,10 @@ module Reline
|
|
444
446
|
}
|
445
447
|
end
|
446
448
|
|
449
|
+
def self.ungetc(c)
|
450
|
+
Reline::IOGate.ungetc(c)
|
451
|
+
end
|
452
|
+
|
447
453
|
def self.line_editor
|
448
454
|
core.line_editor
|
449
455
|
end
|
data/lib/reline/config.rb
CHANGED
@@ -34,8 +34,8 @@ class Reline::Config
|
|
34
34
|
show-all-if-unmodified
|
35
35
|
visible-stats
|
36
36
|
show-mode-in-prompt
|
37
|
-
vi-cmd-mode-
|
38
|
-
vi-ins-mode-
|
37
|
+
vi-cmd-mode-string
|
38
|
+
vi-ins-mode-string
|
39
39
|
emacs-mode-string
|
40
40
|
enable-bracketed-paste
|
41
41
|
isearch-terminators
|
@@ -56,8 +56,8 @@ class Reline::Config
|
|
56
56
|
@key_actors[:emacs] = Reline::KeyActor::Emacs.new
|
57
57
|
@key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new
|
58
58
|
@key_actors[:vi_command] = Reline::KeyActor::ViCommand.new
|
59
|
-
@
|
60
|
-
@
|
59
|
+
@vi_cmd_mode_string = '(cmd)'
|
60
|
+
@vi_ins_mode_string = '(ins)'
|
61
61
|
@emacs_mode_string = '@'
|
62
62
|
# https://tiswww.case.edu/php/chet/readline/readline.html#IDX25
|
63
63
|
@history_size = -1 # unlimited
|
@@ -270,9 +270,9 @@ class Reline::Config
|
|
270
270
|
@show_mode_in_prompt = false
|
271
271
|
end
|
272
272
|
when 'vi-cmd-mode-string'
|
273
|
-
@
|
273
|
+
@vi_cmd_mode_string = retrieve_string(value)
|
274
274
|
when 'vi-ins-mode-string'
|
275
|
-
@
|
275
|
+
@vi_ins_mode_string = retrieve_string(value)
|
276
276
|
when 'emacs-mode-string'
|
277
277
|
@emacs_mode_string = retrieve_string(value)
|
278
278
|
when *VARIABLE_NAMES then
|
data/lib/reline/line_editor.rb
CHANGED
@@ -58,34 +58,38 @@ class Reline::LineEditor
|
|
58
58
|
reset_variables(encoding: encoding)
|
59
59
|
end
|
60
60
|
|
61
|
+
def set_pasting_state(in_pasting)
|
62
|
+
@in_pasting = in_pasting
|
63
|
+
end
|
64
|
+
|
61
65
|
def simplified_rendering?
|
62
66
|
if finished?
|
63
67
|
false
|
64
68
|
elsif @just_cursor_moving and not @rerender_all
|
65
69
|
true
|
66
70
|
else
|
67
|
-
not @rerender_all and not finished? and
|
71
|
+
not @rerender_all and not finished? and @in_pasting
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
71
|
-
private def
|
72
|
-
|
75
|
+
private def check_mode_string
|
76
|
+
mode_string = nil
|
73
77
|
if @config.show_mode_in_prompt
|
74
78
|
if @config.editing_mode_is?(:vi_command)
|
75
|
-
|
79
|
+
mode_string = @config.vi_cmd_mode_string
|
76
80
|
elsif @config.editing_mode_is?(:vi_insert)
|
77
|
-
|
81
|
+
mode_string = @config.vi_ins_mode_string
|
78
82
|
elsif @config.editing_mode_is?(:emacs)
|
79
|
-
|
83
|
+
mode_string = @config.emacs_mode_string
|
80
84
|
else
|
81
|
-
|
85
|
+
mode_string = '?'
|
82
86
|
end
|
83
87
|
end
|
84
|
-
if
|
88
|
+
if mode_string != @prev_mode_string
|
85
89
|
@rerender_all = true
|
86
90
|
end
|
87
|
-
@
|
88
|
-
|
91
|
+
@prev_mode_string = mode_string
|
92
|
+
mode_string
|
89
93
|
end
|
90
94
|
|
91
95
|
private def check_multiline_prompt(buffer, prompt)
|
@@ -99,8 +103,8 @@ class Reline::LineEditor
|
|
99
103
|
prompt = @prompt
|
100
104
|
end
|
101
105
|
if simplified_rendering?
|
102
|
-
|
103
|
-
prompt =
|
106
|
+
mode_string = check_mode_string
|
107
|
+
prompt = mode_string + prompt if mode_string
|
104
108
|
return [prompt, calculate_width(prompt, true), [prompt] * buffer.size]
|
105
109
|
end
|
106
110
|
if @prompt_proc
|
@@ -112,6 +116,7 @@ class Reline::LineEditor
|
|
112
116
|
use_cached_prompt_list = true
|
113
117
|
end
|
114
118
|
end
|
119
|
+
use_cached_prompt_list = false if @rerender_all
|
115
120
|
if use_cached_prompt_list
|
116
121
|
prompt_list = @cached_prompt_list
|
117
122
|
else
|
@@ -119,15 +124,22 @@ class Reline::LineEditor
|
|
119
124
|
@prompt_cache_time = Time.now.to_f
|
120
125
|
end
|
121
126
|
prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
|
122
|
-
|
123
|
-
|
127
|
+
prompt_list = [prompt] if prompt_list.empty?
|
128
|
+
mode_string = check_mode_string
|
129
|
+
prompt_list = prompt_list.map{ |pr| mode_string + pr } if mode_string
|
124
130
|
prompt = prompt_list[@line_index]
|
125
131
|
prompt = prompt_list[0] if prompt.nil?
|
132
|
+
prompt = prompt_list.last if prompt.nil?
|
133
|
+
if buffer.size > prompt_list.size
|
134
|
+
(buffer.size - prompt_list.size).times do
|
135
|
+
prompt_list << prompt_list.last
|
136
|
+
end
|
137
|
+
end
|
126
138
|
prompt_width = calculate_width(prompt, true)
|
127
139
|
[prompt, prompt_width, prompt_list]
|
128
140
|
else
|
129
|
-
|
130
|
-
prompt =
|
141
|
+
mode_string = check_mode_string
|
142
|
+
prompt = mode_string + prompt if mode_string
|
131
143
|
prompt_width = calculate_width(prompt, true)
|
132
144
|
[prompt, prompt_width, nil]
|
133
145
|
end
|
@@ -139,6 +151,13 @@ class Reline::LineEditor
|
|
139
151
|
@screen_height = @screen_size.first
|
140
152
|
reset_variables(prompt, encoding: encoding)
|
141
153
|
@old_trap = Signal.trap('SIGINT') {
|
154
|
+
if @scroll_partial_screen
|
155
|
+
move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1)
|
156
|
+
else
|
157
|
+
move_cursor_down(@highest_in_all - @line_index - 1)
|
158
|
+
end
|
159
|
+
Reline::IOGate.move_cursor_column(0)
|
160
|
+
scroll_down(1)
|
142
161
|
@old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
|
143
162
|
raise Interrupt
|
144
163
|
}
|
@@ -218,8 +237,10 @@ class Reline::LineEditor
|
|
218
237
|
@eof = false
|
219
238
|
@continuous_insertion_buffer = String.new(encoding: @encoding)
|
220
239
|
@scroll_partial_screen = nil
|
221
|
-
@
|
240
|
+
@prev_mode_string = nil
|
222
241
|
@drop_terminate_spaces = false
|
242
|
+
@in_pasting = false
|
243
|
+
@auto_indent_proc = nil
|
223
244
|
reset_line
|
224
245
|
end
|
225
246
|
|
@@ -323,8 +344,9 @@ class Reline::LineEditor
|
|
323
344
|
else
|
324
345
|
end_of_line_cursor = new_cursor_max
|
325
346
|
end
|
326
|
-
line_to_calc.
|
327
|
-
|
347
|
+
line_to_calc.grapheme_clusters.each do |gc|
|
348
|
+
mbchar = gc.encode(Encoding::UTF_8)
|
349
|
+
mbchar_width = Reline::Unicode.get_mbchar_width(mbchar)
|
328
350
|
now = new_cursor + mbchar_width
|
329
351
|
if now > end_of_line_cursor or now > cursor
|
330
352
|
break
|
@@ -368,10 +390,29 @@ class Reline::LineEditor
|
|
368
390
|
@cleared = false
|
369
391
|
return
|
370
392
|
end
|
393
|
+
if @is_multiline and finished? and @scroll_partial_screen
|
394
|
+
# Re-output all code higher than the screen when finished.
|
395
|
+
Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen)
|
396
|
+
Reline::IOGate.move_cursor_column(0)
|
397
|
+
@scroll_partial_screen = nil
|
398
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
|
399
|
+
if @previous_line_index
|
400
|
+
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
401
|
+
else
|
402
|
+
new_lines = whole_lines
|
403
|
+
end
|
404
|
+
modify_lines(new_lines).each_with_index do |line, index|
|
405
|
+
@output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\n"
|
406
|
+
Reline::IOGate.erase_after_cursor
|
407
|
+
end
|
408
|
+
@output.flush
|
409
|
+
return
|
410
|
+
end
|
371
411
|
new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line))
|
372
412
|
# FIXME: end of logical line sometimes breaks
|
413
|
+
rendered = false
|
373
414
|
if @add_newline_to_end_of_buffer
|
374
|
-
rerender_added_newline
|
415
|
+
rerender_added_newline(prompt, prompt_width)
|
375
416
|
@add_newline_to_end_of_buffer = false
|
376
417
|
else
|
377
418
|
if @just_cursor_moving and not @rerender_all
|
@@ -389,20 +430,32 @@ class Reline::LineEditor
|
|
389
430
|
else
|
390
431
|
end
|
391
432
|
end
|
392
|
-
line = modify_lines(whole_lines)[@line_index]
|
393
433
|
if @is_multiline
|
394
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
|
395
434
|
if finished?
|
396
435
|
# Always rerender on finish because output_modifier_proc may return a different output.
|
436
|
+
if @previous_line_index
|
437
|
+
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
438
|
+
else
|
439
|
+
new_lines = whole_lines
|
440
|
+
end
|
441
|
+
line = modify_lines(new_lines)[@line_index]
|
442
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines, prompt)
|
397
443
|
render_partial(prompt, prompt_width, line, @first_line_started_from)
|
444
|
+
move_cursor_down(@highest_in_all - (@first_line_started_from + @highest_in_this - 1) - 1)
|
398
445
|
scroll_down(1)
|
399
446
|
Reline::IOGate.move_cursor_column(0)
|
400
447
|
Reline::IOGate.erase_after_cursor
|
401
448
|
elsif not rendered
|
402
|
-
|
449
|
+
unless @in_pasting
|
450
|
+
line = modify_lines(whole_lines)[@line_index]
|
451
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
|
452
|
+
render_partial(prompt, prompt_width, line, @first_line_started_from)
|
453
|
+
end
|
403
454
|
end
|
404
455
|
@buffer_of_lines[@line_index] = @line
|
456
|
+
@rest_height = 0 if @scroll_partial_screen
|
405
457
|
else
|
458
|
+
line = modify_lines(whole_lines)[@line_index]
|
406
459
|
render_partial(prompt, prompt_width, line, 0)
|
407
460
|
if finished?
|
408
461
|
scroll_down(1)
|
@@ -445,13 +498,13 @@ class Reline::LineEditor
|
|
445
498
|
end
|
446
499
|
end
|
447
500
|
|
448
|
-
private def rerender_added_newline
|
501
|
+
private def rerender_added_newline(prompt, prompt_width)
|
449
502
|
scroll_down(1)
|
450
|
-
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
451
|
-
prompt, prompt_width, = check_multiline_prompt(new_lines, prompt)
|
452
503
|
@buffer_of_lines[@previous_line_index] = @line
|
453
504
|
@line = @buffer_of_lines[@line_index]
|
454
|
-
|
505
|
+
unless @in_pasting
|
506
|
+
render_partial(prompt, prompt_width, @line, @first_line_started_from + @started_from + 1, with_control: false)
|
507
|
+
end
|
455
508
|
@cursor = @cursor_max = calculate_width(@line)
|
456
509
|
@byte_pointer = @line.bytesize
|
457
510
|
@highest_in_all += @highest_in_this
|
@@ -471,7 +524,7 @@ class Reline::LineEditor
|
|
471
524
|
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
472
525
|
end
|
473
526
|
first_line_diff = new_first_line_started_from - @first_line_started_from
|
474
|
-
new_cursor,
|
527
|
+
new_cursor, new_cursor_max, new_started_from, new_byte_pointer = calculate_nearest_cursor(@buffer_of_lines[@line_index], @cursor, @started_from, @byte_pointer, false)
|
475
528
|
new_started_from = calculate_height_by_width(prompt_width + new_cursor) - 1
|
476
529
|
calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from)
|
477
530
|
@previous_line_index = nil
|
@@ -485,6 +538,8 @@ class Reline::LineEditor
|
|
485
538
|
@first_line_started_from = new_first_line_started_from
|
486
539
|
@started_from = new_started_from
|
487
540
|
@cursor = new_cursor
|
541
|
+
@cursor_max = new_cursor_max
|
542
|
+
@byte_pointer = new_byte_pointer
|
488
543
|
move_cursor_down(first_line_diff + @started_from)
|
489
544
|
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
490
545
|
false
|
@@ -558,7 +613,13 @@ class Reline::LineEditor
|
|
558
613
|
new_first_line_started_from = calculate_height_by_lines(new_buffer[0..(@line_index - 1)], prompt_list || prompt)
|
559
614
|
end
|
560
615
|
new_started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
561
|
-
|
616
|
+
calculate_scroll_partial_screen(back, new_first_line_started_from + new_started_from)
|
617
|
+
if @scroll_partial_screen
|
618
|
+
move_cursor_up(@first_line_started_from + @started_from)
|
619
|
+
scroll_down(@screen_height - 1)
|
620
|
+
move_cursor_up(@screen_height)
|
621
|
+
Reline::IOGate.move_cursor_column(0)
|
622
|
+
elsif back > old_highest_in_all
|
562
623
|
scroll_down(back - 1)
|
563
624
|
move_cursor_up(back - 1)
|
564
625
|
elsif back < old_highest_in_all
|
@@ -570,7 +631,6 @@ class Reline::LineEditor
|
|
570
631
|
end
|
571
632
|
move_cursor_up(old_highest_in_all - 1)
|
572
633
|
end
|
573
|
-
calculate_scroll_partial_screen(back, new_first_line_started_from + new_started_from)
|
574
634
|
render_whole_lines(new_buffer, prompt_list || prompt, prompt_width)
|
575
635
|
if @prompt_proc
|
576
636
|
prompt = prompt_list[@line_index]
|
@@ -656,8 +716,8 @@ class Reline::LineEditor
|
|
656
716
|
@highest_in_this = height
|
657
717
|
end
|
658
718
|
move_cursor_up(@started_from)
|
659
|
-
cursor_up_from_last_line = height - 1 - @started_from
|
660
719
|
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
720
|
+
cursor_up_from_last_line = height - 1 - @started_from
|
661
721
|
end
|
662
722
|
if Reline::Unicode::CSI_REGEXP.match?(prompt + line_to_render)
|
663
723
|
@output.write "\e[0m" # clear character decorations
|
@@ -667,7 +727,7 @@ class Reline::LineEditor
|
|
667
727
|
if line.nil?
|
668
728
|
if calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last
|
669
729
|
# reaches the end of line
|
670
|
-
if Reline::IOGate.win?
|
730
|
+
if Reline::IOGate.win? and Reline::IOGate.win_legacy_console?
|
671
731
|
# A newline is automatically inserted if a character is rendered at
|
672
732
|
# eol on command prompt.
|
673
733
|
else
|
@@ -685,7 +745,7 @@ class Reline::LineEditor
|
|
685
745
|
next
|
686
746
|
end
|
687
747
|
@output.write line
|
688
|
-
if Reline::IOGate.win? and calculate_width(line, true) == Reline::IOGate.get_screen_size.last
|
748
|
+
if Reline::IOGate.win? and Reline::IOGate.win_legacy_console? and calculate_width(line, true) == Reline::IOGate.get_screen_size.last
|
689
749
|
# A newline is automatically inserted if a character is rendered at eol on command prompt.
|
690
750
|
@rest_height -= 1 if @rest_height > 0
|
691
751
|
end
|
@@ -753,6 +813,7 @@ class Reline::LineEditor
|
|
753
813
|
end
|
754
814
|
move_cursor_up(back)
|
755
815
|
move_cursor_down(@first_line_started_from + @started_from)
|
816
|
+
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
756
817
|
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
757
818
|
end
|
758
819
|
|
@@ -1080,7 +1141,7 @@ class Reline::LineEditor
|
|
1080
1141
|
unless completion_occurs
|
1081
1142
|
@completion_state = CompletionState::NORMAL
|
1082
1143
|
end
|
1083
|
-
if not
|
1144
|
+
if not @in_pasting and @just_cursor_moving.nil?
|
1084
1145
|
if @previous_line_index and @buffer_of_lines[@previous_line_index] == @line
|
1085
1146
|
@just_cursor_moving = true
|
1086
1147
|
elsif @previous_line_index.nil? and @buffer_of_lines[@line_index] == @line and old_line == @line
|
@@ -1098,8 +1159,25 @@ class Reline::LineEditor
|
|
1098
1159
|
|
1099
1160
|
def call_completion_proc
|
1100
1161
|
result = retrieve_completion_block(true)
|
1101
|
-
|
1102
|
-
|
1162
|
+
preposing, target, postposing = result
|
1163
|
+
if @completion_proc and target
|
1164
|
+
argnum = @completion_proc.parameters.inject(0) { |result, item|
|
1165
|
+
case item.first
|
1166
|
+
when :req, :opt
|
1167
|
+
result + 1
|
1168
|
+
when :rest
|
1169
|
+
break 3
|
1170
|
+
end
|
1171
|
+
}
|
1172
|
+
case argnum
|
1173
|
+
when 1
|
1174
|
+
result = @completion_proc.(target)
|
1175
|
+
when 2
|
1176
|
+
result = @completion_proc.(target, preposing)
|
1177
|
+
when 3..Float::INFINITY
|
1178
|
+
result = @completion_proc.(target, preposing, postposing)
|
1179
|
+
end
|
1180
|
+
end
|
1103
1181
|
Reline.core.instance_variable_set(:@completion_quote_character, nil)
|
1104
1182
|
result
|
1105
1183
|
end
|
@@ -1129,6 +1207,7 @@ class Reline::LineEditor
|
|
1129
1207
|
new_lines = whole_lines
|
1130
1208
|
end
|
1131
1209
|
new_indent = @auto_indent_proc.(new_lines, @line_index, @byte_pointer, @check_new_auto_indent)
|
1210
|
+
new_indent = @cursor_max if new_indent&.> @cursor_max
|
1132
1211
|
if new_indent&.>= 0
|
1133
1212
|
md = new_lines[@line_index].match(/\A */)
|
1134
1213
|
prev_indent = md[0].count(' ')
|
@@ -1146,8 +1225,16 @@ class Reline::LineEditor
|
|
1146
1225
|
end
|
1147
1226
|
|
1148
1227
|
def retrieve_completion_block(set_completion_quote_character = false)
|
1149
|
-
|
1150
|
-
|
1228
|
+
if Reline.completer_word_break_characters.empty?
|
1229
|
+
word_break_regexp = nil
|
1230
|
+
else
|
1231
|
+
word_break_regexp = /\A[#{Regexp.escape(Reline.completer_word_break_characters)}]/
|
1232
|
+
end
|
1233
|
+
if Reline.completer_quote_characters.empty?
|
1234
|
+
quote_characters_regexp = nil
|
1235
|
+
else
|
1236
|
+
quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/
|
1237
|
+
end
|
1151
1238
|
before = @line.byteslice(0, @byte_pointer)
|
1152
1239
|
rest = nil
|
1153
1240
|
break_pointer = nil
|
@@ -1168,14 +1255,14 @@ class Reline::LineEditor
|
|
1168
1255
|
elsif quote and slice.start_with?(escaped_quote)
|
1169
1256
|
# skip
|
1170
1257
|
i += 2
|
1171
|
-
elsif slice =~ quote_characters_regexp # find new "
|
1258
|
+
elsif quote_characters_regexp and slice =~ quote_characters_regexp # find new "
|
1172
1259
|
rest = $'
|
1173
1260
|
quote = $&
|
1174
1261
|
closing_quote = /(?!\\)#{Regexp.escape(quote)}/
|
1175
1262
|
escaped_quote = /\\#{Regexp.escape(quote)}/
|
1176
1263
|
i += 1
|
1177
1264
|
break_pointer = i - 1
|
1178
|
-
elsif not quote and slice =~ word_break_regexp
|
1265
|
+
elsif word_break_regexp and not quote and slice =~ word_break_regexp
|
1179
1266
|
rest = $'
|
1180
1267
|
i += 1
|
1181
1268
|
before = @line.byteslice(i, @byte_pointer - i)
|
@@ -1203,6 +1290,19 @@ class Reline::LineEditor
|
|
1203
1290
|
end
|
1204
1291
|
target = before
|
1205
1292
|
end
|
1293
|
+
if @is_multiline
|
1294
|
+
if @previous_line_index
|
1295
|
+
lines = whole_lines(index: @previous_line_index, line: @line)
|
1296
|
+
else
|
1297
|
+
lines = whole_lines
|
1298
|
+
end
|
1299
|
+
if @line_index > 0
|
1300
|
+
preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
|
1301
|
+
end
|
1302
|
+
if (lines.size - 1) > @line_index
|
1303
|
+
postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
|
1304
|
+
end
|
1305
|
+
end
|
1206
1306
|
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
|
1207
1307
|
end
|
1208
1308
|
|
@@ -1230,10 +1330,32 @@ class Reline::LineEditor
|
|
1230
1330
|
|
1231
1331
|
def delete_text(start = nil, length = nil)
|
1232
1332
|
if start.nil? and length.nil?
|
1233
|
-
@
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1333
|
+
if @is_multiline
|
1334
|
+
if @buffer_of_lines.size == 1
|
1335
|
+
@line&.clear
|
1336
|
+
@byte_pointer = 0
|
1337
|
+
@cursor = 0
|
1338
|
+
@cursor_max = 0
|
1339
|
+
elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
|
1340
|
+
@buffer_of_lines.pop
|
1341
|
+
@line_index -= 1
|
1342
|
+
@line = @buffer_of_lines[@line_index]
|
1343
|
+
@byte_pointer = 0
|
1344
|
+
@cursor = 0
|
1345
|
+
@cursor_max = calculate_width(@line)
|
1346
|
+
elsif @line_index < (@buffer_of_lines.size - 1)
|
1347
|
+
@buffer_of_lines.delete_at(@line_index)
|
1348
|
+
@line = @buffer_of_lines[@line_index]
|
1349
|
+
@byte_pointer = 0
|
1350
|
+
@cursor = 0
|
1351
|
+
@cursor_max = calculate_width(@line)
|
1352
|
+
end
|
1353
|
+
else
|
1354
|
+
@line&.clear
|
1355
|
+
@byte_pointer = 0
|
1356
|
+
@cursor = 0
|
1357
|
+
@cursor_max = 0
|
1358
|
+
end
|
1237
1359
|
elsif not start.nil? and not length.nil?
|
1238
1360
|
if @line
|
1239
1361
|
before = @line.byteslice(0, start)
|
@@ -1283,7 +1405,11 @@ class Reline::LineEditor
|
|
1283
1405
|
if @buffer_of_lines.size == 1 and @line.nil?
|
1284
1406
|
nil
|
1285
1407
|
else
|
1286
|
-
|
1408
|
+
if @previous_line_index
|
1409
|
+
whole_lines(index: @previous_line_index, line: @line).join("\n")
|
1410
|
+
else
|
1411
|
+
whole_lines.join("\n")
|
1412
|
+
end
|
1287
1413
|
end
|
1288
1414
|
end
|
1289
1415
|
|
@@ -1329,14 +1455,14 @@ class Reline::LineEditor
|
|
1329
1455
|
cursor_line = @line.byteslice(0, @byte_pointer)
|
1330
1456
|
insert_new_line(cursor_line, next_line)
|
1331
1457
|
@cursor = 0
|
1332
|
-
@check_new_auto_indent = true
|
1458
|
+
@check_new_auto_indent = true unless @in_pasting
|
1333
1459
|
end
|
1334
1460
|
end
|
1335
1461
|
|
1336
1462
|
private def ed_unassigned(key) end # do nothing
|
1337
1463
|
|
1338
1464
|
private def process_insert(force: false)
|
1339
|
-
return if @continuous_insertion_buffer.empty? or (
|
1465
|
+
return if @continuous_insertion_buffer.empty? or (@in_pasting and not force)
|
1340
1466
|
width = Reline::Unicode.calculate_width(@continuous_insertion_buffer)
|
1341
1467
|
bytesize = @continuous_insertion_buffer.bytesize
|
1342
1468
|
if @cursor == @cursor_max
|
@@ -1371,7 +1497,7 @@ class Reline::LineEditor
|
|
1371
1497
|
str = key.chr
|
1372
1498
|
bytesize = 1
|
1373
1499
|
end
|
1374
|
-
if
|
1500
|
+
if @in_pasting
|
1375
1501
|
@continuous_insertion_buffer << str
|
1376
1502
|
return
|
1377
1503
|
elsif not @continuous_insertion_buffer.empty?
|
@@ -1722,7 +1848,7 @@ class Reline::LineEditor
|
|
1722
1848
|
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
1723
1849
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1724
1850
|
@line_index = line_no
|
1725
|
-
@line = @buffer_of_lines
|
1851
|
+
@line = @buffer_of_lines[@line_index]
|
1726
1852
|
@rerender_all = true
|
1727
1853
|
else
|
1728
1854
|
@line = Reline::HISTORY[@history_pointer]
|
@@ -1770,7 +1896,7 @@ class Reline::LineEditor
|
|
1770
1896
|
@line_index = line_no
|
1771
1897
|
end
|
1772
1898
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1773
|
-
@line = @buffer_of_lines
|
1899
|
+
@line = @buffer_of_lines[@line_index]
|
1774
1900
|
@rerender_all = true
|
1775
1901
|
else
|
1776
1902
|
if @history_pointer.nil? and substr.empty?
|
@@ -2385,6 +2511,9 @@ class Reline::LineEditor
|
|
2385
2511
|
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2386
2512
|
@cursor_max -= width
|
2387
2513
|
if @cursor > 0 and @cursor >= @cursor_max
|
2514
|
+
byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
|
2515
|
+
mbchar = @line.byteslice(@byte_pointer - byte_size, byte_size)
|
2516
|
+
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2388
2517
|
@byte_pointer -= byte_size
|
2389
2518
|
@cursor -= width
|
2390
2519
|
end
|
@@ -2418,11 +2547,23 @@ class Reline::LineEditor
|
|
2418
2547
|
|
2419
2548
|
private def vi_histedit(key)
|
2420
2549
|
path = Tempfile.open { |fp|
|
2421
|
-
|
2550
|
+
if @is_multiline
|
2551
|
+
fp.write whole_lines.join("\n")
|
2552
|
+
else
|
2553
|
+
fp.write @line
|
2554
|
+
end
|
2422
2555
|
fp.path
|
2423
2556
|
}
|
2424
2557
|
system("#{ENV['EDITOR']} #{path}")
|
2425
|
-
@
|
2558
|
+
if @is_multiline
|
2559
|
+
@buffer_of_lines = File.read(path).split("\n")
|
2560
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2561
|
+
@line_index = 0
|
2562
|
+
@line = @buffer_of_lines[@line_index]
|
2563
|
+
@rerender_all = true
|
2564
|
+
else
|
2565
|
+
@line = File.read(path)
|
2566
|
+
end
|
2426
2567
|
finish
|
2427
2568
|
end
|
2428
2569
|
|