reline 0.5.3 → 0.5.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77e916d771c2f7219d8cba4be2e3b5e6102dddcb505b342375b8717e069caab1
4
- data.tar.gz: ec4262c712ed77b4807255d12887542b37e74cf0e1ccf1dfef78d803d886ba17
3
+ metadata.gz: 45922535b3972631020c6b33bc6b88fd400062fb2c0820ab95ab991704c1fc42
4
+ data.tar.gz: 53f36ad5e7e196ba34a22990c32b38556653b7384bd99108a791d1b4c7cd3b36
5
5
  SHA512:
6
- metadata.gz: b0b88eb00ce703b01f691c2fc780a7f9ff43fefdcc9d42d22122bba742ddc03b20db19ecca2c21082081f66d4993f70a3a4cb53ea50ed5a0255728635360c45c
7
- data.tar.gz: eb4b51fb15f94e2c349fe4cf19c2d6426f7fdf0800320b89a14d66e6f18ea72f327d7792a8edb6d6034df708bb7c25fbffb625fe7cc03271efdb6662d9c90deb
6
+ metadata.gz: eb1b50add8dc60baeefd1fecce83abbaf0e134c16c30ca7fd268efe46d364638280bd2a16100e54be6dbf691bc8a9d4220c53210233a06a0278361c07bd5a56f
7
+ data.tar.gz: 5ed4f57373cd6e9329de58b9361037e4f8e510020c0ba59970de5733a8c8f4b5c004b871d8e21f013ee065daed9b55f433142529b5e4039276a0f0adbc00c4d9
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 = []
@@ -190,9 +188,7 @@ class Reline::Config
190
188
  end
191
189
  end
192
190
  end
193
- conditions = [@skip_section, @if_stack]
194
- @skip_section = nil
195
- @if_stack = []
191
+ if_stack = []
196
192
 
197
193
  lines.each_with_index do |line, no|
198
194
  next if line.match(/\A\s*#/)
@@ -201,11 +197,11 @@ class Reline::Config
201
197
 
202
198
  line = line.chomp.lstrip
203
199
  if line.start_with?('$')
204
- handle_directive(line[1..-1], file, no)
200
+ handle_directive(line[1..-1], file, no, if_stack)
205
201
  next
206
202
  end
207
203
 
208
- next if @skip_section
204
+ next if if_stack.any? { |_no, skip| skip }
209
205
 
210
206
  case line
211
207
  when /^set +([^ ]+) +([^ ]+)/i
@@ -214,43 +210,47 @@ class Reline::Config
214
210
  next
215
211
  when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
216
212
  key, func_name = $1, $2
213
+ func_name = func_name.split.first
217
214
  keystroke, func = bind_key(key, func_name)
218
215
  next unless keystroke
219
216
  @additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func
220
217
  end
221
218
  end
222
- unless @if_stack.empty?
223
- raise InvalidInputrc, "#{file}:#{@if_stack.last[1]}: unclosed if"
219
+ unless if_stack.empty?
220
+ raise InvalidInputrc, "#{file}:#{if_stack.last[0]}: unclosed if"
224
221
  end
225
- ensure
226
- @skip_section, @if_stack = conditions
227
222
  end
228
223
 
229
- def handle_directive(directive, file, no)
224
+ def handle_directive(directive, file, no, if_stack)
230
225
  directive, args = directive.split(' ')
231
226
  case directive
232
227
  when 'if'
233
228
  condition = false
234
229
  case args
235
- when 'mode'
230
+ when /^mode=(vi|emacs)$/i
231
+ mode = $1.downcase
232
+ # NOTE: mode=vi means vi-insert mode
233
+ mode = 'vi_insert' if mode == 'vi'
234
+ if @editing_mode_label == mode.to_sym
235
+ condition = true
236
+ end
236
237
  when 'term'
237
238
  when 'version'
238
239
  else # application name
239
240
  condition = true if args == 'Ruby'
240
241
  condition = true if args == 'Reline'
241
242
  end
242
- @if_stack << [file, no, @skip_section]
243
- @skip_section = !condition
243
+ if_stack << [no, !condition]
244
244
  when 'else'
245
- if @if_stack.empty?
245
+ if if_stack.empty?
246
246
  raise InvalidInputrc, "#{file}:#{no}: unmatched else"
247
247
  end
248
- @skip_section = !@skip_section
248
+ if_stack.last[1] = !if_stack.last[1]
249
249
  when 'endif'
250
- if @if_stack.empty?
250
+ if if_stack.empty?
251
251
  raise InvalidInputrc, "#{file}:#{no}: unmatched endif"
252
252
  end
253
- @skip_section = @if_stack.pop
253
+ if_stack.pop
254
254
  when 'include'
255
255
  read(File.expand_path(args))
256
256
  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
- content = Reline::Unicode.take_range(content, base_x - x, width) unless x == base_x && w == width
418
- Reline::IOGate.move_cursor_column base_x
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 = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
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 = 0
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
 
@@ -145,7 +145,13 @@ class Reline::Unicode
145
145
  lines.last << NON_PRINTING_END
146
146
  when csi
147
147
  lines.last << csi
148
- seq << csi
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
- mbchar_width = get_mbchar_width(gc)
195
- total_width += mbchar_width
196
- break if (start_col + max_width) < total_width
197
- chunk << gc if start_col < total_width
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
- chunk
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)
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.5.3'
2
+ VERSION = '0.5.4'
3
3
  end
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.3
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-23 00:00:00.000000000 Z
11
+ date: 2024-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console