reline 0.4.3 → 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 +3 -3
- data/lib/reline/general_io.rb +1 -1
- data/lib/reline/history.rb +1 -1
- data/lib/reline/kill_ring.rb +1 -1
- data/lib/reline/line_editor.rb +605 -1293
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +10 -7
- metadata +6 -9
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)
|
512
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
|
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
|
-
@
|
1316
|
-
line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n")
|
1317
|
-
@cursor_max = calculate_width(@line)
|
1318
|
-
@cursor = calculate_width(line_to_pointer)
|
890
|
+
@buffer_of_lines[@line_index] = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
|
891
|
+
line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n").last || String.new(encoding: @encoding)
|
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
|
1604
1168
|
end
|
1605
|
-
|
1606
|
-
|
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
|
1175
|
+
end
|
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,30 +1983,16 @@ 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
|
2565
1995
|
|
2566
|
-
# Editline:: +vi_change_to_eol+ (vi command: +C+) + Kill and change from the cursor to the end of the line.
|
2567
|
-
private def vi_change_to_eol(key)
|
2568
|
-
ed_kill_line(key)
|
2569
|
-
|
2570
|
-
@config.editing_mode = :vi_insert
|
2571
|
-
end
|
2572
|
-
|
2573
1996
|
# Editline:: +vi-kill-line-prev+ (vi: +Ctrl-U+) Delete the string from the
|
2574
1997
|
# beginning of the edit buffer to the cursor and save it to the
|
2575
1998
|
# cut buffer.
|
@@ -2577,11 +2000,9 @@ class Reline::LineEditor
|
|
2577
2000
|
# to the beginning of the current line.
|
2578
2001
|
private def vi_kill_line_prev(key)
|
2579
2002
|
if @byte_pointer > 0
|
2580
|
-
|
2581
|
-
|
2003
|
+
line, deleted = byteslice!(current_line, 0, @byte_pointer)
|
2004
|
+
set_current_line(line, 0)
|
2582
2005
|
@kill_ring.append(deleted, true)
|
2583
|
-
@cursor_max = calculate_width(@line)
|
2584
|
-
@cursor = 0
|
2585
2006
|
end
|
2586
2007
|
end
|
2587
2008
|
alias_method :unix_line_discard, :vi_kill_line_prev
|
@@ -2591,45 +2012,30 @@ class Reline::LineEditor
|
|
2591
2012
|
# GNU Readline:: +kill-whole-line+ (not bound) Kill all characters on the
|
2592
2013
|
# current line, no matter where point is.
|
2593
2014
|
private def em_kill_line(key)
|
2594
|
-
if
|
2595
|
-
@kill_ring.append(
|
2596
|
-
|
2597
|
-
@byte_pointer = 0
|
2598
|
-
@cursor_max = 0
|
2599
|
-
@cursor = 0
|
2015
|
+
if current_line.size > 0
|
2016
|
+
@kill_ring.append(current_line.dup, true)
|
2017
|
+
set_current_line('', 0)
|
2600
2018
|
end
|
2601
2019
|
end
|
2602
2020
|
alias_method :kill_whole_line, :em_kill_line
|
2603
2021
|
|
2604
2022
|
private def em_delete(key)
|
2605
|
-
if
|
2606
|
-
@line = nil
|
2607
|
-
if @buffer_of_lines.size > 1
|
2608
|
-
scroll_down(@highest_in_all - @first_line_started_from)
|
2609
|
-
end
|
2610
|
-
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
|
2611
2024
|
@eof = true
|
2612
2025
|
finish
|
2613
|
-
elsif @byte_pointer <
|
2614
|
-
splitted_last =
|
2026
|
+
elsif @byte_pointer < current_line.bytesize
|
2027
|
+
splitted_last = current_line.byteslice(@byte_pointer, current_line.bytesize)
|
2615
2028
|
mbchar = splitted_last.grapheme_clusters.first
|
2616
|
-
|
2617
|
-
|
2618
|
-
|
2619
|
-
|
2620
|
-
@cursor = calculate_width(@line)
|
2621
|
-
@byte_pointer = @line.bytesize
|
2622
|
-
@line += @buffer_of_lines.delete_at(@line_index + 1)
|
2623
|
-
@cursor_max = calculate_width(@line)
|
2624
|
-
@buffer_of_lines[@line_index] = @line
|
2625
|
-
@rerender_all = true
|
2626
|
-
@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)
|
2627
2033
|
end
|
2628
2034
|
end
|
2629
2035
|
alias_method :delete_char, :em_delete
|
2630
2036
|
|
2631
2037
|
private def em_delete_or_list(key)
|
2632
|
-
if
|
2038
|
+
if current_line.empty? or @byte_pointer < current_line.bytesize
|
2633
2039
|
em_delete(key)
|
2634
2040
|
else # show completed list
|
2635
2041
|
result = call_completion_proc
|
@@ -2642,29 +2048,16 @@ class Reline::LineEditor
|
|
2642
2048
|
|
2643
2049
|
private def em_yank(key)
|
2644
2050
|
yanked = @kill_ring.yank
|
2645
|
-
if yanked
|
2646
|
-
@line = byteinsert(@line, @byte_pointer, yanked)
|
2647
|
-
yanked_width = calculate_width(yanked)
|
2648
|
-
@cursor += yanked_width
|
2649
|
-
@cursor_max += yanked_width
|
2650
|
-
@byte_pointer += yanked.bytesize
|
2651
|
-
end
|
2051
|
+
insert_text(yanked) if yanked
|
2652
2052
|
end
|
2653
2053
|
alias_method :yank, :em_yank
|
2654
2054
|
|
2655
2055
|
private def em_yank_pop(key)
|
2656
2056
|
yanked, prev_yank = @kill_ring.yank_pop
|
2657
2057
|
if yanked
|
2658
|
-
|
2659
|
-
@
|
2660
|
-
|
2661
|
-
@byte_pointer -= prev_yank.bytesize
|
2662
|
-
@line, = byteslice!(@line, @byte_pointer, prev_yank.bytesize)
|
2663
|
-
@line = byteinsert(@line, @byte_pointer, yanked)
|
2664
|
-
yanked_width = calculate_width(yanked)
|
2665
|
-
@cursor += yanked_width
|
2666
|
-
@cursor_max += yanked_width
|
2667
|
-
@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)
|
2668
2061
|
end
|
2669
2062
|
end
|
2670
2063
|
alias_method :yank_pop, :em_yank_pop
|
@@ -2675,131 +2068,112 @@ class Reline::LineEditor
|
|
2675
2068
|
alias_method :clear_screen, :ed_clear_screen
|
2676
2069
|
|
2677
2070
|
private def em_next_word(key)
|
2678
|
-
if
|
2679
|
-
byte_size,
|
2071
|
+
if current_line.bytesize > @byte_pointer
|
2072
|
+
byte_size, _ = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
|
2680
2073
|
@byte_pointer += byte_size
|
2681
|
-
@cursor += width
|
2682
2074
|
end
|
2683
2075
|
end
|
2684
2076
|
alias_method :forward_word, :em_next_word
|
2685
2077
|
|
2686
2078
|
private def ed_prev_word(key)
|
2687
2079
|
if @byte_pointer > 0
|
2688
|
-
byte_size,
|
2080
|
+
byte_size, _ = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
|
2689
2081
|
@byte_pointer -= byte_size
|
2690
|
-
@cursor -= width
|
2691
2082
|
end
|
2692
2083
|
end
|
2693
2084
|
alias_method :backward_word, :ed_prev_word
|
2694
2085
|
|
2695
2086
|
private def em_delete_next_word(key)
|
2696
|
-
if
|
2697
|
-
byte_size,
|
2698
|
-
|
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)
|
2699
2091
|
@kill_ring.append(word)
|
2700
|
-
@cursor_max -= width
|
2701
2092
|
end
|
2702
2093
|
end
|
2703
2094
|
alias_method :kill_word, :em_delete_next_word
|
2704
2095
|
|
2705
2096
|
private def ed_delete_prev_word(key)
|
2706
2097
|
if @byte_pointer > 0
|
2707
|
-
byte_size,
|
2708
|
-
|
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)
|
2709
2101
|
@kill_ring.append(word, true)
|
2710
|
-
@byte_pointer -= byte_size
|
2711
|
-
@cursor -= width
|
2712
|
-
@cursor_max -= width
|
2713
2102
|
end
|
2714
2103
|
end
|
2715
2104
|
alias_method :backward_kill_word, :ed_delete_prev_word
|
2716
2105
|
|
2717
2106
|
private def ed_transpose_chars(key)
|
2718
2107
|
if @byte_pointer > 0
|
2719
|
-
if @
|
2720
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
2721
|
-
mbchar = @line.byteslice(@byte_pointer, byte_size)
|
2722
|
-
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2723
|
-
@cursor += width
|
2108
|
+
if @byte_pointer < current_line.bytesize
|
2109
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2724
2110
|
@byte_pointer += byte_size
|
2725
2111
|
end
|
2726
|
-
back1_byte_size = Reline::Unicode.get_prev_mbchar_size(
|
2112
|
+
back1_byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
|
2727
2113
|
if (@byte_pointer - back1_byte_size) > 0
|
2728
|
-
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)
|
2729
2115
|
back2_pointer = @byte_pointer - back1_byte_size - back2_byte_size
|
2730
|
-
|
2731
|
-
|
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))
|
2732
2118
|
end
|
2733
2119
|
end
|
2734
2120
|
end
|
2735
2121
|
alias_method :transpose_chars, :ed_transpose_chars
|
2736
2122
|
|
2737
2123
|
private def ed_transpose_words(key)
|
2738
|
-
left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(
|
2739
|
-
before =
|
2740
|
-
left_word =
|
2741
|
-
middle =
|
2742
|
-
right_word =
|
2743
|
-
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)
|
2744
2130
|
return if left_word.empty? or right_word.empty?
|
2745
|
-
@line = before + right_word + middle + left_word + after
|
2746
2131
|
from_head_to_left_word = before + right_word + middle + left_word
|
2747
|
-
|
2748
|
-
@cursor = calculate_width(from_head_to_left_word)
|
2132
|
+
set_current_line(from_head_to_left_word + after, from_head_to_left_word.bytesize)
|
2749
2133
|
end
|
2750
2134
|
alias_method :transpose_words, :ed_transpose_words
|
2751
2135
|
|
2752
2136
|
private def em_capitol_case(key)
|
2753
|
-
if
|
2754
|
-
byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(
|
2755
|
-
before =
|
2756
|
-
after =
|
2757
|
-
|
2758
|
-
@byte_pointer += new_str.bytesize
|
2759
|
-
@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)
|
2760
2142
|
end
|
2761
2143
|
end
|
2762
2144
|
alias_method :capitalize_word, :em_capitol_case
|
2763
2145
|
|
2764
2146
|
private def em_lower_case(key)
|
2765
|
-
if
|
2766
|
-
byte_size, = Reline::Unicode.em_forward_word(
|
2767
|
-
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|
|
2768
2150
|
mbchar =~ /[A-Z]/ ? mbchar.downcase : mbchar
|
2769
2151
|
}.join
|
2770
|
-
rest =
|
2771
|
-
|
2772
|
-
|
2773
|
-
@cursor = calculate_width(@line)
|
2774
|
-
@cursor_max = @cursor + calculate_width(rest)
|
2775
|
-
@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)
|
2776
2155
|
end
|
2777
2156
|
end
|
2778
2157
|
alias_method :downcase_word, :em_lower_case
|
2779
2158
|
|
2780
2159
|
private def em_upper_case(key)
|
2781
|
-
if
|
2782
|
-
byte_size, = Reline::Unicode.em_forward_word(
|
2783
|
-
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|
|
2784
2163
|
mbchar =~ /[a-z]/ ? mbchar.upcase : mbchar
|
2785
2164
|
}.join
|
2786
|
-
rest =
|
2787
|
-
|
2788
|
-
|
2789
|
-
@cursor = calculate_width(@line)
|
2790
|
-
@cursor_max = @cursor + calculate_width(rest)
|
2791
|
-
@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)
|
2792
2168
|
end
|
2793
2169
|
end
|
2794
2170
|
alias_method :upcase_word, :em_upper_case
|
2795
2171
|
|
2796
2172
|
private def em_kill_region(key)
|
2797
2173
|
if @byte_pointer > 0
|
2798
|
-
byte_size,
|
2799
|
-
|
2800
|
-
@byte_pointer
|
2801
|
-
@cursor -= width
|
2802
|
-
@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)
|
2803
2177
|
@kill_ring.append(deleted, true)
|
2804
2178
|
end
|
2805
2179
|
end
|
@@ -2827,10 +2201,9 @@ class Reline::LineEditor
|
|
2827
2201
|
alias_method :vi_movement_mode, :vi_command_mode
|
2828
2202
|
|
2829
2203
|
private def vi_next_word(key, arg: 1)
|
2830
|
-
if
|
2831
|
-
byte_size,
|
2204
|
+
if current_line.bytesize > @byte_pointer
|
2205
|
+
byte_size, _ = Reline::Unicode.vi_forward_word(current_line, @byte_pointer, @drop_terminate_spaces)
|
2832
2206
|
@byte_pointer += byte_size
|
2833
|
-
@cursor += width
|
2834
2207
|
end
|
2835
2208
|
arg -= 1
|
2836
2209
|
vi_next_word(key, arg: arg) if arg > 0
|
@@ -2838,38 +2211,32 @@ class Reline::LineEditor
|
|
2838
2211
|
|
2839
2212
|
private def vi_prev_word(key, arg: 1)
|
2840
2213
|
if @byte_pointer > 0
|
2841
|
-
byte_size,
|
2214
|
+
byte_size, _ = Reline::Unicode.vi_backward_word(current_line, @byte_pointer)
|
2842
2215
|
@byte_pointer -= byte_size
|
2843
|
-
@cursor -= width
|
2844
2216
|
end
|
2845
2217
|
arg -= 1
|
2846
2218
|
vi_prev_word(key, arg: arg) if arg > 0
|
2847
2219
|
end
|
2848
2220
|
|
2849
2221
|
private def vi_end_word(key, arg: 1, inclusive: false)
|
2850
|
-
if
|
2851
|
-
byte_size,
|
2222
|
+
if current_line.bytesize > @byte_pointer
|
2223
|
+
byte_size, _ = Reline::Unicode.vi_forward_end_word(current_line, @byte_pointer)
|
2852
2224
|
@byte_pointer += byte_size
|
2853
|
-
@cursor += width
|
2854
2225
|
end
|
2855
2226
|
arg -= 1
|
2856
2227
|
if inclusive and arg.zero?
|
2857
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
2228
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2858
2229
|
if byte_size > 0
|
2859
|
-
c = @line.byteslice(@byte_pointer, byte_size)
|
2860
|
-
width = Reline::Unicode.get_mbchar_width(c)
|
2861
2230
|
@byte_pointer += byte_size
|
2862
|
-
@cursor += width
|
2863
2231
|
end
|
2864
2232
|
end
|
2865
2233
|
vi_end_word(key, arg: arg) if arg > 0
|
2866
2234
|
end
|
2867
2235
|
|
2868
2236
|
private def vi_next_big_word(key, arg: 1)
|
2869
|
-
if
|
2870
|
-
byte_size,
|
2237
|
+
if current_line.bytesize > @byte_pointer
|
2238
|
+
byte_size, _ = Reline::Unicode.vi_big_forward_word(current_line, @byte_pointer)
|
2871
2239
|
@byte_pointer += byte_size
|
2872
|
-
@cursor += width
|
2873
2240
|
end
|
2874
2241
|
arg -= 1
|
2875
2242
|
vi_next_big_word(key, arg: arg) if arg > 0
|
@@ -2877,50 +2244,39 @@ class Reline::LineEditor
|
|
2877
2244
|
|
2878
2245
|
private def vi_prev_big_word(key, arg: 1)
|
2879
2246
|
if @byte_pointer > 0
|
2880
|
-
byte_size,
|
2247
|
+
byte_size, _ = Reline::Unicode.vi_big_backward_word(current_line, @byte_pointer)
|
2881
2248
|
@byte_pointer -= byte_size
|
2882
|
-
@cursor -= width
|
2883
2249
|
end
|
2884
2250
|
arg -= 1
|
2885
2251
|
vi_prev_big_word(key, arg: arg) if arg > 0
|
2886
2252
|
end
|
2887
2253
|
|
2888
2254
|
private def vi_end_big_word(key, arg: 1, inclusive: false)
|
2889
|
-
if
|
2890
|
-
byte_size,
|
2255
|
+
if current_line.bytesize > @byte_pointer
|
2256
|
+
byte_size, _ = Reline::Unicode.vi_big_forward_end_word(current_line, @byte_pointer)
|
2891
2257
|
@byte_pointer += byte_size
|
2892
|
-
@cursor += width
|
2893
2258
|
end
|
2894
2259
|
arg -= 1
|
2895
2260
|
if inclusive and arg.zero?
|
2896
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
2261
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2897
2262
|
if byte_size > 0
|
2898
|
-
c = @line.byteslice(@byte_pointer, byte_size)
|
2899
|
-
width = Reline::Unicode.get_mbchar_width(c)
|
2900
2263
|
@byte_pointer += byte_size
|
2901
|
-
@cursor += width
|
2902
2264
|
end
|
2903
2265
|
end
|
2904
2266
|
vi_end_big_word(key, arg: arg) if arg > 0
|
2905
2267
|
end
|
2906
2268
|
|
2907
2269
|
private def vi_delete_prev_char(key)
|
2908
|
-
if @is_multiline and @
|
2909
|
-
@buffer_of_lines[@line_index] = @line
|
2910
|
-
@cursor = calculate_width(@buffer_of_lines[@line_index - 1])
|
2270
|
+
if @is_multiline and @byte_pointer == 0 and @line_index > 0
|
2911
2271
|
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
|
2912
2272
|
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
|
2913
2273
|
@line_index -= 1
|
2914
|
-
|
2915
|
-
|
2916
|
-
|
2917
|
-
elsif @cursor > 0
|
2918
|
-
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)
|
2919
2277
|
@byte_pointer -= byte_size
|
2920
|
-
|
2921
|
-
|
2922
|
-
@cursor -= width
|
2923
|
-
@cursor_max -= width
|
2278
|
+
line, _ = byteslice!(current_line, @byte_pointer, byte_size)
|
2279
|
+
set_current_line(line)
|
2924
2280
|
end
|
2925
2281
|
end
|
2926
2282
|
|
@@ -2937,14 +2293,12 @@ class Reline::LineEditor
|
|
2937
2293
|
private def ed_delete_prev_char(key, arg: 1)
|
2938
2294
|
deleted = ''
|
2939
2295
|
arg.times do
|
2940
|
-
if @
|
2941
|
-
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)
|
2942
2298
|
@byte_pointer -= byte_size
|
2943
|
-
|
2299
|
+
line, mbchar = byteslice!(current_line, @byte_pointer, byte_size)
|
2300
|
+
set_current_line(line)
|
2944
2301
|
deleted.prepend(mbchar)
|
2945
|
-
width = Reline::Unicode.get_mbchar_width(mbchar)
|
2946
|
-
@cursor -= width
|
2947
|
-
@cursor_max -= width
|
2948
2302
|
end
|
2949
2303
|
end
|
2950
2304
|
copy_for_vi(deleted)
|
@@ -2952,20 +2306,18 @@ class Reline::LineEditor
|
|
2952
2306
|
|
2953
2307
|
private def vi_zero(key)
|
2954
2308
|
@byte_pointer = 0
|
2955
|
-
@cursor = 0
|
2956
2309
|
end
|
2957
2310
|
|
2958
2311
|
private def vi_change_meta(key, arg: 1)
|
2959
2312
|
@drop_terminate_spaces = true
|
2960
|
-
@waiting_operator_proc = proc { |
|
2313
|
+
@waiting_operator_proc = proc { |byte_pointer_diff|
|
2961
2314
|
if byte_pointer_diff > 0
|
2962
|
-
|
2315
|
+
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
2963
2316
|
elsif byte_pointer_diff < 0
|
2964
|
-
|
2317
|
+
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2965
2318
|
end
|
2319
|
+
set_current_line(line)
|
2966
2320
|
copy_for_vi(cut)
|
2967
|
-
@cursor += cursor_diff if cursor_diff < 0
|
2968
|
-
@cursor_max -= cursor_diff.abs
|
2969
2321
|
@byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
|
2970
2322
|
@config.editing_mode = :vi_insert
|
2971
2323
|
@drop_terminate_spaces = false
|
@@ -2974,26 +2326,24 @@ class Reline::LineEditor
|
|
2974
2326
|
end
|
2975
2327
|
|
2976
2328
|
private def vi_delete_meta(key, arg: 1)
|
2977
|
-
@waiting_operator_proc = proc { |
|
2329
|
+
@waiting_operator_proc = proc { |byte_pointer_diff|
|
2978
2330
|
if byte_pointer_diff > 0
|
2979
|
-
|
2331
|
+
line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
|
2980
2332
|
elsif byte_pointer_diff < 0
|
2981
|
-
|
2333
|
+
line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2982
2334
|
end
|
2983
2335
|
copy_for_vi(cut)
|
2984
|
-
|
2985
|
-
@cursor_max -= cursor_diff.abs
|
2986
|
-
@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))
|
2987
2337
|
}
|
2988
2338
|
@waiting_operator_vi_arg = arg
|
2989
2339
|
end
|
2990
2340
|
|
2991
2341
|
private def vi_yank(key, arg: 1)
|
2992
|
-
@waiting_operator_proc = proc { |
|
2342
|
+
@waiting_operator_proc = proc { |byte_pointer_diff|
|
2993
2343
|
if byte_pointer_diff > 0
|
2994
|
-
cut =
|
2344
|
+
cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
|
2995
2345
|
elsif byte_pointer_diff < 0
|
2996
|
-
cut =
|
2346
|
+
cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
|
2997
2347
|
end
|
2998
2348
|
copy_for_vi(cut)
|
2999
2349
|
}
|
@@ -3001,12 +2351,8 @@ class Reline::LineEditor
|
|
3001
2351
|
end
|
3002
2352
|
|
3003
2353
|
private def vi_list_or_eof(key)
|
3004
|
-
if (not @is_multiline and
|
3005
|
-
|
3006
|
-
if @buffer_of_lines.size > 1
|
3007
|
-
scroll_down(@highest_in_all - @first_line_started_from)
|
3008
|
-
end
|
3009
|
-
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)
|
3010
2356
|
@eof = true
|
3011
2357
|
finish
|
3012
2358
|
else
|
@@ -3017,18 +2363,15 @@ class Reline::LineEditor
|
|
3017
2363
|
alias_method :vi_eof_maybe, :vi_list_or_eof
|
3018
2364
|
|
3019
2365
|
private def ed_delete_next_char(key, arg: 1)
|
3020
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
3021
|
-
unless
|
3022
|
-
|
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)
|
3023
2369
|
copy_for_vi(mbchar)
|
3024
|
-
|
3025
|
-
|
3026
|
-
|
3027
|
-
|
3028
|
-
|
3029
|
-
width = Reline::Unicode.get_mbchar_width(mbchar)
|
3030
|
-
@byte_pointer -= byte_size
|
3031
|
-
@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)
|
3032
2375
|
end
|
3033
2376
|
end
|
3034
2377
|
arg -= 1
|
@@ -3041,20 +2384,14 @@ class Reline::LineEditor
|
|
3041
2384
|
end
|
3042
2385
|
if @history_pointer.nil?
|
3043
2386
|
@history_pointer = 0
|
3044
|
-
@line_backup_in_history =
|
3045
|
-
|
3046
|
-
@cursor_max = calculate_width(@line)
|
3047
|
-
@cursor = 0
|
3048
|
-
@byte_pointer = 0
|
2387
|
+
@line_backup_in_history = current_line
|
2388
|
+
set_current_line(Reline::HISTORY[@history_pointer], 0)
|
3049
2389
|
elsif @history_pointer.zero?
|
3050
2390
|
return
|
3051
2391
|
else
|
3052
|
-
Reline::HISTORY[@history_pointer] =
|
2392
|
+
Reline::HISTORY[@history_pointer] = current_line
|
3053
2393
|
@history_pointer = 0
|
3054
|
-
|
3055
|
-
@cursor_max = calculate_width(@line)
|
3056
|
-
@cursor = 0
|
3057
|
-
@byte_pointer = 0
|
2394
|
+
set_current_line(Reline::HISTORY[@history_pointer], 0)
|
3058
2395
|
end
|
3059
2396
|
end
|
3060
2397
|
|
@@ -3063,7 +2400,7 @@ class Reline::LineEditor
|
|
3063
2400
|
if @is_multiline
|
3064
2401
|
fp.write whole_lines.join("\n")
|
3065
2402
|
else
|
3066
|
-
fp.write
|
2403
|
+
fp.write current_line
|
3067
2404
|
end
|
3068
2405
|
fp.path
|
3069
2406
|
}
|
@@ -3072,21 +2409,16 @@ class Reline::LineEditor
|
|
3072
2409
|
@buffer_of_lines = File.read(path).split("\n")
|
3073
2410
|
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
3074
2411
|
@line_index = 0
|
3075
|
-
@line = @buffer_of_lines[@line_index]
|
3076
|
-
@rerender_all = true
|
3077
2412
|
else
|
3078
|
-
@
|
2413
|
+
@buffer_of_lines = File.read(path).split("\n")
|
3079
2414
|
end
|
3080
2415
|
finish
|
3081
2416
|
end
|
3082
2417
|
|
3083
2418
|
private def vi_paste_prev(key, arg: 1)
|
3084
2419
|
if @vi_clipboard.size > 0
|
3085
|
-
@line = byteinsert(@line, @byte_pointer, @vi_clipboard)
|
3086
|
-
@cursor_max += calculate_width(@vi_clipboard)
|
3087
2420
|
cursor_point = @vi_clipboard.grapheme_clusters[0..-2].join
|
3088
|
-
@
|
3089
|
-
@byte_pointer += cursor_point.bytesize
|
2421
|
+
set_current_line(byteinsert(current_line, @byte_pointer, @vi_clipboard), @byte_pointer + cursor_point.bytesize)
|
3090
2422
|
end
|
3091
2423
|
arg -= 1
|
3092
2424
|
vi_paste_prev(key, arg: arg) if arg > 0
|
@@ -3094,11 +2426,9 @@ class Reline::LineEditor
|
|
3094
2426
|
|
3095
2427
|
private def vi_paste_next(key, arg: 1)
|
3096
2428
|
if @vi_clipboard.size > 0
|
3097
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
3098
|
-
|
3099
|
-
@
|
3100
|
-
@cursor += calculate_width(@vi_clipboard)
|
3101
|
-
@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)
|
3102
2432
|
end
|
3103
2433
|
arg -= 1
|
3104
2434
|
vi_paste_next(key, arg: arg) if arg > 0
|
@@ -3122,12 +2452,13 @@ class Reline::LineEditor
|
|
3122
2452
|
end
|
3123
2453
|
|
3124
2454
|
private def vi_to_column(key, arg: 0)
|
3125
|
-
|
2455
|
+
current_row_width = calculate_width(current_row)
|
2456
|
+
@byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |total, gc|
|
3126
2457
|
# total has [byte_size, cursor]
|
3127
2458
|
mbchar_width = Reline::Unicode.get_mbchar_width(gc)
|
3128
2459
|
if (total.last + mbchar_width) >= arg
|
3129
2460
|
break total
|
3130
|
-
elsif (total.last + mbchar_width) >=
|
2461
|
+
elsif (total.last + mbchar_width) >= current_row_width
|
3131
2462
|
break total
|
3132
2463
|
else
|
3133
2464
|
total = [total.first + gc.bytesize, total.last + mbchar_width]
|
@@ -3139,26 +2470,22 @@ class Reline::LineEditor
|
|
3139
2470
|
private def vi_replace_char(key, arg: 1)
|
3140
2471
|
@waiting_proc = ->(k) {
|
3141
2472
|
if arg == 1
|
3142
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
3143
|
-
before =
|
2473
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
2474
|
+
before = current_line.byteslice(0, @byte_pointer)
|
3144
2475
|
remaining_point = @byte_pointer + byte_size
|
3145
|
-
after =
|
3146
|
-
|
3147
|
-
@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)
|
3148
2478
|
@waiting_proc = nil
|
3149
2479
|
elsif arg > 1
|
3150
2480
|
byte_size = 0
|
3151
2481
|
arg.times do
|
3152
|
-
byte_size += Reline::Unicode.get_next_mbchar_size(
|
2482
|
+
byte_size += Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer + byte_size)
|
3153
2483
|
end
|
3154
|
-
before =
|
2484
|
+
before = current_line.byteslice(0, @byte_pointer)
|
3155
2485
|
remaining_point = @byte_pointer + byte_size
|
3156
|
-
after =
|
2486
|
+
after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
|
3157
2487
|
replaced = k.chr * arg
|
3158
|
-
|
3159
|
-
@byte_pointer += replaced.bytesize
|
3160
|
-
@cursor += calculate_width(replaced)
|
3161
|
-
@cursor_max = calculate_width(@line)
|
2488
|
+
set_current_line(before + replaced + after, @byte_pointer + replaced.bytesize)
|
3162
2489
|
@waiting_proc = nil
|
3163
2490
|
end
|
3164
2491
|
}
|
@@ -3181,7 +2508,7 @@ class Reline::LineEditor
|
|
3181
2508
|
prev_total = nil
|
3182
2509
|
total = nil
|
3183
2510
|
found = false
|
3184
|
-
|
2511
|
+
current_line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
|
3185
2512
|
# total has [byte_size, cursor]
|
3186
2513
|
unless total
|
3187
2514
|
# skip cursor point
|
@@ -3201,21 +2528,16 @@ class Reline::LineEditor
|
|
3201
2528
|
end
|
3202
2529
|
end
|
3203
2530
|
if not need_prev_char and found and total
|
3204
|
-
byte_size,
|
2531
|
+
byte_size, _ = total
|
3205
2532
|
@byte_pointer += byte_size
|
3206
|
-
@cursor += width
|
3207
2533
|
elsif need_prev_char and found and prev_total
|
3208
|
-
byte_size,
|
2534
|
+
byte_size, _ = prev_total
|
3209
2535
|
@byte_pointer += byte_size
|
3210
|
-
@cursor += width
|
3211
2536
|
end
|
3212
2537
|
if inclusive
|
3213
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(
|
2538
|
+
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
3214
2539
|
if byte_size > 0
|
3215
|
-
c = @line.byteslice(@byte_pointer, byte_size)
|
3216
|
-
width = Reline::Unicode.get_mbchar_width(c)
|
3217
2540
|
@byte_pointer += byte_size
|
3218
|
-
@cursor += width
|
3219
2541
|
end
|
3220
2542
|
end
|
3221
2543
|
@waiting_proc = nil
|
@@ -3238,7 +2560,7 @@ class Reline::LineEditor
|
|
3238
2560
|
prev_total = nil
|
3239
2561
|
total = nil
|
3240
2562
|
found = false
|
3241
|
-
|
2563
|
+
current_line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar|
|
3242
2564
|
# total has [byte_size, cursor]
|
3243
2565
|
unless total
|
3244
2566
|
# skip cursor point
|
@@ -3258,26 +2580,19 @@ class Reline::LineEditor
|
|
3258
2580
|
end
|
3259
2581
|
end
|
3260
2582
|
if not need_next_char and found and total
|
3261
|
-
byte_size,
|
2583
|
+
byte_size, _ = total
|
3262
2584
|
@byte_pointer -= byte_size
|
3263
|
-
@cursor -= width
|
3264
2585
|
elsif need_next_char and found and prev_total
|
3265
|
-
byte_size,
|
2586
|
+
byte_size, _ = prev_total
|
3266
2587
|
@byte_pointer -= byte_size
|
3267
|
-
@cursor -= width
|
3268
2588
|
end
|
3269
2589
|
@waiting_proc = nil
|
3270
2590
|
end
|
3271
2591
|
|
3272
2592
|
private def vi_join_lines(key, arg: 1)
|
3273
2593
|
if @is_multiline and @buffer_of_lines.size > @line_index + 1
|
3274
|
-
|
3275
|
-
|
3276
|
-
@line += ' ' + @buffer_of_lines.delete_at(@line_index + 1).lstrip
|
3277
|
-
@cursor_max = calculate_width(@line)
|
3278
|
-
@buffer_of_lines[@line_index] = @line
|
3279
|
-
@rerender_all = true
|
3280
|
-
@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)
|
3281
2596
|
end
|
3282
2597
|
arg -= 1
|
3283
2598
|
vi_join_lines(key, arg: arg) if arg > 0
|
@@ -3291,10 +2606,7 @@ class Reline::LineEditor
|
|
3291
2606
|
private def em_exchange_mark(key)
|
3292
2607
|
return unless @mark_pointer
|
3293
2608
|
new_pointer = [@byte_pointer, @line_index]
|
3294
|
-
@previous_line_index = @line_index
|
3295
2609
|
@byte_pointer, @line_index = @mark_pointer
|
3296
|
-
@cursor = calculate_width(@line.byteslice(0, @byte_pointer))
|
3297
|
-
@cursor_max = calculate_width(@line)
|
3298
2610
|
@mark_pointer = new_pointer
|
3299
2611
|
end
|
3300
2612
|
alias_method :exchange_point_and_mark, :em_exchange_mark
|