reline 0.2.3 → 0.2.7

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: 8da8b8b73cb81c8d6288188ba05a0ea83a7dade5e60a54c5e9a591cdaa6ce729
4
- data.tar.gz: b810a0521daf74369007cd0195f861e30f66cb75c86c29630216691ceb3cfd64
3
+ metadata.gz: 1bb2255429504a1beb1a5a9f863f7cba5c4c65781b7cd8b2aa843b0df639fb26
4
+ data.tar.gz: c9372db87ad831e06d0e99d20981cb14a08e8b15ca3011f4b6df2a05aaeef7b3
5
5
  SHA512:
6
- metadata.gz: bcdfacec31f8a2a672629b6a709cc9378d215758156ba11490a02d9372fa349706a3d7129db08832969baf3de823c5f553062e536dce69dd524f24e602807fc1
7
- data.tar.gz: e7eb36a5936ff7ad3642b27869a57b766f33c77b149296d06e2c34b3ab1676b21880ba3dde12f1a5faae0f6280e662adc29fa1fd0daf43e6a394e5c1569765a8
6
+ metadata.gz: 63e8b6f4a9de8a69a8f22c979b6fee92026143be658b9e928da43dddb868fb6b641b5f140de436c1dd5ed1f3cdbc3c42c7c41084fcc1d811cd713c684aedda8e
7
+ data.tar.gz: 7a459412f528f43d5e65f4c7c6a5c74055e2c5334f21a65411bc4f187b55b649c15fd612ed27f2dc0032f7fdc5973c7fa57b674b0a323ac2d9537b23fff19664
data/README.md CHANGED
@@ -8,6 +8,52 @@ This is a screen capture of *IRB improved by Reline*.
8
8
 
9
9
  Reline is compatible with the API of Ruby's stdlib 'readline', GNU Readline and Editline by pure Ruby implementation.
10
10
 
11
+ ## Usage
12
+
13
+ ### Single line editing mode
14
+
15
+ It's compatible with the readline standard library.
16
+
17
+ See [the document of readline stdlib](https://ruby-doc.org/stdlib/libdoc/readline/rdoc/Readline.html) or [bin/example](https://github.com/ruby/reline/blob/master/bin/example).
18
+
19
+ ### Multi-line editing mode
20
+
21
+ ```ruby
22
+ require "reline"
23
+
24
+ prompt = 'prompt> '
25
+ use_history = true
26
+
27
+ begin
28
+ while true
29
+ text = Reline.readmultiline(prompt, use_history) do |multiline_input|
30
+ # Accept the input until `end` is entered
31
+ multiline_input.split.last == "end"
32
+ end
33
+
34
+ puts 'You entered:'
35
+ puts text
36
+ end
37
+ # If you want to exit, type Ctrl-C
38
+ rescue Interrupt
39
+ puts '^C'
40
+ exit 0
41
+ end
42
+ ```
43
+
44
+ ```bash
45
+ $ ruby example.rb
46
+ prompt> aaa
47
+ prompt> bbb
48
+ prompt> end
49
+ You entered:
50
+ aaa
51
+ bbb
52
+ end
53
+ ```
54
+
55
+ See also: [test/reline/yamatanooroti/multiline_repl](https://github.com/ruby/reline/blob/master/test/reline/yamatanooroti/multiline_repl)
56
+
11
57
  ## License
12
58
 
13
59
  The gem is available as open source under the terms of the [Ruby License](https://www.ruby-lang.org/en/about/license.txt).
data/lib/reline.rb CHANGED
@@ -7,12 +7,15 @@ require 'reline/key_actor'
7
7
  require 'reline/key_stroke'
8
8
  require 'reline/line_editor'
9
9
  require 'reline/history'
10
+ require 'reline/terminfo'
10
11
  require 'rbconfig'
11
12
 
12
13
  module Reline
13
14
  FILENAME_COMPLETION_PROC = nil
14
15
  USERNAME_COMPLETION_PROC = nil
15
16
 
17
+ class ConfigEncodingConversionError < StandardError; end
18
+
16
19
  Key = Struct.new('Key', :char, :combined_char, :with_meta)
17
20
  CursorPos = Struct.new(:x, :y)
18
21
 
@@ -231,9 +234,7 @@ module Reline
231
234
  unless config.test_mode
232
235
  config.read
233
236
  config.reset_default_key_bindings
234
- Reline::IOGate::RAW_KEYSTROKE_CONFIG.each_pair do |key, func|
235
- config.add_default_key_binding(key, func)
236
- end
237
+ Reline::IOGate.set_default_key_bindings(config)
237
238
  end
238
239
 
239
240
  line_editor.rerender
@@ -273,11 +274,12 @@ module Reline
273
274
  Reline::IOGate.deprep(otio)
274
275
  end
275
276
 
276
- # Keystrokes of GNU Readline will timeout it with the specification of
277
- # "keyseq-timeout" when waiting for the 2nd character after the 1st one.
278
- # If the 2nd character comes after 1st ESC without timeout it has a
279
- # meta-property of meta-key to discriminate modified key with meta-key
280
- # from multibyte characters that come with 8th bit on.
277
+ # GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
278
+ # is followed by a character, and times out and treats it as a standalone
279
+ # ESC if the second character does not arrive. If the second character
280
+ # comes before timed out, it is treated as a modifier key with the
281
+ # meta-property of meta-key, so that it can be distinguished from
282
+ # multibyte characters with the 8th bit turned on.
281
283
  #
282
284
  # GNU Readline will wait for the 2nd character with "keyseq-timeout"
283
285
  # milli-seconds but wait forever after 3rd characters.
@@ -446,22 +448,34 @@ module Reline
446
448
  }
447
449
  end
448
450
 
451
+ def self.ungetc(c)
452
+ Reline::IOGate.ungetc(c)
453
+ end
454
+
449
455
  def self.line_editor
450
456
  core.line_editor
451
457
  end
452
458
  end
453
459
 
460
+ require 'reline/general_io'
454
461
  if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
455
462
  require 'reline/windows'
456
463
  if Reline::Windows.msys_tty?
457
- require 'reline/ansi'
458
- Reline::IOGate = Reline::ANSI
464
+ Reline::IOGate = if ENV['TERM'] == 'dumb'
465
+ Reline::GeneralIO
466
+ else
467
+ require 'reline/ansi'
468
+ Reline::ANSI
469
+ end
459
470
  else
460
471
  Reline::IOGate = Reline::Windows
461
472
  end
462
473
  else
463
- require 'reline/ansi'
464
- Reline::IOGate = Reline::ANSI
474
+ Reline::IOGate = if $stdout.isatty
475
+ require 'reline/ansi'
476
+ Reline::ANSI
477
+ else
478
+ Reline::GeneralIO
479
+ end
465
480
  end
466
481
  Reline::HISTORY = Reline::History.new(Reline.core.config)
467
- require 'reline/general_io'
data/lib/reline/ansi.rb CHANGED
@@ -1,7 +1,13 @@
1
1
  require 'io/console'
2
+ require 'io/wait'
2
3
  require 'timeout'
4
+ require_relative 'terminfo'
3
5
 
4
6
  class Reline::ANSI
7
+ if Reline::Terminfo.enabled?
8
+ Reline::Terminfo.setupterm(0, 2)
9
+ end
10
+
5
11
  def self.encoding
6
12
  Encoding.default_external
7
13
  end
@@ -10,52 +16,99 @@ class Reline::ANSI
10
16
  false
11
17
  end
12
18
 
13
- RAW_KEYSTROKE_CONFIG = {
14
- # Console (80x25)
15
- [27, 91, 49, 126] => :ed_move_to_beg, # Home
16
- [27, 91, 52, 126] => :ed_move_to_end, # End
17
- [27, 91, 51, 126] => :key_delete, # Del
18
- [27, 91, 65] => :ed_prev_history, # ↑
19
- [27, 91, 66] => :ed_next_history, # ↓
20
- [27, 91, 67] => :ed_next_char, # →
21
- [27, 91, 68] => :ed_prev_char, #
22
-
23
- # KDE
24
- [27, 91, 72] => :ed_move_to_beg, # Home
25
- [27, 91, 70] => :ed_move_to_end, # End
26
- # Del is 0x08
27
- [27, 71, 65] => :ed_prev_history, # ↑
28
- [27, 71, 66] => :ed_next_history, # ↓
29
- [27, 71, 67] => :ed_next_char, # →
30
- [27, 71, 68] => :ed_prev_char, # ←
31
-
32
- # urxvt / exoterm
33
- [27, 91, 55, 126] => :ed_move_to_beg, # Home
34
- [27, 91, 56, 126] => :ed_move_to_end, # End
35
-
36
- # GNOME
37
- [27, 79, 72] => :ed_move_to_beg, # Home
38
- [27, 79, 70] => :ed_move_to_end, # End
39
- # Del is 0x08
40
- # Arrow keys are the same of KDE
41
-
42
- # iTerm2
43
- [27, 27, 91, 67] => :em_next_word, # Option+→
44
- [27, 27, 91, 68] => :ed_prev_word, # Option+←
45
- [195, 166] => :em_next_word, # Option+f
46
- [195, 162] => :ed_prev_word, # Option+b
47
-
48
- # others
49
- [27, 32] => :em_set_mark, # M-<space>
50
- [24, 24] => :em_exchange_mark, # C-x C-x TODO also add Windows
51
- [27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→
52
- [27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←
53
-
54
- [27, 79, 65] => :ed_prev_history, # ↑
55
- [27, 79, 66] => :ed_next_history, # ↓
56
- [27, 79, 67] => :ed_next_char, # →
57
- [27, 79, 68] => :ed_prev_char, # ←
58
- }
19
+ def self.set_default_key_bindings(config)
20
+ if Reline::Terminfo.enabled?
21
+ set_default_key_bindings_terminfo(config)
22
+ else
23
+ set_default_key_bindings_comprehensive_list(config)
24
+ end
25
+ {
26
+ # extended entries of terminfo
27
+ [27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→, extended entry
28
+ [27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+←, extended entry
29
+ [27, 91, 49, 59, 51, 67] => :em_next_word, # Meta+→, extended entry
30
+ [27, 91, 49, 59, 51, 68] => :ed_prev_word, # Meta+←, extended entry
31
+ }.each_pair do |key, func|
32
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
33
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
34
+ config.add_default_key_binding_by_keymap(:vi_command, key, func)
35
+ end
36
+ {
37
+ # default bindings
38
+ [27, 32] => :em_set_mark, # M-<space>
39
+ [24, 24] => :em_exchange_mark, # C-x C-x
40
+ }.each_pair do |key, func|
41
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
42
+ end
43
+ end
44
+
45
+ def self.set_default_key_bindings_terminfo(config)
46
+ {
47
+ Reline::Terminfo.tigetstr('khome').bytes => :ed_move_to_beg,
48
+ Reline::Terminfo.tigetstr('kend').bytes => :ed_move_to_end,
49
+ Reline::Terminfo.tigetstr('kcuu1').bytes => :ed_prev_history,
50
+ Reline::Terminfo.tigetstr('kcud1').bytes => :ed_next_history,
51
+ Reline::Terminfo.tigetstr('kcuf1').bytes => :ed_next_char,
52
+ Reline::Terminfo.tigetstr('kcub1').bytes => :ed_prev_char,
53
+ # Escape sequences that omit the move distance and are set to defaults
54
+ # value 1 may be sometimes sent by pressing the arrow-key.
55
+ Reline::Terminfo.tigetstr('cuu').sub(/%p1%d/, '').bytes => :ed_prev_history,
56
+ Reline::Terminfo.tigetstr('cud').sub(/%p1%d/, '').bytes => :ed_next_history,
57
+ Reline::Terminfo.tigetstr('cuf').sub(/%p1%d/, '').bytes => :ed_next_char,
58
+ Reline::Terminfo.tigetstr('cub').sub(/%p1%d/, '').bytes => :ed_prev_char,
59
+ }.each_pair do |key, func|
60
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
61
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
62
+ config.add_default_key_binding_by_keymap(:vi_command, key, func)
63
+ end
64
+ end
65
+
66
+ def self.set_default_key_bindings_comprehensive_list(config)
67
+ {
68
+ # Console (80x25)
69
+ [27, 91, 49, 126] => :ed_move_to_beg, # Home
70
+ [27, 91, 52, 126] => :ed_move_to_end, # End
71
+ [27, 91, 51, 126] => :key_delete, # Del
72
+ [27, 91, 65] => :ed_prev_history, # ↑
73
+ [27, 91, 66] => :ed_next_history, # ↓
74
+ [27, 91, 67] => :ed_next_char, # →
75
+ [27, 91, 68] => :ed_prev_char, # ←
76
+
77
+ # KDE
78
+ [27, 91, 72] => :ed_move_to_beg, # Home
79
+ [27, 91, 70] => :ed_move_to_end, # End
80
+ # Del is 0x08
81
+ [27, 71, 65] => :ed_prev_history, # ↑
82
+ [27, 71, 66] => :ed_next_history, # ↓
83
+ [27, 71, 67] => :ed_next_char, # →
84
+ [27, 71, 68] => :ed_prev_char, # ←
85
+
86
+ # urxvt / exoterm
87
+ [27, 91, 55, 126] => :ed_move_to_beg, # Home
88
+ [27, 91, 56, 126] => :ed_move_to_end, # End
89
+
90
+ # GNOME
91
+ [27, 79, 72] => :ed_move_to_beg, # Home
92
+ [27, 79, 70] => :ed_move_to_end, # End
93
+ # Del is 0x08
94
+ # Arrow keys are the same of KDE
95
+
96
+ # iTerm2
97
+ [27, 27, 91, 67] => :em_next_word, # Option+→, extended entry
98
+ [27, 27, 91, 68] => :ed_prev_word, # Option+←, extended entry
99
+ [195, 166] => :em_next_word, # Option+f
100
+ [195, 162] => :ed_prev_word, # Option+b
101
+
102
+ [27, 79, 65] => :ed_prev_history, # ↑
103
+ [27, 79, 66] => :ed_next_history, # ↓
104
+ [27, 79, 67] => :ed_next_char, # →
105
+ [27, 79, 68] => :ed_prev_char, # ←
106
+ }.each_pair do |key, func|
107
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
108
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
109
+ config.add_default_key_binding_by_keymap(:vi_command, key, func)
110
+ end
111
+ end
59
112
 
60
113
  @@input = STDIN
61
114
  def self.input=(val)
@@ -79,6 +132,8 @@ class Reline::ANSI
79
132
  rescue Errno::EIO
80
133
  # Maybe the I/O has been closed.
81
134
  nil
135
+ rescue Errno::ENOTTY
136
+ nil
82
137
  end
83
138
 
84
139
  @@in_bracketed_paste_mode = false
@@ -129,12 +184,7 @@ class Reline::ANSI
129
184
  unless @@buf.empty?
130
185
  return false
131
186
  end
132
- rs, = IO.select([@@input], [], [], 0.00001)
133
- if rs and rs[0]
134
- false
135
- else
136
- true
137
- end
187
+ !@@input.wait_readable(0)
138
188
  end
139
189
 
140
190
  def self.ungetc(c)
@@ -143,8 +193,7 @@ class Reline::ANSI
143
193
 
144
194
  def self.retrieve_keybuffer
145
195
  begin
146
- result = select([@@input], [], [], 0.001)
147
- return if result.nil?
196
+ return unless @@input.wait_readable(0.001)
148
197
  str = @@input.read_nonblock(1024)
149
198
  str.bytes.each do |c|
150
199
  @@buf.push(c)
data/lib/reline/config.rb CHANGED
@@ -47,7 +47,9 @@ class Reline::Config
47
47
 
48
48
  def initialize
49
49
  @additional_key_bindings = {} # from inputrc
50
- @default_key_bindings = {} # environment-dependent
50
+ @additional_key_bindings[:emacs] = {}
51
+ @additional_key_bindings[:vi_insert] = {}
52
+ @additional_key_bindings[:vi_command] = {}
51
53
  @skip_section = nil
52
54
  @if_stack = nil
53
55
  @editing_mode_label = :emacs
@@ -69,8 +71,10 @@ class Reline::Config
69
71
  if editing_mode_is?(:vi_command)
70
72
  @editing_mode_label = :vi_insert
71
73
  end
72
- @additional_key_bindings = {}
73
- @default_key_bindings = {}
74
+ @additional_key_bindings.keys.each do |key|
75
+ @additional_key_bindings[key].clear
76
+ end
77
+ reset_default_key_bindings
74
78
  end
75
79
 
76
80
  def editing_mode
@@ -135,19 +139,35 @@ class Reline::Config
135
139
  end
136
140
 
137
141
  def key_bindings
138
- # override @default_key_bindings with @additional_key_bindings
139
- @default_key_bindings.merge(@additional_key_bindings)
142
+ # override @key_actors[@editing_mode_label].default_key_bindings with @additional_key_bindings[@editing_mode_label]
143
+ @key_actors[@editing_mode_label].default_key_bindings.merge(@additional_key_bindings[@editing_mode_label])
144
+ end
145
+
146
+ def add_default_key_binding_by_keymap(keymap, keystroke, target)
147
+ @key_actors[keymap].default_key_bindings[keystroke] = target
140
148
  end
141
149
 
142
150
  def add_default_key_binding(keystroke, target)
143
- @default_key_bindings[keystroke] = target
151
+ @key_actors[@keymap_label].default_key_bindings[keystroke] = target
144
152
  end
145
153
 
146
154
  def reset_default_key_bindings
147
- @default_key_bindings = {}
155
+ @key_actors.values.each do |ka|
156
+ ka.reset_default_key_bindings
157
+ end
148
158
  end
149
159
 
150
160
  def read_lines(lines, file = nil)
161
+ if not lines.empty? and lines.first.encoding != Reline.encoding_system_needs
162
+ begin
163
+ lines = lines.map do |l|
164
+ l.encode(Reline.encoding_system_needs)
165
+ rescue Encoding::UndefinedConversionError
166
+ mes = "The inputrc encoded in #{lines.first.encoding.name} can't be converted to the locale #{Reline.encoding_system_needs.name}."
167
+ raise Reline::ConfigEncodingConversionError.new(mes)
168
+ end
169
+ end
170
+ end
151
171
  conditions = [@skip_section, @if_stack]
152
172
  @skip_section = nil
153
173
  @if_stack = []
@@ -174,7 +194,7 @@ class Reline::Config
174
194
  key, func_name = $1, $2
175
195
  keystroke, func = bind_key(key, func_name)
176
196
  next unless keystroke
177
- @additional_key_bindings[keystroke] = func
197
+ @additional_key_bindings[@keymap_label][keystroke] = func
178
198
  end
179
199
  end
180
200
  unless @if_stack.empty?
@@ -282,11 +302,8 @@ class Reline::Config
282
302
  end
283
303
 
284
304
  def retrieve_string(str)
285
- if str =~ /\A"(.*)"\z/
286
- parse_keyseq($1).map(&:chr).join
287
- else
288
- parse_keyseq(str).map(&:chr).join
289
- end
305
+ str = $1 if str =~ /\A"(.*)"\z/
306
+ parse_keyseq(str).map { |c| c.chr(Reline.encoding_system_needs) }.join
290
307
  end
291
308
 
292
309
  def bind_key(key, func_name)
@@ -1,19 +1,27 @@
1
1
  require 'timeout'
2
2
 
3
3
  class Reline::GeneralIO
4
- def self.reset
4
+ def self.reset(encoding: nil)
5
5
  @@pasting = false
6
+ @@encoding = encoding
6
7
  end
7
8
 
8
9
  def self.encoding
9
- RUBY_PLATFORM =~ /mswin|mingw/ ? Encoding::UTF_8 : Encoding::default_external
10
+ if defined?(@@encoding)
11
+ @@encoding
12
+ elsif RUBY_PLATFORM =~ /mswin|mingw/
13
+ Encoding::UTF_8
14
+ else
15
+ Encoding::default_external
16
+ end
10
17
  end
11
18
 
12
19
  def self.win?
13
20
  false
14
21
  end
15
22
 
16
- RAW_KEYSTROKE_CONFIG = {}
23
+ def self.set_default_key_bindings(_)
24
+ end
17
25
 
18
26
  @@buf = []
19
27