reline 0.5.3 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/reline/ansi.rb +1 -1
- data/lib/reline/config.rb +25 -29
- data/lib/reline/key_actor/base.rb +0 -4
- data/lib/reline/line_editor.rb +11 -16
- data/lib/reline/unicode.rb +58 -6
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +9 -7
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 590a83a7301ffc23869017938e580376b9e3025130ebb0f102fa47d5ac9be28f
|
4
|
+
data.tar.gz: 4652d400dba7e688591f1795e1c2a42b51ce4c9ad8381420c56e68c167034535
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d3272d6b13d84818a895910d2a0201fa1629ea0dfc71037904a9c5f862c277866780df9aad323a5898941c9f2162fa2684892451617b30e7b9ec637ec3c143d
|
7
|
+
data.tar.gz: 67004e4bf5b626ebf7d098750ffa7b198539ae8d344ad65b80f101faef0f0f57504e05cd2cd90a167feaea0f6a78c179abd1d698cecb29c290a7d2dbac3923ae
|
data/lib/reline/ansi.rb
CHANGED
@@ -284,7 +284,7 @@ class Reline::ANSI
|
|
284
284
|
buf = @@output.pread(@@output.pos, 0)
|
285
285
|
row = buf.count("\n")
|
286
286
|
column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
|
287
|
-
rescue Errno::ESPIPE
|
287
|
+
rescue Errno::ESPIPE, IOError
|
288
288
|
# Just returns column 1 for ambiguous width because this I/O is not
|
289
289
|
# tty and can't seek.
|
290
290
|
row = 0
|
data/lib/reline/config.rb
CHANGED
@@ -53,8 +53,6 @@ class Reline::Config
|
|
53
53
|
@additional_key_bindings[:vi_insert] = {}
|
54
54
|
@additional_key_bindings[:vi_command] = {}
|
55
55
|
@oneshot_key_bindings = {}
|
56
|
-
@skip_section = nil
|
57
|
-
@if_stack = nil
|
58
56
|
@editing_mode_label = :emacs
|
59
57
|
@keymap_label = :emacs
|
60
58
|
@keymap_prefix = []
|
@@ -71,17 +69,14 @@ class Reline::Config
|
|
71
69
|
@test_mode = false
|
72
70
|
@autocompletion = false
|
73
71
|
@convert_meta = true if seven_bit_encoding?(Reline::IOGate.encoding)
|
72
|
+
@loaded = false
|
74
73
|
end
|
75
74
|
|
76
75
|
def reset
|
77
76
|
if editing_mode_is?(:vi_command)
|
78
77
|
@editing_mode_label = :vi_insert
|
79
78
|
end
|
80
|
-
@additional_key_bindings.keys.each do |key|
|
81
|
-
@additional_key_bindings[key].clear
|
82
|
-
end
|
83
79
|
@oneshot_key_bindings.clear
|
84
|
-
reset_default_key_bindings
|
85
80
|
end
|
86
81
|
|
87
82
|
def editing_mode
|
@@ -100,6 +95,10 @@ class Reline::Config
|
|
100
95
|
@key_actors[@keymap_label]
|
101
96
|
end
|
102
97
|
|
98
|
+
def loaded?
|
99
|
+
@loaded
|
100
|
+
end
|
101
|
+
|
103
102
|
def inputrc_path
|
104
103
|
case ENV['INPUTRC']
|
105
104
|
when nil, ''
|
@@ -131,6 +130,7 @@ class Reline::Config
|
|
131
130
|
end
|
132
131
|
|
133
132
|
def read(file = nil)
|
133
|
+
@loaded = true
|
134
134
|
file ||= default_inputrc_path
|
135
135
|
begin
|
136
136
|
if file.respond_to?(:readlines)
|
@@ -173,12 +173,6 @@ class Reline::Config
|
|
173
173
|
@key_actors[@keymap_label].default_key_bindings[keystroke] = target
|
174
174
|
end
|
175
175
|
|
176
|
-
def reset_default_key_bindings
|
177
|
-
@key_actors.values.each do |ka|
|
178
|
-
ka.reset_default_key_bindings
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
176
|
def read_lines(lines, file = nil)
|
183
177
|
if not lines.empty? and lines.first.encoding != Reline.encoding_system_needs
|
184
178
|
begin
|
@@ -190,9 +184,7 @@ class Reline::Config
|
|
190
184
|
end
|
191
185
|
end
|
192
186
|
end
|
193
|
-
|
194
|
-
@skip_section = nil
|
195
|
-
@if_stack = []
|
187
|
+
if_stack = []
|
196
188
|
|
197
189
|
lines.each_with_index do |line, no|
|
198
190
|
next if line.match(/\A\s*#/)
|
@@ -201,11 +193,11 @@ class Reline::Config
|
|
201
193
|
|
202
194
|
line = line.chomp.lstrip
|
203
195
|
if line.start_with?('$')
|
204
|
-
handle_directive(line[1..-1], file, no)
|
196
|
+
handle_directive(line[1..-1], file, no, if_stack)
|
205
197
|
next
|
206
198
|
end
|
207
199
|
|
208
|
-
next if
|
200
|
+
next if if_stack.any? { |_no, skip| skip }
|
209
201
|
|
210
202
|
case line
|
211
203
|
when /^set +([^ ]+) +([^ ]+)/i
|
@@ -214,43 +206,47 @@ class Reline::Config
|
|
214
206
|
next
|
215
207
|
when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
|
216
208
|
key, func_name = $1, $2
|
209
|
+
func_name = func_name.split.first
|
217
210
|
keystroke, func = bind_key(key, func_name)
|
218
211
|
next unless keystroke
|
219
212
|
@additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func
|
220
213
|
end
|
221
214
|
end
|
222
|
-
unless
|
223
|
-
raise InvalidInputrc, "#{file}:#{
|
215
|
+
unless if_stack.empty?
|
216
|
+
raise InvalidInputrc, "#{file}:#{if_stack.last[0]}: unclosed if"
|
224
217
|
end
|
225
|
-
ensure
|
226
|
-
@skip_section, @if_stack = conditions
|
227
218
|
end
|
228
219
|
|
229
|
-
def handle_directive(directive, file, no)
|
220
|
+
def handle_directive(directive, file, no, if_stack)
|
230
221
|
directive, args = directive.split(' ')
|
231
222
|
case directive
|
232
223
|
when 'if'
|
233
224
|
condition = false
|
234
225
|
case args
|
235
|
-
when
|
226
|
+
when /^mode=(vi|emacs)$/i
|
227
|
+
mode = $1.downcase
|
228
|
+
# NOTE: mode=vi means vi-insert mode
|
229
|
+
mode = 'vi_insert' if mode == 'vi'
|
230
|
+
if @editing_mode_label == mode.to_sym
|
231
|
+
condition = true
|
232
|
+
end
|
236
233
|
when 'term'
|
237
234
|
when 'version'
|
238
235
|
else # application name
|
239
236
|
condition = true if args == 'Ruby'
|
240
237
|
condition = true if args == 'Reline'
|
241
238
|
end
|
242
|
-
|
243
|
-
@skip_section = !condition
|
239
|
+
if_stack << [no, !condition]
|
244
240
|
when 'else'
|
245
|
-
if
|
241
|
+
if if_stack.empty?
|
246
242
|
raise InvalidInputrc, "#{file}:#{no}: unmatched else"
|
247
243
|
end
|
248
|
-
|
244
|
+
if_stack.last[1] = !if_stack.last[1]
|
249
245
|
when 'endif'
|
250
|
-
if
|
246
|
+
if if_stack.empty?
|
251
247
|
raise InvalidInputrc, "#{file}:#{no}: unmatched endif"
|
252
248
|
end
|
253
|
-
|
249
|
+
if_stack.pop
|
254
250
|
when 'include'
|
255
251
|
read(File.expand_path(args))
|
256
252
|
end
|
data/lib/reline/line_editor.rb
CHANGED
@@ -387,7 +387,7 @@ class Reline::LineEditor
|
|
387
387
|
next cached
|
388
388
|
end
|
389
389
|
*wrapped_prompts, code_line_prompt = split_by_width(prompt, width).first.compact
|
390
|
-
wrapped_lines = split_by_width(line, width, offset: calculate_width(code_line_prompt)).first.compact
|
390
|
+
wrapped_lines = split_by_width(line, width, offset: calculate_width(code_line_prompt, true)).first.compact
|
391
391
|
wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
|
392
392
|
end
|
393
393
|
end
|
@@ -414,8 +414,13 @@ class Reline::LineEditor
|
|
414
414
|
@output.write "#{Reline::IOGate::RESET_COLOR}#{' ' * width}"
|
415
415
|
else
|
416
416
|
x, w, content = new_items[level]
|
417
|
-
|
418
|
-
|
417
|
+
cover_begin = base_x != 0 && new_levels[base_x - 1] == level
|
418
|
+
cover_end = new_levels[base_x + width] == level
|
419
|
+
pos = 0
|
420
|
+
unless x == base_x && w == width
|
421
|
+
content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
|
422
|
+
end
|
423
|
+
Reline::IOGate.move_cursor_column x + pos
|
419
424
|
@output.write "#{Reline::IOGate::RESET_COLOR}#{content}#{Reline::IOGate::RESET_COLOR}"
|
420
425
|
end
|
421
426
|
base_x += width
|
@@ -699,13 +704,6 @@ class Reline::LineEditor
|
|
699
704
|
|
700
705
|
DIALOG_DEFAULT_HEIGHT = 20
|
701
706
|
|
702
|
-
private def padding_space_with_escape_sequences(str, width)
|
703
|
-
padding_width = width - calculate_width(str, true)
|
704
|
-
# padding_width should be only positive value. But macOS and Alacritty returns negative value.
|
705
|
-
padding_width = 0 if padding_width < 0
|
706
|
-
str + (' ' * padding_width)
|
707
|
-
end
|
708
|
-
|
709
707
|
private def dialog_range(dialog, dialog_y)
|
710
708
|
x_range = dialog.column...dialog.column + dialog.width
|
711
709
|
y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
|
@@ -778,7 +776,7 @@ class Reline::LineEditor
|
|
778
776
|
dialog.contents = contents.map.with_index do |item, i|
|
779
777
|
line_sgr = i == pointer ? enhanced_sgr : default_sgr
|
780
778
|
str_width = dialog.width - (scrollbar_pos.nil? ? 0 : @block_elem_width)
|
781
|
-
str =
|
779
|
+
str, = Reline::Unicode.take_mbchar_range(item, 0, str_width, padding: true)
|
782
780
|
colored_content = "#{line_sgr}#{str}"
|
783
781
|
if scrollbar_pos
|
784
782
|
if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height)
|
@@ -1120,6 +1118,7 @@ class Reline::LineEditor
|
|
1120
1118
|
end
|
1121
1119
|
end
|
1122
1120
|
if key.char.nil?
|
1121
|
+
process_insert(force: true)
|
1123
1122
|
if @first_char
|
1124
1123
|
@eof = true
|
1125
1124
|
end
|
@@ -1542,11 +1541,7 @@ class Reline::LineEditor
|
|
1542
1541
|
alias_method :vi_zero, :ed_move_to_beg
|
1543
1542
|
|
1544
1543
|
private def ed_move_to_end(key)
|
1545
|
-
@byte_pointer =
|
1546
|
-
while @byte_pointer < current_line.bytesize
|
1547
|
-
byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
|
1548
|
-
@byte_pointer += byte_size
|
1549
|
-
end
|
1544
|
+
@byte_pointer = current_line.bytesize
|
1550
1545
|
end
|
1551
1546
|
alias_method :end_of_line, :ed_move_to_end
|
1552
1547
|
|
data/lib/reline/unicode.rb
CHANGED
@@ -145,7 +145,13 @@ class Reline::Unicode
|
|
145
145
|
lines.last << NON_PRINTING_END
|
146
146
|
when csi
|
147
147
|
lines.last << csi
|
148
|
-
|
148
|
+
unless in_zero_width
|
149
|
+
if csi == -"\e[m" || csi == -"\e[0m"
|
150
|
+
seq.clear
|
151
|
+
else
|
152
|
+
seq << csi
|
153
|
+
end
|
154
|
+
end
|
149
155
|
when osc
|
150
156
|
lines.last << osc
|
151
157
|
seq << osc
|
@@ -173,32 +179,78 @@ class Reline::Unicode
|
|
173
179
|
|
174
180
|
# Take a chunk of a String cut by width with escape sequences.
|
175
181
|
def self.take_range(str, start_col, max_width)
|
182
|
+
take_mbchar_range(str, start_col, max_width).first
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.take_mbchar_range(str, start_col, width, cover_begin: false, cover_end: false, padding: false)
|
176
186
|
chunk = String.new(encoding: str.encoding)
|
187
|
+
|
188
|
+
end_col = start_col + width
|
177
189
|
total_width = 0
|
178
190
|
rest = str.encode(Encoding::UTF_8)
|
179
191
|
in_zero_width = false
|
192
|
+
chunk_start_col = nil
|
193
|
+
chunk_end_col = nil
|
194
|
+
has_csi = false
|
180
195
|
rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
|
181
196
|
case
|
182
197
|
when non_printing_start
|
183
198
|
in_zero_width = true
|
199
|
+
chunk << NON_PRINTING_START
|
184
200
|
when non_printing_end
|
185
201
|
in_zero_width = false
|
202
|
+
chunk << NON_PRINTING_END
|
186
203
|
when csi
|
204
|
+
has_csi = true
|
187
205
|
chunk << csi
|
188
206
|
when osc
|
189
207
|
chunk << osc
|
190
208
|
when gc
|
191
209
|
if in_zero_width
|
192
210
|
chunk << gc
|
211
|
+
next
|
212
|
+
end
|
213
|
+
|
214
|
+
mbchar_width = get_mbchar_width(gc)
|
215
|
+
prev_width = total_width
|
216
|
+
total_width += mbchar_width
|
217
|
+
|
218
|
+
if (cover_begin || padding ? total_width <= start_col : prev_width < start_col)
|
219
|
+
# Current character haven't reached start_col yet
|
220
|
+
next
|
221
|
+
elsif padding && !cover_begin && prev_width < start_col && start_col < total_width
|
222
|
+
# Add preceding padding. This padding might have background color.
|
223
|
+
chunk << ' '
|
224
|
+
chunk_start_col ||= start_col
|
225
|
+
chunk_end_col = total_width
|
226
|
+
next
|
227
|
+
elsif (cover_end ? prev_width < end_col : total_width <= end_col)
|
228
|
+
# Current character is in the range
|
229
|
+
chunk << gc
|
230
|
+
chunk_start_col ||= prev_width
|
231
|
+
chunk_end_col = total_width
|
232
|
+
break if total_width >= end_col
|
193
233
|
else
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
234
|
+
# Current character exceeds end_col
|
235
|
+
if padding && end_col < total_width
|
236
|
+
# Add succeeding padding. This padding might have background color.
|
237
|
+
chunk << ' '
|
238
|
+
chunk_start_col ||= prev_width
|
239
|
+
chunk_end_col = end_col
|
240
|
+
end
|
241
|
+
break
|
198
242
|
end
|
199
243
|
end
|
200
244
|
end
|
201
|
-
|
245
|
+
chunk_start_col ||= start_col
|
246
|
+
chunk_end_col ||= start_col
|
247
|
+
if padding && chunk_end_col < end_col
|
248
|
+
# Append padding. This padding should not include background color.
|
249
|
+
chunk << "\e[0m" if has_csi
|
250
|
+
chunk << ' ' * (end_col - chunk_end_col)
|
251
|
+
chunk_end_col = end_col
|
252
|
+
end
|
253
|
+
[chunk, chunk_start_col, chunk_end_col - chunk_start_col]
|
202
254
|
end
|
203
255
|
|
204
256
|
def self.get_next_mbchar_size(line, byte_pointer)
|
data/lib/reline/version.rb
CHANGED
data/lib/reline.rb
CHANGED
@@ -225,17 +225,20 @@ module Reline
|
|
225
225
|
journey_data = completion_journey_data
|
226
226
|
return unless journey_data
|
227
227
|
|
228
|
-
target = journey_data.list
|
228
|
+
target = journey_data.list.first
|
229
|
+
completed = journey_data.list[journey_data.pointer]
|
229
230
|
result = journey_data.list.drop(1)
|
230
231
|
pointer = journey_data.pointer - 1
|
231
|
-
return if
|
232
|
+
return if completed.empty? || (result == [completed] && pointer < 0)
|
232
233
|
|
233
234
|
target_width = Reline::Unicode.calculate_width(target)
|
234
|
-
|
235
|
-
if x
|
236
|
-
|
235
|
+
completed_width = Reline::Unicode.calculate_width(completed)
|
236
|
+
if cursor_pos.x <= completed_width - target_width
|
237
|
+
# When target is rendered on the line above cursor position
|
238
|
+
x = screen_width - completed_width
|
237
239
|
y = -1
|
238
240
|
else
|
241
|
+
x = [cursor_pos.x - completed_width, 0].max
|
239
242
|
y = 0
|
240
243
|
end
|
241
244
|
cursor_pos_to_render = Reline::CursorPos.new(x, y)
|
@@ -335,9 +338,8 @@ module Reline
|
|
335
338
|
end
|
336
339
|
end
|
337
340
|
|
338
|
-
unless config.test_mode
|
341
|
+
unless config.test_mode or config.loaded?
|
339
342
|
config.read
|
340
|
-
config.reset_default_key_bindings
|
341
343
|
io_gate.set_default_key_bindings(config)
|
342
344
|
end
|
343
345
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: io-console
|
@@ -76,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
78
|
requirements: []
|
79
|
-
rubygems_version: 3.5.
|
79
|
+
rubygems_version: 3.5.9
|
80
80
|
signing_key:
|
81
81
|
specification_version: 4
|
82
82
|
summary: Alternative GNU Readline or Editline implementation by pure Ruby.
|