reline 0.0.4

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: 5871c5fe137b41dce9b91a8c3507c871c00440393af055c1d546a17e2613fc1b
4
+ data.tar.gz: d6add41c6538d3cd07b813eab3b8998f57759209f821bf7950bf1a69d1f33966
5
+ SHA512:
6
+ metadata.gz: 105ed33c513bc997c46f6167da553f098f372272fe026b24afd2b472776dd840484afc0f284cd9d973b3db35940d84d99b4110b3d135d16944269c306ba33003
7
+ data.tar.gz: d28e6fe88b8a16022febeba31ead5a4e533f2a50fa65ed93328f35e5c0b2634b01b0e0b35efa278f6bbfd96b4fd42adee2d8e15e3f9d3092de5da2b61b1ef550
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,402 @@
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
+ if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
20
+ IS_WINDOWS = true
21
+ else
22
+ IS_WINDOWS = false
23
+ end
24
+
25
+ ATTR_READER_NAMES = %i(
26
+ completion_append_character
27
+ basic_word_break_characters
28
+ completer_word_break_characters
29
+ basic_quote_characters
30
+ completer_quote_characters
31
+ filename_quote_characters
32
+ special_prefixes
33
+ completion_proc
34
+ output_modifier_proc
35
+ prompt_proc
36
+ auto_indent_proc
37
+ pre_input_hook
38
+ dig_perfect_match_proc
39
+ ).each(&method(:attr_reader))
40
+
41
+ ATTR_ACCESSOR_NAMES = %i(
42
+ completion_case_fold
43
+ ).each(&method(:attr_accessor))
44
+
45
+ attr_accessor :config
46
+ attr_accessor :key_stroke
47
+ attr_accessor :line_editor
48
+ attr_accessor :ambiguous_width
49
+ attr_reader :output
50
+
51
+ def initialize
52
+ self.output = STDOUT
53
+ yield self
54
+ end
55
+
56
+ def completion_append_character=(val)
57
+ if val.nil?
58
+ @completion_append_character = nil
59
+ elsif val.size == 1
60
+ @completion_append_character = val.encode(Encoding::default_external)
61
+ elsif val.size > 1
62
+ @completion_append_character = val[0].encode(Encoding::default_external)
63
+ else
64
+ @completion_append_character = nil
65
+ end
66
+ end
67
+
68
+ def basic_word_break_characters=(v)
69
+ @basic_word_break_characters = v.encode(Encoding::default_external)
70
+ end
71
+
72
+ def completer_word_break_characters=(v)
73
+ @completer_word_break_characters = v.encode(Encoding::default_external)
74
+ end
75
+
76
+ def basic_quote_characters=(v)
77
+ @basic_quote_characters = v.encode(Encoding::default_external)
78
+ end
79
+
80
+ def completer_quote_characters=(v)
81
+ @completer_quote_characters = v.encode(Encoding::default_external)
82
+ end
83
+
84
+ def filename_quote_characters=(v)
85
+ @filename_quote_characters = v.encode(Encoding::default_external)
86
+ end
87
+
88
+ def special_prefixes=(v)
89
+ @special_prefixes = v.encode(Encoding::default_external)
90
+ end
91
+
92
+ def completion_proc=(p)
93
+ raise ArgumentError unless p.is_a?(Proc)
94
+ @completion_proc = p
95
+ end
96
+
97
+ def output_modifier_proc=(p)
98
+ raise ArgumentError unless p.is_a?(Proc)
99
+ @output_modifier_proc = p
100
+ end
101
+
102
+ def prompt_proc=(p)
103
+ raise ArgumentError unless p.is_a?(Proc)
104
+ @prompt_proc = p
105
+ end
106
+
107
+ def auto_indent_proc=(p)
108
+ raise ArgumentError unless p.is_a?(Proc)
109
+ @auto_indent_proc = p
110
+ end
111
+
112
+ def pre_input_hook=(p)
113
+ @pre_input_hook = p
114
+ end
115
+
116
+ def dig_perfect_match_proc=(p)
117
+ raise ArgumentError unless p.is_a?(Proc)
118
+ @dig_perfect_match_proc = p
119
+ end
120
+
121
+ def input=(val)
122
+ raise TypeError unless val.respond_to?(:getc) or val.nil?
123
+ if val.respond_to?(:getc)
124
+ if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
125
+ Reline::ANSI.input = val
126
+ elsif Reline::IOGate == Reline::GeneralIO
127
+ Reline::GeneralIO.input = val
128
+ end
129
+ end
130
+ end
131
+
132
+ def output=(val)
133
+ raise TypeError unless val.respond_to?(:write) or val.nil?
134
+ @output = val
135
+ if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
136
+ Reline::ANSI.output = val
137
+ end
138
+ end
139
+
140
+ def vi_editing_mode
141
+ config.editing_mode = :vi_insert
142
+ nil
143
+ end
144
+
145
+ def emacs_editing_mode
146
+ config.editing_mode = :emacs
147
+ nil
148
+ end
149
+
150
+ def vi_editing_mode?
151
+ config.editing_mode_is?(:vi_insert, :vi_command)
152
+ end
153
+
154
+ def emacs_editing_mode?
155
+ config.editing_mode_is?(:emacs)
156
+ end
157
+
158
+ def get_screen_size
159
+ Reline::IOGate.get_screen_size
160
+ end
161
+
162
+ def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
163
+ unless confirm_multiline_termination
164
+ raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
165
+ end
166
+ inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
167
+
168
+ whole_buffer = line_editor.whole_buffer.dup
169
+ whole_buffer.taint
170
+ if add_hist and whole_buffer and whole_buffer.chomp.size > 0
171
+ Reline::HISTORY << whole_buffer
172
+ end
173
+
174
+ line_editor.reset_line if line_editor.whole_buffer.nil?
175
+ whole_buffer
176
+ end
177
+
178
+ def readline(prompt = '', add_hist = false)
179
+ inner_readline(prompt, add_hist, false)
180
+
181
+ line = line_editor.line.dup
182
+ line.taint
183
+ if add_hist and line and line.chomp.size > 0
184
+ Reline::HISTORY << line.chomp
185
+ end
186
+
187
+ line_editor.reset_line if line_editor.line.nil?
188
+ line
189
+ end
190
+
191
+ private def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
192
+ if ENV['RELINE_STDERR_TTY']
193
+ $stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
194
+ $stderr.sync = true
195
+ $stderr.puts "Reline is used by #{Process.pid}"
196
+ end
197
+ otio = Reline::IOGate.prep
198
+
199
+ may_req_ambiguous_char_width
200
+ line_editor.reset(prompt)
201
+ if multiline
202
+ line_editor.multiline_on
203
+ if block_given?
204
+ line_editor.confirm_multiline_termination_proc = confirm_multiline_termination
205
+ end
206
+ else
207
+ line_editor.multiline_off
208
+ end
209
+ line_editor.output = output
210
+ line_editor.completion_proc = completion_proc
211
+ line_editor.output_modifier_proc = output_modifier_proc
212
+ line_editor.prompt_proc = prompt_proc
213
+ line_editor.auto_indent_proc = auto_indent_proc
214
+ line_editor.dig_perfect_match_proc = dig_perfect_match_proc
215
+ line_editor.pre_input_hook = pre_input_hook
216
+ line_editor.rerender
217
+
218
+ unless config.test_mode
219
+ config.read
220
+ config.reset_default_key_bindings
221
+ Reline::IOGate::RAW_KEYSTROKE_CONFIG.each_pair do |key, func|
222
+ config.add_default_key_binding(key, func)
223
+ end
224
+ end
225
+
226
+ begin
227
+ loop do
228
+ read_io(config.keyseq_timeout) { |inputs|
229
+ inputs.each { |c|
230
+ line_editor.input_key(c)
231
+ line_editor.rerender
232
+ }
233
+ }
234
+ break if line_editor.finished?
235
+ end
236
+ Reline::IOGate.move_cursor_column(0)
237
+ rescue StandardError => e
238
+ line_editor.finalize
239
+ Reline::IOGate.deprep(otio)
240
+ raise e
241
+ end
242
+
243
+ line_editor.finalize
244
+ Reline::IOGate.deprep(otio)
245
+ end
246
+
247
+ # Keystrokes of GNU Readline will timeout it with the specification of
248
+ # "keyseq-timeout" when waiting for the 2nd character after the 1st one.
249
+ # If the 2nd character comes after 1st ESC without timeout it has a
250
+ # meta-property of meta-key to discriminate modified key with meta-key
251
+ # from multibyte characters that come with 8th bit on.
252
+ #
253
+ # GNU Readline will wait for the 2nd character with "keyseq-timeout"
254
+ # milli-seconds but wait forever after 3rd characters.
255
+ private def read_io(keyseq_timeout, &block)
256
+ buffer = []
257
+ loop do
258
+ c = Reline::IOGate.getc
259
+ buffer << c
260
+ result = key_stroke.match_status(buffer)
261
+ case result
262
+ when :matched
263
+ block.(key_stroke.expand(buffer).map{ |c| Reline::Key.new(c, c, false) })
264
+ break
265
+ when :matching
266
+ if buffer.size == 1
267
+ begin
268
+ succ_c = nil
269
+ Timeout.timeout(keyseq_timeout / 1000.0) {
270
+ succ_c = Reline::IOGate.getc
271
+ }
272
+ rescue Timeout::Error # cancel matching only when first byte
273
+ block.([Reline::Key.new(c, c, false)])
274
+ break
275
+ else
276
+ if key_stroke.match_status(buffer.dup.push(succ_c)) == :unmatched
277
+ if c == "\e".ord
278
+ block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
279
+ else
280
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
281
+ end
282
+ break
283
+ else
284
+ Reline::IOGate.ungetc(succ_c)
285
+ end
286
+ end
287
+ end
288
+ when :unmatched
289
+ if buffer.size == 1 and c == "\e".ord
290
+ read_escaped_key(keyseq_timeout, c, block)
291
+ else
292
+ block.(buffer.map{ |c| Reline::Key.new(c, c, false) })
293
+ end
294
+ break
295
+ end
296
+ end
297
+ end
298
+
299
+ private def read_escaped_key(keyseq_timeout, c, block)
300
+ begin
301
+ escaped_c = nil
302
+ Timeout.timeout(keyseq_timeout / 1000.0) {
303
+ escaped_c = Reline::IOGate.getc
304
+ }
305
+ rescue Timeout::Error # independent ESC
306
+ block.([Reline::Key.new(c, c, false)])
307
+ else
308
+ if escaped_c.nil?
309
+ block.([Reline::Key.new(c, c, false)])
310
+ elsif escaped_c >= 128 # maybe, first byte of multi byte
311
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
312
+ elsif escaped_c == "\e".ord # escape twice
313
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
314
+ else
315
+ block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
316
+ end
317
+ end
318
+ end
319
+
320
+ private def may_req_ambiguous_char_width
321
+ @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
322
+ return if @ambiguous_width
323
+ Reline::IOGate.move_cursor_column(0)
324
+ print "\u{25bd}"
325
+ @ambiguous_width = Reline::IOGate.cursor_pos.x
326
+ Reline::IOGate.move_cursor_column(0)
327
+ Reline::IOGate.erase_after_cursor
328
+ end
329
+ end
330
+
331
+ extend Forwardable
332
+ extend SingleForwardable
333
+
334
+ #--------------------------------------------------------
335
+ # Documented API
336
+ #--------------------------------------------------------
337
+
338
+ (Core::ATTR_READER_NAMES + Core::ATTR_ACCESSOR_NAMES).each { |name|
339
+ def_single_delegators :core, "#{name}", "#{name}="
340
+ }
341
+ def_single_delegators :core, :input=, :output=
342
+ def_single_delegators :core, :vi_editing_mode, :emacs_editing_mode
343
+ def_single_delegators :core, :readline
344
+ def_instance_delegators self, :readline
345
+
346
+
347
+ #--------------------------------------------------------
348
+ # Undocumented API
349
+ #--------------------------------------------------------
350
+
351
+ # Testable in original
352
+ def_single_delegators :core, :get_screen_size
353
+ def_single_delegators :line_editor, :eof?
354
+ def_instance_delegators self, :eof?
355
+ def_single_delegators :line_editor, :delete_text
356
+ def_single_delegator :line_editor, :line, :line_buffer
357
+ def_single_delegator :line_editor, :byte_pointer, :point
358
+ def_single_delegator :line_editor, :byte_pointer=, :point=
359
+
360
+ def self.insert_text(*args, &block)
361
+ line_editor.insert_text(*args, &block)
362
+ self
363
+ end
364
+
365
+ # Untestable in original
366
+ def_single_delegator :line_editor, :rerender, :redisplay
367
+ def_single_delegators :core, :vi_editing_mode?, :emacs_editing_mode?
368
+ def_single_delegators :core, :ambiguous_width
369
+
370
+ def_single_delegators :core, :readmultiline
371
+ def_instance_delegators self, :readmultiline
372
+
373
+ def self.core
374
+ @core ||= Core.new { |core|
375
+ core.config = Reline::Config.new
376
+ core.key_stroke = Reline::KeyStroke.new(core.config)
377
+ core.line_editor = Reline::LineEditor.new(core.config)
378
+
379
+ core.basic_word_break_characters = " \t\n`><=;|&{("
380
+ core.completer_word_break_characters = " \t\n`><=;|&{("
381
+ core.basic_quote_characters = '"\''
382
+ core.completer_quote_characters = '"\''
383
+ core.filename_quote_characters = ""
384
+ core.special_prefixes = ""
385
+ }
386
+ end
387
+
388
+ def self.line_editor
389
+ core.line_editor
390
+ end
391
+
392
+ HISTORY = History.new(core.config)
393
+ end
394
+
395
+ if Reline::Core::IS_WINDOWS
396
+ require 'reline/windows'
397
+ Reline::IOGate = Reline::Windows
398
+ else
399
+ require 'reline/ansi'
400
+ Reline::IOGate = Reline::ANSI
401
+ end
402
+ require 'reline/general_io'