reline 0.3.2 → 0.5.9

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.
data/lib/reline.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'io/console'
2
- require 'timeout'
3
2
  require 'forwardable'
4
3
  require 'reline/version'
5
4
  require 'reline/config'
@@ -8,38 +7,29 @@ require 'reline/key_stroke'
8
7
  require 'reline/line_editor'
9
8
  require 'reline/history'
10
9
  require 'reline/terminfo'
10
+ require 'reline/io'
11
+ require 'reline/face'
11
12
  require 'rbconfig'
12
13
 
13
14
  module Reline
15
+ # NOTE: For making compatible with the rb-readline gem
14
16
  FILENAME_COMPLETION_PROC = nil
15
17
  USERNAME_COMPLETION_PROC = nil
16
18
 
17
19
  class ConfigEncodingConversionError < StandardError; end
18
20
 
19
- Key = Struct.new('Key', :char, :combined_char, :with_meta) do
20
- def match?(other)
21
- case other
22
- when Reline::Key
23
- (other.char.nil? or char.nil? or char == other.char) and
24
- (other.combined_char.nil? or combined_char.nil? or combined_char == other.combined_char) and
25
- (other.with_meta.nil? or with_meta.nil? or with_meta == other.with_meta)
26
- when Integer, Symbol
27
- (combined_char and combined_char == other) or
28
- (combined_char.nil? and char and char == other)
29
- else
30
- false
31
- end
21
+ Key = Struct.new(:char, :combined_char, :with_meta) do
22
+ # For dialog_proc `key.match?(dialog.name)`
23
+ def match?(sym)
24
+ combined_char.is_a?(Symbol) && combined_char == sym
32
25
  end
33
- alias_method :==, :match?
34
26
  end
35
27
  CursorPos = Struct.new(:x, :y)
36
28
  DialogRenderInfo = Struct.new(
37
29
  :pos,
38
30
  :contents,
39
- :bg_color,
40
- :pointer_bg_color,
41
- :fg_color,
42
- :pointer_fg_color,
31
+ :face,
32
+ :bg_color, # For the time being, this line should stay here for the compatibility with IRB.
43
33
  :width,
44
34
  :height,
45
35
  :scrollbar,
@@ -76,50 +66,54 @@ module Reline
76
66
 
77
67
  def initialize
78
68
  self.output = STDOUT
69
+ @mutex = Mutex.new
79
70
  @dialog_proc_list = {}
80
71
  yield self
81
72
  @completion_quote_character = nil
82
- @bracketed_paste_finished = false
73
+ end
74
+
75
+ def io_gate
76
+ Reline::IOGate
83
77
  end
84
78
 
85
79
  def encoding
86
- Reline::IOGate.encoding
80
+ io_gate.encoding
87
81
  end
88
82
 
89
83
  def completion_append_character=(val)
90
84
  if val.nil?
91
85
  @completion_append_character = nil
92
86
  elsif val.size == 1
93
- @completion_append_character = val.encode(Reline::IOGate.encoding)
87
+ @completion_append_character = val.encode(encoding)
94
88
  elsif val.size > 1
95
- @completion_append_character = val[0].encode(Reline::IOGate.encoding)
89
+ @completion_append_character = val[0].encode(encoding)
96
90
  else
97
91
  @completion_append_character = nil
98
92
  end
99
93
  end
100
94
 
101
95
  def basic_word_break_characters=(v)
102
- @basic_word_break_characters = v.encode(Reline::IOGate.encoding)
96
+ @basic_word_break_characters = v.encode(encoding)
103
97
  end
104
98
 
105
99
  def completer_word_break_characters=(v)
106
- @completer_word_break_characters = v.encode(Reline::IOGate.encoding)
100
+ @completer_word_break_characters = v.encode(encoding)
107
101
  end
108
102
 
109
103
  def basic_quote_characters=(v)
110
- @basic_quote_characters = v.encode(Reline::IOGate.encoding)
104
+ @basic_quote_characters = v.encode(encoding)
111
105
  end
112
106
 
113
107
  def completer_quote_characters=(v)
114
- @completer_quote_characters = v.encode(Reline::IOGate.encoding)
108
+ @completer_quote_characters = v.encode(encoding)
115
109
  end
116
110
 
117
111
  def filename_quote_characters=(v)
118
- @filename_quote_characters = v.encode(Reline::IOGate.encoding)
112
+ @filename_quote_characters = v.encode(encoding)
119
113
  end
120
114
 
121
115
  def special_prefixes=(v)
122
- @special_prefixes = v.encode(Reline::IOGate.encoding)
116
+ @special_prefixes = v.encode(encoding)
123
117
  end
124
118
 
125
119
  def completion_case_fold=(v)
@@ -165,9 +159,13 @@ module Reline
165
159
 
166
160
  DialogProc = Struct.new(:dialog_proc, :context)
167
161
  def add_dialog_proc(name_sym, p, context = nil)
168
- raise ArgumentError unless p.respond_to?(:call) or p.nil?
169
162
  raise ArgumentError unless name_sym.instance_of?(Symbol)
170
- @dialog_proc_list[name_sym] = DialogProc.new(p, context)
163
+ if p.nil?
164
+ @dialog_proc_list.delete(name_sym)
165
+ else
166
+ raise ArgumentError unless p.respond_to?(:call)
167
+ @dialog_proc_list[name_sym] = DialogProc.new(p, context)
168
+ end
171
169
  end
172
170
 
173
171
  def dialog_proc(name_sym)
@@ -176,20 +174,16 @@ module Reline
176
174
 
177
175
  def input=(val)
178
176
  raise TypeError unless val.respond_to?(:getc) or val.nil?
179
- if val.respond_to?(:getc)
180
- if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
181
- Reline::ANSI.input = val
182
- elsif Reline::IOGate == Reline::GeneralIO
183
- Reline::GeneralIO.input = val
184
- end
177
+ if val.respond_to?(:getc) && io_gate.respond_to?(:input=)
178
+ io_gate.input = val
185
179
  end
186
180
  end
187
181
 
188
182
  def output=(val)
189
183
  raise TypeError unless val.respond_to?(:write) or val.nil?
190
184
  @output = val
191
- if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
192
- Reline::ANSI.output = val
185
+ if io_gate.respond_to?(:output=)
186
+ io_gate.output = val
193
187
  end
194
188
  end
195
189
 
@@ -212,37 +206,30 @@ module Reline
212
206
  end
213
207
 
214
208
  def get_screen_size
215
- Reline::IOGate.get_screen_size
209
+ io_gate.get_screen_size
216
210
  end
217
211
 
218
212
  Reline::DEFAULT_DIALOG_PROC_AUTOCOMPLETE = ->() {
219
213
  # autocomplete
220
- return nil unless config.autocompletion
221
- if just_cursor_moving and completion_journey_data.nil?
222
- # Auto complete starts only when edited
223
- return nil
224
- end
225
- pre, target, post = retrieve_completion_block(true)
226
- if target.nil? or target.empty? or (completion_journey_data&.pointer == -1 and target.size <= 3)
227
- return nil
228
- end
229
- if completion_journey_data and completion_journey_data.list
230
- result = completion_journey_data.list.dup
231
- result.shift
232
- pointer = completion_journey_data.pointer - 1
233
- else
234
- result = call_completion_proc_with_checking_args(pre, target, post)
235
- pointer = nil
236
- end
237
- if result and result.size == 1 and result[0] == target and pointer != 0
238
- result = nil
239
- end
214
+ return unless config.autocompletion
215
+
216
+ journey_data = completion_journey_data
217
+ return unless journey_data
218
+
219
+ target = journey_data.list.first
220
+ completed = journey_data.list[journey_data.pointer]
221
+ result = journey_data.list.drop(1)
222
+ pointer = journey_data.pointer - 1
223
+ return if completed.empty? || (result == [completed] && pointer < 0)
224
+
240
225
  target_width = Reline::Unicode.calculate_width(target)
241
- x = cursor_pos.x - target_width
242
- if x < 0
243
- x = screen_width + x
226
+ completed_width = Reline::Unicode.calculate_width(completed)
227
+ if cursor_pos.x <= completed_width - target_width
228
+ # When target is rendered on the line above cursor position
229
+ x = screen_width - completed_width
244
230
  y = -1
245
231
  else
232
+ x = [cursor_pos.x - completed_width, 0].max
246
233
  y = 0
247
234
  end
248
235
  cursor_pos_to_render = Reline::CursorPos.new(x, y)
@@ -255,47 +242,58 @@ module Reline
255
242
  pos: cursor_pos_to_render,
256
243
  contents: result,
257
244
  scrollbar: true,
258
- height: 15,
259
- bg_color: 46,
260
- pointer_bg_color: 45,
261
- fg_color: 37,
262
- pointer_fg_color: 37
245
+ height: [15, preferred_dialog_height].min,
246
+ face: :completion_dialog
263
247
  )
264
248
  }
265
249
  Reline::DEFAULT_DIALOG_CONTEXT = Array.new
266
250
 
267
251
  def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
268
- unless confirm_multiline_termination
269
- raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
270
- end
271
- inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
252
+ @mutex.synchronize do
253
+ unless confirm_multiline_termination
254
+ raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
255
+ end
272
256
 
273
- whole_buffer = line_editor.whole_buffer.dup
274
- whole_buffer.taint if RUBY_VERSION < '2.7'
275
- if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
276
- Reline::HISTORY << whole_buffer
277
- end
257
+ io_gate.with_raw_input do
258
+ inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
259
+ end
260
+
261
+ whole_buffer = line_editor.whole_buffer.dup
262
+ whole_buffer.taint if RUBY_VERSION < '2.7'
263
+ if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
264
+ Reline::HISTORY << whole_buffer
265
+ end
278
266
 
279
- line_editor.reset_line if line_editor.whole_buffer.nil?
280
- whole_buffer
267
+ if line_editor.eof?
268
+ line_editor.reset_line
269
+ # Return nil if the input is aborted by C-d.
270
+ nil
271
+ else
272
+ whole_buffer
273
+ end
274
+ end
281
275
  end
282
276
 
283
277
  def readline(prompt = '', add_hist = false)
284
- inner_readline(prompt, add_hist, false)
278
+ @mutex.synchronize do
279
+ io_gate.with_raw_input do
280
+ inner_readline(prompt, add_hist, false)
281
+ end
285
282
 
286
- line = line_editor.line.dup
287
- line.taint if RUBY_VERSION < '2.7'
288
- if add_hist and line and line.chomp("\n").size > 0
289
- Reline::HISTORY << line.chomp("\n")
290
- end
283
+ line = line_editor.line.dup
284
+ line.taint if RUBY_VERSION < '2.7'
285
+ if add_hist and line and line.chomp("\n").size > 0
286
+ Reline::HISTORY << line.chomp("\n")
287
+ end
291
288
 
292
- line_editor.reset_line if line_editor.line.nil?
293
- line
289
+ line_editor.reset_line if line_editor.line.nil?
290
+ line
291
+ end
294
292
  end
295
293
 
296
294
  private def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
297
295
  if ENV['RELINE_STDERR_TTY']
298
- if Reline::IOGate.win?
296
+ if io_gate.win?
299
297
  $stderr = File.open(ENV['RELINE_STDERR_TTY'], 'a')
300
298
  else
301
299
  $stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
@@ -303,10 +301,14 @@ module Reline
303
301
  $stderr.sync = true
304
302
  $stderr.puts "Reline is used by #{Process.pid}"
305
303
  end
306
- otio = Reline::IOGate.prep
304
+ unless config.test_mode or config.loaded?
305
+ config.read
306
+ io_gate.set_default_key_bindings(config)
307
+ end
308
+ otio = io_gate.prep
307
309
 
308
310
  may_req_ambiguous_char_width
309
- line_editor.reset(prompt, encoding: Reline::IOGate.encoding)
311
+ line_editor.reset(prompt, encoding: encoding)
310
312
  if multiline
311
313
  line_editor.multiline_on
312
314
  if block_given?
@@ -322,157 +324,81 @@ module Reline
322
324
  line_editor.prompt_proc = prompt_proc
323
325
  line_editor.auto_indent_proc = auto_indent_proc
324
326
  line_editor.dig_perfect_match_proc = dig_perfect_match_proc
325
- line_editor.pre_input_hook = pre_input_hook
326
- @dialog_proc_list.each_pair do |name_sym, d|
327
- line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
328
- end
329
-
330
- unless config.test_mode
331
- config.read
332
- config.reset_default_key_bindings
333
- Reline::IOGate.set_default_key_bindings(config)
327
+ pre_input_hook&.call
328
+ unless Reline::IOGate.dumb?
329
+ @dialog_proc_list.each_pair do |name_sym, d|
330
+ line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
331
+ end
334
332
  end
335
333
 
334
+ line_editor.print_nomultiline_prompt(prompt)
335
+ line_editor.update_dialogs
336
336
  line_editor.rerender
337
337
 
338
338
  begin
339
339
  line_editor.set_signal_handlers
340
- prev_pasting_state = false
341
340
  loop do
342
- prev_pasting_state = Reline::IOGate.in_pasting?
343
341
  read_io(config.keyseq_timeout) { |inputs|
344
- line_editor.set_pasting_state(Reline::IOGate.in_pasting?)
345
- inputs.each { |c|
346
- line_editor.input_key(c)
347
- line_editor.rerender
348
- }
349
- if @bracketed_paste_finished
350
- line_editor.rerender_all
351
- @bracketed_paste_finished = false
342
+ line_editor.set_pasting_state(io_gate.in_pasting?)
343
+ inputs.each do |key|
344
+ if key.char == :bracketed_paste_start
345
+ text = io_gate.read_bracketed_paste
346
+ line_editor.insert_pasted_text(text)
347
+ line_editor.scroll_into_view
348
+ else
349
+ line_editor.update(key)
350
+ end
352
351
  end
353
352
  }
354
- if prev_pasting_state == true and not Reline::IOGate.in_pasting? and not line_editor.finished?
355
- line_editor.set_pasting_state(false)
356
- prev_pasting_state = false
357
- line_editor.rerender_all
353
+ if line_editor.finished?
354
+ line_editor.render_finished
355
+ break
356
+ else
357
+ line_editor.set_pasting_state(io_gate.in_pasting?)
358
+ line_editor.rerender
358
359
  end
359
- break if line_editor.finished?
360
360
  end
361
- Reline::IOGate.move_cursor_column(0)
361
+ io_gate.move_cursor_column(0)
362
362
  rescue Errno::EIO
363
363
  # Maybe the I/O has been closed.
364
- rescue StandardError => e
364
+ ensure
365
365
  line_editor.finalize
366
- Reline::IOGate.deprep(otio)
367
- raise e
368
- rescue Exception
369
- # Including Interrupt
370
- line_editor.finalize
371
- Reline::IOGate.deprep(otio)
372
- raise
366
+ io_gate.deprep(otio)
373
367
  end
374
-
375
- line_editor.finalize
376
- Reline::IOGate.deprep(otio)
377
368
  end
378
369
 
379
- # GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
380
- # is followed by a character, and times out and treats it as a standalone
381
- # ESC if the second character does not arrive. If the second character
382
- # comes before timed out, it is treated as a modifier key with the
383
- # meta-property of meta-key, so that it can be distinguished from
384
- # multibyte characters with the 8th bit turned on.
385
- #
386
- # GNU Readline will wait for the 2nd character with "keyseq-timeout"
387
- # milli-seconds but wait forever after 3rd characters.
370
+ # GNU Readline watis for "keyseq-timeout" milliseconds when the input is
371
+ # ambiguous whether it is matching or matched.
372
+ # If the next character does not arrive within the specified timeout, input
373
+ # is considered as matched.
374
+ # `ESC` is ambiguous because it can be a standalone ESC (matched) or part of
375
+ # `ESC char` or part of CSI sequence (matching).
388
376
  private def read_io(keyseq_timeout, &block)
389
377
  buffer = []
378
+ status = KeyStroke::MATCHING
390
379
  loop do
391
- c = Reline::IOGate.getc
392
- if c == -1
393
- result = :unmatched
394
- @bracketed_paste_finished = true
395
- else
396
- buffer << c
397
- result = key_stroke.match_status(buffer)
398
- end
399
- case result
400
- when :matched
401
- expanded = key_stroke.expand(buffer).map{ |expanded_c|
402
- Reline::Key.new(expanded_c, expanded_c, false)
403
- }
404
- block.(expanded)
405
- break
406
- when :matching
407
- if buffer.size == 1
408
- case read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
409
- when :break then break
410
- when :next then next
411
- end
412
- end
413
- when :unmatched
414
- if buffer.size == 1 and c == "\e".ord
415
- read_escaped_key(keyseq_timeout, c, block)
380
+ timeout = status == KeyStroke::MATCHING_MATCHED ? keyseq_timeout.fdiv(1000) : Float::INFINITY
381
+ c = io_gate.getc(timeout)
382
+ if c.nil? || c == -1
383
+ if status == KeyStroke::MATCHING_MATCHED
384
+ status = KeyStroke::MATCHED
385
+ elsif buffer.empty?
386
+ # io_gate is closed and reached EOF
387
+ block.call([Key.new(nil, nil, false)])
388
+ return
416
389
  else
417
- expanded = buffer.map{ |expanded_c|
418
- Reline::Key.new(expanded_c, expanded_c, false)
419
- }
420
- block.(expanded)
390
+ status = KeyStroke::UNMATCHED
421
391
  end
422
- break
423
- end
424
- end
425
- end
426
-
427
- private def read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
428
- begin
429
- succ_c = nil
430
- Timeout.timeout(keyseq_timeout / 1000.0) {
431
- succ_c = Reline::IOGate.getc
432
- }
433
- rescue Timeout::Error # cancel matching only when first byte
434
- block.([Reline::Key.new(c, c, false)])
435
- return :break
436
- else
437
- case key_stroke.match_status(buffer.dup.push(succ_c))
438
- when :unmatched
439
- if c == "\e".ord
440
- block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
441
- else
442
- block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
443
- end
444
- return :break
445
- when :matching
446
- Reline::IOGate.ungetc(succ_c)
447
- return :next
448
- when :matched
449
- buffer << succ_c
450
- expanded = key_stroke.expand(buffer).map{ |expanded_c|
451
- Reline::Key.new(expanded_c, expanded_c, false)
452
- }
453
- block.(expanded)
454
- return :break
392
+ else
393
+ buffer << c
394
+ status = key_stroke.match_status(buffer)
455
395
  end
456
- end
457
- end
458
396
 
459
- private def read_escaped_key(keyseq_timeout, c, block)
460
- begin
461
- escaped_c = nil
462
- Timeout.timeout(keyseq_timeout / 1000.0) {
463
- escaped_c = Reline::IOGate.getc
464
- }
465
- rescue Timeout::Error # independent ESC
466
- block.([Reline::Key.new(c, c, false)])
467
- else
468
- if escaped_c.nil?
469
- block.([Reline::Key.new(c, c, false)])
470
- elsif escaped_c >= 128 # maybe, first byte of multi byte
471
- block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
472
- elsif escaped_c == "\e".ord # escape twice
473
- block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
474
- else
475
- block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
397
+ if status == KeyStroke::MATCHED || status == KeyStroke::UNMATCHED
398
+ expanded, rest_bytes = key_stroke.expand(buffer)
399
+ rest_bytes.reverse_each { |c| io_gate.ungetc(c) }
400
+ block.call(expanded)
401
+ return
476
402
  end
477
403
  end
478
404
  end
@@ -483,19 +409,19 @@ module Reline
483
409
  end
484
410
 
485
411
  private def may_req_ambiguous_char_width
486
- @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or !STDOUT.tty?
412
+ @ambiguous_width = 2 if io_gate.dumb? || !STDIN.tty? || !STDOUT.tty?
487
413
  return if defined? @ambiguous_width
488
- Reline::IOGate.move_cursor_column(0)
414
+ io_gate.move_cursor_column(0)
489
415
  begin
490
416
  output.write "\u{25bd}"
491
417
  rescue Encoding::UndefinedConversionError
492
418
  # LANG=C
493
419
  @ambiguous_width = 1
494
420
  else
495
- @ambiguous_width = Reline::IOGate.cursor_pos.x
421
+ @ambiguous_width = io_gate.cursor_pos.x
496
422
  end
497
- Reline::IOGate.move_cursor_column(0)
498
- Reline::IOGate.erase_after_cursor
423
+ io_gate.move_cursor_column(0)
424
+ io_gate.erase_after_cursor
499
425
  end
500
426
  end
501
427
 
@@ -558,7 +484,7 @@ module Reline
558
484
  @core ||= Core.new { |core|
559
485
  core.config = Reline::Config.new
560
486
  core.key_stroke = Reline::KeyStroke.new(core.config)
561
- core.line_editor = Reline::LineEditor.new(core.config, Reline::IOGate.encoding)
487
+ core.line_editor = Reline::LineEditor.new(core.config, core.encoding)
562
488
 
563
489
  core.basic_word_break_characters = " \t\n`><=;|&{("
564
490
  core.completer_word_break_characters = " \t\n`><=;|&{("
@@ -571,7 +497,7 @@ module Reline
571
497
  end
572
498
 
573
499
  def self.ungetc(c)
574
- Reline::IOGate.ungetc(c)
500
+ core.io_gate.ungetc(c)
575
501
  end
576
502
 
577
503
  def self.line_editor
@@ -579,22 +505,12 @@ module Reline
579
505
  end
580
506
  end
581
507
 
582
- require 'reline/general_io'
583
- io = Reline::GeneralIO
584
- unless ENV['TERM'] == 'dumb'
585
- case RbConfig::CONFIG['host_os']
586
- when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
587
- require 'reline/windows'
588
- tty = (io = Reline::Windows).msys_tty?
589
- else
590
- tty = $stdout.tty?
591
- end
592
- end
593
- Reline::IOGate = if tty
594
- require 'reline/ansi'
595
- Reline::ANSI
596
- else
597
- io
598
- end
508
+
509
+ Reline::IOGate = Reline::IO.decide_io_gate
510
+
511
+ # Deprecated
512
+ Reline::GeneralIO = Reline::Dumb.new
513
+
514
+ Reline::Face.load_initial_configs
599
515
 
600
516
  Reline::HISTORY = Reline::History.new(Reline.core.config)
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.3.2
4
+ version: 0.5.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - aycabta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-14 00:00:00.000000000 Z
11
+ date: 2024-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -35,12 +35,16 @@ files:
35
35
  - COPYING
36
36
  - README.md
37
37
  - lib/reline.rb
38
- - lib/reline/ansi.rb
39
38
  - lib/reline/config.rb
40
- - lib/reline/general_io.rb
39
+ - lib/reline/face.rb
41
40
  - lib/reline/history.rb
41
+ - lib/reline/io.rb
42
+ - lib/reline/io/ansi.rb
43
+ - lib/reline/io/dumb.rb
44
+ - lib/reline/io/windows.rb
42
45
  - lib/reline/key_actor.rb
43
46
  - lib/reline/key_actor/base.rb
47
+ - lib/reline/key_actor/composite.rb
44
48
  - lib/reline/key_actor/emacs.rb
45
49
  - lib/reline/key_actor/vi_command.rb
46
50
  - lib/reline/key_actor/vi_insert.rb
@@ -51,12 +55,14 @@ files:
51
55
  - lib/reline/unicode.rb
52
56
  - lib/reline/unicode/east_asian_width.rb
53
57
  - lib/reline/version.rb
54
- - lib/reline/windows.rb
55
58
  - license_of_rb-readline
56
59
  homepage: https://github.com/ruby/reline
57
60
  licenses:
58
61
  - Ruby
59
- metadata: {}
62
+ metadata:
63
+ bug_tracker_uri: https://github.com/ruby/reline/issues
64
+ changelog_uri: https://github.com/ruby/reline/releases
65
+ source_code_uri: https://github.com/ruby/reline
60
66
  post_install_message:
61
67
  rdoc_options: []
62
68
  require_paths:
@@ -72,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
78
  - !ruby/object:Gem::Version
73
79
  version: '0'
74
80
  requirements: []
75
- rubygems_version: 3.4.0.dev
81
+ rubygems_version: 3.5.9
76
82
  signing_key:
77
83
  specification_version: 4
78
84
  summary: Alternative GNU Readline or Editline implementation by pure Ruby.