reline 0.0.2 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/reline.rb +28 -20
- data/lib/reline/ansi.rb +22 -11
- data/lib/reline/general_io.rb +1 -1
- data/lib/reline/key_actor/vi_command.rb +1 -1
- data/lib/reline/key_actor/vi_insert.rb +1 -1
- data/lib/reline/key_stroke.rb +1 -1
- data/lib/reline/line_editor.rb +133 -96
- data/lib/reline/version.rb +1 -1
- data/lib/reline/windows.rb +86 -62
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 985d3ce68260542cce79b3d3291c29ca30ee82250e50089c2de7bb16f60d755d
|
4
|
+
data.tar.gz: d3444d9e894a66fd2a0e5be4fddd5d36b9b254f0aaff7ed1d590fec26c13b3f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a5651134aeb6d0eba7e33b4fa6e85c2ac43677432a7b94e8aa24d1c9f05326126c81669aa297f9cb03bea7f92c2ee8600364205c8a8eafa7c6185441472f9d1
|
7
|
+
data.tar.gz: 63cc8b0b0b936e8ac1a490c9a1c849631b2c4c33c520eb2dd666b9b93b641417f3640542067de4f64ff2e28fd4dd883ed3821c7704bb82a64485ee52d5273c3b
|
data/lib/reline.rb
CHANGED
@@ -16,12 +16,6 @@ module Reline
|
|
16
16
|
CursorPos = Struct.new(:x, :y)
|
17
17
|
|
18
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
19
|
ATTR_READER_NAMES = %i(
|
26
20
|
completion_append_character
|
27
21
|
basic_word_break_characters
|
@@ -90,22 +84,22 @@ module Reline
|
|
90
84
|
end
|
91
85
|
|
92
86
|
def completion_proc=(p)
|
93
|
-
raise ArgumentError unless p.
|
87
|
+
raise ArgumentError unless p.respond_to?(:call)
|
94
88
|
@completion_proc = p
|
95
89
|
end
|
96
90
|
|
97
91
|
def output_modifier_proc=(p)
|
98
|
-
raise ArgumentError unless p.
|
92
|
+
raise ArgumentError unless p.respond_to?(:call)
|
99
93
|
@output_modifier_proc = p
|
100
94
|
end
|
101
95
|
|
102
96
|
def prompt_proc=(p)
|
103
|
-
raise ArgumentError unless p.
|
97
|
+
raise ArgumentError unless p.respond_to?(:call)
|
104
98
|
@prompt_proc = p
|
105
99
|
end
|
106
100
|
|
107
101
|
def auto_indent_proc=(p)
|
108
|
-
raise ArgumentError unless p.
|
102
|
+
raise ArgumentError unless p.respond_to?(:call)
|
109
103
|
@auto_indent_proc = p
|
110
104
|
end
|
111
105
|
|
@@ -114,7 +108,7 @@ module Reline
|
|
114
108
|
end
|
115
109
|
|
116
110
|
def dig_perfect_match_proc=(p)
|
117
|
-
raise ArgumentError unless p.
|
111
|
+
raise ArgumentError unless p.respond_to?(:call)
|
118
112
|
@dig_perfect_match_proc = p
|
119
113
|
end
|
120
114
|
|
@@ -166,7 +160,7 @@ module Reline
|
|
166
160
|
inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
|
167
161
|
|
168
162
|
whole_buffer = line_editor.whole_buffer.dup
|
169
|
-
whole_buffer.taint
|
163
|
+
whole_buffer.taint if RUBY_VERSION < '2.7'
|
170
164
|
if add_hist and whole_buffer and whole_buffer.chomp.size > 0
|
171
165
|
Reline::HISTORY << whole_buffer
|
172
166
|
end
|
@@ -179,7 +173,7 @@ module Reline
|
|
179
173
|
inner_readline(prompt, add_hist, false)
|
180
174
|
|
181
175
|
line = line_editor.line.dup
|
182
|
-
line.taint
|
176
|
+
line.taint if RUBY_VERSION < '2.7'
|
183
177
|
if add_hist and line and line.chomp.size > 0
|
184
178
|
Reline::HISTORY << line.chomp
|
185
179
|
end
|
@@ -260,7 +254,10 @@ module Reline
|
|
260
254
|
result = key_stroke.match_status(buffer)
|
261
255
|
case result
|
262
256
|
when :matched
|
263
|
-
|
257
|
+
expanded = key_stroke.expand(buffer).map{ |expanded_c|
|
258
|
+
Reline::Key.new(expanded_c, expanded_c, false)
|
259
|
+
}
|
260
|
+
block.(expanded)
|
264
261
|
break
|
265
262
|
when :matching
|
266
263
|
if buffer.size == 1
|
@@ -287,16 +284,19 @@ module Reline
|
|
287
284
|
end
|
288
285
|
when :unmatched
|
289
286
|
if buffer.size == 1 and c == "\e".ord
|
290
|
-
read_escaped_key(keyseq_timeout,
|
287
|
+
read_escaped_key(keyseq_timeout, c, block)
|
291
288
|
else
|
292
|
-
|
289
|
+
expanded = buffer.map{ |expanded_c|
|
290
|
+
Reline::Key.new(expanded_c, expanded_c, false)
|
291
|
+
}
|
292
|
+
block.(expanded)
|
293
293
|
end
|
294
294
|
break
|
295
295
|
end
|
296
296
|
end
|
297
297
|
end
|
298
298
|
|
299
|
-
private def read_escaped_key(keyseq_timeout,
|
299
|
+
private def read_escaped_key(keyseq_timeout, c, block)
|
300
300
|
begin
|
301
301
|
escaped_c = nil
|
302
302
|
Timeout.timeout(keyseq_timeout / 1000.0) {
|
@@ -319,7 +319,7 @@ module Reline
|
|
319
319
|
|
320
320
|
private def may_req_ambiguous_char_width
|
321
321
|
@ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or STDOUT.is_a?(File)
|
322
|
-
return if
|
322
|
+
return if ambiguous_width
|
323
323
|
Reline::IOGate.move_cursor_column(0)
|
324
324
|
print "\u{25bd}"
|
325
325
|
@ambiguous_width = Reline::IOGate.cursor_pos.x
|
@@ -342,6 +342,7 @@ module Reline
|
|
342
342
|
def_single_delegators :core, :vi_editing_mode, :emacs_editing_mode
|
343
343
|
def_single_delegators :core, :readline
|
344
344
|
def_instance_delegators self, :readline
|
345
|
+
private :readline
|
345
346
|
|
346
347
|
|
347
348
|
#--------------------------------------------------------
|
@@ -369,6 +370,7 @@ module Reline
|
|
369
370
|
|
370
371
|
def_single_delegators :core, :readmultiline
|
371
372
|
def_instance_delegators self, :readmultiline
|
373
|
+
private :readmultiline
|
372
374
|
|
373
375
|
def self.core
|
374
376
|
@core ||= Core.new { |core|
|
@@ -392,9 +394,15 @@ module Reline
|
|
392
394
|
HISTORY = History.new(core.config)
|
393
395
|
end
|
394
396
|
|
395
|
-
if
|
397
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
396
398
|
require 'reline/windows'
|
397
|
-
Reline::
|
399
|
+
if Reline::Windows.get_screen_size == [0, 0]
|
400
|
+
# Maybe Mintty on Cygwin
|
401
|
+
require 'reline/ansi'
|
402
|
+
Reline::IOGate = Reline::ANSI
|
403
|
+
else
|
404
|
+
Reline::IOGate = Reline::Windows
|
405
|
+
end
|
398
406
|
else
|
399
407
|
require 'reline/ansi'
|
400
408
|
Reline::IOGate = Reline::ANSI
|
data/lib/reline/ansi.rb
CHANGED
@@ -7,7 +7,11 @@ class Reline::ANSI
|
|
7
7
|
[27, 91, 51, 126] => :key_delete, # Del
|
8
8
|
[27, 91, 49, 126] => :ed_move_to_beg, # Home
|
9
9
|
[27, 91, 52, 126] => :ed_move_to_end, # End
|
10
|
-
|
10
|
+
[27, 91, 72] => :ed_move_to_beg, # Home
|
11
|
+
[27, 91, 70] => :ed_move_to_end, # End
|
12
|
+
[27, 32] => :em_set_mark, # M-<space>
|
13
|
+
[24, 24] => :em_exchange_mark, # C-x C-x TODO also add Windows
|
14
|
+
}
|
11
15
|
|
12
16
|
@@input = STDIN
|
13
17
|
def self.input=(val)
|
@@ -24,20 +28,22 @@ class Reline::ANSI
|
|
24
28
|
unless @@buf.empty?
|
25
29
|
return @@buf.shift
|
26
30
|
end
|
27
|
-
|
28
|
-
loop do
|
29
|
-
result = select([@@input], [], [], 0.1)
|
30
|
-
next if result.nil?
|
31
|
-
c = @@input.read(1)
|
32
|
-
break
|
33
|
-
end
|
34
|
-
c&.ord
|
31
|
+
@@input.getbyte
|
35
32
|
end
|
36
33
|
|
37
34
|
def self.ungetc(c)
|
38
35
|
@@buf.unshift(c)
|
39
36
|
end
|
40
37
|
|
38
|
+
def self.retrieve_keybuffer
|
39
|
+
result = select([@@input], [], [], 0.001)
|
40
|
+
return if result.nil?
|
41
|
+
str = @@input.read_nonblock(1024)
|
42
|
+
str.bytes.each do |c|
|
43
|
+
@@buf.push(c)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
41
47
|
def self.get_screen_size
|
42
48
|
@@input.winsize
|
43
49
|
rescue Errno::ENOTTY
|
@@ -112,12 +118,17 @@ class Reline::ANSI
|
|
112
118
|
end
|
113
119
|
|
114
120
|
def self.prep
|
121
|
+
retrieve_keybuffer
|
115
122
|
int_handle = Signal.trap('INT', 'IGNORE')
|
116
123
|
otio = `stty -g`.chomp
|
117
124
|
setting = ' -echo -icrnl cbreak'
|
118
|
-
|
125
|
+
stty = `stty -a`
|
126
|
+
if /-parenb\b/ =~ stty
|
119
127
|
setting << ' pass8'
|
120
128
|
end
|
129
|
+
if /\bdsusp *=/ =~ stty
|
130
|
+
setting << ' dsusp undef'
|
131
|
+
end
|
121
132
|
setting << ' -ixoff'
|
122
133
|
`stty #{setting}`
|
123
134
|
Signal.trap('INT', int_handle)
|
@@ -126,7 +137,7 @@ class Reline::ANSI
|
|
126
137
|
|
127
138
|
def self.deprep(otio)
|
128
139
|
int_handle = Signal.trap('INT', 'IGNORE')
|
129
|
-
|
140
|
+
system("stty #{otio}", err: File::NULL)
|
130
141
|
Signal.trap('INT', int_handle)
|
131
142
|
Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
|
132
143
|
end
|
data/lib/reline/general_io.rb
CHANGED
data/lib/reline/key_stroke.rb
CHANGED
@@ -32,7 +32,7 @@ class Reline::KeyStroke
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def expand(input)
|
35
|
-
lhs = key_mapping.keys.select { |
|
35
|
+
lhs = key_mapping.keys.select { |item| input.start_with? item }.sort_by(&:size).reverse.first
|
36
36
|
return input unless lhs
|
37
37
|
rhs = key_mapping[lhs]
|
38
38
|
|
data/lib/reline/line_editor.rb
CHANGED
@@ -60,14 +60,35 @@ class Reline::LineEditor
|
|
60
60
|
reset_variables
|
61
61
|
end
|
62
62
|
|
63
|
+
private def check_multiline_prompt(buffer, prompt)
|
64
|
+
if @vi_arg
|
65
|
+
prompt = "(arg: #{@vi_arg}) "
|
66
|
+
@rerender_all = true
|
67
|
+
elsif @searching_prompt
|
68
|
+
prompt = @searching_prompt
|
69
|
+
@rerender_all = true
|
70
|
+
else
|
71
|
+
prompt = @prompt
|
72
|
+
end
|
73
|
+
if @prompt_proc
|
74
|
+
prompt_list = @prompt_proc.(buffer)
|
75
|
+
prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
|
76
|
+
prompt = prompt_list[@line_index]
|
77
|
+
prompt_width = calculate_width(prompt, true)
|
78
|
+
[prompt, prompt_width, prompt_list]
|
79
|
+
else
|
80
|
+
prompt_width = calculate_width(prompt, true)
|
81
|
+
[prompt, prompt_width, nil]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
63
85
|
def reset(prompt = '', encoding = Encoding.default_external)
|
64
86
|
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
65
87
|
@screen_size = Reline::IOGate.get_screen_size
|
66
88
|
reset_variables(prompt, encoding)
|
67
89
|
@old_trap = Signal.trap('SIGINT') {
|
68
|
-
scroll_down(@highest_in_all - @first_line_started_from)
|
69
|
-
Reline::IOGate.move_cursor_column(0)
|
70
90
|
@old_trap.call if @old_trap.respond_to?(:call) # can also be string, ex: "DEFAULT"
|
91
|
+
raise Interrupt
|
71
92
|
}
|
72
93
|
Reline::IOGate.set_winch_handler do
|
73
94
|
@rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
|
@@ -77,28 +98,9 @@ class Reline::LineEditor
|
|
77
98
|
@rerender_all = true
|
78
99
|
rerender
|
79
100
|
else
|
80
|
-
special_prompt = nil
|
81
|
-
if @vi_arg
|
82
|
-
prompt = "(arg: #{@vi_arg}) "
|
83
|
-
prompt_width = calculate_width(prompt)
|
84
|
-
special_prompt = prompt
|
85
|
-
elsif @searching_prompt
|
86
|
-
prompt = @searching_prompt
|
87
|
-
prompt_width = calculate_width(prompt)
|
88
|
-
special_prompt = prompt
|
89
|
-
else
|
90
|
-
prompt = @prompt
|
91
|
-
prompt_width = calculate_width(prompt, true)
|
92
|
-
end
|
93
101
|
back = 0
|
94
102
|
new_buffer = whole_lines
|
95
|
-
prompt_list =
|
96
|
-
if @prompt_proc
|
97
|
-
prompt_list = @prompt_proc.(new_buffer)
|
98
|
-
prompt_list[@line_index] = special_prompt if special_prompt
|
99
|
-
prompt = prompt_list[@line_index]
|
100
|
-
prompt_width = calculate_width(prompt, true)
|
101
|
-
end
|
103
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer, prompt)
|
102
104
|
new_buffer.each_with_index do |line, index|
|
103
105
|
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
104
106
|
width = prompt_width + calculate_width(line)
|
@@ -111,9 +113,7 @@ class Reline::LineEditor
|
|
111
113
|
if @line_index.zero?
|
112
114
|
0
|
113
115
|
else
|
114
|
-
@buffer_of_lines[0..(@line_index - 1)]
|
115
|
-
result + calculate_height_by_width(prompt_width + calculate_width(line)) # TODO prompt_list
|
116
|
-
}
|
116
|
+
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list)
|
117
117
|
end
|
118
118
|
if @prompt_proc
|
119
119
|
prompt = prompt_list[@line_index]
|
@@ -138,6 +138,7 @@ class Reline::LineEditor
|
|
138
138
|
|
139
139
|
def reset_variables(prompt = '', encoding = Encoding.default_external)
|
140
140
|
@prompt = prompt
|
141
|
+
@mark_pointer = nil
|
141
142
|
@encoding = encoding
|
142
143
|
@is_multiline = false
|
143
144
|
@finished = false
|
@@ -186,6 +187,16 @@ class Reline::LineEditor
|
|
186
187
|
@is_multiline = false
|
187
188
|
end
|
188
189
|
|
190
|
+
private def calculate_height_by_lines(lines, prompt_list)
|
191
|
+
result = 0
|
192
|
+
lines.each_with_index { |line, i|
|
193
|
+
prompt = ''
|
194
|
+
prompt = prompt_list[i] if prompt_list and prompt_list[i]
|
195
|
+
result += calculate_height_by_width(calculate_width(prompt, true) + calculate_width(line))
|
196
|
+
}
|
197
|
+
result
|
198
|
+
end
|
199
|
+
|
189
200
|
private def insert_new_line(cursor_line, next_line)
|
190
201
|
@line = cursor_line
|
191
202
|
@buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding: @encoding))
|
@@ -306,36 +317,18 @@ class Reline::LineEditor
|
|
306
317
|
@menu_info.list.each do |item|
|
307
318
|
Reline::IOGate.move_cursor_column(0)
|
308
319
|
@output.print item
|
320
|
+
@output.flush
|
309
321
|
scroll_down(1)
|
310
322
|
end
|
311
323
|
scroll_down(@highest_in_all - 1)
|
312
324
|
move_cursor_up(@highest_in_all - 1 - @first_line_started_from)
|
313
325
|
@menu_info = nil
|
314
326
|
end
|
315
|
-
|
316
|
-
if @vi_arg
|
317
|
-
prompt = "(arg: #{@vi_arg}) "
|
318
|
-
prompt_width = calculate_width(prompt)
|
319
|
-
special_prompt = prompt
|
320
|
-
elsif @searching_prompt
|
321
|
-
prompt = @searching_prompt
|
322
|
-
prompt_width = calculate_width(prompt)
|
323
|
-
special_prompt = prompt
|
324
|
-
else
|
325
|
-
prompt = @prompt
|
326
|
-
prompt_width = calculate_width(prompt, true)
|
327
|
-
end
|
327
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
|
328
328
|
if @cleared
|
329
329
|
Reline::IOGate.clear_screen
|
330
330
|
@cleared = false
|
331
331
|
back = 0
|
332
|
-
prompt_list = nil
|
333
|
-
if @prompt_proc
|
334
|
-
prompt_list = @prompt_proc.(whole_lines)
|
335
|
-
prompt_list[@line_index] = special_prompt if special_prompt
|
336
|
-
prompt = prompt_list[@line_index]
|
337
|
-
prompt_width = calculate_width(prompt, true)
|
338
|
-
end
|
339
332
|
modify_lines(whole_lines).each_with_index do |line, index|
|
340
333
|
if @prompt_proc
|
341
334
|
pr = prompt_list[index]
|
@@ -361,16 +354,8 @@ class Reline::LineEditor
|
|
361
354
|
else
|
362
355
|
new_lines = whole_lines
|
363
356
|
end
|
364
|
-
prompt_list =
|
365
|
-
|
366
|
-
prompt_list = @prompt_proc.(new_lines)
|
367
|
-
prompt_list[@line_index] = special_prompt if special_prompt
|
368
|
-
prompt = prompt_list[@line_index]
|
369
|
-
prompt_width = calculate_width(prompt, true)
|
370
|
-
end
|
371
|
-
all_height = new_lines.inject(0) { |result, line|
|
372
|
-
result + calculate_height_by_width(prompt_width + calculate_width(line)) # TODO prompt_list
|
373
|
-
}
|
357
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines, prompt)
|
358
|
+
all_height = calculate_height_by_lines(new_lines, prompt_list)
|
374
359
|
diff = all_height - @highest_in_all
|
375
360
|
move_cursor_down(@highest_in_all - @first_line_started_from - @started_from - 1)
|
376
361
|
if diff > 0
|
@@ -410,9 +395,7 @@ class Reline::LineEditor
|
|
410
395
|
if @line_index.zero?
|
411
396
|
0
|
412
397
|
else
|
413
|
-
@buffer_of_lines[0..(@line_index - 1)]
|
414
|
-
result + calculate_height_by_width(prompt_width + calculate_width(line)) # TODO prompt_list
|
415
|
-
}
|
398
|
+
calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list)
|
416
399
|
end
|
417
400
|
if @prompt_proc
|
418
401
|
prompt = prompt_list[@line_index]
|
@@ -431,13 +414,7 @@ class Reline::LineEditor
|
|
431
414
|
Reline::IOGate.move_cursor_column(0)
|
432
415
|
back = 0
|
433
416
|
new_buffer = whole_lines
|
434
|
-
prompt_list =
|
435
|
-
if @prompt_proc
|
436
|
-
prompt_list = @prompt_proc.(new_buffer)
|
437
|
-
prompt_list[@line_index] = special_prompt if special_prompt
|
438
|
-
prompt = prompt_list[@line_index]
|
439
|
-
prompt_width = calculate_width(prompt, true)
|
440
|
-
end
|
417
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer, prompt)
|
441
418
|
new_buffer.each_with_index do |line, index|
|
442
419
|
prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
|
443
420
|
width = prompt_width + calculate_width(line)
|
@@ -477,9 +454,7 @@ class Reline::LineEditor
|
|
477
454
|
if @line_index.zero?
|
478
455
|
0
|
479
456
|
else
|
480
|
-
new_buffer[0..(@line_index - 1)]
|
481
|
-
result + calculate_height_by_width(prompt_width + calculate_width(line)) # TODO prompt_list
|
482
|
-
}
|
457
|
+
calculate_height_by_lines(new_buffer[0..(@line_index - 1)], prompt_list)
|
483
458
|
end
|
484
459
|
@started_from = calculate_height_by_width(prompt_width + @cursor) - 1
|
485
460
|
move_cursor_down(@first_line_started_from + @started_from)
|
@@ -489,13 +464,7 @@ class Reline::LineEditor
|
|
489
464
|
end
|
490
465
|
line = modify_lines(whole_lines)[@line_index]
|
491
466
|
if @is_multiline
|
492
|
-
prompt_list =
|
493
|
-
if @prompt_proc
|
494
|
-
prompt_list = @prompt_proc.(whole_lines)
|
495
|
-
prompt_list[@line_index] = special_prompt if special_prompt
|
496
|
-
prompt = prompt_list[@line_index]
|
497
|
-
prompt_width = calculate_width(prompt, true)
|
498
|
-
end
|
467
|
+
prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines, prompt)
|
499
468
|
if finished?
|
500
469
|
# Always rerender on finish because output_modifier_proc may return a different output.
|
501
470
|
render_partial(prompt, prompt_width, line)
|
@@ -541,6 +510,7 @@ class Reline::LineEditor
|
|
541
510
|
next
|
542
511
|
end
|
543
512
|
@output.print line
|
513
|
+
@output.flush
|
544
514
|
if @first_prompt
|
545
515
|
@first_prompt = false
|
546
516
|
@pre_input_hook&.call
|
@@ -683,9 +653,9 @@ class Reline::LineEditor
|
|
683
653
|
else
|
684
654
|
old_waiting_proc = @waiting_proc
|
685
655
|
old_waiting_operator_proc = @waiting_operator_proc
|
686
|
-
@waiting_proc = proc { |
|
656
|
+
@waiting_proc = proc { |k|
|
687
657
|
old_cursor, old_byte_pointer = @cursor, @byte_pointer
|
688
|
-
old_waiting_proc.(
|
658
|
+
old_waiting_proc.(k)
|
689
659
|
cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer
|
690
660
|
@cursor, @byte_pointer = old_cursor, old_byte_pointer
|
691
661
|
@waiting_operator_proc.(cursor_diff, byte_pointer_diff)
|
@@ -796,7 +766,7 @@ class Reline::LineEditor
|
|
796
766
|
end
|
797
767
|
|
798
768
|
def input_key(key)
|
799
|
-
if key.
|
769
|
+
if key.char.nil?
|
800
770
|
if @first_char
|
801
771
|
@line = nil
|
802
772
|
end
|
@@ -836,6 +806,26 @@ class Reline::LineEditor
|
|
836
806
|
|
837
807
|
private def process_auto_indent
|
838
808
|
return if not @check_new_auto_indent and @previous_line_index # move cursor up or down
|
809
|
+
if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index
|
810
|
+
# Fix indent of a line when a newline is inserted to the next
|
811
|
+
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
812
|
+
new_indent = @auto_indent_proc.(new_lines[0..-3].push(''), @line_index - 1, 0, true)
|
813
|
+
md = @line.match(/\A */)
|
814
|
+
prev_indent = md[0].count(' ')
|
815
|
+
@line = ' ' * new_indent + @line.lstrip
|
816
|
+
|
817
|
+
new_indent = nil
|
818
|
+
(new_lines[-2].size + 1).times do |n|
|
819
|
+
result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, n, false)
|
820
|
+
if result
|
821
|
+
new_indent = result
|
822
|
+
break
|
823
|
+
end
|
824
|
+
end
|
825
|
+
if new_indent&.>= 0
|
826
|
+
@line = ' ' * new_indent + @line.lstrip
|
827
|
+
end
|
828
|
+
end
|
839
829
|
if @previous_line_index
|
840
830
|
new_lines = whole_lines(index: @previous_line_index, line: @line)
|
841
831
|
else
|
@@ -1027,8 +1017,8 @@ class Reline::LineEditor
|
|
1027
1017
|
end
|
1028
1018
|
width
|
1029
1019
|
else
|
1030
|
-
str.encode(Encoding::UTF_8).grapheme_clusters.inject(0) { |
|
1031
|
-
|
1020
|
+
str.encode(Encoding::UTF_8).grapheme_clusters.inject(0) { |w, gc|
|
1021
|
+
w + Reline::Unicode.get_mbchar_width(gc)
|
1032
1022
|
}
|
1033
1023
|
end
|
1034
1024
|
end
|
@@ -1049,6 +1039,8 @@ class Reline::LineEditor
|
|
1049
1039
|
end
|
1050
1040
|
end
|
1051
1041
|
|
1042
|
+
private def ed_unassigned(key) end # do nothing
|
1043
|
+
|
1052
1044
|
private def ed_insert(key)
|
1053
1045
|
if key.instance_of?(String)
|
1054
1046
|
width = Reline::Unicode.get_mbchar_width(key)
|
@@ -1153,7 +1145,11 @@ class Reline::LineEditor
|
|
1153
1145
|
alias_method :end_of_line, :ed_move_to_end
|
1154
1146
|
|
1155
1147
|
private def ed_search_prev_history(key)
|
1156
|
-
|
1148
|
+
if @is_multiline
|
1149
|
+
@line_backup_in_history = whole_buffer
|
1150
|
+
else
|
1151
|
+
@line_backup_in_history = @line
|
1152
|
+
end
|
1157
1153
|
searcher = Fiber.new do
|
1158
1154
|
search_word = String.new(encoding: @encoding)
|
1159
1155
|
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
@@ -1188,18 +1184,32 @@ class Reline::LineEditor
|
|
1188
1184
|
end
|
1189
1185
|
end
|
1190
1186
|
if hit
|
1191
|
-
@
|
1192
|
-
|
1187
|
+
if @is_multiline
|
1188
|
+
@buffer_of_lines = hit.split("\n")
|
1189
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1190
|
+
@line_index = @buffer_of_lines.size - 1
|
1191
|
+
@line = @buffer_of_lines.last
|
1192
|
+
@rerender_all = true
|
1193
|
+
@searching_prompt = "(reverse-i-search)`%s'" % [search_word]
|
1194
|
+
else
|
1195
|
+
@line = hit
|
1196
|
+
@searching_prompt = "(reverse-i-search)`%s': %s" % [search_word, hit]
|
1197
|
+
end
|
1193
1198
|
last_hit = hit
|
1194
1199
|
else
|
1195
|
-
@
|
1200
|
+
if @is_multiline
|
1201
|
+
@rerender_all = true
|
1202
|
+
@searching_prompt = "(failed reverse-i-search)`%s'" % [search_word]
|
1203
|
+
else
|
1204
|
+
@searching_prompt = "(failed reverse-i-search)`%s': %s" % [search_word, last_hit]
|
1205
|
+
end
|
1196
1206
|
end
|
1197
1207
|
end
|
1198
1208
|
end
|
1199
1209
|
searcher.resume
|
1200
1210
|
@searching_prompt = "(reverse-i-search)`': "
|
1201
|
-
@waiting_proc = ->(
|
1202
|
-
case
|
1211
|
+
@waiting_proc = ->(k) {
|
1212
|
+
case k
|
1203
1213
|
when "\C-j".ord, "\C-?".ord
|
1204
1214
|
if @history_pointer
|
1205
1215
|
@line = Reline::HISTORY[@history_pointer]
|
@@ -1219,14 +1229,25 @@ class Reline::LineEditor
|
|
1219
1229
|
@cursor_max = calculate_width(@line)
|
1220
1230
|
@cursor = @byte_pointer = 0
|
1221
1231
|
else
|
1222
|
-
chr =
|
1223
|
-
if chr.match?(/[[:print:]]/)
|
1224
|
-
searcher.resume(
|
1232
|
+
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
|
1233
|
+
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == 127
|
1234
|
+
searcher.resume(k)
|
1225
1235
|
else
|
1226
1236
|
if @history_pointer
|
1227
|
-
|
1237
|
+
line = Reline::HISTORY[@history_pointer]
|
1228
1238
|
else
|
1229
|
-
|
1239
|
+
line = @line_backup_in_history
|
1240
|
+
end
|
1241
|
+
if @is_multiline
|
1242
|
+
@line_backup_in_history = whole_buffer
|
1243
|
+
@buffer_of_lines = line.split("\n")
|
1244
|
+
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
|
1245
|
+
@line_index = @buffer_of_lines.size - 1
|
1246
|
+
@line = @buffer_of_lines.last
|
1247
|
+
@rerender_all = true
|
1248
|
+
else
|
1249
|
+
@line_backup_in_history = @line
|
1250
|
+
@line = line
|
1230
1251
|
end
|
1231
1252
|
@searching_prompt = nil
|
1232
1253
|
@waiting_proc = nil
|
@@ -1279,7 +1300,7 @@ class Reline::LineEditor
|
|
1279
1300
|
@line = Reline::HISTORY[@history_pointer]
|
1280
1301
|
end
|
1281
1302
|
end
|
1282
|
-
if @config.editing_mode_is?(:emacs)
|
1303
|
+
if @config.editing_mode_is?(:emacs, :vi_insert)
|
1283
1304
|
@cursor_max = @cursor = calculate_width(@line)
|
1284
1305
|
@byte_pointer = @line.bytesize
|
1285
1306
|
elsif @config.editing_mode_is?(:vi_command)
|
@@ -1326,7 +1347,7 @@ class Reline::LineEditor
|
|
1326
1347
|
end
|
1327
1348
|
end
|
1328
1349
|
@line = '' unless @line
|
1329
|
-
if @config.editing_mode_is?(:emacs)
|
1350
|
+
if @config.editing_mode_is?(:emacs, :vi_insert)
|
1330
1351
|
@cursor_max = @cursor = calculate_width(@line)
|
1331
1352
|
@byte_pointer = @line.bytesize
|
1332
1353
|
elsif @config.editing_mode_is?(:vi_command)
|
@@ -1863,13 +1884,13 @@ class Reline::LineEditor
|
|
1863
1884
|
end
|
1864
1885
|
|
1865
1886
|
private def vi_replace_char(key, arg: 1)
|
1866
|
-
@waiting_proc = ->(
|
1887
|
+
@waiting_proc = ->(k) {
|
1867
1888
|
if arg == 1
|
1868
1889
|
byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
|
1869
1890
|
before = @line.byteslice(0, @byte_pointer)
|
1870
1891
|
remaining_point = @byte_pointer + byte_size
|
1871
1892
|
after = @line.byteslice(remaining_point, @line.size - remaining_point)
|
1872
|
-
@line = before +
|
1893
|
+
@line = before + k.chr + after
|
1873
1894
|
@cursor_max = calculate_width(@line)
|
1874
1895
|
@waiting_proc = nil
|
1875
1896
|
elsif arg > 1
|
@@ -1880,7 +1901,7 @@ class Reline::LineEditor
|
|
1880
1901
|
before = @line.byteslice(0, @byte_pointer)
|
1881
1902
|
remaining_point = @byte_pointer + byte_size
|
1882
1903
|
after = @line.byteslice(remaining_point, @line.size - remaining_point)
|
1883
|
-
replaced =
|
1904
|
+
replaced = k.chr * arg
|
1884
1905
|
@line = before + replaced + after
|
1885
1906
|
@byte_pointer += replaced.bytesize
|
1886
1907
|
@cursor += calculate_width(replaced)
|
@@ -1941,4 +1962,20 @@ class Reline::LineEditor
|
|
1941
1962
|
arg -= 1
|
1942
1963
|
vi_join_lines(key, arg: arg) if arg > 0
|
1943
1964
|
end
|
1965
|
+
|
1966
|
+
private def em_set_mark(key)
|
1967
|
+
@mark_pointer = [@byte_pointer, @line_index]
|
1968
|
+
end
|
1969
|
+
alias_method :set_mark, :em_set_mark
|
1970
|
+
|
1971
|
+
private def em_exchange_mark(key)
|
1972
|
+
new_pointer = [@byte_pointer, @line_index]
|
1973
|
+
@previous_line_index = @line_index
|
1974
|
+
@byte_pointer, @line_index = @mark_pointer
|
1975
|
+
@byte_pointer, @line_index = @mark_pointer
|
1976
|
+
@cursor = calculate_width(@line.byteslice(0, @byte_pointer))
|
1977
|
+
@cursor_max = calculate_width(@line)
|
1978
|
+
@mark_pointer = new_pointer
|
1979
|
+
end
|
1980
|
+
alias_method :exchange_point_and_mark, :em_exchange_mark
|
1944
1981
|
end
|
data/lib/reline/version.rb
CHANGED
data/lib/reline/windows.rb
CHANGED
@@ -9,47 +9,61 @@ class Reline::Windows
|
|
9
9
|
[224, 83] => :key_delete, # Del
|
10
10
|
[224, 71] => :ed_move_to_beg, # Home
|
11
11
|
[224, 79] => :ed_move_to_end, # End
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
12
|
+
[ 0, 41] => :ed_unassigned, # input method on/off
|
13
|
+
[ 0, 72] => :ed_prev_history, # ↑
|
14
|
+
[ 0, 80] => :ed_next_history, # ↓
|
15
|
+
[ 0, 77] => :ed_next_char, # →
|
16
|
+
[ 0, 75] => :ed_prev_char, # ←
|
17
|
+
[ 0, 83] => :key_delete, # Del
|
18
|
+
[ 0, 71] => :ed_move_to_beg, # Home
|
19
|
+
[ 0, 79] => :ed_move_to_end # End
|
20
|
+
}
|
21
|
+
|
22
|
+
if defined? JRUBY_VERSION
|
23
|
+
require 'win32api'
|
24
|
+
else
|
25
|
+
class Win32API
|
26
|
+
DLL = {}
|
27
|
+
TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
|
28
|
+
POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
|
29
|
+
|
30
|
+
WIN32_TYPES = "VPpNnLlIi"
|
31
|
+
DL_TYPES = "0SSI"
|
32
|
+
|
33
|
+
def initialize(dllname, func, import, export = "0", calltype = :stdcall)
|
34
|
+
@proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
|
35
|
+
import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
|
36
|
+
export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
|
37
|
+
calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
|
38
|
+
|
39
|
+
handle = DLL[dllname] ||=
|
40
|
+
begin
|
41
|
+
Fiddle.dlopen(dllname)
|
42
|
+
rescue Fiddle::DLError
|
43
|
+
raise unless File.extname(dllname).empty?
|
44
|
+
Fiddle.dlopen(dllname + ".dll")
|
45
|
+
end
|
46
|
+
|
47
|
+
@func = Fiddle::Function.new(handle[func], import, export, calltype)
|
48
|
+
rescue Fiddle::DLError => e
|
49
|
+
raise LoadError, e.message, e.backtrace
|
50
|
+
end
|
40
51
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
52
|
+
def call(*args)
|
53
|
+
import = @proto.split("")
|
54
|
+
args.each_with_index do |x, i|
|
55
|
+
args[i], = [x == 0 ? nil : x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
|
56
|
+
args[i], = [x].pack("I").unpack("i") if import[i] == "I"
|
57
|
+
end
|
58
|
+
ret, = @func.call(*args)
|
59
|
+
return ret || 0
|
46
60
|
end
|
47
|
-
ret, = @func.call(*args)
|
48
|
-
return ret || 0
|
49
61
|
end
|
50
62
|
end
|
51
63
|
|
52
64
|
VK_MENU = 0x12
|
65
|
+
VK_LMENU = 0xA4
|
66
|
+
VK_CONTROL = 0x11
|
53
67
|
VK_SHIFT = 0x10
|
54
68
|
STD_INPUT_HANDLE = -10
|
55
69
|
STD_OUTPUT_HANDLE = -11
|
@@ -66,23 +80,33 @@ class Reline::Windows
|
|
66
80
|
@@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
|
67
81
|
@@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
|
68
82
|
@@ReadConsoleInput = Win32API.new('kernel32', 'ReadConsoleInput', ['L', 'P', 'L', 'P'], 'L')
|
69
|
-
@@
|
83
|
+
@@input_buf = []
|
84
|
+
@@output_buf = []
|
70
85
|
|
71
86
|
def self.getwch
|
87
|
+
unless @@input_buf.empty?
|
88
|
+
return @@input_buf.shift
|
89
|
+
end
|
72
90
|
while @@kbhit.call == 0
|
73
91
|
sleep(0.001)
|
74
92
|
end
|
75
|
-
result = []
|
76
93
|
until @@kbhit.call == 0
|
77
94
|
ret = @@getwch.call
|
95
|
+
if ret == 0 or ret == 0xE0
|
96
|
+
@@input_buf << ret
|
97
|
+
ret = @@getwch.call
|
98
|
+
@@input_buf << ret
|
99
|
+
return @@input_buf.shift
|
100
|
+
end
|
78
101
|
begin
|
79
|
-
|
102
|
+
bytes = ret.chr(Encoding::UTF_8).encode(Encoding.default_external).bytes
|
103
|
+
@@input_buf.push(*bytes)
|
80
104
|
rescue Encoding::UndefinedConversionError
|
81
|
-
|
82
|
-
|
105
|
+
@@input_buf << ret
|
106
|
+
@@input_buf << @@getwch.call if ret == 224
|
83
107
|
end
|
84
108
|
end
|
85
|
-
|
109
|
+
@@input_buf.shift
|
86
110
|
end
|
87
111
|
|
88
112
|
def self.getc
|
@@ -97,44 +121,44 @@ class Reline::Windows
|
|
97
121
|
end
|
98
122
|
end
|
99
123
|
end
|
100
|
-
unless @@
|
101
|
-
return @@
|
124
|
+
unless @@output_buf.empty?
|
125
|
+
return @@output_buf.shift
|
102
126
|
end
|
103
127
|
input = getwch
|
104
|
-
|
105
|
-
|
106
|
-
|
128
|
+
meta = (@@GetKeyState.call(VK_LMENU) & 0x80) != 0
|
129
|
+
control = (@@GetKeyState.call(VK_CONTROL) & 0x80) != 0
|
130
|
+
shift = (@@GetKeyState.call(VK_SHIFT) & 0x80) != 0
|
131
|
+
force_enter = !input.instance_of?(Array) && (control or shift) && input == 0x0D
|
132
|
+
if force_enter
|
107
133
|
# It's treated as Meta+Enter on Windows
|
108
|
-
@@
|
109
|
-
@@
|
110
|
-
|
111
|
-
|
112
|
-
else # single byte
|
113
|
-
case input[0]
|
134
|
+
@@output_buf.push("\e".ord)
|
135
|
+
@@output_buf.push(input)
|
136
|
+
else
|
137
|
+
case input
|
114
138
|
when 0x00
|
115
|
-
|
116
|
-
|
139
|
+
meta = false
|
140
|
+
@@output_buf.push(input)
|
117
141
|
input = getwch
|
118
|
-
@@
|
142
|
+
@@output_buf.push(*input)
|
119
143
|
when 0xE0
|
120
|
-
@@
|
144
|
+
@@output_buf.push(input)
|
121
145
|
input = getwch
|
122
|
-
@@
|
146
|
+
@@output_buf.push(*input)
|
123
147
|
when 0x03
|
124
|
-
@@
|
148
|
+
@@output_buf.push(input)
|
125
149
|
else
|
126
|
-
@@
|
150
|
+
@@output_buf.push(input)
|
127
151
|
end
|
128
152
|
end
|
129
|
-
if
|
153
|
+
if meta
|
130
154
|
"\e".ord
|
131
155
|
else
|
132
|
-
@@
|
156
|
+
@@output_buf.shift
|
133
157
|
end
|
134
158
|
end
|
135
159
|
|
136
160
|
def self.ungetc(c)
|
137
|
-
@@
|
161
|
+
@@output_buf.unshift(c)
|
138
162
|
end
|
139
163
|
|
140
164
|
def self.get_screen_size
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|