reline 0.5.4 → 0.5.6

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: 45922535b3972631020c6b33bc6b88fd400062fb2c0820ab95ab991704c1fc42
4
- data.tar.gz: 53f36ad5e7e196ba34a22990c32b38556653b7384bd99108a791d1b4c7cd3b36
3
+ metadata.gz: a87d2a8f8718292be59386f13b873af0fa94cb20f6837761332174c413dc7755
4
+ data.tar.gz: 342c0dfbcf1e99af3c31ac4370f576e6a447728b2942328db1fc2a8a5b458b9e
5
5
  SHA512:
6
- metadata.gz: eb1b50add8dc60baeefd1fecce83abbaf0e134c16c30ca7fd268efe46d364638280bd2a16100e54be6dbf691bc8a9d4220c53210233a06a0278361c07bd5a56f
7
- data.tar.gz: 5ed4f57373cd6e9329de58b9361037e4f8e510020c0ba59970de5733a8c8f4b5c004b871d8e21f013ee065daed9b55f433142529b5e4039276a0f0adbc00c4d9
6
+ metadata.gz: 0031f7bd3660b7adda54149c1e15da1d1d2f9ef5c7e240828c9a1f3337d0c7bf2e1796c5ba6f61f1352c18819225697e4dd7c32149ff3297f65ddf0fd8f06e82
7
+ data.tar.gz: ea8bfe21ce43dbd3f1f6fa23d1d1a1948005cdda278485bba9010060f1ad1e3900c749e1a2966caf39f892c4c38692bc4abe8283425e3c3138e273f65b170ca9
data/lib/reline/ansi.rb CHANGED
@@ -45,6 +45,7 @@ class Reline::ANSI
45
45
  end
46
46
 
47
47
  def self.set_default_key_bindings(config, allow_terminfo: true)
48
+ set_bracketed_paste_key_bindings(config)
48
49
  set_default_key_bindings_ansi_cursor(config)
49
50
  if allow_terminfo && Reline::Terminfo.enabled?
50
51
  set_default_key_bindings_terminfo(config)
@@ -66,6 +67,12 @@ class Reline::ANSI
66
67
  end
67
68
  end
68
69
 
70
+ def self.set_bracketed_paste_key_bindings(config)
71
+ [:emacs, :vi_insert, :vi_command].each do |keymap|
72
+ config.add_default_key_binding_by_keymap(keymap, START_BRACKETED_PASTE.bytes, :bracketed_paste_start)
73
+ end
74
+ end
75
+
69
76
  def self.set_default_key_bindings_ansi_cursor(config)
70
77
  ANSI_CURSOR_KEY_BINDINGS.each do |char, (default_func, modifiers)|
71
78
  bindings = [["\e[#{char}", default_func]] # CSI + char
@@ -178,46 +185,26 @@ class Reline::ANSI
178
185
  nil
179
186
  end
180
187
 
181
- @@in_bracketed_paste_mode = false
182
- START_BRACKETED_PASTE = String.new("\e[200~,", encoding: Encoding::ASCII_8BIT)
183
- END_BRACKETED_PASTE = String.new("\e[200~.", encoding: Encoding::ASCII_8BIT)
184
- def self.getc_with_bracketed_paste(timeout_second)
188
+ START_BRACKETED_PASTE = String.new("\e[200~", encoding: Encoding::ASCII_8BIT)
189
+ END_BRACKETED_PASTE = String.new("\e[201~", encoding: Encoding::ASCII_8BIT)
190
+ def self.read_bracketed_paste
185
191
  buffer = String.new(encoding: Encoding::ASCII_8BIT)
186
- buffer << inner_getc(timeout_second)
187
- while START_BRACKETED_PASTE.start_with?(buffer) or END_BRACKETED_PASTE.start_with?(buffer) do
188
- if START_BRACKETED_PASTE == buffer
189
- @@in_bracketed_paste_mode = true
190
- return inner_getc(timeout_second)
191
- elsif END_BRACKETED_PASTE == buffer
192
- @@in_bracketed_paste_mode = false
193
- ungetc(-1)
194
- return inner_getc(timeout_second)
195
- end
196
- succ_c = inner_getc(Reline.core.config.keyseq_timeout)
197
-
198
- if succ_c
199
- buffer << succ_c
200
- else
201
- break
202
- end
192
+ until buffer.end_with?(END_BRACKETED_PASTE)
193
+ c = inner_getc(Float::INFINITY)
194
+ break unless c
195
+ buffer << c
203
196
  end
204
- buffer.bytes.reverse_each do |ch|
205
- ungetc ch
206
- end
207
- inner_getc(timeout_second)
197
+ string = buffer.delete_suffix(END_BRACKETED_PASTE).force_encoding(encoding)
198
+ string.valid_encoding? ? string : ''
208
199
  end
209
200
 
210
201
  # if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
211
202
  def self.getc(timeout_second)
212
- if Reline.core.config.enable_bracketed_paste
213
- getc_with_bracketed_paste(timeout_second)
214
- else
215
- inner_getc(timeout_second)
216
- end
203
+ inner_getc(timeout_second)
217
204
  end
218
205
 
219
206
  def self.in_pasting?
220
- @@in_bracketed_paste_mode or (not empty_buffer?)
207
+ not empty_buffer?
221
208
  end
222
209
 
223
210
  def self.empty_buffer?
@@ -361,11 +348,15 @@ class Reline::ANSI
361
348
  end
362
349
 
363
350
  def self.prep
351
+ # Enable bracketed paste
352
+ @@output.write "\e[?2004h" if Reline.core.config.enable_bracketed_paste
364
353
  retrieve_keybuffer
365
354
  nil
366
355
  end
367
356
 
368
357
  def self.deprep(otio)
358
+ # Disable bracketed paste
359
+ @@output.write "\e[?2004l" if Reline.core.config.enable_bracketed_paste
369
360
  Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
370
361
  end
371
362
  end
data/lib/reline/config.rb CHANGED
@@ -8,31 +8,12 @@ class Reline::Config
8
8
  end
9
9
 
10
10
  VARIABLE_NAMES = %w{
11
- bind-tty-special-chars
12
- blink-matching-paren
13
- byte-oriented
14
11
  completion-ignore-case
15
12
  convert-meta
16
13
  disable-completion
17
- enable-keypad
18
- expand-tilde
19
- history-preserve-point
20
14
  history-size
21
- horizontal-scroll-mode
22
- input-meta
23
15
  keyseq-timeout
24
- mark-directories
25
- mark-modified-lines
26
- mark-symlinked-directories
27
- match-hidden-files
28
- meta-flag
29
- output-meta
30
- page-completions
31
- prefer-visible-bell
32
- print-completions-horizontally
33
16
  show-all-if-ambiguous
34
- show-all-if-unmodified
35
- visible-stats
36
17
  show-mode-in-prompt
37
18
  vi-cmd-mode-string
38
19
  vi-ins-mode-string
@@ -69,17 +50,15 @@ class Reline::Config
69
50
  @test_mode = false
70
51
  @autocompletion = false
71
52
  @convert_meta = true if seven_bit_encoding?(Reline::IOGate.encoding)
53
+ @loaded = false
54
+ @enable_bracketed_paste = true
72
55
  end
73
56
 
74
57
  def reset
75
58
  if editing_mode_is?(:vi_command)
76
59
  @editing_mode_label = :vi_insert
77
60
  end
78
- @additional_key_bindings.keys.each do |key|
79
- @additional_key_bindings[key].clear
80
- end
81
61
  @oneshot_key_bindings.clear
82
- reset_default_key_bindings
83
62
  end
84
63
 
85
64
  def editing_mode
@@ -98,6 +77,10 @@ class Reline::Config
98
77
  @key_actors[@keymap_label]
99
78
  end
100
79
 
80
+ def loaded?
81
+ @loaded
82
+ end
83
+
101
84
  def inputrc_path
102
85
  case ENV['INPUTRC']
103
86
  when nil, ''
@@ -129,6 +112,7 @@ class Reline::Config
129
112
  end
130
113
 
131
114
  def read(file = nil)
115
+ @loaded = true
132
116
  file ||= default_inputrc_path
133
117
  begin
134
118
  if file.respond_to?(:readlines)
@@ -171,12 +155,6 @@ class Reline::Config
171
155
  @key_actors[@keymap_label].default_key_bindings[keystroke] = target
172
156
  end
173
157
 
174
- def reset_default_key_bindings
175
- @key_actors.values.each do |ka|
176
- ka.reset_default_key_bindings
177
- end
178
- end
179
-
180
158
  def read_lines(lines, file = nil)
181
159
  if not lines.empty? and lines.first.encoding != Reline.encoding_system_needs
182
160
  begin
@@ -12,8 +12,4 @@ class Reline::KeyActor::Base
12
12
  def default_key_bindings
13
13
  @default_key_bindings
14
14
  end
15
-
16
- def reset_default_key_bindings
17
- @default_key_bindings.clear
18
- end
19
15
  end
@@ -19,7 +19,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
19
19
  # 8 ^H
20
20
  :em_delete_prev_char,
21
21
  # 9 ^I
22
- :ed_unassigned,
22
+ :complete,
23
23
  # 10 ^J
24
24
  :ed_newline,
25
25
  # 11 ^K
@@ -19,7 +19,7 @@ class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
19
19
  # 8 ^H
20
20
  :vi_delete_prev_char,
21
21
  # 9 ^I
22
- :ed_insert,
22
+ :complete,
23
23
  # 10 ^J
24
24
  :ed_newline,
25
25
  # 11 ^K
@@ -29,11 +29,11 @@ class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
29
29
  # 13 ^M
30
30
  :ed_newline,
31
31
  # 14 ^N
32
- :ed_insert,
32
+ :menu_complete,
33
33
  # 15 ^O
34
34
  :ed_insert,
35
35
  # 16 ^P
36
- :ed_insert,
36
+ :menu_complete_backward,
37
37
  # 17 ^Q
38
38
  :ed_ignore,
39
39
  # 18 ^R
@@ -235,7 +235,6 @@ class Reline::LineEditor
235
235
  @vi_waiting_operator_arg = nil
236
236
  @completion_journey_state = nil
237
237
  @completion_state = CompletionState::NORMAL
238
- @completion_occurs = false
239
238
  @perfect_matched = nil
240
239
  @menu_info = nil
241
240
  @searching_prompt = nil
@@ -284,7 +283,7 @@ class Reline::LineEditor
284
283
  indent1 = @auto_indent_proc.(@buffer_of_lines.take(@line_index - 1).push(''), @line_index - 1, 0, true)
285
284
  indent2 = @auto_indent_proc.(@buffer_of_lines.take(@line_index), @line_index - 1, @buffer_of_lines[@line_index - 1].bytesize, false)
286
285
  indent = indent2 || indent1
287
- @buffer_of_lines[@line_index - 1] = ' ' * indent + @buffer_of_lines[@line_index - 1].gsub(/\A */, '')
286
+ @buffer_of_lines[@line_index - 1] = ' ' * indent + @buffer_of_lines[@line_index - 1].gsub(/\A\s*/, '')
288
287
  )
289
288
  process_auto_indent @line_index, add_newline: true
290
289
  else
@@ -387,7 +386,7 @@ class Reline::LineEditor
387
386
  next cached
388
387
  end
389
388
  *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
389
+ wrapped_lines = split_by_width(line, width, offset: calculate_width(code_line_prompt, true)).first.compact
391
390
  wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
392
391
  end
393
392
  end
@@ -856,7 +855,7 @@ class Reline::LineEditor
856
855
  [target, preposing, completed, postposing]
857
856
  end
858
857
 
859
- private def complete(list, just_show_list)
858
+ private def perform_completion(list, just_show_list)
860
859
  case @completion_state
861
860
  when CompletionState::NORMAL
862
861
  @completion_state = CompletionState::COMPLETION
@@ -885,12 +884,12 @@ class Reline::LineEditor
885
884
  @completion_state = CompletionState::PERFECT_MATCH
886
885
  else
887
886
  @completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
888
- complete(list, true) if @config.show_all_if_ambiguous
887
+ perform_completion(list, true) if @config.show_all_if_ambiguous
889
888
  end
890
889
  @perfect_matched = completed
891
890
  else
892
891
  @completion_state = CompletionState::MENU
893
- complete(list, true) if @config.show_all_if_ambiguous
892
+ perform_completion(list, true) if @config.show_all_if_ambiguous
894
893
  end
895
894
  if not just_show_list and target < completed
896
895
  @buffer_of_lines[@line_index] = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
@@ -1065,10 +1064,6 @@ class Reline::LineEditor
1065
1064
  end
1066
1065
 
1067
1066
  private def normal_char(key)
1068
- if key.combined_char.is_a?(Symbol)
1069
- process_key(key.combined_char, key.combined_char)
1070
- return
1071
- end
1072
1067
  @multibyte_buffer << key.combined_char
1073
1068
  if @multibyte_buffer.size > 1
1074
1069
  if @multibyte_buffer.dup.force_encoding(@encoding).valid_encoding?
@@ -1128,29 +1123,8 @@ class Reline::LineEditor
1128
1123
  old_lines = @buffer_of_lines.dup
1129
1124
  @first_char = false
1130
1125
  @completion_occurs = false
1131
- if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
1132
- if !@config.disable_completion
1133
- process_insert(force: true)
1134
- if @config.autocompletion
1135
- @completion_state = CompletionState::NORMAL
1136
- @completion_occurs = move_completed_list(:down)
1137
- else
1138
- @completion_journey_state = nil
1139
- result = call_completion_proc
1140
- if result.is_a?(Array)
1141
- @completion_occurs = true
1142
- complete(result, false)
1143
- end
1144
- end
1145
- end
1146
- elsif @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
1147
- # In vi mode, move completed list even if autocompletion is off
1148
- if not @config.disable_completion
1149
- process_insert(force: true)
1150
- @completion_state = CompletionState::NORMAL
1151
- @completion_occurs = move_completed_list("\C-p".ord == key.char ? :up : :down)
1152
- end
1153
- elsif Symbol === key.char and respond_to?(key.char, true)
1126
+
1127
+ if key.char.is_a?(Symbol)
1154
1128
  process_key(key.char, key.char)
1155
1129
  else
1156
1130
  normal_char(key)
@@ -1331,6 +1305,16 @@ class Reline::LineEditor
1331
1305
  @confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
1332
1306
  end
1333
1307
 
1308
+ def insert_pasted_text(text)
1309
+ pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
1310
+ post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
1311
+ lines = (pre + text.gsub(/\r\n?/, "\n") + post).split("\n", -1)
1312
+ lines << '' if lines.empty?
1313
+ @buffer_of_lines[@line_index, 1] = lines
1314
+ @line_index += lines.size - 1
1315
+ @byte_pointer = @buffer_of_lines[@line_index].bytesize - post.bytesize
1316
+ end
1317
+
1334
1318
  def insert_text(text)
1335
1319
  if @buffer_of_lines[@line_index].bytesize == @byte_pointer
1336
1320
  @buffer_of_lines[@line_index] += text
@@ -1429,13 +1413,42 @@ class Reline::LineEditor
1429
1413
  end
1430
1414
  end
1431
1415
 
1432
- private def completion_journey_up(key)
1433
- if not @config.disable_completion and @config.autocompletion
1416
+ private def complete(_key)
1417
+ return if @config.disable_completion
1418
+
1419
+ process_insert(force: true)
1420
+ if @config.autocompletion
1434
1421
  @completion_state = CompletionState::NORMAL
1435
- @completion_occurs = move_completed_list(:up)
1422
+ @completion_occurs = move_completed_list(:down)
1423
+ else
1424
+ @completion_journey_state = nil
1425
+ result = call_completion_proc
1426
+ if result.is_a?(Array)
1427
+ @completion_occurs = true
1428
+ perform_completion(result, false)
1429
+ end
1436
1430
  end
1437
1431
  end
1438
- alias_method :menu_complete_backward, :completion_journey_up
1432
+
1433
+ private def completion_journey_move(direction)
1434
+ return if @config.disable_completion
1435
+
1436
+ process_insert(force: true)
1437
+ @completion_state = CompletionState::NORMAL
1438
+ @completion_occurs = move_completed_list(direction)
1439
+ end
1440
+
1441
+ private def menu_complete(_key)
1442
+ completion_journey_move(:down)
1443
+ end
1444
+
1445
+ private def menu_complete_backward(_key)
1446
+ completion_journey_move(:up)
1447
+ end
1448
+
1449
+ private def completion_journey_up(_key)
1450
+ completion_journey_move(:up) if @config.autocompletion
1451
+ end
1439
1452
 
1440
1453
  # Editline:: +ed-unassigned+ This editor command always results in an error.
1441
1454
  # GNU Readline:: There is no corresponding macro.
@@ -1904,7 +1917,7 @@ class Reline::LineEditor
1904
1917
  elsif !@config.autocompletion # show completed list
1905
1918
  result = call_completion_proc
1906
1919
  if result.is_a?(Array)
1907
- complete(result, true)
1920
+ perform_completion(result, true)
1908
1921
  end
1909
1922
  end
1910
1923
  end
@@ -43,11 +43,13 @@ class Reline::Unicode
43
43
 
44
44
  def self.escape_for_print(str)
45
45
  str.chars.map! { |gr|
46
- escaped = EscapedPairs[gr.ord]
47
- if escaped && gr != -"\n" && gr != -"\t"
48
- escaped
49
- else
46
+ case gr
47
+ when -"\n"
50
48
  gr
49
+ when -"\t"
50
+ -' '
51
+ else
52
+ EscapedPairs[gr.ord] || gr
51
53
  end
52
54
  }.join
53
55
  end
@@ -1,3 +1,3 @@
1
1
  module Reline
2
- VERSION = '0.5.4'
2
+ VERSION = '0.5.6'
3
3
  end
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[journey_data.pointer]
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 target.empty? || (result == [target] && pointer < 0)
232
+ return if completed.empty? || (result == [completed] && pointer < 0)
232
233
 
233
234
  target_width = Reline::Unicode.calculate_width(target)
234
- x = cursor_pos.x - target_width
235
- if x < 0
236
- x = screen_width + x
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)
@@ -309,6 +312,10 @@ module Reline
309
312
  $stderr.sync = true
310
313
  $stderr.puts "Reline is used by #{Process.pid}"
311
314
  end
315
+ unless config.test_mode or config.loaded?
316
+ config.read
317
+ io_gate.set_default_key_bindings(config)
318
+ end
312
319
  otio = io_gate.prep
313
320
 
314
321
  may_req_ambiguous_char_width
@@ -335,12 +342,6 @@ module Reline
335
342
  end
336
343
  end
337
344
 
338
- unless config.test_mode
339
- config.read
340
- config.reset_default_key_bindings
341
- io_gate.set_default_key_bindings(config)
342
- end
343
-
344
345
  line_editor.print_nomultiline_prompt(prompt)
345
346
  line_editor.update_dialogs
346
347
  line_editor.rerender
@@ -350,7 +351,15 @@ module Reline
350
351
  loop do
351
352
  read_io(config.keyseq_timeout) { |inputs|
352
353
  line_editor.set_pasting_state(io_gate.in_pasting?)
353
- inputs.each { |key| line_editor.update(key) }
354
+ inputs.each do |key|
355
+ if key.char == :bracketed_paste_start
356
+ text = io_gate.read_bracketed_paste
357
+ line_editor.insert_pasted_text(text)
358
+ line_editor.scroll_into_view
359
+ else
360
+ line_editor.update(key)
361
+ end
362
+ end
354
363
  }
355
364
  if line_editor.finished?
356
365
  line_editor.render_finished
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
4
+ version: 0.5.6
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-29 00:00:00.000000000 Z
11
+ date: 2024-05-09 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.3
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.