reline 0.0.4

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: 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'