reline 0.1.3

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d6e100afbceacfa4a270221c7e5158f211dc9972efbbec251108661a380d43b1
4
+ data.tar.gz: 051ef05dac8d446be2b0268202da3762d702287650dc05a3041aa7910f481624
5
+ SHA512:
6
+ metadata.gz: '0068601561915d76b2ce265c7de49252941dbe1e57464db9b08876dfd49da6fc12c3821d90d8240b4f64728a4a55a469726233689fa077ef7296796495025295'
7
+ data.tar.gz: 4385616c29cba0596c84d98219d658361cae3dc8c9427e8460d1703972995a9adcb242ab252c30fe2abcf712d2d824a4cb41691b44e241a9d711a89da3e0d62d
data/BSDL ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
data/COPYING ADDED
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the
3
+ 2-clause BSDL (see the file BSDL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a) distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
@@ -0,0 +1,9 @@
1
+ [![Build Status](https://travis-ci.com/ruby/reline.svg?branch=master)](https://travis-ci.com/ruby/reline)
2
+
3
+ # Reline
4
+
5
+ Reline is compatible with the API of Ruby's stdlib 'readline', GNU Readline and Editline by pure Ruby implementation.
6
+
7
+ ## License
8
+
9
+ The gem is available as open source under the terms of the [Ruby License](https://www.ruby-lang.org/en/about/license.txt).
@@ -0,0 +1,431 @@
1
+ require 'io/console'
2
+ require 'timeout'
3
+ require 'forwardable'
4
+ require 'reline/version'
5
+ require 'reline/config'
6
+ require 'reline/key_actor'
7
+ require 'reline/key_stroke'
8
+ require 'reline/line_editor'
9
+ require 'reline/history'
10
+
11
+ module Reline
12
+ FILENAME_COMPLETION_PROC = nil
13
+ USERNAME_COMPLETION_PROC = nil
14
+
15
+ Key = Struct.new('Key', :char, :combined_char, :with_meta)
16
+ CursorPos = Struct.new(:x, :y)
17
+
18
+ class Core
19
+ ATTR_READER_NAMES = %i(
20
+ completion_append_character
21
+ basic_word_break_characters
22
+ completer_word_break_characters
23
+ basic_quote_characters
24
+ completer_quote_characters
25
+ filename_quote_characters
26
+ special_prefixes
27
+ completion_proc
28
+ output_modifier_proc
29
+ prompt_proc
30
+ auto_indent_proc
31
+ pre_input_hook
32
+ dig_perfect_match_proc
33
+ ).each(&method(:attr_reader))
34
+
35
+ attr_accessor :config
36
+ attr_accessor :key_stroke
37
+ attr_accessor :line_editor
38
+ attr_accessor :ambiguous_width
39
+ attr_accessor :last_incremental_search
40
+ attr_reader :output
41
+
42
+ def initialize
43
+ self.output = STDOUT
44
+ yield self
45
+ @completion_quote_character = nil
46
+ end
47
+
48
+ def encoding
49
+ Reline::IOGate.encoding
50
+ end
51
+
52
+ def completion_append_character=(val)
53
+ if val.nil?
54
+ @completion_append_character = nil
55
+ elsif val.size == 1
56
+ @completion_append_character = val.encode(Reline::IOGate.encoding)
57
+ elsif val.size > 1
58
+ @completion_append_character = val[0].encode(Reline::IOGate.encoding)
59
+ else
60
+ @completion_append_character = nil
61
+ end
62
+ end
63
+
64
+ def basic_word_break_characters=(v)
65
+ @basic_word_break_characters = v.encode(Reline::IOGate.encoding)
66
+ end
67
+
68
+ def completer_word_break_characters=(v)
69
+ @completer_word_break_characters = v.encode(Reline::IOGate.encoding)
70
+ end
71
+
72
+ def basic_quote_characters=(v)
73
+ @basic_quote_characters = v.encode(Reline::IOGate.encoding)
74
+ end
75
+
76
+ def completer_quote_characters=(v)
77
+ @completer_quote_characters = v.encode(Reline::IOGate.encoding)
78
+ end
79
+
80
+ def filename_quote_characters=(v)
81
+ @filename_quote_characters = v.encode(Reline::IOGate.encoding)
82
+ end
83
+
84
+ def special_prefixes=(v)
85
+ @special_prefixes = v.encode(Reline::IOGate.encoding)
86
+ end
87
+
88
+ def completion_case_fold=(v)
89
+ @config.completion_ignore_case = v
90
+ end
91
+
92
+ def completion_case_fold
93
+ @config.completion_ignore_case
94
+ end
95
+
96
+ def completion_quote_character
97
+ @completion_quote_character
98
+ end
99
+
100
+ def completion_proc=(p)
101
+ raise ArgumentError unless p.respond_to?(:call)
102
+ @completion_proc = p
103
+ end
104
+
105
+ def output_modifier_proc=(p)
106
+ raise ArgumentError unless p.respond_to?(:call)
107
+ @output_modifier_proc = p
108
+ end
109
+
110
+ def prompt_proc=(p)
111
+ raise ArgumentError unless p.respond_to?(:call)
112
+ @prompt_proc = p
113
+ end
114
+
115
+ def auto_indent_proc=(p)
116
+ raise ArgumentError unless p.respond_to?(:call)
117
+ @auto_indent_proc = p
118
+ end
119
+
120
+ def pre_input_hook=(p)
121
+ @pre_input_hook = p
122
+ end
123
+
124
+ def dig_perfect_match_proc=(p)
125
+ raise ArgumentError unless p.respond_to?(:call)
126
+ @dig_perfect_match_proc = p
127
+ end
128
+
129
+ def input=(val)
130
+ raise TypeError unless val.respond_to?(:getc) or val.nil?
131
+ if val.respond_to?(:getc)
132
+ if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
133
+ Reline::ANSI.input = val
134
+ elsif Reline::IOGate == Reline::GeneralIO
135
+ Reline::GeneralIO.input = val
136
+ end
137
+ end
138
+ end
139
+
140
+ def output=(val)
141
+ raise TypeError unless val.respond_to?(:write) or val.nil?
142
+ @output = val
143
+ if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
144
+ Reline::ANSI.output = val
145
+ end
146
+ end
147
+
148
+ def vi_editing_mode
149
+ config.editing_mode = :vi_insert
150
+ nil
151
+ end
152
+
153
+ def emacs_editing_mode
154
+ config.editing_mode = :emacs
155
+ nil
156
+ end
157
+
158
+ def vi_editing_mode?
159
+ config.editing_mode_is?(:vi_insert, :vi_command)
160
+ end
161
+
162
+ def emacs_editing_mode?
163
+ config.editing_mode_is?(:emacs)
164
+ end
165
+
166
+ def get_screen_size
167
+ Reline::IOGate.get_screen_size
168
+ end
169
+
170
+ def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
171
+ unless confirm_multiline_termination
172
+ raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
173
+ end
174
+ inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
175
+
176
+ whole_buffer = line_editor.whole_buffer.dup
177
+ whole_buffer.taint if RUBY_VERSION < '2.7'
178
+ if add_hist and whole_buffer and whole_buffer.chomp.size > 0
179
+ Reline::HISTORY << whole_buffer
180
+ end
181
+
182
+ line_editor.reset_line if line_editor.whole_buffer.nil?
183
+ whole_buffer
184
+ end
185
+
186
+ def readline(prompt = '', add_hist = false)
187
+ inner_readline(prompt, add_hist, false)
188
+
189
+ line = line_editor.line.dup
190
+ line.taint if RUBY_VERSION < '2.7'
191
+ if add_hist and line and line.chomp.size > 0
192
+ Reline::HISTORY << line.chomp
193
+ end
194
+
195
+ line_editor.reset_line if line_editor.line.nil?
196
+ line
197
+ end
198
+
199
+ private def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
200
+ if ENV['RELINE_STDERR_TTY']
201
+ $stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
202
+ $stderr.sync = true
203
+ $stderr.puts "Reline is used by #{Process.pid}"
204
+ end
205
+ otio = Reline::IOGate.prep
206
+
207
+ may_req_ambiguous_char_width
208
+ line_editor.reset(prompt, encoding: Reline::IOGate.encoding)
209
+ if multiline
210
+ line_editor.multiline_on
211
+ if block_given?
212
+ line_editor.confirm_multiline_termination_proc = confirm_multiline_termination
213
+ end
214
+ else
215
+ line_editor.multiline_off
216
+ end
217
+ line_editor.output = output
218
+ line_editor.completion_proc = completion_proc
219
+ line_editor.completion_append_character = completion_append_character
220
+ line_editor.output_modifier_proc = output_modifier_proc
221
+ line_editor.prompt_proc = prompt_proc
222
+ line_editor.auto_indent_proc = auto_indent_proc
223
+ line_editor.dig_perfect_match_proc = dig_perfect_match_proc
224
+ line_editor.pre_input_hook = pre_input_hook
225
+ line_editor.rerender
226
+
227
+ unless config.test_mode
228
+ config.read
229
+ config.reset_default_key_bindings
230
+ Reline::IOGate::RAW_KEYSTROKE_CONFIG.each_pair do |key, func|
231
+ config.add_default_key_binding(key, func)
232
+ end
233
+ end
234
+
235
+ begin
236
+ loop do
237
+ read_io(config.keyseq_timeout) { |inputs|
238
+ inputs.each { |c|
239
+ line_editor.input_key(c)
240
+ line_editor.rerender
241
+ }
242
+ }
243
+ break if line_editor.finished?
244
+ end
245
+ Reline::IOGate.move_cursor_column(0)
246
+ rescue StandardError => e
247
+ line_editor.finalize
248
+ Reline::IOGate.deprep(otio)
249
+ raise e
250
+ end
251
+
252
+ line_editor.finalize
253
+ Reline::IOGate.deprep(otio)
254
+ end
255
+
256
+ # Keystrokes of GNU Readline will timeout it with the specification of
257
+ # "keyseq-timeout" when waiting for the 2nd character after the 1st one.
258
+ # If the 2nd character comes after 1st ESC without timeout it has a
259
+ # meta-property of meta-key to discriminate modified key with meta-key
260
+ # from multibyte characters that come with 8th bit on.
261
+ #
262
+ # GNU Readline will wait for the 2nd character with "keyseq-timeout"
263
+ # milli-seconds but wait forever after 3rd characters.
264
+ private def read_io(keyseq_timeout, &block)
265
+ buffer = []
266
+ loop do
267
+ c = Reline::IOGate.getc
268
+ buffer << c
269
+ result = key_stroke.match_status(buffer)
270
+ case result
271
+ when :matched
272
+ expanded = key_stroke.expand(buffer).map{ |expanded_c|
273
+ Reline::Key.new(expanded_c, expanded_c, false)
274
+ }
275
+ block.(expanded)
276
+ break
277
+ when :matching
278
+ if buffer.size == 1
279
+ begin
280
+ succ_c = nil
281
+ Timeout.timeout(keyseq_timeout / 1000.0) {
282
+ succ_c = Reline::IOGate.getc
283
+ }
284
+ rescue Timeout::Error # cancel matching only when first byte
285
+ block.([Reline::Key.new(c, c, false)])
286
+ break
287
+ else
288
+ if key_stroke.match_status(buffer.dup.push(succ_c)) == :unmatched
289
+ if c == "\e".ord
290
+ block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
291
+ else
292
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
293
+ end
294
+ break
295
+ else
296
+ Reline::IOGate.ungetc(succ_c)
297
+ end
298
+ end
299
+ end
300
+ when :unmatched
301
+ if buffer.size == 1 and c == "\e".ord
302
+ read_escaped_key(keyseq_timeout, c, block)
303
+ else
304
+ expanded = buffer.map{ |expanded_c|
305
+ Reline::Key.new(expanded_c, expanded_c, false)
306
+ }
307
+ block.(expanded)
308
+ end
309
+ break
310
+ end
311
+ end
312
+ end
313
+
314
+ private def read_escaped_key(keyseq_timeout, c, block)
315
+ begin
316
+ escaped_c = nil
317
+ Timeout.timeout(keyseq_timeout / 1000.0) {
318
+ escaped_c = Reline::IOGate.getc
319
+ }
320
+ rescue Timeout::Error # independent ESC
321
+ block.([Reline::Key.new(c, c, false)])
322
+ else
323
+ if escaped_c.nil?
324
+ block.([Reline::Key.new(c, c, false)])
325
+ elsif escaped_c >= 128 # maybe, first byte of multi byte
326
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
327
+ elsif escaped_c == "\e".ord # escape twice
328
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
329
+ else
330
+ block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
331
+ end
332
+ end
333
+ end
334
+
335
+ private def may_req_ambiguous_char_width
336
+ @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
337
+ return if ambiguous_width
338
+ Reline::IOGate.move_cursor_column(0)
339
+ output.write "\u{25bd}"
340
+ @ambiguous_width = Reline::IOGate.cursor_pos.x
341
+ Reline::IOGate.move_cursor_column(0)
342
+ Reline::IOGate.erase_after_cursor
343
+ end
344
+ end
345
+
346
+ extend Forwardable
347
+ extend SingleForwardable
348
+
349
+ #--------------------------------------------------------
350
+ # Documented API
351
+ #--------------------------------------------------------
352
+
353
+ (Core::ATTR_READER_NAMES).each { |name|
354
+ def_single_delegators :core, "#{name}", "#{name}="
355
+ }
356
+ def_single_delegators :core, :input=, :output=
357
+ def_single_delegators :core, :vi_editing_mode, :emacs_editing_mode
358
+ def_single_delegators :core, :readline
359
+ def_single_delegators :core, :completion_case_fold, :completion_case_fold=
360
+ def_single_delegators :core, :completion_quote_character
361
+ def_instance_delegators self, :readline
362
+ private :readline
363
+
364
+
365
+ #--------------------------------------------------------
366
+ # Undocumented API
367
+ #--------------------------------------------------------
368
+
369
+ # Testable in original
370
+ def_single_delegators :core, :get_screen_size
371
+ def_single_delegators :line_editor, :eof?
372
+ def_instance_delegators self, :eof?
373
+ def_single_delegators :line_editor, :delete_text
374
+ def_single_delegator :line_editor, :line, :line_buffer
375
+ def_single_delegator :line_editor, :byte_pointer, :point
376
+ def_single_delegator :line_editor, :byte_pointer=, :point=
377
+
378
+ def self.insert_text(*args, &block)
379
+ line_editor.insert_text(*args, &block)
380
+ self
381
+ end
382
+
383
+ # Untestable in original
384
+ def_single_delegator :line_editor, :rerender, :redisplay
385
+ def_single_delegators :core, :vi_editing_mode?, :emacs_editing_mode?
386
+ def_single_delegators :core, :ambiguous_width
387
+ def_single_delegators :core, :last_incremental_search
388
+ def_single_delegators :core, :last_incremental_search=
389
+
390
+ def_single_delegators :core, :readmultiline
391
+ def_instance_delegators self, :readmultiline
392
+ private :readmultiline
393
+
394
+ def self.encoding_system_needs
395
+ self.core.encoding
396
+ end
397
+
398
+ def self.core
399
+ @core ||= Core.new { |core|
400
+ core.config = Reline::Config.new
401
+ core.key_stroke = Reline::KeyStroke.new(core.config)
402
+ core.line_editor = Reline::LineEditor.new(core.config, Reline::IOGate.encoding)
403
+
404
+ core.basic_word_break_characters = " \t\n`><=;|&{("
405
+ core.completer_word_break_characters = " \t\n`><=;|&{("
406
+ core.basic_quote_characters = '"\''
407
+ core.completer_quote_characters = '"\''
408
+ core.filename_quote_characters = ""
409
+ core.special_prefixes = ""
410
+ }
411
+ end
412
+
413
+ def self.line_editor
414
+ core.line_editor
415
+ end
416
+ end
417
+
418
+ if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
419
+ require 'reline/windows'
420
+ if Reline::Windows.msys_tty?
421
+ require 'reline/ansi'
422
+ Reline::IOGate = Reline::ANSI
423
+ else
424
+ Reline::IOGate = Reline::Windows
425
+ end
426
+ else
427
+ require 'reline/ansi'
428
+ Reline::IOGate = Reline::ANSI
429
+ end
430
+ Reline::HISTORY = Reline::History.new(Reline.core.config)
431
+ require 'reline/general_io'