reline 0.4.0 → 0.5.0.pre.1
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/face.rb +42 -0
- data/lib/reline/general_io.rb +1 -1
- data/lib/reline/line_editor.rb +604 -1285
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +10 -7
- metadata +5 -5
data/lib/reline/line_editor.rb
CHANGED
@@ -6,7 +6,6 @@ require 'tempfile'
|
|
6
6
|
class Reline::LineEditor
|
7
7
|
# TODO: undo
|
8
8
|
# TODO: Use "private alias_method" idiom after drop Ruby 2.5.
|
9
|
-
attr_reader :line
|
10
9
|
attr_reader :byte_pointer
|
11
10
|
attr_accessor :confirm_multiline_termination_proc
|
12
11
|
attr_accessor :completion_proc
|
@@ -14,7 +13,6 @@ class Reline::LineEditor
|
|
14
13
|
attr_accessor :output_modifier_proc
|
15
14
|
attr_accessor :prompt_proc
|
16
15
|
attr_accessor :auto_indent_proc
|
17
|
-
attr_accessor :pre_input_hook
|
18
16
|
attr_accessor :dig_perfect_match_proc
|
19
17
|
attr_writer :output
|
20
18
|
|
@@ -57,6 +55,8 @@ class Reline::LineEditor
|
|
57
55
|
def initialize(config, encoding)
|
58
56
|
@config = config
|
59
57
|
@completion_append_character = ''
|
58
|
+
@cursor_base_y = 0
|
59
|
+
@screen_size = Reline::IOGate.get_screen_size
|
60
60
|
reset_variables(encoding: encoding)
|
61
61
|
end
|
62
62
|
|
@@ -68,67 +68,30 @@ class Reline::LineEditor
|
|
68
68
|
@in_pasting = in_pasting
|
69
69
|
end
|
70
70
|
|
71
|
-
def simplified_rendering?
|
72
|
-
if finished?
|
73
|
-
false
|
74
|
-
elsif @just_cursor_moving and not @rerender_all
|
75
|
-
true
|
76
|
-
else
|
77
|
-
not @rerender_all and not finished? and @in_pasting
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
71
|
private def check_mode_string
|
82
|
-
mode_string = nil
|
83
72
|
if @config.show_mode_in_prompt
|
84
73
|
if @config.editing_mode_is?(:vi_command)
|
85
|
-
|
74
|
+
@config.vi_cmd_mode_string
|
86
75
|
elsif @config.editing_mode_is?(:vi_insert)
|
87
|
-
|
76
|
+
@config.vi_ins_mode_string
|
88
77
|
elsif @config.editing_mode_is?(:emacs)
|
89
|
-
|
78
|
+
@config.emacs_mode_string
|
90
79
|
else
|
91
|
-
|
80
|
+
'?'
|
92
81
|
end
|
93
82
|
end
|
94
|
-
if mode_string != @prev_mode_string
|
95
|
-
@rerender_all = true
|
96
|
-
end
|
97
|
-
@prev_mode_string = mode_string
|
98
|
-
mode_string
|
99
83
|
end
|
100
84
|
|
101
|
-
private def check_multiline_prompt(buffer
|
85
|
+
private def check_multiline_prompt(buffer)
|
102
86
|
if @vi_arg
|
103
87
|
prompt = "(arg: #{@vi_arg}) "
|
104
|
-
@rerender_all = true
|
105
88
|
elsif @searching_prompt
|
106
89
|
prompt = @searching_prompt
|
107
|
-
@rerender_all = true
|
108
90
|
else
|
109
91
|
prompt = @prompt
|
110
92
|
end
|
111
|
-
if simplified_rendering? && !force_recalc
|
112
|
-
mode_string = check_mode_string
|
113
|
-
prompt = mode_string + prompt if mode_string
|
114
|
-
return [prompt, calculate_width(prompt, true), [prompt] * buffer.size]
|
115
|
-
end
|
116
93
|
if @prompt_proc
|
117
|
-
|
118
|
-
if @cached_prompt_list
|
119
|
-
if @just_cursor_moving
|
120
|
-
use_cached_prompt_list = true
|
121
|
-
elsif Time.now.to_f < (@prompt_cache_time + PROMPT_LIST_CACHE_TIMEOUT) and buffer.size == @cached_prompt_list.size
|
122
|
-
use_cached_prompt_list = true
|
123
|
-
end
|
124
|
-
end
|
125
|
-
use_cached_prompt_list = false if @rerender_all
|
126
|
-
if use_cached_prompt_list
|
127
|
-
prompt_list = @cached_prompt_list
|
128
|
-
else
|
129
|
-
prompt_list = @cached_prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
|
130
|
-
@prompt_cache_time = Time.now.to_f
|
131
|
-
end
|
94
|
+
prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
|
132
95
|
prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
|
133
96
|
prompt_list = [prompt] if prompt_list.empty?
|
134
97
|
mode_string = check_mode_string
|
@@ -141,20 +104,17 @@ class Reline::LineEditor
|
|
141
104
|
prompt_list << prompt_list.last
|
142
105
|
end
|
143
106
|
end
|
144
|
-
|
145
|
-
[prompt, prompt_width, prompt_list]
|
107
|
+
prompt_list
|
146
108
|
else
|
147
109
|
mode_string = check_mode_string
|
148
110
|
prompt = mode_string + prompt if mode_string
|
149
|
-
|
150
|
-
[prompt, prompt_width, nil]
|
111
|
+
[prompt] * buffer.size
|
151
112
|
end
|
152
113
|
end
|
153
114
|
|
154
115
|
def reset(prompt = '', encoding:)
|
155
|
-
@
|
116
|
+
@cursor_base_y = Reline::IOGate.cursor_pos.y
|
156
117
|
@screen_size = Reline::IOGate.get_screen_size
|
157
|
-
@screen_height = @screen_size.first
|
158
118
|
reset_variables(prompt, encoding: encoding)
|
159
119
|
Reline::IOGate.set_winch_handler do
|
160
120
|
@resized = true
|
@@ -184,54 +144,28 @@ class Reline::LineEditor
|
|
184
144
|
|
185
145
|
def resize
|
186
146
|
return unless @resized
|
187
|
-
|
188
|
-
|
189
|
-
old_screen_size = @screen_size
|
147
|
+
|
148
|
+
Reline::IOGate.hide_cursor
|
190
149
|
@screen_size = Reline::IOGate.get_screen_size
|
191
|
-
@
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
new_buffer.each_with_index do |line, index|
|
200
|
-
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
201
|
-
width = prompt_width + calculate_width(line)
|
202
|
-
height = calculate_height_by_width(width)
|
203
|
-
back += height
|
204
|
-
end
|
205
|
-
@highest_in_all = back
|
206
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
207
|
-
@first_line_started_from =
|
208
|
-
if @line_index.zero?
|
209
|
-
0
|
210
|
-
else
|
211
|
-
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
212
|
-
end
|
213
|
-
if @prompt_proc
|
214
|
-
prompt = prompt_list[@line_index]
|
215
|
-
prompt_width = calculate_width(prompt, true)
|
216
|
-
end
|
217
|
-
calculate_nearest_cursor
|
218
|
-
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
219
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
220
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
221
|
-
@rerender_all = true
|
222
|
-
end
|
150
|
+
@resized = false
|
151
|
+
scroll_into_view
|
152
|
+
Reline::IOGate.move_cursor_up @cursor_y
|
153
|
+
@cursor_base_y = Reline::IOGate.cursor_pos.y
|
154
|
+
@cursor_y = 0
|
155
|
+
@rendered_screen_cache = nil
|
156
|
+
render_differential
|
157
|
+
Reline::IOGate.show_cursor
|
223
158
|
end
|
224
159
|
|
225
160
|
def set_signal_handlers
|
226
161
|
@old_trap = Signal.trap('INT') {
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
Reline::IOGate.
|
234
|
-
scroll_down(1)
|
162
|
+
Reline::IOGate.hide_cursor
|
163
|
+
clear_dialogs
|
164
|
+
scrolldown = render_differential
|
165
|
+
Reline::IOGate.scroll_down scrolldown
|
166
|
+
Reline::IOGate.move_cursor_column 0
|
167
|
+
@rendered_screen_cache = nil
|
168
|
+
Reline::IOGate.show_cursor
|
235
169
|
case @old_trap
|
236
170
|
when 'DEFAULT', 'SYSTEM_DEFAULT'
|
237
171
|
raise Interrupt
|
@@ -260,7 +194,6 @@ class Reline::LineEditor
|
|
260
194
|
@is_multiline = false
|
261
195
|
@finished = false
|
262
196
|
@cleared = false
|
263
|
-
@rerender_all = false
|
264
197
|
@history_pointer = nil
|
265
198
|
@kill_ring ||= Reline::KillRing.new
|
266
199
|
@vi_clipboard = ''
|
@@ -275,40 +208,27 @@ class Reline::LineEditor
|
|
275
208
|
@first_prompt = true
|
276
209
|
@searching_prompt = nil
|
277
210
|
@first_char = true
|
278
|
-
@add_newline_to_end_of_buffer = false
|
279
|
-
@just_cursor_moving = nil
|
280
|
-
@cached_prompt_list = nil
|
281
|
-
@prompt_cache_time = nil
|
282
211
|
@eof = false
|
283
212
|
@continuous_insertion_buffer = String.new(encoding: @encoding)
|
284
|
-
@scroll_partial_screen =
|
285
|
-
@prev_mode_string = nil
|
213
|
+
@scroll_partial_screen = 0
|
286
214
|
@drop_terminate_spaces = false
|
287
215
|
@in_pasting = false
|
288
216
|
@auto_indent_proc = nil
|
289
217
|
@dialogs = []
|
290
|
-
@previous_rendered_dialog_y = 0
|
291
|
-
@last_key = nil
|
292
218
|
@resized = false
|
219
|
+
@cursor_y = 0
|
220
|
+
@cache = {}
|
221
|
+
@rendered_screen_cache = nil
|
293
222
|
reset_line
|
294
223
|
end
|
295
224
|
|
296
225
|
def reset_line
|
297
|
-
@cursor = 0
|
298
|
-
@cursor_max = 0
|
299
226
|
@byte_pointer = 0
|
300
227
|
@buffer_of_lines = [String.new(encoding: @encoding)]
|
301
228
|
@line_index = 0
|
302
|
-
@
|
303
|
-
@line = @buffer_of_lines[0]
|
304
|
-
@first_line_started_from = 0
|
305
|
-
@move_up = 0
|
306
|
-
@started_from = 0
|
307
|
-
@highest_in_this = 1
|
308
|
-
@highest_in_all = 1
|
229
|
+
@cache.clear
|
309
230
|
@line_backup_in_history = nil
|
310
231
|
@multibyte_buffer = String.new(encoding: 'ASCII-8BIT')
|
311
|
-
@check_new_auto_indent = false
|
312
232
|
end
|
313
233
|
|
314
234
|
def multiline_on
|
@@ -319,26 +239,27 @@ class Reline::LineEditor
|
|
319
239
|
@is_multiline = false
|
320
240
|
end
|
321
241
|
|
322
|
-
private def calculate_height_by_lines(lines, prompt)
|
323
|
-
result = 0
|
324
|
-
prompt_list = prompt.is_a?(Array) ? prompt : nil
|
325
|
-
lines.each_with_index { |line, i|
|
326
|
-
prompt = prompt_list[i] if prompt_list and prompt_list[i]
|
327
|
-
result += calculate_height_by_width(calculate_width(prompt, true) + calculate_width(line))
|
328
|
-
}
|
329
|
-
result
|
330
|
-
end
|
331
|
-
|
332
242
|
private def insert_new_line(cursor_line, next_line)
|
333
|
-
@line = cursor_line
|
334
243
|
@buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding: @encoding))
|
335
|
-
@
|
244
|
+
@buffer_of_lines[@line_index] = cursor_line
|
336
245
|
@line_index += 1
|
337
|
-
@
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
246
|
+
@byte_pointer = 0
|
247
|
+
if @auto_indent_proc && !@in_pasting
|
248
|
+
if next_line.empty?
|
249
|
+
(
|
250
|
+
# For compatibility, use this calculation instead of just `process_auto_indent @line_index - 1, cursor_dependent: false`
|
251
|
+
indent1 = @auto_indent_proc.(@buffer_of_lines.take(@line_index - 1).push(''), @line_index - 1, 0, true)
|
252
|
+
indent2 = @auto_indent_proc.(@buffer_of_lines.take(@line_index), @line_index - 1, @buffer_of_lines[@line_index - 1].bytesize, false)
|
253
|
+
indent = indent2 || indent1
|
254
|
+
@buffer_of_lines[@line_index - 1] = ' ' * indent + @buffer_of_lines[@line_index - 1].gsub(/\A */, '')
|
255
|
+
)
|
256
|
+
process_auto_indent @line_index, add_newline: true
|
257
|
+
else
|
258
|
+
process_auto_indent @line_index - 1, cursor_dependent: false
|
259
|
+
process_auto_indent @line_index, add_newline: true # Need for compatibility
|
260
|
+
process_auto_indent @line_index, cursor_dependent: false
|
261
|
+
end
|
262
|
+
end
|
342
263
|
end
|
343
264
|
|
344
265
|
private def split_by_width(str, max_width)
|
@@ -346,41 +267,30 @@ class Reline::LineEditor
|
|
346
267
|
end
|
347
268
|
|
348
269
|
private def scroll_down(val)
|
349
|
-
if val
|
270
|
+
if @cursor_base_y + @cursor_y + val < screen_height
|
350
271
|
Reline::IOGate.move_cursor_down(val)
|
351
|
-
@
|
272
|
+
@cursor_y += val
|
352
273
|
else
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
private def move_cursor_up(val)
|
360
|
-
if val > 0
|
361
|
-
Reline::IOGate.move_cursor_up(val)
|
362
|
-
@rest_height += val
|
363
|
-
elsif val < 0
|
364
|
-
move_cursor_down(-val)
|
274
|
+
move = screen_height - @cursor_base_y - @cursor_y - 1
|
275
|
+
scroll = val - move
|
276
|
+
Reline::IOGate.scroll_down(move)
|
277
|
+
Reline::IOGate.scroll_down(scroll)
|
278
|
+
@cursor_y += move
|
279
|
+
@cursor_base_y = [@cursor_base_y - scroll, 0].max
|
365
280
|
end
|
366
281
|
end
|
367
282
|
|
368
|
-
|
369
|
-
|
370
|
-
Reline::IOGate.move_cursor_down(val)
|
371
|
-
@rest_height -= val
|
372
|
-
@rest_height = 0 if @rest_height < 0
|
373
|
-
elsif val < 0
|
374
|
-
move_cursor_up(-val)
|
375
|
-
end
|
283
|
+
def current_byte_pointer_cursor
|
284
|
+
calculate_width(current_line.byteslice(0, @byte_pointer))
|
376
285
|
end
|
377
286
|
|
378
|
-
private def calculate_nearest_cursor(
|
287
|
+
private def calculate_nearest_cursor(cursor)
|
288
|
+
line_to_calc = current_line
|
379
289
|
new_cursor_max = calculate_width(line_to_calc)
|
380
290
|
new_cursor = 0
|
381
291
|
new_byte_pointer = 0
|
382
292
|
height = 1
|
383
|
-
max_width =
|
293
|
+
max_width = screen_width
|
384
294
|
if @config.editing_mode_is?(:vi_command)
|
385
295
|
last_byte_size = Reline::Unicode.get_prev_mbchar_size(line_to_calc, line_to_calc.bytesize)
|
386
296
|
if last_byte_size > 0
|
@@ -406,110 +316,246 @@ class Reline::LineEditor
|
|
406
316
|
end
|
407
317
|
new_byte_pointer += gc.bytesize
|
408
318
|
end
|
409
|
-
|
410
|
-
if update
|
411
|
-
@cursor = new_cursor
|
412
|
-
@cursor_max = new_cursor_max
|
413
|
-
@started_from = new_started_from
|
414
|
-
@byte_pointer = new_byte_pointer
|
415
|
-
else
|
416
|
-
[new_cursor, new_cursor_max, new_started_from, new_byte_pointer]
|
417
|
-
end
|
319
|
+
@byte_pointer = new_byte_pointer
|
418
320
|
end
|
419
321
|
|
420
|
-
def
|
421
|
-
|
422
|
-
|
423
|
-
|
322
|
+
def with_cache(key, *deps)
|
323
|
+
cached_deps, value = @cache[key]
|
324
|
+
if cached_deps != deps
|
325
|
+
@cache[key] = [deps, value = yield(*deps, cached_deps, value)]
|
326
|
+
end
|
327
|
+
value
|
424
328
|
end
|
425
329
|
|
426
|
-
def
|
427
|
-
|
428
|
-
|
429
|
-
scroll_down(@highest_in_all - @first_line_started_from)
|
430
|
-
@rerender_all = true
|
330
|
+
def modified_lines
|
331
|
+
with_cache(__method__, whole_lines, finished?) do |whole, complete|
|
332
|
+
modify_lines(whole, complete)
|
431
333
|
end
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
cursor_column = (prompt_width + @cursor) % @screen_size.last
|
438
|
-
if @cleared
|
439
|
-
clear_screen_buffer(prompt, prompt_list, prompt_width)
|
440
|
-
@cleared = false
|
441
|
-
return
|
334
|
+
end
|
335
|
+
|
336
|
+
def prompt_list
|
337
|
+
with_cache(__method__, whole_lines, @vi_arg, @searching_prompt) do |lines|
|
338
|
+
check_multiline_prompt(lines)
|
442
339
|
end
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
340
|
+
end
|
341
|
+
|
342
|
+
def screen_height
|
343
|
+
@screen_size.first
|
344
|
+
end
|
345
|
+
|
346
|
+
def screen_width
|
347
|
+
@screen_size.last
|
348
|
+
end
|
349
|
+
|
350
|
+
def screen_scroll_top
|
351
|
+
@scroll_partial_screen
|
352
|
+
end
|
353
|
+
|
354
|
+
def wrapped_lines
|
355
|
+
with_cache(__method__, @buffer_of_lines.size, modified_lines, prompt_list, screen_width) do |n, lines, prompts, width, prev_cache_key, cached_value|
|
356
|
+
prev_n, prev_lines, prev_prompts, prev_width = prev_cache_key
|
357
|
+
cached_wraps = {}
|
358
|
+
if prev_width == width
|
359
|
+
prev_n.times do |i|
|
360
|
+
cached_wraps[[prev_prompts[i], prev_lines[i]]] = cached_value[i]
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
n.times.map do |i|
|
365
|
+
prompt = prompts[i]
|
366
|
+
line = lines[i]
|
367
|
+
cached_wraps[[prompt, line]] || split_by_width("#{prompt}#{line}", width).first.compact
|
453
368
|
end
|
454
|
-
@output.flush
|
455
|
-
clear_dialog(cursor_column)
|
456
|
-
return
|
457
369
|
end
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
370
|
+
end
|
371
|
+
|
372
|
+
def calculate_overlay_levels(overlay_levels)
|
373
|
+
levels = []
|
374
|
+
overlay_levels.each do |x, w, l|
|
375
|
+
levels.fill(l, x, w)
|
376
|
+
end
|
377
|
+
levels
|
378
|
+
end
|
379
|
+
|
380
|
+
def render_line_differential(old_items, new_items)
|
381
|
+
old_levels = calculate_overlay_levels(old_items.zip(new_items).each_with_index.map {|((x, w, c), (nx, _nw, nc)), i| [x, w, c == nc && x == nx ? i : -1] if x }.compact)
|
382
|
+
new_levels = calculate_overlay_levels(new_items.each_with_index.map { |(x, w), i| [x, w, i] if x }.compact).take(screen_width)
|
383
|
+
base_x = 0
|
384
|
+
new_levels.zip(old_levels).chunk { |n, o| n == o ? :skip : n || :blank }.each do |level, chunk|
|
385
|
+
width = chunk.size
|
386
|
+
if level == :skip
|
387
|
+
# do nothing
|
388
|
+
elsif level == :blank
|
389
|
+
Reline::IOGate.move_cursor_column base_x
|
390
|
+
@output.write "\e[0m#{' ' * width}"
|
479
391
|
else
|
392
|
+
x, w, content = new_items[level]
|
393
|
+
content = Reline::Unicode.take_range(content, base_x - x, width) unless x == base_x && w == width
|
394
|
+
Reline::IOGate.move_cursor_column base_x
|
395
|
+
@output.write "\e[0m#{content}\e[0m"
|
480
396
|
end
|
397
|
+
base_x += width
|
481
398
|
end
|
482
|
-
if
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
399
|
+
if old_levels.size > new_levels.size
|
400
|
+
Reline::IOGate.move_cursor_column new_levels.size
|
401
|
+
Reline::IOGate.erase_after_cursor
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def editor_cursor_position
|
406
|
+
line = ' ' * calculate_width(prompt_list[@line_index], true) + whole_lines[@line_index].byteslice(0, @byte_pointer)
|
407
|
+
wrapped_line_before_cursor = split_by_width(line, screen_width).first.compact
|
408
|
+
editor_cursor_y = wrapped_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
|
409
|
+
editor_cursor_x = calculate_width(wrapped_line_before_cursor.last)
|
410
|
+
[editor_cursor_x, editor_cursor_y]
|
411
|
+
end
|
412
|
+
|
413
|
+
def clear_dialogs
|
414
|
+
@dialogs.each do |dialog|
|
415
|
+
dialog.contents = nil
|
416
|
+
dialog.trap_key = nil
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
def update_dialogs(key = nil)
|
421
|
+
@dialog_initialzed = true
|
422
|
+
editor_cursor_x, editor_cursor_y = editor_cursor_position
|
423
|
+
@dialogs.each do |dialog|
|
424
|
+
dialog.trap_key = nil
|
425
|
+
update_each_dialog(dialog, editor_cursor_x, editor_cursor_y - screen_scroll_top, key)
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def clear_rendered_lines
|
430
|
+
Reline::IOGate.move_cursor_up @cursor_y
|
431
|
+
Reline::IOGate.move_cursor_column 0
|
432
|
+
|
433
|
+
num_lines = @rendered_screen_cache&.size
|
434
|
+
return unless num_lines && num_lines >= 1
|
435
|
+
|
436
|
+
Reline::IOGate.move_cursor_down num_lines - 1
|
437
|
+
(num_lines - 1).times do
|
438
|
+
Reline::IOGate.erase_after_cursor
|
439
|
+
Reline::IOGate.move_cursor_up 1
|
440
|
+
end
|
441
|
+
Reline::IOGate.erase_after_cursor
|
442
|
+
@rendered_screen_cache = nil
|
443
|
+
end
|
444
|
+
|
445
|
+
def render_full_content
|
446
|
+
lines = @buffer_of_lines.size.times.map do |i|
|
447
|
+
line = prompt_list[i] + modified_lines[i]
|
448
|
+
wrapped_lines, = split_by_width(line, screen_width)
|
449
|
+
wrapped_lines.last.empty? ? "#{line} " : line
|
450
|
+
end
|
451
|
+
@output.puts lines.map { |l| "#{l}\r\n" }.join
|
452
|
+
end
|
453
|
+
|
454
|
+
def print_nomultiline_prompt(prompt)
|
455
|
+
return unless prompt && !@is_multiline
|
456
|
+
|
457
|
+
# Readline's test `TestRelineAsReadline#test_readline` requires first output to be prompt, not cursor reset escape sequence.
|
458
|
+
@rendered_screen_cache = [[[0, Reline::Unicode.calculate_width(prompt, true), prompt]]]
|
459
|
+
@output.write prompt
|
460
|
+
end
|
461
|
+
|
462
|
+
def render_differential
|
463
|
+
unless @dialog_initialzed
|
464
|
+
update_dialogs
|
465
|
+
end
|
466
|
+
|
467
|
+
editor_cursor_x, editor_cursor_y = editor_cursor_position
|
468
|
+
|
469
|
+
rendered_lines = @rendered_screen_cache || []
|
470
|
+
new_lines = wrapped_lines.flatten[screen_scroll_top, screen_height].map do |l|
|
471
|
+
[[0, Reline::Unicode.calculate_width(l, true), l]]
|
472
|
+
end
|
473
|
+
if @menu_info
|
474
|
+
@menu_info.list.sort!.each do |item|
|
475
|
+
new_lines << [[0, Reline::Unicode.calculate_width(item), item]]
|
501
476
|
end
|
502
|
-
@
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
477
|
+
@menu_info = nil # TODO: do not change state here
|
478
|
+
end
|
479
|
+
|
480
|
+
@dialogs.each_with_index do |dialog, index|
|
481
|
+
next unless dialog.contents
|
482
|
+
|
483
|
+
x_range, y_range = dialog_range dialog, editor_cursor_y - screen_scroll_top
|
484
|
+
y_range.each do |row|
|
485
|
+
next if row < 0 || row >= screen_height
|
486
|
+
dialog_rows = new_lines[row] ||= []
|
487
|
+
dialog_rows[index + 1] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
num_lines = [[new_lines.size, rendered_lines.size].max, screen_height].min
|
492
|
+
scroll_down(num_lines - 1 - @cursor_y) if (num_lines - 1 - @cursor_y) > 0
|
493
|
+
@cursor_y = num_lines - 1
|
494
|
+
num_lines.times do |i|
|
495
|
+
rendered_line = rendered_lines[i] || []
|
496
|
+
line_to_render = new_lines[i] || []
|
497
|
+
next if rendered_line == line_to_render
|
498
|
+
|
499
|
+
Reline::IOGate.move_cursor_down i - @cursor_y
|
500
|
+
@cursor_y = i
|
501
|
+
unless rendered_lines[i]
|
502
|
+
Reline::IOGate.move_cursor_column 0
|
510
503
|
Reline::IOGate.erase_after_cursor
|
511
504
|
end
|
505
|
+
render_line_differential(rendered_line, line_to_render)
|
506
|
+
end
|
507
|
+
@rendered_screen_cache = new_lines
|
508
|
+
y = editor_cursor_y - screen_scroll_top
|
509
|
+
Reline::IOGate.move_cursor_column editor_cursor_x
|
510
|
+
Reline::IOGate.move_cursor_down y - @cursor_y
|
511
|
+
@cursor_y = y
|
512
|
+
new_lines.size - @cursor_y
|
513
|
+
end
|
514
|
+
|
515
|
+
def current_row
|
516
|
+
wrapped_lines.flatten[editor_cursor_y]
|
517
|
+
end
|
518
|
+
|
519
|
+
def upper_space_height
|
520
|
+
@cursor_y - 1
|
521
|
+
end
|
522
|
+
|
523
|
+
def rest_height
|
524
|
+
screen_height - @cursor_y - @cursor_base_y - 1
|
525
|
+
end
|
526
|
+
|
527
|
+
def rerender_all
|
528
|
+
Reline::IOGate.hide_cursor
|
529
|
+
process_insert(force: true)
|
530
|
+
handle_cleared
|
531
|
+
render_differential unless @in_pasting
|
532
|
+
Reline::IOGate.show_cursor
|
533
|
+
end
|
534
|
+
|
535
|
+
def handle_cleared
|
536
|
+
return unless @cleared
|
537
|
+
|
538
|
+
@cleared = false
|
539
|
+
@rendered_screen_cache = nil
|
540
|
+
Reline::IOGate.clear_screen
|
541
|
+
@screen_size = Reline::IOGate.get_screen_size
|
542
|
+
@cursor_base_y = 0
|
543
|
+
@cursor_y = 0
|
544
|
+
scroll_into_view
|
545
|
+
render_differential
|
546
|
+
end
|
547
|
+
|
548
|
+
def rerender
|
549
|
+
Reline::IOGate.hide_cursor
|
550
|
+
finished = finished?
|
551
|
+
handle_cleared
|
552
|
+
if finished
|
553
|
+
clear_rendered_lines
|
554
|
+
render_full_content
|
555
|
+
elsif !@in_pasting
|
556
|
+
render_differential
|
512
557
|
end
|
558
|
+
Reline::IOGate.show_cursor
|
513
559
|
end
|
514
560
|
|
515
561
|
class DialogProcScope
|
@@ -563,17 +609,16 @@ class Reline::LineEditor
|
|
563
609
|
end
|
564
610
|
|
565
611
|
def screen_width
|
566
|
-
@line_editor.
|
612
|
+
@line_editor.screen_width
|
567
613
|
end
|
568
614
|
|
569
615
|
def screen_height
|
570
|
-
@line_editor.
|
616
|
+
@line_editor.screen_height
|
571
617
|
end
|
572
618
|
|
573
619
|
def preferred_dialog_height
|
574
|
-
|
575
|
-
|
576
|
-
[cursor_pos.y - scroll_partial_screen, rest_height, (screen_height + 6) / 5].max
|
620
|
+
_editor_cursor_x, editor_cursor_y = @line_editor.editor_cursor_position
|
621
|
+
[editor_cursor_y - @line_editor.screen_scroll_top, @line_editor.rest_height, (screen_height + 6) / 5].max
|
577
622
|
end
|
578
623
|
|
579
624
|
def completion_journey_data
|
@@ -646,14 +691,6 @@ class Reline::LineEditor
|
|
646
691
|
end
|
647
692
|
|
648
693
|
DIALOG_DEFAULT_HEIGHT = 20
|
649
|
-
private def render_dialog(cursor_column)
|
650
|
-
changes = @dialogs.map do |dialog|
|
651
|
-
old_dialog = dialog.dup
|
652
|
-
update_each_dialog(dialog, cursor_column)
|
653
|
-
[old_dialog, dialog]
|
654
|
-
end
|
655
|
-
render_dialog_changes(changes, cursor_column)
|
656
|
-
end
|
657
694
|
|
658
695
|
private def padding_space_with_escape_sequences(str, width)
|
659
696
|
padding_width = width - calculate_width(str, true)
|
@@ -662,118 +699,15 @@ class Reline::LineEditor
|
|
662
699
|
str + (' ' * padding_width)
|
663
700
|
end
|
664
701
|
|
665
|
-
private def range_subtract(base_ranges, subtract_ranges)
|
666
|
-
indices = base_ranges.flat_map(&:to_a).uniq.sort - subtract_ranges.flat_map(&:to_a)
|
667
|
-
chunks = indices.chunk_while { |a, b| a + 1 == b }
|
668
|
-
chunks.map { |a| a.first...a.last + 1 }
|
669
|
-
end
|
670
|
-
|
671
702
|
private def dialog_range(dialog, dialog_y)
|
672
703
|
x_range = dialog.column...dialog.column + dialog.width
|
673
704
|
y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
|
674
705
|
[x_range, y_range]
|
675
706
|
end
|
676
707
|
|
677
|
-
private def
|
678
|
-
|
679
|
-
|
680
|
-
new_dialog_ranges = {}
|
681
|
-
new_dialog_contents = {}
|
682
|
-
changes.each do |old_dialog, new_dialog|
|
683
|
-
if old_dialog.contents
|
684
|
-
x_range, y_range = dialog_range(old_dialog, @previous_rendered_dialog_y)
|
685
|
-
y_range.each do |y|
|
686
|
-
(old_dialog_ranges[y] ||= []) << x_range
|
687
|
-
end
|
688
|
-
end
|
689
|
-
if new_dialog.contents
|
690
|
-
x_range, y_range = dialog_range(new_dialog, @first_line_started_from + @started_from)
|
691
|
-
y_range.each do |y|
|
692
|
-
(new_dialog_ranges[y] ||= []) << x_range
|
693
|
-
(new_dialog_contents[y] ||= []) << [x_range, new_dialog.contents[y - y_range.begin]]
|
694
|
-
end
|
695
|
-
end
|
696
|
-
end
|
697
|
-
return if old_dialog_ranges.empty? && new_dialog_ranges.empty?
|
698
|
-
|
699
|
-
# Calculate x-coordinate ranges to restore text that was hidden behind dialogs for each line
|
700
|
-
ranges_to_restore = {}
|
701
|
-
subtract_cache = {}
|
702
|
-
old_dialog_ranges.each do |y, old_x_ranges|
|
703
|
-
new_x_ranges = new_dialog_ranges[y] || []
|
704
|
-
ranges = subtract_cache[[old_x_ranges, new_x_ranges]] ||= range_subtract(old_x_ranges, new_x_ranges)
|
705
|
-
ranges_to_restore[y] = ranges if ranges.any?
|
706
|
-
end
|
707
|
-
|
708
|
-
# Create visual_lines for restoring text hidden behind dialogs
|
709
|
-
if ranges_to_restore.any?
|
710
|
-
lines = whole_lines
|
711
|
-
prompt, _prompt_width, prompt_list = check_multiline_prompt(lines, force_recalc: true)
|
712
|
-
modified_lines = modify_lines(lines, force_recalc: true)
|
713
|
-
visual_lines = []
|
714
|
-
modified_lines.each_with_index { |l, i|
|
715
|
-
pr = prompt_list ? prompt_list[i] : prompt
|
716
|
-
vl, = split_by_width(pr + l, @screen_size.last)
|
717
|
-
vl.compact!
|
718
|
-
visual_lines.concat(vl)
|
719
|
-
}
|
720
|
-
end
|
721
|
-
|
722
|
-
# Clear and rerender all dialogs line by line
|
723
|
-
Reline::IOGate.hide_cursor
|
724
|
-
ymin, ymax = (ranges_to_restore.keys + new_dialog_ranges.keys).minmax
|
725
|
-
scroll_partial_screen = @scroll_partial_screen || 0
|
726
|
-
screen_y_range = scroll_partial_screen..(scroll_partial_screen + @screen_height - 1)
|
727
|
-
ymin = ymin.clamp(screen_y_range.begin, screen_y_range.end)
|
728
|
-
ymax = ymax.clamp(screen_y_range.begin, screen_y_range.end)
|
729
|
-
dialog_y = @first_line_started_from + @started_from
|
730
|
-
cursor_y = dialog_y
|
731
|
-
if @highest_in_all <= ymax
|
732
|
-
scroll_down(ymax - cursor_y)
|
733
|
-
move_cursor_up(ymax - cursor_y)
|
734
|
-
end
|
735
|
-
(ymin..ymax).each do |y|
|
736
|
-
move_cursor_down(y - cursor_y)
|
737
|
-
cursor_y = y
|
738
|
-
new_x_ranges = new_dialog_ranges[y]
|
739
|
-
restore_ranges = ranges_to_restore[y]
|
740
|
-
# Restore text that was hidden behind dialogs
|
741
|
-
if restore_ranges
|
742
|
-
line = visual_lines[y] || ''
|
743
|
-
restore_ranges.each do |range|
|
744
|
-
col = range.begin
|
745
|
-
width = range.end - range.begin
|
746
|
-
s = padding_space_with_escape_sequences(Reline::Unicode.take_range(line, col, width), width)
|
747
|
-
Reline::IOGate.move_cursor_column(col)
|
748
|
-
@output.write "\e[0m#{s}\e[0m"
|
749
|
-
end
|
750
|
-
max_column = [calculate_width(line, true), new_x_ranges&.map(&:end)&.max || 0].max
|
751
|
-
if max_column < restore_ranges.map(&:end).max
|
752
|
-
Reline::IOGate.move_cursor_column(max_column)
|
753
|
-
Reline::IOGate.erase_after_cursor
|
754
|
-
end
|
755
|
-
end
|
756
|
-
# Render dialog contents
|
757
|
-
new_dialog_contents[y]&.each do |x_range, content|
|
758
|
-
Reline::IOGate.move_cursor_column(x_range.begin)
|
759
|
-
@output.write "\e[0m#{content}\e[0m"
|
760
|
-
end
|
761
|
-
end
|
762
|
-
move_cursor_up(cursor_y - dialog_y)
|
763
|
-
Reline::IOGate.move_cursor_column(cursor_column)
|
764
|
-
Reline::IOGate.show_cursor
|
765
|
-
|
766
|
-
@previous_rendered_dialog_y = dialog_y
|
767
|
-
end
|
768
|
-
|
769
|
-
private def update_each_dialog(dialog, cursor_column)
|
770
|
-
if @in_pasting
|
771
|
-
dialog.contents = nil
|
772
|
-
dialog.trap_key = nil
|
773
|
-
return
|
774
|
-
end
|
775
|
-
dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
|
776
|
-
dialog_render_info = dialog.call(@last_key)
|
708
|
+
private def update_each_dialog(dialog, cursor_column, cursor_row, key = nil)
|
709
|
+
dialog.set_cursor_pos(cursor_column, cursor_row)
|
710
|
+
dialog_render_info = dialog.call(key)
|
777
711
|
if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
|
778
712
|
dialog.contents = nil
|
779
713
|
dialog.trap_key = nil
|
@@ -813,14 +747,14 @@ class Reline::LineEditor
|
|
813
747
|
else
|
814
748
|
scrollbar_pos = nil
|
815
749
|
end
|
816
|
-
upper_space =
|
750
|
+
upper_space = upper_space_height
|
817
751
|
dialog.column = dialog_render_info.pos.x
|
818
752
|
dialog.width += @block_elem_width if scrollbar_pos
|
819
|
-
diff = (dialog.column + dialog.width) -
|
753
|
+
diff = (dialog.column + dialog.width) - screen_width
|
820
754
|
if diff > 0
|
821
755
|
dialog.column -= diff
|
822
756
|
end
|
823
|
-
if (
|
757
|
+
if (rest_height - dialog_render_info.pos.y) >= height
|
824
758
|
dialog.vertical_offset = dialog_render_info.pos.y + 1
|
825
759
|
elsif upper_space >= height
|
826
760
|
dialog.vertical_offset = dialog_render_info.pos.y - height
|
@@ -829,7 +763,7 @@ class Reline::LineEditor
|
|
829
763
|
end
|
830
764
|
if dialog.column < 0
|
831
765
|
dialog.column = 0
|
832
|
-
dialog.width =
|
766
|
+
dialog.width = screen_width
|
833
767
|
end
|
834
768
|
face = Reline::Face[dialog_render_info.face || :default]
|
835
769
|
scrollbar_sgr = face[:scrollbar]
|
@@ -856,373 +790,14 @@ class Reline::LineEditor
|
|
856
790
|
end
|
857
791
|
end
|
858
792
|
|
859
|
-
private def
|
860
|
-
|
861
|
-
old_dialog = dialog.dup
|
862
|
-
dialog.contents = nil
|
863
|
-
[old_dialog, dialog]
|
864
|
-
end
|
865
|
-
render_dialog_changes(changes, cursor_column)
|
866
|
-
end
|
867
|
-
|
868
|
-
private def clear_dialog_with_trap_key(cursor_column)
|
869
|
-
clear_dialog(cursor_column)
|
870
|
-
@dialogs.each do |dialog|
|
871
|
-
dialog.trap_key = nil
|
872
|
-
end
|
873
|
-
end
|
874
|
-
|
875
|
-
private def calculate_scroll_partial_screen(highest_in_all, cursor_y)
|
876
|
-
if @screen_height < highest_in_all
|
877
|
-
old_scroll_partial_screen = @scroll_partial_screen
|
878
|
-
if cursor_y == 0
|
879
|
-
@scroll_partial_screen = 0
|
880
|
-
elsif cursor_y == (highest_in_all - 1)
|
881
|
-
@scroll_partial_screen = highest_in_all - @screen_height
|
882
|
-
else
|
883
|
-
if @scroll_partial_screen
|
884
|
-
if cursor_y <= @scroll_partial_screen
|
885
|
-
@scroll_partial_screen = cursor_y
|
886
|
-
elsif (@scroll_partial_screen + @screen_height - 1) < cursor_y
|
887
|
-
@scroll_partial_screen = cursor_y - (@screen_height - 1)
|
888
|
-
end
|
889
|
-
else
|
890
|
-
if cursor_y > (@screen_height - 1)
|
891
|
-
@scroll_partial_screen = cursor_y - (@screen_height - 1)
|
892
|
-
else
|
893
|
-
@scroll_partial_screen = 0
|
894
|
-
end
|
895
|
-
end
|
896
|
-
end
|
897
|
-
if @scroll_partial_screen != old_scroll_partial_screen
|
898
|
-
@rerender_all = true
|
899
|
-
end
|
900
|
-
else
|
901
|
-
if @scroll_partial_screen
|
902
|
-
@rerender_all = true
|
903
|
-
end
|
904
|
-
@scroll_partial_screen = nil
|
905
|
-
end
|
906
|
-
end
|
907
|
-
|
908
|
-
private def rerender_added_newline(prompt, prompt_width, prompt_list)
|
909
|
-
@buffer_of_lines[@previous_line_index] = @line
|
910
|
-
@line = @buffer_of_lines[@line_index]
|
911
|
-
@previous_line_index = nil
|
912
|
-
if @in_pasting
|
913
|
-
scroll_down(1)
|
914
|
-
else
|
915
|
-
lines = whole_lines
|
916
|
-
prev_line_prompt = @prompt_proc ? prompt_list[@line_index - 1] : prompt
|
917
|
-
prev_line_prompt_width = @prompt_proc ? calculate_width(prev_line_prompt, true) : prompt_width
|
918
|
-
prev_line = modify_lines(lines)[@line_index - 1]
|
919
|
-
move_cursor_up(@started_from)
|
920
|
-
render_partial(prev_line_prompt, prev_line_prompt_width, prev_line, @first_line_started_from + @started_from, with_control: false)
|
921
|
-
scroll_down(1)
|
922
|
-
render_partial(prompt, prompt_width, @line, @first_line_started_from + @started_from + 1, with_control: false)
|
923
|
-
end
|
924
|
-
@cursor = @cursor_max = calculate_width(@line)
|
925
|
-
@byte_pointer = @line.bytesize
|
926
|
-
@highest_in_all += @highest_in_this
|
927
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
928
|
-
@first_line_started_from += @started_from + 1
|
929
|
-
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
930
|
-
end
|
931
|
-
|
932
|
-
def just_move_cursor
|
933
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines)
|
934
|
-
move_cursor_up(@started_from)
|
935
|
-
new_first_line_started_from =
|
936
|
-
if @line_index.zero?
|
937
|
-
0
|
938
|
-
else
|
939
|
-
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
940
|
-
end
|
941
|
-
first_line_diff = new_first_line_started_from - @first_line_started_from
|
942
|
-
@cursor, @cursor_max, _, @byte_pointer = calculate_nearest_cursor(@buffer_of_lines[@line_index], @cursor, @started_from, @byte_pointer, false)
|
943
|
-
new_started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
944
|
-
calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from)
|
945
|
-
@previous_line_index = nil
|
946
|
-
@line = @buffer_of_lines[@line_index]
|
947
|
-
if @rerender_all
|
948
|
-
rerender_all_lines
|
949
|
-
@rerender_all = false
|
950
|
-
true
|
951
|
-
else
|
952
|
-
@first_line_started_from = new_first_line_started_from
|
953
|
-
@started_from = new_started_from
|
954
|
-
move_cursor_down(first_line_diff + @started_from)
|
955
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
956
|
-
false
|
957
|
-
end
|
958
|
-
end
|
959
|
-
|
960
|
-
private def rerender_changed_current_line
|
961
|
-
new_lines = whole_lines
|
962
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
|
963
|
-
all_height = calculate_height_by_lines(new_lines, prompt_list || prompt)
|
964
|
-
diff = all_height - @highest_in_all
|
965
|
-
move_cursor_down(@highest_in_all - @first_line_started_from - @started_from - 1)
|
966
|
-
if diff > 0
|
967
|
-
scroll_down(diff)
|
968
|
-
move_cursor_up(all_height - 1)
|
969
|
-
elsif diff < 0
|
970
|
-
(-diff).times do
|
971
|
-
Reline::IOGate.move_cursor_column(0)
|
972
|
-
Reline::IOGate.erase_after_cursor
|
973
|
-
move_cursor_up(1)
|
974
|
-
end
|
975
|
-
move_cursor_up(all_height - 1)
|
976
|
-
else
|
977
|
-
move_cursor_up(all_height - 1)
|
978
|
-
end
|
979
|
-
@highest_in_all = all_height
|
980
|
-
back = render_whole_lines(new_lines, prompt_list || prompt, prompt_width)
|
981
|
-
move_cursor_up(back)
|
982
|
-
if @previous_line_index
|
983
|
-
@buffer_of_lines[@previous_line_index] = @line
|
984
|
-
@line = @buffer_of_lines[@line_index]
|
985
|
-
end
|
986
|
-
@first_line_started_from =
|
987
|
-
if @line_index.zero?
|
988
|
-
0
|
989
|
-
else
|
990
|
-
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
|
991
|
-
end
|
992
|
-
if @prompt_proc
|
993
|
-
prompt = prompt_list[@line_index]
|
994
|
-
prompt_width = calculate_width(prompt, true)
|
995
|
-
end
|
996
|
-
move_cursor_down(@first_line_started_from)
|
997
|
-
calculate_nearest_cursor
|
998
|
-
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
999
|
-
move_cursor_down(@started_from)
|
1000
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
1001
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
1002
|
-
end
|
1003
|
-
|
1004
|
-
private def rerender_all_lines
|
1005
|
-
move_cursor_up(@first_line_started_from + @started_from)
|
1006
|
-
Reline::IOGate.move_cursor_column(0)
|
1007
|
-
back = 0
|
1008
|
-
new_buffer = whole_lines
|
1009
|
-
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
|
1010
|
-
new_buffer.each_with_index do |line, index|
|
1011
|
-
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
1012
|
-
width = prompt_width + calculate_width(line)
|
1013
|
-
height = calculate_height_by_width(width)
|
1014
|
-
back += height
|
1015
|
-
end
|
1016
|
-
old_highest_in_all = @highest_in_all
|
1017
|
-
if @line_index.zero?
|
1018
|
-
new_first_line_started_from = 0
|
1019
|
-
else
|
1020
|
-
new_first_line_started_from = calculate_height_by_lines(new_buffer[0..(@line_index - 1)], prompt_list || prompt)
|
1021
|
-
end
|
1022
|
-
new_started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
1023
|
-
calculate_scroll_partial_screen(back, new_first_line_started_from + new_started_from)
|
1024
|
-
if @scroll_partial_screen
|
1025
|
-
move_cursor_up(@first_line_started_from + @started_from)
|
1026
|
-
scroll_down(@screen_height - 1)
|
1027
|
-
move_cursor_up(@screen_height)
|
1028
|
-
Reline::IOGate.move_cursor_column(0)
|
1029
|
-
elsif back > old_highest_in_all
|
1030
|
-
scroll_down(back - 1)
|
1031
|
-
move_cursor_up(back - 1)
|
1032
|
-
elsif back < old_highest_in_all
|
1033
|
-
scroll_down(back)
|
1034
|
-
Reline::IOGate.erase_after_cursor
|
1035
|
-
(old_highest_in_all - back - 1).times do
|
1036
|
-
scroll_down(1)
|
1037
|
-
Reline::IOGate.erase_after_cursor
|
1038
|
-
end
|
1039
|
-
move_cursor_up(old_highest_in_all - 1)
|
1040
|
-
end
|
1041
|
-
render_whole_lines(new_buffer, prompt_list || prompt, prompt_width)
|
1042
|
-
if @prompt_proc
|
1043
|
-
prompt = prompt_list[@line_index]
|
1044
|
-
prompt_width = calculate_width(prompt, true)
|
1045
|
-
end
|
1046
|
-
@highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
|
1047
|
-
@highest_in_all = back
|
1048
|
-
@first_line_started_from = new_first_line_started_from
|
1049
|
-
@started_from = new_started_from
|
1050
|
-
if @scroll_partial_screen
|
1051
|
-
Reline::IOGate.move_cursor_up(@screen_height - (@first_line_started_from + @started_from - @scroll_partial_screen) - 1)
|
1052
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
1053
|
-
else
|
1054
|
-
move_cursor_down(@first_line_started_from + @started_from - back + 1)
|
1055
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
1056
|
-
end
|
1057
|
-
end
|
1058
|
-
|
1059
|
-
private def render_whole_lines(lines, prompt, prompt_width)
|
1060
|
-
rendered_height = 0
|
1061
|
-
modify_lines(lines).each_with_index do |line, index|
|
1062
|
-
if prompt.is_a?(Array)
|
1063
|
-
line_prompt = prompt[index]
|
1064
|
-
prompt_width = calculate_width(line_prompt, true)
|
1065
|
-
else
|
1066
|
-
line_prompt = prompt
|
1067
|
-
end
|
1068
|
-
height = render_partial(line_prompt, prompt_width, line, rendered_height, with_control: false)
|
1069
|
-
if index < (lines.size - 1)
|
1070
|
-
if @scroll_partial_screen
|
1071
|
-
if (@scroll_partial_screen - height) < rendered_height and (@scroll_partial_screen + @screen_height - 1) >= (rendered_height + height)
|
1072
|
-
move_cursor_down(1)
|
1073
|
-
end
|
1074
|
-
else
|
1075
|
-
scroll_down(1)
|
1076
|
-
end
|
1077
|
-
rendered_height += height
|
1078
|
-
else
|
1079
|
-
rendered_height += height - 1
|
1080
|
-
end
|
1081
|
-
end
|
1082
|
-
rendered_height
|
1083
|
-
end
|
1084
|
-
|
1085
|
-
private def render_partial(prompt, prompt_width, line_to_render, this_started_from, with_control: true)
|
1086
|
-
visual_lines, height = split_by_width(line_to_render.nil? ? prompt : prompt + line_to_render, @screen_size.last)
|
1087
|
-
cursor_up_from_last_line = 0
|
1088
|
-
if @scroll_partial_screen
|
1089
|
-
last_visual_line = this_started_from + (height - 1)
|
1090
|
-
last_screen_line = @scroll_partial_screen + (@screen_height - 1)
|
1091
|
-
if (@scroll_partial_screen - this_started_from) >= height
|
1092
|
-
# Render nothing because this line is before the screen.
|
1093
|
-
visual_lines = []
|
1094
|
-
elsif this_started_from > last_screen_line
|
1095
|
-
# Render nothing because this line is after the screen.
|
1096
|
-
visual_lines = []
|
1097
|
-
else
|
1098
|
-
deleted_lines_before_screen = []
|
1099
|
-
if @scroll_partial_screen > this_started_from and last_visual_line >= @scroll_partial_screen
|
1100
|
-
# A part of visual lines are before the screen.
|
1101
|
-
deleted_lines_before_screen = visual_lines.shift((@scroll_partial_screen - this_started_from) * 2)
|
1102
|
-
deleted_lines_before_screen.compact!
|
1103
|
-
end
|
1104
|
-
if this_started_from <= last_screen_line and last_screen_line < last_visual_line
|
1105
|
-
# A part of visual lines are after the screen.
|
1106
|
-
visual_lines.pop((last_visual_line - last_screen_line) * 2)
|
1107
|
-
end
|
1108
|
-
move_cursor_up(deleted_lines_before_screen.size - @started_from)
|
1109
|
-
cursor_up_from_last_line = @started_from - deleted_lines_before_screen.size
|
1110
|
-
end
|
1111
|
-
end
|
1112
|
-
if with_control
|
1113
|
-
if height > @highest_in_this
|
1114
|
-
diff = height - @highest_in_this
|
1115
|
-
scroll_down(diff)
|
1116
|
-
@highest_in_all += diff
|
1117
|
-
@highest_in_this = height
|
1118
|
-
move_cursor_up(diff)
|
1119
|
-
elsif height < @highest_in_this
|
1120
|
-
diff = @highest_in_this - height
|
1121
|
-
@highest_in_all -= diff
|
1122
|
-
@highest_in_this = height
|
1123
|
-
end
|
1124
|
-
move_cursor_up(@started_from)
|
1125
|
-
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
1126
|
-
cursor_up_from_last_line = height - 1 - @started_from
|
1127
|
-
end
|
1128
|
-
if Reline::Unicode::CSI_REGEXP.match?(prompt + line_to_render)
|
1129
|
-
@output.write "\e[0m" # clear character decorations
|
1130
|
-
end
|
1131
|
-
visual_lines.each_with_index do |line, index|
|
1132
|
-
Reline::IOGate.move_cursor_column(0)
|
1133
|
-
if line.nil?
|
1134
|
-
if calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last
|
1135
|
-
# reaches the end of line
|
1136
|
-
if Reline::IOGate.win? and Reline::IOGate.win_legacy_console?
|
1137
|
-
# A newline is automatically inserted if a character is rendered at
|
1138
|
-
# eol on command prompt.
|
1139
|
-
else
|
1140
|
-
# When the cursor is at the end of the line and erases characters
|
1141
|
-
# after the cursor, some terminals delete the character at the
|
1142
|
-
# cursor position.
|
1143
|
-
move_cursor_down(1)
|
1144
|
-
Reline::IOGate.move_cursor_column(0)
|
1145
|
-
end
|
1146
|
-
else
|
1147
|
-
Reline::IOGate.erase_after_cursor
|
1148
|
-
move_cursor_down(1)
|
1149
|
-
Reline::IOGate.move_cursor_column(0)
|
1150
|
-
end
|
1151
|
-
next
|
1152
|
-
end
|
1153
|
-
@output.write line
|
1154
|
-
if Reline::IOGate.win? and Reline::IOGate.win_legacy_console? and calculate_width(line, true) == Reline::IOGate.get_screen_size.last
|
1155
|
-
# A newline is automatically inserted if a character is rendered at eol on command prompt.
|
1156
|
-
@rest_height -= 1 if @rest_height > 0
|
1157
|
-
end
|
1158
|
-
@output.flush
|
1159
|
-
if @first_prompt
|
1160
|
-
@first_prompt = false
|
1161
|
-
@pre_input_hook&.call
|
1162
|
-
end
|
1163
|
-
end
|
1164
|
-
unless visual_lines.empty?
|
1165
|
-
Reline::IOGate.erase_after_cursor
|
1166
|
-
Reline::IOGate.move_cursor_column(0)
|
1167
|
-
end
|
1168
|
-
if with_control
|
1169
|
-
# Just after rendring, so the cursor is on the last line.
|
1170
|
-
if finished?
|
1171
|
-
Reline::IOGate.move_cursor_column(0)
|
1172
|
-
else
|
1173
|
-
# Moves up from bottom of lines to the cursor position.
|
1174
|
-
move_cursor_up(cursor_up_from_last_line)
|
1175
|
-
# This logic is buggy if a fullwidth char is wrapped because there is only one halfwidth at end of a line.
|
1176
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
1177
|
-
end
|
1178
|
-
end
|
1179
|
-
height
|
1180
|
-
end
|
1181
|
-
|
1182
|
-
private def modify_lines(before, force_recalc: false)
|
1183
|
-
return before if !force_recalc && (before.nil? || before.empty? || simplified_rendering?)
|
1184
|
-
|
1185
|
-
if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: finished?)
|
793
|
+
private def modify_lines(before, complete)
|
794
|
+
if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: complete)
|
1186
795
|
after.lines("\n").map { |l| l.chomp('') }
|
1187
796
|
else
|
1188
797
|
before
|
1189
798
|
end
|
1190
799
|
end
|
1191
800
|
|
1192
|
-
private def show_menu
|
1193
|
-
scroll_down(@highest_in_all - @first_line_started_from)
|
1194
|
-
@rerender_all = true
|
1195
|
-
@menu_info.list.sort!.each do |item|
|
1196
|
-
Reline::IOGate.move_cursor_column(0)
|
1197
|
-
@output.write item
|
1198
|
-
@output.flush
|
1199
|
-
scroll_down(1)
|
1200
|
-
end
|
1201
|
-
scroll_down(@highest_in_all - 1)
|
1202
|
-
move_cursor_up(@highest_in_all - 1 - @first_line_started_from)
|
1203
|
-
end
|
1204
|
-
|
1205
|
-
private def clear_screen_buffer(prompt, prompt_list, prompt_width)
|
1206
|
-
Reline::IOGate.clear_screen
|
1207
|
-
back = 0
|
1208
|
-
modify_lines(whole_lines).each_with_index do |line, index|
|
1209
|
-
if @prompt_proc
|
1210
|
-
pr = prompt_list[index]
|
1211
|
-
height = render_partial(pr, calculate_width(pr), line, back, with_control: false)
|
1212
|
-
else
|
1213
|
-
height = render_partial(prompt, prompt_width, line, back, with_control: false)
|
1214
|
-
end
|
1215
|
-
if index < (@buffer_of_lines.size - 1)
|
1216
|
-
move_cursor_down(1)
|
1217
|
-
back += height
|
1218
|
-
end
|
1219
|
-
end
|
1220
|
-
move_cursor_up(back)
|
1221
|
-
move_cursor_down(@first_line_started_from + @started_from)
|
1222
|
-
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
1223
|
-
Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
|
1224
|
-
end
|
1225
|
-
|
1226
801
|
def editing_mode
|
1227
802
|
@config.editing_mode
|
1228
803
|
end
|
@@ -1312,10 +887,8 @@ class Reline::LineEditor
|
|
1312
887
|
@completion_state = CompletionState::MENU
|
1313
888
|
end
|
1314
889
|
if not just_show_list and target < completed
|
1315
|
-
@
|
890
|
+
@buffer_of_lines[@line_index] = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
|
1316
891
|
line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n").last || String.new(encoding: @encoding)
|
1317
|
-
@cursor_max = calculate_width(@line)
|
1318
|
-
@cursor = calculate_width(line_to_pointer)
|
1319
892
|
@byte_pointer = line_to_pointer.bytesize
|
1320
893
|
end
|
1321
894
|
end
|
@@ -1358,35 +931,31 @@ class Reline::LineEditor
|
|
1358
931
|
end
|
1359
932
|
end
|
1360
933
|
completed = @completion_journey_data.list[@completion_journey_data.pointer]
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
line_to_pointer = String.new(encoding: @encoding) if line_to_pointer.nil?
|
1365
|
-
@cursor_max = calculate_width(@line)
|
1366
|
-
@cursor = calculate_width(line_to_pointer)
|
1367
|
-
@byte_pointer = line_to_pointer.bytesize
|
934
|
+
line_to_pointer = (@completion_journey_data.preposing + completed).split("\n")[@line_index] || String.new(encoding: @encoding)
|
935
|
+
new_line = line_to_pointer + (@completion_journey_data.postposing.split("\n").first || '')
|
936
|
+
set_current_line(new_line, line_to_pointer.bytesize)
|
1368
937
|
end
|
1369
938
|
|
1370
939
|
private def run_for_operators(key, method_symbol, &block)
|
1371
940
|
if @waiting_operator_proc
|
1372
941
|
if VI_MOTIONS.include?(method_symbol)
|
1373
|
-
|
942
|
+
old_byte_pointer = @byte_pointer
|
1374
943
|
@vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg&.> 1
|
1375
944
|
block.(true)
|
1376
945
|
unless @waiting_proc
|
1377
|
-
|
1378
|
-
@
|
1379
|
-
@waiting_operator_proc.(
|
946
|
+
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
947
|
+
@byte_pointer = old_byte_pointer
|
948
|
+
@waiting_operator_proc.(byte_pointer_diff)
|
1380
949
|
else
|
1381
950
|
old_waiting_proc = @waiting_proc
|
1382
951
|
old_waiting_operator_proc = @waiting_operator_proc
|
1383
952
|
current_waiting_operator_proc = @waiting_operator_proc
|
1384
953
|
@waiting_proc = proc { |k|
|
1385
|
-
|
954
|
+
old_byte_pointer = @byte_pointer
|
1386
955
|
old_waiting_proc.(k)
|
1387
|
-
|
1388
|
-
@
|
1389
|
-
current_waiting_operator_proc.(
|
956
|
+
byte_pointer_diff = @byte_pointer - old_byte_pointer
|
957
|
+
@byte_pointer = old_byte_pointer
|
958
|
+
current_waiting_operator_proc.(byte_pointer_diff)
|
1390
959
|
@waiting_operator_proc = old_waiting_operator_proc
|
1391
960
|
}
|
1392
961
|
end
|
@@ -1397,7 +966,6 @@ class Reline::LineEditor
|
|
1397
966
|
@waiting_operator_proc = nil
|
1398
967
|
@waiting_operator_vi_arg = nil
|
1399
968
|
if @vi_arg
|
1400
|
-
@rerender_all = true
|
1401
969
|
@vi_arg = nil
|
1402
970
|
end
|
1403
971
|
else
|
@@ -1451,7 +1019,6 @@ class Reline::LineEditor
|
|
1451
1019
|
end
|
1452
1020
|
@kill_ring.process
|
1453
1021
|
if @vi_arg
|
1454
|
-
@rerender_al = true
|
1455
1022
|
@vi_arg = nil
|
1456
1023
|
end
|
1457
1024
|
elsif @vi_arg
|
@@ -1471,7 +1038,6 @@ class Reline::LineEditor
|
|
1471
1038
|
end
|
1472
1039
|
@kill_ring.process
|
1473
1040
|
if @vi_arg
|
1474
|
-
@rerender_all = true
|
1475
1041
|
@vi_arg = nil
|
1476
1042
|
end
|
1477
1043
|
end
|
@@ -1493,7 +1059,6 @@ class Reline::LineEditor
|
|
1493
1059
|
end
|
1494
1060
|
|
1495
1061
|
private def normal_char(key)
|
1496
|
-
method_symbol = method_obj = nil
|
1497
1062
|
if key.combined_char.is_a?(Symbol)
|
1498
1063
|
process_key(key.combined_char, key.combined_char)
|
1499
1064
|
return
|
@@ -1523,32 +1088,37 @@ class Reline::LineEditor
|
|
1523
1088
|
end
|
1524
1089
|
@multibyte_buffer.clear
|
1525
1090
|
end
|
1526
|
-
if @config.editing_mode_is?(:vi_command) and @
|
1527
|
-
byte_size = Reline::Unicode.get_prev_mbchar_size(@
|
1091
|
+
if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
|
1092
|
+
byte_size = Reline::Unicode.get_prev_mbchar_size(@buffer_of_lines[@line_index], @byte_pointer)
|
1528
1093
|
@byte_pointer -= byte_size
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1094
|
+
end
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
def update(key)
|
1098
|
+
modified = input_key(key)
|
1099
|
+
unless @in_pasting
|
1100
|
+
scroll_into_view
|
1101
|
+
@just_cursor_moving = !modified
|
1102
|
+
update_dialogs(key)
|
1103
|
+
@just_cursor_moving = false
|
1532
1104
|
end
|
1533
1105
|
end
|
1534
1106
|
|
1535
1107
|
def input_key(key)
|
1536
|
-
@last_key = key
|
1537
1108
|
@config.reset_oneshot_key_bindings
|
1538
1109
|
@dialogs.each do |dialog|
|
1539
1110
|
if key.char.instance_of?(Symbol) and key.char == dialog.name
|
1540
1111
|
return
|
1541
1112
|
end
|
1542
1113
|
end
|
1543
|
-
@just_cursor_moving = nil
|
1544
1114
|
if key.char.nil?
|
1545
1115
|
if @first_char
|
1546
|
-
@
|
1116
|
+
@eof = true
|
1547
1117
|
end
|
1548
1118
|
finish
|
1549
1119
|
return
|
1550
1120
|
end
|
1551
|
-
|
1121
|
+
old_lines = @buffer_of_lines.dup
|
1552
1122
|
@first_char = false
|
1553
1123
|
completion_occurs = false
|
1554
1124
|
if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
|
@@ -1591,19 +1161,20 @@ class Reline::LineEditor
|
|
1591
1161
|
@completion_state = CompletionState::NORMAL
|
1592
1162
|
@completion_journey_data = nil
|
1593
1163
|
end
|
1594
|
-
if
|
1595
|
-
|
1596
|
-
@just_cursor_moving = true
|
1597
|
-
elsif @previous_line_index.nil? and @buffer_of_lines[@line_index] == @line and old_line == @line
|
1598
|
-
@just_cursor_moving = true
|
1599
|
-
else
|
1600
|
-
@just_cursor_moving = false
|
1601
|
-
end
|
1164
|
+
if @in_pasting
|
1165
|
+
clear_dialogs
|
1602
1166
|
else
|
1603
|
-
|
1167
|
+
return old_lines != @buffer_of_lines
|
1168
|
+
end
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
def scroll_into_view
|
1172
|
+
_editor_cursor_x, editor_cursor_y = editor_cursor_position
|
1173
|
+
if editor_cursor_y < screen_scroll_top
|
1174
|
+
@scroll_partial_screen = editor_cursor_y
|
1604
1175
|
end
|
1605
|
-
if
|
1606
|
-
|
1176
|
+
if editor_cursor_y >= screen_scroll_top + screen_height
|
1177
|
+
@scroll_partial_screen = editor_cursor_y - screen_height + 1
|
1607
1178
|
end
|
1608
1179
|
end
|
1609
1180
|
|
@@ -1637,43 +1208,40 @@ class Reline::LineEditor
|
|
1637
1208
|
result
|
1638
1209
|
end
|
1639
1210
|
|
1640
|
-
private def process_auto_indent
|
1641
|
-
return if
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
new_indent = result
|
1654
|
-
end
|
1655
|
-
if new_indent&.>= 0
|
1656
|
-
@line = ' ' * new_indent + @line.lstrip
|
1657
|
-
end
|
1658
|
-
end
|
1659
|
-
new_lines = whole_lines
|
1660
|
-
new_indent = @auto_indent_proc.(new_lines, @line_index, @byte_pointer, @check_new_auto_indent)
|
1661
|
-
if new_indent&.>= 0
|
1662
|
-
md = new_lines[@line_index].match(/\A */)
|
1663
|
-
prev_indent = md[0].count(' ')
|
1664
|
-
if @check_new_auto_indent
|
1665
|
-
line = @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
|
1666
|
-
@cursor = new_indent
|
1667
|
-
@cursor_max = calculate_width(line)
|
1668
|
-
@byte_pointer = new_indent
|
1669
|
-
else
|
1670
|
-
@line = ' ' * new_indent + @line.lstrip
|
1671
|
-
@cursor += new_indent - prev_indent
|
1672
|
-
@cursor_max = calculate_width(@line)
|
1673
|
-
@byte_pointer += new_indent - prev_indent
|
1674
|
-
end
|
1211
|
+
private def process_auto_indent(line_index = @line_index, cursor_dependent: true, add_newline: false)
|
1212
|
+
return if @in_pasting
|
1213
|
+
return unless @auto_indent_proc
|
1214
|
+
|
1215
|
+
line = @buffer_of_lines[line_index]
|
1216
|
+
byte_pointer = cursor_dependent && @line_index == line_index ? @byte_pointer : line.bytesize
|
1217
|
+
new_indent = @auto_indent_proc.(@buffer_of_lines.take(line_index + 1).push(''), line_index, byte_pointer, add_newline)
|
1218
|
+
return unless new_indent
|
1219
|
+
|
1220
|
+
@buffer_of_lines[line_index] = ' ' * new_indent + line.lstrip
|
1221
|
+
if @line_index == line_index
|
1222
|
+
old_indent = line[/\A */].size
|
1223
|
+
@byte_pointer = [@byte_pointer + new_indent - old_indent, 0].max
|
1675
1224
|
end
|
1676
|
-
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
def line()
|
1228
|
+
current_line unless eof?
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
def current_line
|
1232
|
+
@buffer_of_lines[@line_index]
|
1233
|
+
end
|
1234
|
+
|
1235
|
+
def set_current_line(line, byte_pointer = nil)
|
1236
|
+
@modified = true
|
1237
|
+
cursor = current_byte_pointer_cursor
|
1238
|
+
@buffer_of_lines[@line_index] = line
|
1239
|
+
if byte_pointer
|
1240
|
+
@byte_pointer = byte_pointer
|
1241
|
+
else
|
1242
|
+
calculate_nearest_cursor(cursor)
|
1243
|
+
end
|
1244
|
+
process_auto_indent
|
1677
1245
|
end
|
1678
1246
|
|
1679
1247
|
def retrieve_completion_block(set_completion_quote_character = false)
|
@@ -1687,7 +1255,7 @@ class Reline::LineEditor
|
|
1687
1255
|
else
|
1688
1256
|
quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/
|
1689
1257
|
end
|
1690
|
-
before =
|
1258
|
+
before = current_line.byteslice(0, @byte_pointer)
|
1691
1259
|
rest = nil
|
1692
1260
|
break_pointer = nil
|
1693
1261
|
quote = nil
|
@@ -1695,7 +1263,7 @@ class Reline::LineEditor
|
|
1695
1263
|
escaped_quote = nil
|
1696
1264
|
i = 0
|
1697
1265
|
while i < @byte_pointer do
|
1698
|
-
slice =
|
1266
|
+
slice = current_line.byteslice(i, @byte_pointer - i)
|
1699
1267
|
unless slice.valid_encoding?
|
1700
1268
|
i += 1
|
1701
1269
|
next
|
@@ -1717,15 +1285,15 @@ class Reline::LineEditor
|
|
1717
1285
|
elsif word_break_regexp and not quote and slice =~ word_break_regexp
|
1718
1286
|
rest = $'
|
1719
1287
|
i += 1
|
1720
|
-
before =
|
1288
|
+
before = current_line.byteslice(i, @byte_pointer - i)
|
1721
1289
|
break_pointer = i
|
1722
1290
|
else
|
1723
1291
|
i += 1
|
1724
1292
|
end
|
1725
1293
|
end
|
1726
|
-
postposing =
|
1294
|
+
postposing = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
|
1727
1295
|
if rest
|
1728
|
-
preposing =
|
1296
|
+
preposing = current_line.byteslice(0, break_pointer)
|
1729
1297
|
target = rest
|
1730
1298
|
if set_completion_quote_character and quote
|
1731
1299
|
Reline.core.instance_variable_set(:@completion_quote_character, quote)
|
@@ -1736,7 +1304,7 @@ class Reline::LineEditor
|
|
1736
1304
|
else
|
1737
1305
|
preposing = ''
|
1738
1306
|
if break_pointer
|
1739
|
-
preposing =
|
1307
|
+
preposing = current_line.byteslice(0, break_pointer)
|
1740
1308
|
else
|
1741
1309
|
preposing = ''
|
1742
1310
|
end
|
@@ -1756,106 +1324,67 @@ class Reline::LineEditor
|
|
1756
1324
|
|
1757
1325
|
def confirm_multiline_termination
|
1758
1326
|
temp_buffer = @buffer_of_lines.dup
|
1759
|
-
if @previous_line_index and @line_index == (@buffer_of_lines.size - 1)
|
1760
|
-
temp_buffer[@previous_line_index] = @line
|
1761
|
-
else
|
1762
|
-
temp_buffer[@line_index] = @line
|
1763
|
-
end
|
1764
1327
|
@confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
|
1765
1328
|
end
|
1766
1329
|
|
1767
1330
|
def insert_text(text)
|
1768
|
-
|
1769
|
-
|
1770
|
-
@line += text
|
1331
|
+
if @buffer_of_lines[@line_index].bytesize == @byte_pointer
|
1332
|
+
@buffer_of_lines[@line_index] += text
|
1771
1333
|
else
|
1772
|
-
@
|
1334
|
+
@buffer_of_lines[@line_index] = byteinsert(@buffer_of_lines[@line_index], @byte_pointer, text)
|
1773
1335
|
end
|
1774
1336
|
@byte_pointer += text.bytesize
|
1775
|
-
|
1776
|
-
@cursor_max += width
|
1337
|
+
process_auto_indent
|
1777
1338
|
end
|
1778
1339
|
|
1779
1340
|
def delete_text(start = nil, length = nil)
|
1780
1341
|
if start.nil? and length.nil?
|
1781
1342
|
if @is_multiline
|
1782
1343
|
if @buffer_of_lines.size == 1
|
1783
|
-
@
|
1344
|
+
@buffer_of_lines[@line_index] = ''
|
1784
1345
|
@byte_pointer = 0
|
1785
|
-
@cursor = 0
|
1786
|
-
@cursor_max = 0
|
1787
1346
|
elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
|
1788
1347
|
@buffer_of_lines.pop
|
1789
1348
|
@line_index -= 1
|
1790
|
-
@line = @buffer_of_lines[@line_index]
|
1791
1349
|
@byte_pointer = 0
|
1792
|
-
@cursor = 0
|
1793
|
-
@cursor_max = calculate_width(@line)
|
1794
1350
|
elsif @line_index < (@buffer_of_lines.size - 1)
|
1795
1351
|
@buffer_of_lines.delete_at(@line_index)
|
1796
|
-
@line = @buffer_of_lines[@line_index]
|
1797
1352
|
@byte_pointer = 0
|
1798
|
-
@cursor = 0
|
1799
|
-
@cursor_max = calculate_width(@line)
|
1800
1353
|
end
|
1801
1354
|
else
|
1802
|
-
|
1803
|
-
@byte_pointer = 0
|
1804
|
-
@cursor = 0
|
1805
|
-
@cursor_max = 0
|
1355
|
+
set_current_line('', 0)
|
1806
1356
|
end
|
1807
1357
|
elsif not start.nil? and not length.nil?
|
1808
|
-
if
|
1809
|
-
before =
|
1810
|
-
after =
|
1811
|
-
|
1812
|
-
@byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
|
1813
|
-
str = @line.byteslice(0, @byte_pointer)
|
1814
|
-
@cursor = calculate_width(str)
|
1815
|
-
@cursor_max = calculate_width(@line)
|
1358
|
+
if current_line
|
1359
|
+
before = current_line.byteslice(0, start)
|
1360
|
+
after = current_line.byteslice(start + length, current_line.bytesize)
|
1361
|
+
set_current_line(before + after)
|
1816
1362
|
end
|
1817
1363
|
elsif start.is_a?(Range)
|
1818
1364
|
range = start
|
1819
1365
|
first = range.first
|
1820
1366
|
last = range.last
|
1821
|
-
last =
|
1822
|
-
last +=
|
1823
|
-
first +=
|
1367
|
+
last = current_line.bytesize - 1 if last > current_line.bytesize
|
1368
|
+
last += current_line.bytesize if last < 0
|
1369
|
+
first += current_line.bytesize if first < 0
|
1824
1370
|
range = range.exclude_end? ? first...last : first..last
|
1825
|
-
|
1826
|
-
|
1827
|
-
str = @line.byteslice(0, @byte_pointer)
|
1828
|
-
@cursor = calculate_width(str)
|
1829
|
-
@cursor_max = calculate_width(@line)
|
1371
|
+
line = current_line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(@encoding)
|
1372
|
+
set_current_line(line)
|
1830
1373
|
else
|
1831
|
-
|
1832
|
-
@byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
|
1833
|
-
str = @line.byteslice(0, @byte_pointer)
|
1834
|
-
@cursor = calculate_width(str)
|
1835
|
-
@cursor_max = calculate_width(@line)
|
1374
|
+
set_current_line(current_line.byteslice(0, start))
|
1836
1375
|
end
|
1837
1376
|
end
|
1838
1377
|
|
1839
1378
|
def byte_pointer=(val)
|
1840
1379
|
@byte_pointer = val
|
1841
|
-
str = @line.byteslice(0, @byte_pointer)
|
1842
|
-
@cursor = calculate_width(str)
|
1843
|
-
@cursor_max = calculate_width(@line)
|
1844
1380
|
end
|
1845
1381
|
|
1846
1382
|
def whole_lines
|
1847
|
-
|
1848
|
-
temp_lines = @buffer_of_lines.dup
|
1849
|
-
temp_lines[index] = @line
|
1850
|
-
temp_lines
|
1383
|
+
@buffer_of_lines.dup
|
1851
1384
|
end
|
1852
1385
|
|
1853
1386
|
def whole_buffer
|
1854
|
-
|
1855
|
-
nil
|
1856
|
-
else
|
1857
|
-
whole_lines.join("\n")
|
1858
|
-
end
|
1387
|
+
whole_lines.join("\n")
|
1859
1388
|
end
|
1860
1389
|
|
1861
1390
|
def finished?
|
@@ -1864,7 +1393,6 @@ class Reline::LineEditor
|
|
1864
1393
|
|
1865
1394
|
def finish
|
1866
1395
|
@finished = true
|
1867
|
-
@rerender_all = true
|
1868
1396
|
@config.reset
|
1869
1397
|
end
|
1870
1398
|
|
@@ -1895,14 +1423,9 @@ class Reline::LineEditor
|
|
1895
1423
|
|
1896
1424
|
private def key_newline(key)
|
1897
1425
|
if @is_multiline
|
1898
|
-
|
1899
|
-
|
1900
|
-
end
|
1901
|
-
next_line = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
|
1902
|
-
cursor_line = @line.byteslice(0, @byte_pointer)
|
1426
|
+
next_line = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
|
1427
|
+
cursor_line = current_line.byteslice(0, @byte_pointer)
|
1903
1428
|
insert_new_line(cursor_line, next_line)
|
1904
|
-
@cursor = 0
|
1905
|
-
@check_new_auto_indent = true unless @in_pasting
|
1906
1429
|
end
|
1907
1430
|
end
|
1908
1431
|
|
@@ -1912,16 +1435,7 @@ class Reline::LineEditor
|
|
1912
1435
|
|
1913
1436
|
private def process_insert(force: false)
|
1914
1437
|
return if @continuous_insertion_buffer.empty? or (@in_pasting and not force)
|
1915
|
-
|
1916
|
-
bytesize = @continuous_insertion_buffer.bytesize
|
1917
|
-
if @cursor == @cursor_max
|
1918
|
-
@line += @continuous_insertion_buffer
|
1919
|
-
else
|
1920
|
-
@line = byteinsert(@line, @byte_pointer, @continuous_insertion_buffer)
|
1921
|
-
end
|
1922
|
-
@byte_pointer += bytesize
|
1923
|
-
@cursor += width
|
1924
|
-
@cursor_max += width
|
1438
|
+
insert_text(@continuous_insertion_buffer)
|
1925
1439
|
@continuous_insertion_buffer.clear
|
1926
1440
|
end
|
1927
1441
|
|
@@ -1939,9 +1453,6 @@ class Reline::LineEditor
|
|
1939
1453
|
# million.
|
1940
1454
|
# GNU Readline:: +self-insert+ (a, b, A, 1, !, …) Insert yourself.
|
1941
1455
|
private def ed_insert(key)
|
1942
|
-
str = nil
|
1943
|
-
width = nil
|
1944
|
-
bytesize = nil
|
1945
1456
|
if key.instance_of?(String)
|
1946
1457
|
begin
|
1947
1458
|
key.encode(Encoding::UTF_8)
|
@@ -1949,7 +1460,6 @@ class Reline::LineEditor
|
|
1949
1460
|
return
|
1950
1461
|
end
|
1951
1462
|
str = key
|
1952
|
-
bytesize = key.bytesize
|
1953
1463
|
else
|
1954
1464
|
begin
|
1955
1465
|
key.chr.encode(Encoding::UTF_8)
|
@@ -1957,7 +1467,6 @@ class Reline::LineEditor
|
|
1957
1467
|
return
|
1958
1468
|
end
|
1959
1469
|
str = key.chr
|
1960
|
-
bytesize = 1
|
1961
1470
|
end
|
1962
1471
|
if @in_pasting
|
1963
1472
|
@continuous_insertion_buffer << str
|
@@ -1965,28 +1474,8 @@ class Reline::LineEditor
|
|
1965
1474
|
elsif not @continuous_insertion_buffer.empty?
|
1966
1475
|
process_insert
|
1967
1476
|
end
|
1968
|
-
|
1969
|
-
|
1970
|
-
@line += str
|
1971
|
-
else
|
1972
|
-
@line = byteinsert(@line, @byte_pointer, str)
|
1973
|
-
end
|
1974
|
-
last_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
|
1975
|
-
@byte_pointer += bytesize
|
1976
|
-
last_mbchar = @line.byteslice((@byte_pointer - bytesize - last_byte_size), last_byte_size)
|
1977
|
-
combined_char = last_mbchar + str
|
1978
|
-
if last_byte_size != 0 and combined_char.grapheme_clusters.size == 1
|
1979
|
-
# combined char
|
1980
|
-
last_mbchar_width = Reline::Unicode.get_mbchar_width(last_mbchar)
|
1981
|
-
combined_char_width = Reline::Unicode.get_mbchar_width(combined_char)
|
1982
|
-
if combined_char_width > last_mbchar_width
|
1983
|
-
width = combined_char_width - last_mbchar_width
|
1984
|
-
else
|
1985
|
-
width = 0
|
1986
|
-
end
|
1987
|
-
end
|
1988
|
-
@cursor += width
|
1989
|
-
@cursor_max += width
|
1477
|
+
|
1478
|
+
insert_text(str)
|
1990
1479
|
end
|
1991
1480
|
alias_method :ed_digit, :ed_insert
|
1992
1481
|
alias_method :self_insert, :ed_insert
|
@@ -2008,18 +1497,11 @@ class Reline::LineEditor
|
|
2008
1497
|
alias_method :quoted_insert, :ed_quoted_insert
|
2009
1498
|
|
2010
1499
|
private def ed_next_char(key, arg: 1)
|
2011
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
2012
|
-
if (@byte_pointer <
|
2013
|
-
mbchar = @line.byteslice(@byte_pointer, byte_size)
|
2014
|
-
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2015
|
-
@cursor += width if width
|
1500
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
1501
|
+
if (@byte_pointer < current_line.bytesize)
|
2016
1502
|
@byte_pointer += byte_size
|
2017
|
-
elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer ==
|
2018
|
-
next_line = @buffer_of_lines[@line_index + 1]
|
2019
|
-
@cursor = 0
|
1503
|
+
elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == current_line.bytesize and @line_index < @buffer_of_lines.size - 1
|
2020
1504
|
@byte_pointer = 0
|
2021
|
-
@cursor_max = calculate_width(next_line)
|
2022
|
-
@previous_line_index = @line_index
|
2023
1505
|
@line_index += 1
|
2024
1506
|
end
|
2025
1507
|
arg -= 1
|
@@ -2028,19 +1510,12 @@ class Reline::LineEditor
|
|
2028
1510
|
alias_method :forward_char, :ed_next_char
|
2029
1511
|
|
2030
1512
|
private def ed_prev_char(key, arg: 1)
|
2031
|
-
if @
|
2032
|
-
byte_size = Reline::Unicode.get_prev_mbchar_size(
|
1513
|
+
if @byte_pointer > 0
|
1514
|
+
byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
|
2033
1515
|
@byte_pointer -= byte_size
|
2034
|
-
mbchar = @line.byteslice(@byte_pointer, byte_size)
|
2035
|
-
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2036
|
-
@cursor -= width
|
2037
1516
|
elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
|
2038
|
-
prev_line = @buffer_of_lines[@line_index - 1]
|
2039
|
-
@cursor = calculate_width(prev_line)
|
2040
|
-
@byte_pointer = prev_line.bytesize
|
2041
|
-
@cursor_max = calculate_width(prev_line)
|
2042
|
-
@previous_line_index = @line_index
|
2043
1517
|
@line_index -= 1
|
1518
|
+
@byte_pointer = current_line.bytesize
|
2044
1519
|
end
|
2045
1520
|
arg -= 1
|
2046
1521
|
ed_prev_char(key, arg: arg) if arg > 0
|
@@ -2048,24 +1523,18 @@ class Reline::LineEditor
|
|
2048
1523
|
alias_method :backward_char, :ed_prev_char
|
2049
1524
|
|
2050
1525
|
private def vi_first_print(key)
|
2051
|
-
@byte_pointer,
|
1526
|
+
@byte_pointer, = Reline::Unicode.vi_first_print(current_line)
|
2052
1527
|
end
|
2053
1528
|
|
2054
1529
|
private def ed_move_to_beg(key)
|
2055
|
-
@byte_pointer =
|
1530
|
+
@byte_pointer = 0
|
2056
1531
|
end
|
2057
1532
|
alias_method :beginning_of_line, :ed_move_to_beg
|
2058
1533
|
|
2059
1534
|
private def ed_move_to_end(key)
|
2060
1535
|
@byte_pointer = 0
|
2061
|
-
@
|
2062
|
-
|
2063
|
-
while @byte_pointer < @line.bytesize
|
2064
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
|
2065
|
-
if byte_size > 0
|
2066
|
-
mbchar = @line.byteslice(@byte_pointer, byte_size)
|
2067
|
-
@cursor += Reline::Unicode.get_mbchar_width(mbchar)
|
2068
|
-
end
|
1536
|
+
while @byte_pointer < current_line.bytesize
|
1537
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2069
1538
|
@byte_pointer += byte_size
|
2070
1539
|
end
|
2071
1540
|
end
|
@@ -2167,19 +1636,16 @@ class Reline::LineEditor
|
|
2167
1636
|
@buffer_of_lines = hit.split("\n")
|
2168
1637
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2169
1638
|
@line_index = @buffer_of_lines.size - 1
|
2170
|
-
@
|
2171
|
-
@byte_pointer = @line.bytesize
|
2172
|
-
@cursor = @cursor_max = calculate_width(@line)
|
2173
|
-
@rerender_all = true
|
1639
|
+
@byte_pointer = current_line.bytesize
|
2174
1640
|
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
2175
1641
|
else
|
2176
|
-
@
|
1642
|
+
@buffer_of_lines = [hit]
|
1643
|
+
@byte_pointer = hit.bytesize
|
2177
1644
|
@searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
|
2178
1645
|
end
|
2179
1646
|
last_hit = hit
|
2180
1647
|
else
|
2181
1648
|
if @is_multiline
|
2182
|
-
@rerender_all = true
|
2183
1649
|
@searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
|
2184
1650
|
else
|
2185
1651
|
@searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
|
@@ -2194,7 +1660,7 @@ class Reline::LineEditor
|
|
2194
1660
|
if @is_multiline
|
2195
1661
|
@line_backup_in_history = whole_buffer
|
2196
1662
|
else
|
2197
|
-
@line_backup_in_history =
|
1663
|
+
@line_backup_in_history = current_line
|
2198
1664
|
end
|
2199
1665
|
end
|
2200
1666
|
searcher = generate_searcher
|
@@ -2214,35 +1680,26 @@ class Reline::LineEditor
|
|
2214
1680
|
@buffer_of_lines = buffer.split("\n")
|
2215
1681
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2216
1682
|
@line_index = @buffer_of_lines.size - 1
|
2217
|
-
@line = @buffer_of_lines.last
|
2218
|
-
@rerender_all = true
|
2219
1683
|
else
|
2220
|
-
@
|
1684
|
+
@buffer_of_lines = [buffer]
|
2221
1685
|
end
|
2222
1686
|
@searching_prompt = nil
|
2223
1687
|
@waiting_proc = nil
|
2224
|
-
@
|
2225
|
-
@cursor = @byte_pointer = 0
|
2226
|
-
@rerender_all = true
|
2227
|
-
@cached_prompt_list = nil
|
1688
|
+
@byte_pointer = 0
|
2228
1689
|
searcher.resume(-1)
|
2229
1690
|
when "\C-g".ord
|
2230
1691
|
if @is_multiline
|
2231
1692
|
@buffer_of_lines = @line_backup_in_history.split("\n")
|
2232
1693
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2233
1694
|
@line_index = @buffer_of_lines.size - 1
|
2234
|
-
@line = @buffer_of_lines.last
|
2235
|
-
@rerender_all = true
|
2236
1695
|
else
|
2237
|
-
@
|
1696
|
+
@buffer_of_lines = [@line_backup_in_history]
|
2238
1697
|
end
|
2239
1698
|
@history_pointer = nil
|
2240
1699
|
@searching_prompt = nil
|
2241
1700
|
@waiting_proc = nil
|
2242
1701
|
@line_backup_in_history = nil
|
2243
|
-
@
|
2244
|
-
@cursor = @byte_pointer = 0
|
2245
|
-
@rerender_all = true
|
1702
|
+
@byte_pointer = 0
|
2246
1703
|
else
|
2247
1704
|
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
2248
1705
|
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
|
@@ -2258,18 +1715,13 @@ class Reline::LineEditor
|
|
2258
1715
|
@buffer_of_lines = line.split("\n")
|
2259
1716
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2260
1717
|
@line_index = @buffer_of_lines.size - 1
|
2261
|
-
@line = @buffer_of_lines.last
|
2262
|
-
@rerender_all = true
|
2263
1718
|
else
|
2264
|
-
@line_backup_in_history =
|
2265
|
-
@
|
1719
|
+
@line_backup_in_history = current_line
|
1720
|
+
@buffer_of_lines = [line]
|
2266
1721
|
end
|
2267
1722
|
@searching_prompt = nil
|
2268
1723
|
@waiting_proc = nil
|
2269
|
-
@
|
2270
|
-
@cursor = @byte_pointer = 0
|
2271
|
-
@rerender_all = true
|
2272
|
-
@cached_prompt_list = nil
|
1724
|
+
@byte_pointer = 0
|
2273
1725
|
searcher.resume(-1)
|
2274
1726
|
end
|
2275
1727
|
end
|
@@ -2290,9 +1742,9 @@ class Reline::LineEditor
|
|
2290
1742
|
history = nil
|
2291
1743
|
h_pointer = nil
|
2292
1744
|
line_no = nil
|
2293
|
-
substr =
|
1745
|
+
substr = current_line.slice(0, @byte_pointer)
|
2294
1746
|
if @history_pointer.nil?
|
2295
|
-
return if not
|
1747
|
+
return if not current_line.empty? and substr.empty?
|
2296
1748
|
history = Reline::HISTORY
|
2297
1749
|
elsif @history_pointer.zero?
|
2298
1750
|
history = nil
|
@@ -2318,23 +1770,23 @@ class Reline::LineEditor
|
|
2318
1770
|
end
|
2319
1771
|
return if h_pointer.nil?
|
2320
1772
|
@history_pointer = h_pointer
|
1773
|
+
cursor = current_byte_pointer_cursor
|
2321
1774
|
if @is_multiline
|
2322
1775
|
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
2323
1776
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2324
1777
|
@line_index = line_no
|
2325
|
-
|
2326
|
-
@rerender_all = true
|
1778
|
+
calculate_nearest_cursor(cursor)
|
2327
1779
|
else
|
2328
|
-
@
|
1780
|
+
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1781
|
+
calculate_nearest_cursor(cursor)
|
2329
1782
|
end
|
2330
|
-
@cursor_max = calculate_width(@line)
|
2331
1783
|
arg -= 1
|
2332
1784
|
ed_search_prev_history(key, arg: arg) if arg > 0
|
2333
1785
|
end
|
2334
1786
|
alias_method :history_search_backward, :ed_search_prev_history
|
2335
1787
|
|
2336
1788
|
private def ed_search_next_history(key, arg: 1)
|
2337
|
-
substr =
|
1789
|
+
substr = current_line.slice(0, @byte_pointer)
|
2338
1790
|
if @history_pointer.nil?
|
2339
1791
|
return
|
2340
1792
|
elsif @history_pointer == (Reline::HISTORY.size - 1) and not substr.empty?
|
@@ -2365,21 +1817,21 @@ class Reline::LineEditor
|
|
2365
1817
|
if @history_pointer.nil? and substr.empty?
|
2366
1818
|
@buffer_of_lines = []
|
2367
1819
|
@line_index = 0
|
1820
|
+
@byte_pointer = 0
|
2368
1821
|
else
|
1822
|
+
cursor = current_byte_pointer_cursor
|
2369
1823
|
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
2370
1824
|
@line_index = line_no
|
1825
|
+
calculate_nearest_cursor(cursor)
|
2371
1826
|
end
|
2372
1827
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2373
|
-
@line = @buffer_of_lines[@line_index]
|
2374
|
-
@rerender_all = true
|
2375
1828
|
else
|
2376
1829
|
if @history_pointer.nil? and substr.empty?
|
2377
|
-
|
1830
|
+
set_current_line('', 0)
|
2378
1831
|
else
|
2379
|
-
|
1832
|
+
set_current_line(Reline::HISTORY[@history_pointer])
|
2380
1833
|
end
|
2381
1834
|
end
|
2382
|
-
@cursor_max = calculate_width(@line)
|
2383
1835
|
arg -= 1
|
2384
1836
|
ed_search_next_history(key, arg: arg) if arg > 0
|
2385
1837
|
end
|
@@ -2387,8 +1839,9 @@ class Reline::LineEditor
|
|
2387
1839
|
|
2388
1840
|
private def ed_prev_history(key, arg: 1)
|
2389
1841
|
if @is_multiline and @line_index > 0
|
2390
|
-
|
1842
|
+
cursor = current_byte_pointer_cursor
|
2391
1843
|
@line_index -= 1
|
1844
|
+
calculate_nearest_cursor(cursor)
|
2392
1845
|
return
|
2393
1846
|
end
|
2394
1847
|
if Reline::HISTORY.empty?
|
@@ -2396,16 +1849,17 @@ class Reline::LineEditor
|
|
2396
1849
|
end
|
2397
1850
|
if @history_pointer.nil?
|
2398
1851
|
@history_pointer = Reline::HISTORY.size - 1
|
1852
|
+
cursor = current_byte_pointer_cursor
|
2399
1853
|
if @is_multiline
|
2400
1854
|
@line_backup_in_history = whole_buffer
|
2401
1855
|
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
2402
1856
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2403
1857
|
@line_index = @buffer_of_lines.size - 1
|
2404
|
-
|
2405
|
-
@rerender_all = true
|
1858
|
+
calculate_nearest_cursor(cursor)
|
2406
1859
|
else
|
2407
|
-
@line_backup_in_history =
|
2408
|
-
@
|
1860
|
+
@line_backup_in_history = whole_buffer
|
1861
|
+
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
1862
|
+
calculate_nearest_cursor(cursor)
|
2409
1863
|
end
|
2410
1864
|
elsif @history_pointer.zero?
|
2411
1865
|
return
|
@@ -2416,20 +1870,16 @@ class Reline::LineEditor
|
|
2416
1870
|
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
2417
1871
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2418
1872
|
@line_index = @buffer_of_lines.size - 1
|
2419
|
-
@line = @buffer_of_lines.last
|
2420
|
-
@rerender_all = true
|
2421
1873
|
else
|
2422
|
-
Reline::HISTORY[@history_pointer] =
|
1874
|
+
Reline::HISTORY[@history_pointer] = whole_buffer
|
2423
1875
|
@history_pointer -= 1
|
2424
|
-
@
|
1876
|
+
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
2425
1877
|
end
|
2426
1878
|
end
|
2427
1879
|
if @config.editing_mode_is?(:emacs, :vi_insert)
|
2428
|
-
@
|
2429
|
-
@byte_pointer = @line.bytesize
|
1880
|
+
@byte_pointer = current_line.bytesize
|
2430
1881
|
elsif @config.editing_mode_is?(:vi_command)
|
2431
|
-
@byte_pointer =
|
2432
|
-
@cursor_max = calculate_width(@line)
|
1882
|
+
@byte_pointer = 0
|
2433
1883
|
end
|
2434
1884
|
arg -= 1
|
2435
1885
|
ed_prev_history(key, arg: arg) if arg > 0
|
@@ -2438,8 +1888,9 @@ class Reline::LineEditor
|
|
2438
1888
|
|
2439
1889
|
private def ed_next_history(key, arg: 1)
|
2440
1890
|
if @is_multiline and @line_index < (@buffer_of_lines.size - 1)
|
2441
|
-
|
1891
|
+
cursor = current_byte_pointer_cursor
|
2442
1892
|
@line_index += 1
|
1893
|
+
calculate_nearest_cursor(cursor)
|
2443
1894
|
return
|
2444
1895
|
end
|
2445
1896
|
if @history_pointer.nil?
|
@@ -2450,11 +1901,9 @@ class Reline::LineEditor
|
|
2450
1901
|
@buffer_of_lines = @line_backup_in_history.split("\n")
|
2451
1902
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2452
1903
|
@line_index = 0
|
2453
|
-
@line = @buffer_of_lines.first
|
2454
|
-
@rerender_all = true
|
2455
1904
|
else
|
2456
1905
|
@history_pointer = nil
|
2457
|
-
@
|
1906
|
+
@buffer_of_lines = [@line_backup_in_history]
|
2458
1907
|
end
|
2459
1908
|
else
|
2460
1909
|
if @is_multiline
|
@@ -2463,21 +1912,16 @@ class Reline::LineEditor
|
|
2463
1912
|
@buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
|
2464
1913
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
2465
1914
|
@line_index = 0
|
2466
|
-
@line = @buffer_of_lines.first
|
2467
|
-
@rerender_all = true
|
2468
1915
|
else
|
2469
|
-
Reline::HISTORY[@history_pointer] =
|
1916
|
+
Reline::HISTORY[@history_pointer] = whole_buffer
|
2470
1917
|
@history_pointer += 1
|
2471
|
-
@
|
1918
|
+
@buffer_of_lines = [Reline::HISTORY[@history_pointer]]
|
2472
1919
|
end
|
2473
1920
|
end
|
2474
|
-
@line = '' unless @line
|
2475
1921
|
if @config.editing_mode_is?(:emacs, :vi_insert)
|
2476
|
-
@
|
2477
|
-
@byte_pointer = @line.bytesize
|
1922
|
+
@byte_pointer = current_line.bytesize
|
2478
1923
|
elsif @config.editing_mode_is?(:vi_command)
|
2479
|
-
@byte_pointer =
|
2480
|
-
@cursor_max = calculate_width(@line)
|
1924
|
+
@byte_pointer = 0
|
2481
1925
|
end
|
2482
1926
|
arg -= 1
|
2483
1927
|
ed_next_history(key, arg: arg) if arg > 0
|
@@ -2503,14 +1947,14 @@ class Reline::LineEditor
|
|
2503
1947
|
end
|
2504
1948
|
else
|
2505
1949
|
# should check confirm_multiline_termination to finish?
|
2506
|
-
@previous_line_index = @line_index
|
2507
1950
|
@line_index = @buffer_of_lines.size - 1
|
1951
|
+
@byte_pointer = current_line.bytesize
|
2508
1952
|
finish
|
2509
1953
|
end
|
2510
1954
|
end
|
2511
1955
|
else
|
2512
1956
|
if @history_pointer
|
2513
|
-
Reline::HISTORY[@history_pointer] =
|
1957
|
+
Reline::HISTORY[@history_pointer] = whole_buffer
|
2514
1958
|
@history_pointer = nil
|
2515
1959
|
end
|
2516
1960
|
finish
|
@@ -2518,25 +1962,18 @@ class Reline::LineEditor
|
|
2518
1962
|
end
|
2519
1963
|
|
2520
1964
|
private def em_delete_prev_char(key, arg: 1)
|
2521
|
-
|
2522
|
-
@
|
2523
|
-
|
2524
|
-
|
2525
|
-
|
2526
|
-
@
|
2527
|
-
|
2528
|
-
|
2529
|
-
|
2530
|
-
|
2531
|
-
byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
|
2532
|
-
@byte_pointer -= byte_size
|
2533
|
-
@line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
|
2534
|
-
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2535
|
-
@cursor -= width
|
2536
|
-
@cursor_max -= width
|
1965
|
+
arg.times do
|
1966
|
+
if @is_multiline and @byte_pointer == 0 and @line_index > 0
|
1967
|
+
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
|
1968
|
+
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
|
1969
|
+
@line_index -= 1
|
1970
|
+
elsif @byte_pointer > 0
|
1971
|
+
byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
|
1972
|
+
line, = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
|
1973
|
+
set_current_line(line, @byte_pointer - byte_size)
|
1974
|
+
end
|
2537
1975
|
end
|
2538
|
-
|
2539
|
-
em_delete_prev_char(key, arg: arg) if arg > 0
|
1976
|
+
process_auto_indent
|
2540
1977
|
end
|
2541
1978
|
alias_method :backward_delete_char, :em_delete_prev_char
|
2542
1979
|
|
@@ -2546,19 +1983,12 @@ class Reline::LineEditor
|
|
2546
1983
|
# the line. With a negative numeric argument, kill backward
|
2547
1984
|
# from the cursor to the beginning of the current line.
|
2548
1985
|
private def ed_kill_line(key)
|
2549
|
-
if
|
2550
|
-
|
2551
|
-
|
2552
|
-
@cursor = @cursor_max = calculate_width(@line)
|
1986
|
+
if current_line.bytesize > @byte_pointer
|
1987
|
+
line, deleted = byteslice!(current_line, @byte_pointer, current_line.bytesize - @byte_pointer)
|
1988
|
+
set_current_line(line, line.bytesize)
|
2553
1989
|
@kill_ring.append(deleted)
|
2554
|
-
elsif @is_multiline and @byte_pointer ==
|
2555
|
-
|
2556
|
-
@byte_pointer = @line.bytesize
|
2557
|
-
@line += @buffer_of_lines.delete_at(@line_index + 1)
|
2558
|
-
@cursor_max = calculate_width(@line)
|
2559
|
-
@buffer_of_lines[@line_index] = @line
|
2560
|
-
@rerender_all = true
|
2561
|
-
@rest_height += 1
|
1990
|
+
elsif @is_multiline and @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
|
1991
|
+
set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
|
2562
1992
|
end
|
2563
1993
|
end
|
2564
1994
|
alias_method :kill_line, :ed_kill_line
|
@@ -2570,11 +2000,9 @@ class Reline::LineEditor
|
|
2570
2000
|
# to the beginning of the current line.
|
2571
2001
|
private def vi_kill_line_prev(key)
|
2572
2002
|
if @byte_pointer > 0
|
2573
|
-
|
2574
|
-
|
2003
|
+
line, deleted = byteslice!(current_line, 0, @byte_pointer)
|
2004
|
+
set_current_line(line, 0)
|
2575
2005
|
@kill_ring.append(deleted, true)
|
2576
|
-
@cursor_max = calculate_width(@line)
|
2577
|
-
@cursor = 0
|
2578
2006
|
end
|
2579
2007
|
end
|
2580
2008
|
alias_method :unix_line_discard, :vi_kill_line_prev
|
@@ -2584,45 +2012,30 @@ class Reline::LineEditor
|
|
2584
2012
|
# GNU Readline:: +kill-whole-line+ (not bound) Kill all characters on the
|
2585
2013
|
# current line, no matter where point is.
|
2586
2014
|
private def em_kill_line(key)
|
2587
|
-
if
|
2588
|
-
@kill_ring.append(
|
2589
|
-
|
2590
|
-
@byte_pointer = 0
|
2591
|
-
@cursor_max = 0
|
2592
|
-
@cursor = 0
|
2015
|
+
if current_line.size > 0
|
2016
|
+
@kill_ring.append(current_line.dup, true)
|
2017
|
+
set_current_line('', 0)
|
2593
2018
|
end
|
2594
2019
|
end
|
2595
2020
|
alias_method :kill_whole_line, :em_kill_line
|
2596
2021
|
|
2597
2022
|
private def em_delete(key)
|
2598
|
-
if
|
2599
|
-
@line = nil
|
2600
|
-
if @buffer_of_lines.size > 1
|
2601
|
-
scroll_down(@highest_in_all - @first_line_started_from)
|
2602
|
-
end
|
2603
|
-
Reline::IOGate.move_cursor_column(0)
|
2023
|
+
if current_line.empty? and (not @is_multiline or @buffer_of_lines.size == 1) and key == "\C-d".ord
|
2604
2024
|
@eof = true
|
2605
2025
|
finish
|
2606
|
-
elsif @byte_pointer <
|
2607
|
-
splitted_last =
|
2026
|
+
elsif @byte_pointer < current_line.bytesize
|
2027
|
+
splitted_last = current_line.byteslice(@byte_pointer, current_line.bytesize)
|
2608
2028
|
mbchar = splitted_last.grapheme_clusters.first
|
2609
|
-
|
2610
|
-
|
2611
|
-
|
2612
|
-
|
2613
|
-
@cursor = calculate_width(@line)
|
2614
|
-
@byte_pointer = @line.bytesize
|
2615
|
-
@line += @buffer_of_lines.delete_at(@line_index + 1)
|
2616
|
-
@cursor_max = calculate_width(@line)
|
2617
|
-
@buffer_of_lines[@line_index] = @line
|
2618
|
-
@rerender_all = true
|
2619
|
-
@rest_height += 1
|
2029
|
+
line, = byteslice!(current_line, @byte_pointer, mbchar.bytesize)
|
2030
|
+
set_current_line(line)
|
2031
|
+
elsif @is_multiline and @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
|
2032
|
+
set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
|
2620
2033
|
end
|
2621
2034
|
end
|
2622
2035
|
alias_method :delete_char, :em_delete
|
2623
2036
|
|
2624
2037
|
private def em_delete_or_list(key)
|
2625
|
-
if
|
2038
|
+
if current_line.empty? or @byte_pointer < current_line.bytesize
|
2626
2039
|
em_delete(key)
|
2627
2040
|
else # show completed list
|
2628
2041
|
result = call_completion_proc
|
@@ -2635,29 +2048,16 @@ class Reline::LineEditor
|
|
2635
2048
|
|
2636
2049
|
private def em_yank(key)
|
2637
2050
|
yanked = @kill_ring.yank
|
2638
|
-
if yanked
|
2639
|
-
@line = byteinsert(@line, @byte_pointer, yanked)
|
2640
|
-
yanked_width = calculate_width(yanked)
|
2641
|
-
@cursor += yanked_width
|
2642
|
-
@cursor_max += yanked_width
|
2643
|
-
@byte_pointer += yanked.bytesize
|
2644
|
-
end
|
2051
|
+
insert_text(yanked) if yanked
|
2645
2052
|
end
|
2646
2053
|
alias_method :yank, :em_yank
|
2647
2054
|
|
2648
2055
|
private def em_yank_pop(key)
|
2649
2056
|
yanked, prev_yank = @kill_ring.yank_pop
|
2650
2057
|
if yanked
|
2651
|
-
|
2652
|
-
@
|
2653
|
-
|
2654
|
-
@byte_pointer -= prev_yank.bytesize
|
2655
|
-
@line, = byteslice!(@line, @byte_pointer, prev_yank.bytesize)
|
2656
|
-
@line = byteinsert(@line, @byte_pointer, yanked)
|
2657
|
-
yanked_width = calculate_width(yanked)
|
2658
|
-
@cursor += yanked_width
|
2659
|
-
@cursor_max += yanked_width
|
2660
|
-
@byte_pointer += yanked.bytesize
|
2058
|
+
line, = byteslice!(current_line, @byte_pointer - prev_yank.bytesize, prev_yank.bytesize)
|
2059
|
+
set_current_line(line, @byte_pointer - prev_yank.bytesize)
|
2060
|
+
insert_text(yanked)
|
2661
2061
|
end
|
2662
2062
|
end
|
2663
2063
|
alias_method :yank_pop, :em_yank_pop
|
@@ -2668,131 +2068,112 @@ class Reline::LineEditor
|
|
2668
2068
|
alias_method :clear_screen, :ed_clear_screen
|
2669
2069
|
|
2670
2070
|
private def em_next_word(key)
|
2671
|
-
if
|
2672
|
-
byte_size,
|
2071
|
+
if current_line.bytesize > @byte_pointer
|
2072
|
+
byte_size, _ = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
|
2673
2073
|
@byte_pointer += byte_size
|
2674
|
-
@cursor += width
|
2675
2074
|
end
|
2676
2075
|
end
|
2677
2076
|
alias_method :forward_word, :em_next_word
|
2678
2077
|
|
2679
2078
|
private def ed_prev_word(key)
|
2680
2079
|
if @byte_pointer > 0
|
2681
|
-
byte_size,
|
2080
|
+
byte_size, _ = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
|
2682
2081
|
@byte_pointer -= byte_size
|
2683
|
-
@cursor -= width
|
2684
2082
|
end
|
2685
2083
|
end
|
2686
2084
|
alias_method :backward_word, :ed_prev_word
|
2687
2085
|
|
2688
2086
|
private def em_delete_next_word(key)
|
2689
|
-
if
|
2690
|
-
byte_size,
|
2691
|
-
|
2087
|
+
if current_line.bytesize > @byte_pointer
|
2088
|
+
byte_size, _ = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
|
2089
|
+
line, word = byteslice!(current_line, @byte_pointer, byte_size)
|
2090
|
+
set_current_line(line)
|
2692
2091
|
@kill_ring.append(word)
|
2693
|
-
@cursor_max -= width
|
2694
2092
|
end
|
2695
2093
|
end
|
2696
2094
|
alias_method :kill_word, :em_delete_next_word
|
2697
2095
|
|
2698
2096
|
private def ed_delete_prev_word(key)
|
2699
2097
|
if @byte_pointer > 0
|
2700
|
-
byte_size,
|
2701
|
-
|
2098
|
+
byte_size, _ = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
|
2099
|
+
line, word = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
|
2100
|
+
set_current_line(line, @byte_pointer - byte_size)
|
2702
2101
|
@kill_ring.append(word, true)
|
2703
|
-
@byte_pointer -= byte_size
|
2704
|
-
@cursor -= width
|
2705
|
-
@cursor_max -= width
|
2706
2102
|
end
|
2707
2103
|
end
|
2708
2104
|
alias_method :backward_kill_word, :ed_delete_prev_word
|
2709
2105
|
|
2710
2106
|
private def ed_transpose_chars(key)
|
2711
2107
|
if @byte_pointer > 0
|
2712
|
-
if @
|
2713
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
2714
|
-
mbchar = @line.byteslice(@byte_pointer, byte_size)
|
2715
|
-
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2716
|
-
@cursor += width
|
2108
|
+
if @byte_pointer < current_line.bytesize
|
2109
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2717
2110
|
@byte_pointer += byte_size
|
2718
2111
|
end
|
2719
|
-
back1_byte_size = Reline::Unicode.get_prev_mbchar_size(
|
2112
|
+
back1_byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
|
2720
2113
|
if (@byte_pointer - back1_byte_size) > 0
|
2721
|
-
back2_byte_size = Reline::Unicode.get_prev_mbchar_size(
|
2114
|
+
back2_byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer - back1_byte_size)
|
2722
2115
|
back2_pointer = @byte_pointer - back1_byte_size - back2_byte_size
|
2723
|
-
|
2724
|
-
|
2116
|
+
line, back2_mbchar = byteslice!(current_line, back2_pointer, back2_byte_size)
|
2117
|
+
set_current_line(byteinsert(line, @byte_pointer - back2_byte_size, back2_mbchar))
|
2725
2118
|
end
|
2726
2119
|
end
|
2727
2120
|
end
|
2728
2121
|
alias_method :transpose_chars, :ed_transpose_chars
|
2729
2122
|
|
2730
2123
|
private def ed_transpose_words(key)
|
2731
|
-
left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(
|
2732
|
-
before =
|
2733
|
-
left_word =
|
2734
|
-
middle =
|
2735
|
-
right_word =
|
2736
|
-
after =
|
2124
|
+
left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(current_line, @byte_pointer)
|
2125
|
+
before = current_line.byteslice(0, left_word_start)
|
2126
|
+
left_word = current_line.byteslice(left_word_start, middle_start - left_word_start)
|
2127
|
+
middle = current_line.byteslice(middle_start, right_word_start - middle_start)
|
2128
|
+
right_word = current_line.byteslice(right_word_start, after_start - right_word_start)
|
2129
|
+
after = current_line.byteslice(after_start, current_line.bytesize - after_start)
|
2737
2130
|
return if left_word.empty? or right_word.empty?
|
2738
|
-
@line = before + right_word + middle + left_word + after
|
2739
2131
|
from_head_to_left_word = before + right_word + middle + left_word
|
2740
|
-
|
2741
|
-
@cursor = calculate_width(from_head_to_left_word)
|
2132
|
+
set_current_line(from_head_to_left_word + after, from_head_to_left_word.bytesize)
|
2742
2133
|
end
|
2743
2134
|
alias_method :transpose_words, :ed_transpose_words
|
2744
2135
|
|
2745
2136
|
private def em_capitol_case(key)
|
2746
|
-
if
|
2747
|
-
byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(
|
2748
|
-
before =
|
2749
|
-
after =
|
2750
|
-
|
2751
|
-
@byte_pointer += new_str.bytesize
|
2752
|
-
@cursor += calculate_width(new_str)
|
2137
|
+
if current_line.bytesize > @byte_pointer
|
2138
|
+
byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(current_line, @byte_pointer)
|
2139
|
+
before = current_line.byteslice(0, @byte_pointer)
|
2140
|
+
after = current_line.byteslice((@byte_pointer + byte_size)..-1)
|
2141
|
+
set_current_line(before + new_str + after, @byte_pointer + new_str.bytesize)
|
2753
2142
|
end
|
2754
2143
|
end
|
2755
2144
|
alias_method :capitalize_word, :em_capitol_case
|
2756
2145
|
|
2757
2146
|
private def em_lower_case(key)
|
2758
|
-
if
|
2759
|
-
byte_size, = Reline::Unicode.em_forward_word(
|
2760
|
-
part =
|
2147
|
+
if current_line.bytesize > @byte_pointer
|
2148
|
+
byte_size, = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
|
2149
|
+
part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
|
2761
2150
|
mbchar =~ /[A-Z]/ ? mbchar.downcase : mbchar
|
2762
2151
|
}.join
|
2763
|
-
rest =
|
2764
|
-
|
2765
|
-
|
2766
|
-
@cursor = calculate_width(@line)
|
2767
|
-
@cursor_max = @cursor + calculate_width(rest)
|
2768
|
-
@line += rest
|
2152
|
+
rest = current_line.byteslice((@byte_pointer + byte_size)..-1)
|
2153
|
+
line = current_line.byteslice(0, @byte_pointer) + part
|
2154
|
+
set_current_line(line + rest, line.bytesize)
|
2769
2155
|
end
|
2770
2156
|
end
|
2771
2157
|
alias_method :downcase_word, :em_lower_case
|
2772
2158
|
|
2773
2159
|
private def em_upper_case(key)
|
2774
|
-
if
|
2775
|
-
byte_size, = Reline::Unicode.em_forward_word(
|
2776
|
-
part =
|
2160
|
+
if current_line.bytesize > @byte_pointer
|
2161
|
+
byte_size, = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
|
2162
|
+
part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
|
2777
2163
|
mbchar =~ /[a-z]/ ? mbchar.upcase : mbchar
|
2778
2164
|
}.join
|
2779
|
-
rest =
|
2780
|
-
|
2781
|
-
|
2782
|
-
@cursor = calculate_width(@line)
|
2783
|
-
@cursor_max = @cursor + calculate_width(rest)
|
2784
|
-
@line += rest
|
2165
|
+
rest = current_line.byteslice((@byte_pointer + byte_size)..-1)
|
2166
|
+
line = current_line.byteslice(0, @byte_pointer) + part
|
2167
|
+
set_current_line(line + rest, line.bytesize)
|
2785
2168
|
end
|
2786
2169
|
end
|
2787
2170
|
alias_method :upcase_word, :em_upper_case
|
2788
2171
|
|
2789
2172
|
private def em_kill_region(key)
|
2790
2173
|
if @byte_pointer > 0
|
2791
|
-
byte_size,
|
2792
|
-
|
2793
|
-
@byte_pointer
|
2794
|
-
@cursor -= width
|
2795
|
-
@cursor_max -= width
|
2174
|
+
byte_size, _ = Reline::Unicode.em_big_backward_word(current_line, @byte_pointer)
|
2175
|
+
line, deleted = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
|
2176
|
+
set_current_line(line, @byte_pointer - byte_size)
|
2796
2177
|
@kill_ring.append(deleted, true)
|
2797
2178
|
end
|
2798
2179
|
end
|
@@ -2820,10 +2201,9 @@ class Reline::LineEditor
|
|
2820
2201
|
alias_method :vi_movement_mode, :vi_command_mode
|
2821
2202
|
|
2822
2203
|
private def vi_next_word(key, arg: 1)
|
2823
|
-
if
|
2824
|
-
byte_size,
|
2204
|
+
if current_line.bytesize > @byte_pointer
|
2205
|
+
byte_size, _ = Reline::Unicode.vi_forward_word(current_line, @byte_pointer, @drop_terminate_spaces)
|
2825
2206
|
@byte_pointer += byte_size
|
2826
|
-
@cursor += width
|
2827
2207
|
end
|
2828
2208
|
arg -= 1
|
2829
2209
|
vi_next_word(key, arg: arg) if arg > 0
|
@@ -2831,38 +2211,32 @@ class Reline::LineEditor
|
|
2831
2211
|
|
2832
2212
|
private def vi_prev_word(key, arg: 1)
|
2833
2213
|
if @byte_pointer > 0
|
2834
|
-
byte_size,
|
2214
|
+
byte_size, _ = Reline::Unicode.vi_backward_word(current_line, @byte_pointer)
|
2835
2215
|
@byte_pointer -= byte_size
|
2836
|
-
@cursor -= width
|
2837
2216
|
end
|
2838
2217
|
arg -= 1
|
2839
2218
|
vi_prev_word(key, arg: arg) if arg > 0
|
2840
2219
|
end
|
2841
2220
|
|
2842
2221
|
private def vi_end_word(key, arg: 1, inclusive: false)
|
2843
|
-
if
|
2844
|
-
byte_size,
|
2222
|
+
if current_line.bytesize > @byte_pointer
|
2223
|
+
byte_size, _ = Reline::Unicode.vi_forward_end_word(current_line, @byte_pointer)
|
2845
2224
|
@byte_pointer += byte_size
|
2846
|
-
@cursor += width
|
2847
2225
|
end
|
2848
2226
|
arg -= 1
|
2849
2227
|
if inclusive and arg.zero?
|
2850
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
2228
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2851
2229
|
if byte_size > 0
|
2852
|
-
c = @line.byteslice(@byte_pointer, byte_size)
|
2853
|
-
width = Reline::Unicode.get_mbchar_width(c)
|
2854
2230
|
@byte_pointer += byte_size
|
2855
|
-
@cursor += width
|
2856
2231
|
end
|
2857
2232
|
end
|
2858
2233
|
vi_end_word(key, arg: arg) if arg > 0
|
2859
2234
|
end
|
2860
2235
|
|
2861
2236
|
private def vi_next_big_word(key, arg: 1)
|
2862
|
-
if
|
2863
|
-
byte_size,
|
2237
|
+
if current_line.bytesize > @byte_pointer
|
2238
|
+
byte_size, _ = Reline::Unicode.vi_big_forward_word(current_line, @byte_pointer)
|
2864
2239
|
@byte_pointer += byte_size
|
2865
|
-
@cursor += width
|
2866
2240
|
end
|
2867
2241
|
arg -= 1
|
2868
2242
|
vi_next_big_word(key, arg: arg) if arg > 0
|
@@ -2870,50 +2244,39 @@ class Reline::LineEditor
|
|
2870
2244
|
|
2871
2245
|
private def vi_prev_big_word(key, arg: 1)
|
2872
2246
|
if @byte_pointer > 0
|
2873
|
-
byte_size,
|
2247
|
+
byte_size, _ = Reline::Unicode.vi_big_backward_word(current_line, @byte_pointer)
|
2874
2248
|
@byte_pointer -= byte_size
|
2875
|
-
@cursor -= width
|
2876
2249
|
end
|
2877
2250
|
arg -= 1
|
2878
2251
|
vi_prev_big_word(key, arg: arg) if arg > 0
|
2879
2252
|
end
|
2880
2253
|
|
2881
2254
|
private def vi_end_big_word(key, arg: 1, inclusive: false)
|
2882
|
-
if
|
2883
|
-
byte_size,
|
2255
|
+
if current_line.bytesize > @byte_pointer
|
2256
|
+
byte_size, _ = Reline::Unicode.vi_big_forward_end_word(current_line, @byte_pointer)
|
2884
2257
|
@byte_pointer += byte_size
|
2885
|
-
@cursor += width
|
2886
2258
|
end
|
2887
2259
|
arg -= 1
|
2888
2260
|
if inclusive and arg.zero?
|
2889
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
2261
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2890
2262
|
if byte_size > 0
|
2891
|
-
c = @line.byteslice(@byte_pointer, byte_size)
|
2892
|
-
width = Reline::Unicode.get_mbchar_width(c)
|
2893
2263
|
@byte_pointer += byte_size
|
2894
|
-
@cursor += width
|
2895
2264
|
end
|
2896
2265
|
end
|
2897
2266
|
vi_end_big_word(key, arg: arg) if arg > 0
|
2898
2267
|
end
|
2899
2268
|
|
2900
2269
|
private def vi_delete_prev_char(key)
|
2901
|
-
if @is_multiline and @
|
2902
|
-
@buffer_of_lines[@line_index] = @line
|
2903
|
-
@cursor = calculate_width(@buffer_of_lines[@line_index - 1])
|
2270
|
+
if @is_multiline and @byte_pointer == 0 and @line_index > 0
|
2904
2271
|
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
|
2905
2272
|
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
|
2906
2273
|
@line_index -= 1
|
2907
|
-
|
2908
|
-
|
2909
|
-
|
2910
|
-
elsif @cursor > 0
|
2911
|
-
byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
|
2274
|
+
process_auto_indent cursor_dependent: false
|
2275
|
+
elsif @byte_pointer > 0
|
2276
|
+
byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
|
2912
2277
|
@byte_pointer -= byte_size
|
2913
|
-
|
2914
|
-
|
2915
|
-
@cursor -= width
|
2916
|
-
@cursor_max -= width
|
2278
|
+
line, _ = byteslice!(current_line, @byte_pointer, byte_size)
|
2279
|
+
set_current_line(line)
|
2917
2280
|
end
|
2918
2281
|
end
|
2919
2282
|
|
@@ -2930,14 +2293,12 @@ class Reline::LineEditor
|
|
2930
2293
|
private def ed_delete_prev_char(key, arg: 1)
|
2931
2294
|
deleted = ''
|
2932
2295
|
arg.times do
|
2933
|
-
if @
|
2934
|
-
byte_size = Reline::Unicode.get_prev_mbchar_size(
|
2296
|
+
if @byte_pointer > 0
|
2297
|
+
byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
|
2935
2298
|
@byte_pointer -= byte_size
|
2936
|
-
|
2299
|
+
line, mbchar = byteslice!(current_line, @byte_pointer, byte_size)
|
2300
|
+
set_current_line(line)
|
2937
2301
|
deleted.prepend(mbchar)
|
2938
|
-
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2939
|
-
@cursor -= width
|
2940
|
-
@cursor_max -= width
|
2941
2302
|
end
|
2942
2303
|
end
|
2943
2304
|
copy_for_vi(deleted)
|
@@ -2945,20 +2306,18 @@ class Reline::LineEditor
|
|
2945
2306
|
|
2946
2307
|
private def vi_zero(key)
|
2947
2308
|
@byte_pointer = 0
|
2948
|
-
@cursor = 0
|
2949
2309
|
end
|
2950
2310
|
|
2951
2311
|
private def vi_change_meta(key, arg: 1)
|
2952
2312
|
@drop_terminate_spaces = true
|
2953
|
-
@waiting_operator_proc = proc { |
|
2313
|
+
@waiting_operator_proc = proc { |byte_pointer_diff|
|
2954
2314
|
if byte_pointer_diff > 0
|
2955
|
-
|
2315
|
+
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
2956
2316
|
elsif byte_pointer_diff < 0
|
2957
|
-
|
2317
|
+
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2958
2318
|
end
|
2319
|
+
set_current_line(line)
|
2959
2320
|
copy_for_vi(cut)
|
2960
|
-
@cursor += cursor_diff if cursor_diff < 0
|
2961
|
-
@cursor_max -= cursor_diff.abs
|
2962
2321
|
@byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
|
2963
2322
|
@config.editing_mode = :vi_insert
|
2964
2323
|
@drop_terminate_spaces = false
|
@@ -2967,26 +2326,24 @@ class Reline::LineEditor
|
|
2967
2326
|
end
|
2968
2327
|
|
2969
2328
|
private def vi_delete_meta(key, arg: 1)
|
2970
|
-
@waiting_operator_proc = proc { |
|
2329
|
+
@waiting_operator_proc = proc { |byte_pointer_diff|
|
2971
2330
|
if byte_pointer_diff > 0
|
2972
|
-
|
2331
|
+
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
2973
2332
|
elsif byte_pointer_diff < 0
|
2974
|
-
|
2333
|
+
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2975
2334
|
end
|
2976
2335
|
copy_for_vi(cut)
|
2977
|
-
|
2978
|
-
@cursor_max -= cursor_diff.abs
|
2979
|
-
@byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
|
2336
|
+
set_current_line(line || '', @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
|
2980
2337
|
}
|
2981
2338
|
@waiting_operator_vi_arg = arg
|
2982
2339
|
end
|
2983
2340
|
|
2984
2341
|
private def vi_yank(key, arg: 1)
|
2985
|
-
@waiting_operator_proc = proc { |
|
2342
|
+
@waiting_operator_proc = proc { |byte_pointer_diff|
|
2986
2343
|
if byte_pointer_diff > 0
|
2987
|
-
cut =
|
2344
|
+
cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
|
2988
2345
|
elsif byte_pointer_diff < 0
|
2989
|
-
cut =
|
2346
|
+
cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2990
2347
|
end
|
2991
2348
|
copy_for_vi(cut)
|
2992
2349
|
}
|
@@ -2994,12 +2351,8 @@ class Reline::LineEditor
|
|
2994
2351
|
end
|
2995
2352
|
|
2996
2353
|
private def vi_list_or_eof(key)
|
2997
|
-
if (not @is_multiline and
|
2998
|
-
|
2999
|
-
if @buffer_of_lines.size > 1
|
3000
|
-
scroll_down(@highest_in_all - @first_line_started_from)
|
3001
|
-
end
|
3002
|
-
Reline::IOGate.move_cursor_column(0)
|
2354
|
+
if (not @is_multiline and current_line.empty?) or (@is_multiline and current_line.empty? and @buffer_of_lines.size == 1)
|
2355
|
+
set_current_line('', 0)
|
3003
2356
|
@eof = true
|
3004
2357
|
finish
|
3005
2358
|
else
|
@@ -3010,18 +2363,15 @@ class Reline::LineEditor
|
|
3010
2363
|
alias_method :vi_eof_maybe, :vi_list_or_eof
|
3011
2364
|
|
3012
2365
|
private def ed_delete_next_char(key, arg: 1)
|
3013
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
3014
|
-
unless
|
3015
|
-
|
2366
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2367
|
+
unless current_line.empty? || byte_size == 0
|
2368
|
+
line, mbchar = byteslice!(current_line, @byte_pointer, byte_size)
|
3016
2369
|
copy_for_vi(mbchar)
|
3017
|
-
|
3018
|
-
|
3019
|
-
|
3020
|
-
|
3021
|
-
|
3022
|
-
width = Reline::Unicode.get_mbchar_width(mbchar)
|
3023
|
-
@byte_pointer -= byte_size
|
3024
|
-
@cursor -= width
|
2370
|
+
if @byte_pointer > 0 && current_line.bytesize == @byte_pointer + byte_size
|
2371
|
+
byte_size = Reline::Unicode.get_prev_mbchar_size(line, @byte_pointer)
|
2372
|
+
set_current_line(line, @byte_pointer - byte_size)
|
2373
|
+
else
|
2374
|
+
set_current_line(line, @byte_pointer)
|
3025
2375
|
end
|
3026
2376
|
end
|
3027
2377
|
arg -= 1
|
@@ -3034,20 +2384,14 @@ class Reline::LineEditor
|
|
3034
2384
|
end
|
3035
2385
|
if @history_pointer.nil?
|
3036
2386
|
@history_pointer = 0
|
3037
|
-
@line_backup_in_history =
|
3038
|
-
|
3039
|
-
@cursor_max = calculate_width(@line)
|
3040
|
-
@cursor = 0
|
3041
|
-
@byte_pointer = 0
|
2387
|
+
@line_backup_in_history = current_line
|
2388
|
+
set_current_line(Reline::HISTORY[@history_pointer], 0)
|
3042
2389
|
elsif @history_pointer.zero?
|
3043
2390
|
return
|
3044
2391
|
else
|
3045
|
-
Reline::HISTORY[@history_pointer] =
|
2392
|
+
Reline::HISTORY[@history_pointer] = current_line
|
3046
2393
|
@history_pointer = 0
|
3047
|
-
|
3048
|
-
@cursor_max = calculate_width(@line)
|
3049
|
-
@cursor = 0
|
3050
|
-
@byte_pointer = 0
|
2394
|
+
set_current_line(Reline::HISTORY[@history_pointer], 0)
|
3051
2395
|
end
|
3052
2396
|
end
|
3053
2397
|
|
@@ -3056,7 +2400,7 @@ class Reline::LineEditor
|
|
3056
2400
|
if @is_multiline
|
3057
2401
|
fp.write whole_lines.join("\n")
|
3058
2402
|
else
|
3059
|
-
fp.write
|
2403
|
+
fp.write current_line
|
3060
2404
|
end
|
3061
2405
|
fp.path
|
3062
2406
|
}
|
@@ -3065,21 +2409,16 @@ class Reline::LineEditor
|
|
3065
2409
|
@buffer_of_lines = File.read(path).split("\n")
|
3066
2410
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
3067
2411
|
@line_index = 0
|
3068
|
-
@line = @buffer_of_lines[@line_index]
|
3069
|
-
@rerender_all = true
|
3070
2412
|
else
|
3071
|
-
@
|
2413
|
+
@buffer_of_lines = File.read(path).split("\n")
|
3072
2414
|
end
|
3073
2415
|
finish
|
3074
2416
|
end
|
3075
2417
|
|
3076
2418
|
private def vi_paste_prev(key, arg: 1)
|
3077
2419
|
if @vi_clipboard.size > 0
|
3078
|
-
@line = byteinsert(@line, @byte_pointer, @vi_clipboard)
|
3079
|
-
@cursor_max += calculate_width(@vi_clipboard)
|
3080
2420
|
cursor_point = @vi_clipboard.grapheme_clusters[0..-2].join
|
3081
|
-
@
|
3082
|
-
@byte_pointer += cursor_point.bytesize
|
2421
|
+
set_current_line(byteinsert(current_line, @byte_pointer, @vi_clipboard), @byte_pointer + cursor_point.bytesize)
|
3083
2422
|
end
|
3084
2423
|
arg -= 1
|
3085
2424
|
vi_paste_prev(key, arg: arg) if arg > 0
|
@@ -3087,11 +2426,9 @@ class Reline::LineEditor
|
|
3087
2426
|
|
3088
2427
|
private def vi_paste_next(key, arg: 1)
|
3089
2428
|
if @vi_clipboard.size > 0
|
3090
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
3091
|
-
|
3092
|
-
@
|
3093
|
-
@cursor += calculate_width(@vi_clipboard)
|
3094
|
-
@byte_pointer += @vi_clipboard.bytesize
|
2429
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2430
|
+
line = byteinsert(current_line, @byte_pointer + byte_size, @vi_clipboard)
|
2431
|
+
set_current_line(line, @byte_pointer + @vi_clipboard.bytesize)
|
3095
2432
|
end
|
3096
2433
|
arg -= 1
|
3097
2434
|
vi_paste_next(key, arg: arg) if arg > 0
|
@@ -3115,12 +2452,13 @@ class Reline::LineEditor
|
|
3115
2452
|
end
|
3116
2453
|
|
3117
2454
|
private def vi_to_column(key, arg: 0)
|
3118
|
-
|
2455
|
+
current_row_width = calculate_width(current_row)
|
2456
|
+
@byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |total, gc|
|
3119
2457
|
# total has [byte_size, cursor]
|
3120
2458
|
mbchar_width = Reline::Unicode.get_mbchar_width(gc)
|
3121
2459
|
if (total.last + mbchar_width) >= arg
|
3122
2460
|
break total
|
3123
|
-
elsif (total.last + mbchar_width) >=
|
2461
|
+
elsif (total.last + mbchar_width) >= current_row_width
|
3124
2462
|
break total
|
3125
2463
|
else
|
3126
2464
|
total = [total.first + gc.bytesize, total.last + mbchar_width]
|
@@ -3132,26 +2470,22 @@ class Reline::LineEditor
|
|
3132
2470
|
private def vi_replace_char(key, arg: 1)
|
3133
2471
|
@waiting_proc = ->(k) {
|
3134
2472
|
if arg == 1
|
3135
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
3136
|
-
before =
|
2473
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2474
|
+
before = current_line.byteslice(0, @byte_pointer)
|
3137
2475
|
remaining_point = @byte_pointer + byte_size
|
3138
|
-
after =
|
3139
|
-
|
3140
|
-
@cursor_max = calculate_width(@line)
|
2476
|
+
after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
|
2477
|
+
set_current_line(before + k.chr + after)
|
3141
2478
|
@waiting_proc = nil
|
3142
2479
|
elsif arg > 1
|
3143
2480
|
byte_size = 0
|
3144
2481
|
arg.times do
|
3145
|
-
byte_size += Reline::Unicode.get_next_mbchar_size(
|
2482
|
+
byte_size += Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer + byte_size)
|
3146
2483
|
end
|
3147
|
-
before =
|
2484
|
+
before = current_line.byteslice(0, @byte_pointer)
|
3148
2485
|
remaining_point = @byte_pointer + byte_size
|
3149
|
-
after =
|
2486
|
+
after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
|
3150
2487
|
replaced = k.chr * arg
|
3151
|
-
|
3152
|
-
@byte_pointer += replaced.bytesize
|
3153
|
-
@cursor += calculate_width(replaced)
|
3154
|
-
@cursor_max = calculate_width(@line)
|
2488
|
+
set_current_line(before + replaced + after, @byte_pointer + replaced.bytesize)
|
3155
2489
|
@waiting_proc = nil
|
3156
2490
|
end
|
3157
2491
|
}
|
@@ -3174,7 +2508,7 @@ class Reline::LineEditor
|
|
3174
2508
|
prev_total = nil
|
3175
2509
|
total = nil
|
3176
2510
|
found = false
|
3177
|
-
|
2511
|
+
current_line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
|
3178
2512
|
# total has [byte_size, cursor]
|
3179
2513
|
unless total
|
3180
2514
|
# skip cursor point
|
@@ -3194,21 +2528,16 @@ class Reline::LineEditor
|
|
3194
2528
|
end
|
3195
2529
|
end
|
3196
2530
|
if not need_prev_char and found and total
|
3197
|
-
byte_size,
|
2531
|
+
byte_size, _ = total
|
3198
2532
|
@byte_pointer += byte_size
|
3199
|
-
@cursor += width
|
3200
2533
|
elsif need_prev_char and found and prev_total
|
3201
|
-
byte_size,
|
2534
|
+
byte_size, _ = prev_total
|
3202
2535
|
@byte_pointer += byte_size
|
3203
|
-
@cursor += width
|
3204
2536
|
end
|
3205
2537
|
if inclusive
|
3206
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
2538
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
3207
2539
|
if byte_size > 0
|
3208
|
-
c = @line.byteslice(@byte_pointer, byte_size)
|
3209
|
-
width = Reline::Unicode.get_mbchar_width(c)
|
3210
2540
|
@byte_pointer += byte_size
|
3211
|
-
@cursor += width
|
3212
2541
|
end
|
3213
2542
|
end
|
3214
2543
|
@waiting_proc = nil
|
@@ -3231,7 +2560,7 @@ class Reline::LineEditor
|
|
3231
2560
|
prev_total = nil
|
3232
2561
|
total = nil
|
3233
2562
|
found = false
|
3234
|
-
|
2563
|
+
current_line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar|
|
3235
2564
|
# total has [byte_size, cursor]
|
3236
2565
|
unless total
|
3237
2566
|
# skip cursor point
|
@@ -3251,26 +2580,19 @@ class Reline::LineEditor
|
|
3251
2580
|
end
|
3252
2581
|
end
|
3253
2582
|
if not need_next_char and found and total
|
3254
|
-
byte_size,
|
2583
|
+
byte_size, _ = total
|
3255
2584
|
@byte_pointer -= byte_size
|
3256
|
-
@cursor -= width
|
3257
2585
|
elsif need_next_char and found and prev_total
|
3258
|
-
byte_size,
|
2586
|
+
byte_size, _ = prev_total
|
3259
2587
|
@byte_pointer -= byte_size
|
3260
|
-
@cursor -= width
|
3261
2588
|
end
|
3262
2589
|
@waiting_proc = nil
|
3263
2590
|
end
|
3264
2591
|
|
3265
2592
|
private def vi_join_lines(key, arg: 1)
|
3266
2593
|
if @is_multiline and @buffer_of_lines.size > @line_index + 1
|
3267
|
-
|
3268
|
-
|
3269
|
-
@line += ' ' + @buffer_of_lines.delete_at(@line_index + 1).lstrip
|
3270
|
-
@cursor_max = calculate_width(@line)
|
3271
|
-
@buffer_of_lines[@line_index] = @line
|
3272
|
-
@rerender_all = true
|
3273
|
-
@rest_height += 1
|
2594
|
+
next_line = @buffer_of_lines.delete_at(@line_index + 1).lstrip
|
2595
|
+
set_current_line(current_line + ' ' + next_line, current_line.bytesize)
|
3274
2596
|
end
|
3275
2597
|
arg -= 1
|
3276
2598
|
vi_join_lines(key, arg: arg) if arg > 0
|
@@ -3284,10 +2606,7 @@ class Reline::LineEditor
|
|
3284
2606
|
private def em_exchange_mark(key)
|
3285
2607
|
return unless @mark_pointer
|
3286
2608
|
new_pointer = [@byte_pointer, @line_index]
|
3287
|
-
@previous_line_index = @line_index
|
3288
2609
|
@byte_pointer, @line_index = @mark_pointer
|
3289
|
-
@cursor = calculate_width(@line.byteslice(0, @byte_pointer))
|
3290
|
-
@cursor_max = calculate_width(@line)
|
3291
2610
|
@mark_pointer = new_pointer
|
3292
2611
|
end
|
3293
2612
|
alias_method :exchange_point_and_mark, :em_exchange_mark
|