reline 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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.
|