reline 0.2.0 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|