reline 0.1.3

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