reline 0.2.3 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
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