yap-rawline 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rawline/completer.rb +12 -7
- data/lib/rawline/editor.rb +102 -121
- data/lib/rawline/history_buffer.rb +0 -4
- data/lib/rawline/keycode_parser.rb +36 -0
- data/lib/rawline/line.rb +2 -2
- data/lib/rawline/terminal/vt220_terminal.rb +4 -0
- data/lib/rawline/terminal.rb +1 -0
- data/lib/rawline/version.rb +3 -0
- data/lib/rawline.rb +1 -4
- data/lib/tasks/gem.rake +62 -0
- data/spec/editor_spec.rb +70 -5
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be73e6267c8fe5f9ae5dd481a01bace695822a39
|
4
|
+
data.tar.gz: bc7d6f138c08f9fa7c182ddf4fad243a529992dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e32e2906e69dd93fa0a68f10025f1e7396dbb4dbef59134459e8348c534390e71a3e6634331a3264517c71466f44035ec09aff0bbd6bf9867ff1dd9af22f0942
|
7
|
+
data.tar.gz: 935126f5ff9486c6a3bd4ac98b8a98313e4fc0de4817cb403276415fb9aba2130186c0d57891bcb9909c43f5fbed6f4df3f21edaa2963550190d10002b86ee02
|
data/lib/rawline/completer.rb
CHANGED
@@ -38,7 +38,18 @@ module RawLine
|
|
38
38
|
elsif bytes.map(&:ord) != @completion_char
|
39
39
|
@done_proc.call(bytes)
|
40
40
|
elsif @first_time
|
41
|
-
|
41
|
+
unless !@completion_proc || @completion_proc == []
|
42
|
+
word = @line.text[@line.word[:start]..@line.position-1] || ""
|
43
|
+
words = @line.text
|
44
|
+
.split(/\s+/)
|
45
|
+
.delete_if(&:empty?)
|
46
|
+
word_index = words.index(word)
|
47
|
+
matches = @completion_proc.call(
|
48
|
+
word,
|
49
|
+
words,
|
50
|
+
word_index
|
51
|
+
)
|
52
|
+
end
|
42
53
|
matches = matches.to_a.compact.sort.reverse
|
43
54
|
|
44
55
|
if matches.any?
|
@@ -64,12 +75,6 @@ module RawLine
|
|
64
75
|
@completion_found_proc.call(completion: match, possible_completions: @completion_matches.reverse)
|
65
76
|
end
|
66
77
|
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
def sub_word
|
71
|
-
@line.text[@line.word[:start]..@line.position-1] || ""
|
72
|
-
end
|
73
78
|
end
|
74
79
|
|
75
80
|
end
|
data/lib/rawline/editor.rb
CHANGED
@@ -41,9 +41,9 @@ module RawLine
|
|
41
41
|
extend Forwardable
|
42
42
|
include HighLine::SystemExtensions
|
43
43
|
|
44
|
-
attr_accessor :char
|
45
|
-
attr_accessor :terminal, :
|
46
|
-
attr_accessor :
|
44
|
+
attr_accessor :char
|
45
|
+
attr_accessor :terminal, :mode
|
46
|
+
attr_accessor :completion_proc, :line, :history
|
47
47
|
attr_accessor :match_hidden_files
|
48
48
|
attr_accessor :word_break_characters
|
49
49
|
attr_accessor :dom
|
@@ -85,18 +85,42 @@ module RawLine
|
|
85
85
|
)
|
86
86
|
end
|
87
87
|
|
88
|
+
class Environment
|
89
|
+
attr_accessor :keys, :completion_class, :history, :word_separator
|
90
|
+
|
91
|
+
# * <tt>@history_size</tt> - the size of the editor history buffer (30).
|
92
|
+
# * <tt>@keys</tt> - the keys (arrays of character codes) bound to specific actions.
|
93
|
+
# * <tt>@line_history_size</tt> - the size of the editor line history buffer (50).
|
94
|
+
def initialize(env: nil)
|
95
|
+
@env = env
|
96
|
+
@keys = {}
|
97
|
+
|
98
|
+
@completion_class = Completer
|
99
|
+
|
100
|
+
@line_history_size = 50
|
101
|
+
@history_size = 30
|
102
|
+
|
103
|
+
@history = HistoryBuffer.new(@history_size) do |h|
|
104
|
+
h.duplicates = false;
|
105
|
+
h.exclude = lambda { |item| item.strip == "" }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def initialize_line(&blk)
|
110
|
+
Line.new(@line_history_size) do |line|
|
111
|
+
blk.call(line) if blk
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
88
116
|
#
|
89
117
|
# Create an instance of RawLine::Editor which can be used
|
90
118
|
# to read from input and perform line-editing operations.
|
91
119
|
# This method takes an optional block used to override the
|
92
120
|
# following instance attributes:
|
93
|
-
# * <tt>@history_size</tt> - the size of the editor history buffer (30).
|
94
|
-
# * <tt>@line_history_size</tt> - the size of the editor line history buffer (50).
|
95
|
-
# * <tt>@keys</tt> - the keys (arrays of character codes) bound to specific actions.
|
96
121
|
# * <tt>@word_break_characters</tt> - a regex used for word separation, default inclues: " \t\n\"\\'`@$><=;|&{("
|
97
122
|
# * <tt>@mode</tt> - The editor's character insertion mode (:insert).
|
98
123
|
# * <tt>@completion_proc</tt> - a Proc object used to perform word completion.
|
99
|
-
# * <tt>@completion_append_string</tt> - a string to append to completed words ('').
|
100
124
|
# * <tt>@terminal</tt> - a RawLine::Terminal containing character key codes.
|
101
125
|
#
|
102
126
|
def initialize(dom:, input:, renderer:, terminal:)
|
@@ -105,24 +129,17 @@ module RawLine
|
|
105
129
|
@renderer = renderer
|
106
130
|
@terminal = terminal
|
107
131
|
|
108
|
-
@
|
109
|
-
|
110
|
-
@
|
111
|
-
@word_break_characters = " \t\n\"'@\$><=;|&{("
|
132
|
+
@env_stack = [Environment.new]
|
133
|
+
|
134
|
+
@word_break_characters = " \t\n\"'@><=;|&{("
|
112
135
|
@mode = :insert
|
113
|
-
|
136
|
+
|
114
137
|
@completion_proc = filename_completion_proc
|
115
|
-
|
138
|
+
|
116
139
|
@match_hidden_files = false
|
117
140
|
set_default_keys
|
118
141
|
@add_history = false
|
119
|
-
@highlight_history_matching_text = true
|
120
|
-
@history = HistoryBuffer.new(@history_size) do |h|
|
121
|
-
h.duplicates = false;
|
122
|
-
h.exclude = lambda { |item| item.strip == "" }
|
123
|
-
end
|
124
142
|
@keyboard_input_processors = [self]
|
125
|
-
# @allow_prompt_updates = true
|
126
143
|
yield self if block_given?
|
127
144
|
update_word_separator
|
128
145
|
@char = nil
|
@@ -134,11 +151,17 @@ module RawLine
|
|
134
151
|
attr_reader :dom, :event_loop, :input
|
135
152
|
attr_reader :keyboard_input_processors
|
136
153
|
|
154
|
+
def env ; @env_stack.last ; end
|
155
|
+
|
156
|
+
def completion_class ; env.completion_class ; end
|
157
|
+
def history ; env.history ; end
|
158
|
+
def keys ; env.keys ; end
|
159
|
+
|
137
160
|
#
|
138
161
|
# Return the current RawLine version
|
139
162
|
#
|
140
163
|
def library_version
|
141
|
-
"RawLine v#{RawLine
|
164
|
+
"RawLine v#{RawLine::VERSION}"
|
142
165
|
end
|
143
166
|
|
144
167
|
def prompt
|
@@ -214,18 +237,14 @@ module RawLine
|
|
214
237
|
def read_bytes(bytes)
|
215
238
|
return unless bytes.any?
|
216
239
|
old_position = @line.position
|
217
|
-
|
218
|
-
|
219
|
-
|
240
|
+
|
241
|
+
key_code_sequences = parse_key_code_sequences(bytes)
|
242
|
+
key_code_sequences.each do |sequence|
|
243
|
+
@char = sequence
|
220
244
|
process_character
|
221
245
|
|
222
246
|
new_position = @line.position
|
223
247
|
|
224
|
-
if !@ignore_position_change && new_position != old_position
|
225
|
-
@matching_text = @line.text[0...@line.position]
|
226
|
-
end
|
227
|
-
|
228
|
-
@ignore_position_change = false
|
229
248
|
if @char == @terminal.keys[:enter] || !@char
|
230
249
|
process_line
|
231
250
|
end
|
@@ -252,11 +271,10 @@ module RawLine
|
|
252
271
|
# This method is called automatically by <tt>read</tt>
|
253
272
|
#
|
254
273
|
def process_character
|
255
|
-
|
256
|
-
when 'Fixnum' then
|
257
|
-
default_action
|
258
|
-
when 'Array'
|
274
|
+
if @char.is_a?(Array)
|
259
275
|
press_key if key_bound?
|
276
|
+
else
|
277
|
+
default_action
|
260
278
|
end
|
261
279
|
end
|
262
280
|
|
@@ -281,16 +299,16 @@ module RawLine
|
|
281
299
|
case key.class.to_s
|
282
300
|
when 'Symbol' then
|
283
301
|
raise BindingException, "Unknown key or key sequence '#{key.to_s}' (#{key.class.to_s})" unless @terminal.keys[key]
|
284
|
-
|
302
|
+
keys[@terminal.keys[key]] = block
|
285
303
|
when 'Array' then
|
286
304
|
raise BindingException, "Unknown key or key sequence '#{key.join(", ")}' (#{key.class.to_s})" unless @terminal.keys.has_value? key
|
287
|
-
|
305
|
+
keys[key] = block
|
288
306
|
when 'Fixnum' then
|
289
307
|
raise BindingException, "Unknown key or key sequence '#{key.to_s}' (#{key.class.to_s})" unless @terminal.keys.has_value? [key]
|
290
|
-
|
308
|
+
keys[[key]] = block
|
291
309
|
when 'String' then
|
292
310
|
if key.length == 1 then
|
293
|
-
|
311
|
+
keys[[key.ord]] = block
|
294
312
|
else
|
295
313
|
bind_hash({:"#{key}" => key}, block)
|
296
314
|
end
|
@@ -306,14 +324,14 @@ module RawLine
|
|
306
324
|
def unbind(key)
|
307
325
|
block = case key.class.to_s
|
308
326
|
when 'Symbol' then
|
309
|
-
|
327
|
+
keys.delete @terminal.keys[key]
|
310
328
|
when 'Array' then
|
311
|
-
|
329
|
+
keys.delete keys[key]
|
312
330
|
when 'Fixnum' then
|
313
|
-
|
331
|
+
keys.delete[[key]]
|
314
332
|
when 'String' then
|
315
333
|
if key.length == 1 then
|
316
|
-
|
334
|
+
keys.delete([key.ord])
|
317
335
|
else
|
318
336
|
raise NotImplementedError, "This is no implemented yet. It needs to return the previously bound block"
|
319
337
|
bind_hash({:"#{key}" => key}, block)
|
@@ -330,7 +348,7 @@ module RawLine
|
|
330
348
|
# Return true if the last character read via <tt>read</tt> is bound to an action.
|
331
349
|
#
|
332
350
|
def key_bound?
|
333
|
-
|
351
|
+
keys[@char] ? true : false
|
334
352
|
end
|
335
353
|
|
336
354
|
#
|
@@ -338,24 +356,23 @@ module RawLine
|
|
338
356
|
# This method is called automatically by <tt>process_character</tt>.
|
339
357
|
#
|
340
358
|
def press_key
|
341
|
-
|
359
|
+
keys[@char].call
|
342
360
|
end
|
343
361
|
|
344
362
|
#
|
345
363
|
# Execute the default action for the last character read via <tt>read</tt>.
|
346
|
-
# By default it prints the character to the screen via <tt>
|
364
|
+
# By default it prints the character to the screen via <tt>write</tt>.
|
347
365
|
# This method is called automatically by <tt>process_character</tt>.
|
348
366
|
#
|
349
367
|
def default_action
|
350
|
-
@
|
351
|
-
print_character
|
368
|
+
insert(@char)
|
352
369
|
end
|
353
370
|
|
354
371
|
#
|
355
372
|
# Parse a key or key sequence into the corresponding codes.
|
356
373
|
#
|
357
|
-
def
|
358
|
-
KeycodeParser.new(@terminal.keys).
|
374
|
+
def parse_key_code_sequences(bytes)
|
375
|
+
KeycodeParser.new(@terminal.keys).parse_bytes_into_sequences(bytes)
|
359
376
|
end
|
360
377
|
|
361
378
|
#
|
@@ -364,7 +381,7 @@ module RawLine
|
|
364
381
|
#
|
365
382
|
def newline
|
366
383
|
add_to_history
|
367
|
-
|
384
|
+
history.clear_position
|
368
385
|
end
|
369
386
|
|
370
387
|
def on_read_line(&blk)
|
@@ -387,7 +404,7 @@ module RawLine
|
|
387
404
|
@line.text = ""
|
388
405
|
@line.position = 0
|
389
406
|
@dom.input_box.position = @line.position
|
390
|
-
|
407
|
+
history.clear_position
|
391
408
|
end
|
392
409
|
|
393
410
|
def clear_screen
|
@@ -416,7 +433,7 @@ module RawLine
|
|
416
433
|
@dom.input_box.position = @line.position
|
417
434
|
@dom.input_box.content = @line.text
|
418
435
|
add_to_line_history unless no_line_history
|
419
|
-
|
436
|
+
history.clear_position
|
420
437
|
end
|
421
438
|
|
422
439
|
#
|
@@ -434,7 +451,7 @@ module RawLine
|
|
434
451
|
@dom.input_box.content = @line.text
|
435
452
|
@dom.input_box.position = @line.position
|
436
453
|
add_to_line_history unless no_line_history
|
437
|
-
|
454
|
+
history.clear_position
|
438
455
|
end
|
439
456
|
end
|
440
457
|
|
@@ -447,7 +464,7 @@ module RawLine
|
|
447
464
|
@line.text[@line.position..-1] = ANSIString.new("")
|
448
465
|
@dom.input_box.content = line.text
|
449
466
|
@dom.input_box.position = @line.position
|
450
|
-
|
467
|
+
history.clear_position
|
451
468
|
killed_text
|
452
469
|
end
|
453
470
|
|
@@ -456,7 +473,7 @@ module RawLine
|
|
456
473
|
@line.position = line.position + text.length
|
457
474
|
@dom.input_box.content = line.text
|
458
475
|
@dom.input_box.position = @line.position
|
459
|
-
|
476
|
+
history.clear_position
|
460
477
|
end
|
461
478
|
|
462
479
|
#
|
@@ -543,7 +560,6 @@ module RawLine
|
|
543
560
|
new_line = highlight_text_up_to(new_line, options[:highlight_up_to])
|
544
561
|
end
|
545
562
|
|
546
|
-
@ignore_position_change = true
|
547
563
|
@line.position = position || new_line.length
|
548
564
|
@line.text = new_line
|
549
565
|
@dom.input_box.content = @line.text
|
@@ -572,30 +588,6 @@ module RawLine
|
|
572
588
|
#
|
573
589
|
############################################################################
|
574
590
|
|
575
|
-
#
|
576
|
-
# Write a character to <tt>output</tt> at cursor position,
|
577
|
-
# shifting characters as appropriate.
|
578
|
-
# If <tt>no_line_history</tt> is set to <tt>true</tt>, the updated
|
579
|
-
# won't be saved in the history of the current line.
|
580
|
-
#
|
581
|
-
def print_character(char=@char, no_line_history = false)
|
582
|
-
if @line.position < @line.length then
|
583
|
-
chars = select_characters_from_cursor if @mode == :insert
|
584
|
-
@line.text[@line.position] = (@mode == :insert) ? "#{char.chr}#{@line.text[@line.position]}" : "#{char.chr}"
|
585
|
-
@line.right
|
586
|
-
@dom.input_box.position = @line.position
|
587
|
-
# if @mode == :insert then
|
588
|
-
# chars.length.times { @line.left } # move cursor back
|
589
|
-
# end
|
590
|
-
else
|
591
|
-
@line.right
|
592
|
-
@line << char
|
593
|
-
end
|
594
|
-
@dom.input_box.content = @line.text
|
595
|
-
@dom.input_box.position = @line.position
|
596
|
-
add_to_line_history unless no_line_history
|
597
|
-
end
|
598
|
-
|
599
591
|
#
|
600
592
|
# Write to <tt>output</tt> and then immediately re-render.
|
601
593
|
#
|
@@ -605,15 +597,29 @@ module RawLine
|
|
605
597
|
end
|
606
598
|
|
607
599
|
#
|
608
|
-
#
|
600
|
+
# Inserts a string at the current line position, shifting characters
|
601
|
+
# to right if necessary.
|
602
|
+
#
|
603
|
+
def insert(string, add_to_line_history: true)
|
604
|
+
@line.text.insert @line.position, string
|
605
|
+
string.length.times { @line.right }
|
606
|
+
@dom.input_box.position = @line.position
|
607
|
+
@dom.input_box.content = @line.text
|
608
|
+
|
609
|
+
self.add_to_line_history if add_to_line_history
|
610
|
+
end
|
611
|
+
|
612
|
+
#
|
613
|
+
# Write a string starting from the cursor position ovewriting any character
|
614
|
+
# at the current position if necessary.
|
609
615
|
#
|
610
|
-
def write(string)
|
616
|
+
def write(string, add_to_line_history: true)
|
611
617
|
@line.text[@line.position] = string
|
612
618
|
string.length.times { @line.right }
|
613
619
|
@dom.input_box.position = @line.position
|
614
620
|
@dom.input_box.content = @line.text
|
615
621
|
|
616
|
-
add_to_line_history
|
622
|
+
self.add_to_line_history if add_to_line_history
|
617
623
|
end
|
618
624
|
|
619
625
|
############################################################################
|
@@ -635,7 +641,7 @@ module RawLine
|
|
635
641
|
#
|
636
642
|
def complete
|
637
643
|
@dom.input_box.cursor_off
|
638
|
-
completer =
|
644
|
+
completer = completion_class.new(
|
639
645
|
char: @char,
|
640
646
|
line: @line,
|
641
647
|
completion: @completion_proc,
|
@@ -669,7 +675,7 @@ module RawLine
|
|
669
675
|
|
670
676
|
move_to_position @line.word[:end]
|
671
677
|
delete_n_characters(@line.word[:end] - @line.word[:start], true)
|
672
|
-
write completion.to_s
|
678
|
+
write completion.to_s
|
673
679
|
end
|
674
680
|
|
675
681
|
def completion_not_found
|
@@ -729,7 +735,7 @@ module RawLine
|
|
729
735
|
def show_history
|
730
736
|
pos = @line.position
|
731
737
|
text = @line.text
|
732
|
-
|
738
|
+
history.each {|l| puts "- [#{l}]"}
|
733
739
|
overwrite_line(text, pos)
|
734
740
|
end
|
735
741
|
|
@@ -737,7 +743,7 @@ module RawLine
|
|
737
743
|
# Clear the editor history.
|
738
744
|
#
|
739
745
|
def clear_history
|
740
|
-
|
746
|
+
history.empty
|
741
747
|
end
|
742
748
|
|
743
749
|
#
|
@@ -764,7 +770,7 @@ module RawLine
|
|
764
770
|
# This action is bound to the up arrow key by default.
|
765
771
|
#
|
766
772
|
def history_back
|
767
|
-
generic_history_back(
|
773
|
+
generic_history_back(history)
|
768
774
|
add_to_line_history
|
769
775
|
end
|
770
776
|
|
@@ -774,7 +780,7 @@ module RawLine
|
|
774
780
|
# This action is bound to down arrow key by default.
|
775
781
|
#
|
776
782
|
def history_forward
|
777
|
-
generic_history_forward(
|
783
|
+
generic_history_forward(history)
|
778
784
|
add_to_line_history
|
779
785
|
end
|
780
786
|
|
@@ -791,7 +797,7 @@ module RawLine
|
|
791
797
|
# Add the current line (<tt>@line.text</tt>) to the editor history.
|
792
798
|
#
|
793
799
|
def add_to_history
|
794
|
-
|
800
|
+
history << @line.text.dup if @add_history && @line.text != ""
|
795
801
|
end
|
796
802
|
|
797
803
|
############################################################################
|
@@ -831,7 +837,7 @@ module RawLine
|
|
831
837
|
@event_loop.add_event name: "render", source: @dom#, target: event[:target]
|
832
838
|
end
|
833
839
|
|
834
|
-
@dom.on :
|
840
|
+
@dom.on :position_changed do |*args|
|
835
841
|
@renderer.render_cursor(@dom.input_box)
|
836
842
|
end
|
837
843
|
|
@@ -846,8 +852,8 @@ module RawLine
|
|
846
852
|
def initialize_line
|
847
853
|
@dom.input_box.content = ""
|
848
854
|
update_word_separator
|
849
|
-
@add_history = true
|
850
|
-
@line =
|
855
|
+
@add_history = true
|
856
|
+
@line = env.initialize_line do |l|
|
851
857
|
l.prompt = @dom.prompt_box.content
|
852
858
|
l.word_separator = @word_separator
|
853
859
|
end
|
@@ -881,7 +887,7 @@ module RawLine
|
|
881
887
|
raise BindingException, "Unable to bind '#{k.to_s}' (#{k.class.to_s})"
|
882
888
|
end
|
883
889
|
@terminal.keys[j] = code
|
884
|
-
|
890
|
+
keys[code] = block
|
885
891
|
end
|
886
892
|
end
|
887
893
|
|
@@ -891,36 +897,21 @@ module RawLine
|
|
891
897
|
|
892
898
|
def generic_history_back(history)
|
893
899
|
unless history.empty?
|
894
|
-
history.back
|
900
|
+
history.back
|
895
901
|
line = history.get
|
896
902
|
return unless line
|
897
903
|
|
898
904
|
cursor_position = nil
|
899
|
-
if supports_partial_text_matching? && highlight_history_matching_text
|
900
|
-
if line && matching_text
|
901
|
-
cursor_position = [line.length, matching_text.length].min
|
902
|
-
elsif matching_text
|
903
|
-
cursor_position = matching_text.length
|
904
|
-
end
|
905
|
-
end
|
906
|
-
|
907
905
|
overwrite_line(line, cursor_position, highlight_up_to: cursor_position)
|
908
906
|
end
|
909
907
|
end
|
910
908
|
|
911
|
-
def supports_partial_text_matching?
|
912
|
-
history.supports_partial_text_matching?
|
913
|
-
end
|
914
|
-
|
915
909
|
def generic_history_forward(history)
|
916
|
-
if history.forward
|
910
|
+
if history.forward
|
917
911
|
line = history.get
|
918
912
|
return unless line
|
919
913
|
|
920
|
-
cursor_position =
|
921
|
-
[line.length, matching_text.length].min
|
922
|
-
end
|
923
|
-
|
914
|
+
cursor_position = nil
|
924
915
|
overwrite_line(line, cursor_position, highlight_up_to: cursor_position)
|
925
916
|
end
|
926
917
|
end
|
@@ -934,7 +925,7 @@ module RawLine
|
|
934
925
|
end
|
935
926
|
|
936
927
|
def set_default_keys
|
937
|
-
bind(:space) {
|
928
|
+
bind(:space) { insert(' ') }
|
938
929
|
bind(:enter) { newline }
|
939
930
|
bind(:tab) { complete }
|
940
931
|
bind(:backspace) { delete_left_character }
|
@@ -950,16 +941,6 @@ module RawLine
|
|
950
941
|
bind(:insert) { toggle_mode }
|
951
942
|
end
|
952
943
|
|
953
|
-
def matching_text
|
954
|
-
return nil unless @line
|
955
|
-
return nil if @line.text == ""
|
956
|
-
if @history.searching?
|
957
|
-
@matching_text
|
958
|
-
else
|
959
|
-
@matching_text = @line[0...@line.position]
|
960
|
-
end
|
961
|
-
end
|
962
|
-
|
963
944
|
def terminal_row_for_line_position(line_position)
|
964
945
|
((@line.prompt.length + line_position) / terminal_width.to_f).ceil
|
965
946
|
end
|
@@ -5,6 +5,42 @@ module RawLine
|
|
5
5
|
@escape_code = keymap[:escape]
|
6
6
|
end
|
7
7
|
|
8
|
+
# Parses a collection of bytes into key code sequences. All
|
9
|
+
# multi-byte sequences (e.g. [27, 91, 67]) will be left alone where-as
|
10
|
+
# all other byte sequences will be converted to UTF-8.
|
11
|
+
#
|
12
|
+
# E.g.
|
13
|
+
# parse_bytes_into_sequences [97, 98, [27, 91, 67], 99, 198, 146]
|
14
|
+
# # => ["a", "b", [27, 91, 67], "c", "ƒ"]
|
15
|
+
#
|
16
|
+
def parse_bytes_into_sequences(bytes)
|
17
|
+
key_codes = parse_bytes(bytes)
|
18
|
+
|
19
|
+
byte_buffer = []
|
20
|
+
sequences = key_codes.each_with_object([]) do |val, arr|
|
21
|
+
if val.is_a?(Array)
|
22
|
+
arr.push *convert_bytes_to_utf8(byte_buffer)
|
23
|
+
arr << val
|
24
|
+
byte_buffer = []
|
25
|
+
else
|
26
|
+
byte_buffer << val
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# don't forget about remaining bytes in the buffer
|
31
|
+
if byte_buffer.any?
|
32
|
+
sequences.push *convert_bytes_to_utf8(byte_buffer)
|
33
|
+
end
|
34
|
+
|
35
|
+
sequences
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def convert_bytes_to_utf8(bytes)
|
41
|
+
bytes.pack('C*').force_encoding('UTF-8')
|
42
|
+
end
|
43
|
+
|
8
44
|
def parse_bytes(bytes)
|
9
45
|
i = 0
|
10
46
|
results = []
|
data/lib/rawline/line.rb
CHANGED
@@ -22,6 +22,10 @@ module RawLine
|
|
22
22
|
@escape_codes = [?\e.ord]
|
23
23
|
@keys.merge!(
|
24
24
|
{
|
25
|
+
:alt_up_arrow => [?\e.ord, ?\e.ord, ?[.ord, ?A.ord],
|
26
|
+
:alt_down_arrow => [?\e.ord, ?\e.ord, ?[.ord, ?B.ord],
|
27
|
+
:alt_right_arrow => [?\e.ord, ?\e.ord, ?[.ord, ?C.ord],
|
28
|
+
:alt_left_arrow => [?\e.ord, ?\e.ord, ?[.ord, ?D.ord],
|
25
29
|
:up_arrow => [?\e.ord, ?[.ord, ?A.ord],
|
26
30
|
:down_arrow => [?\e.ord, ?[.ord, ?B.ord],
|
27
31
|
:right_arrow => [?\e.ord, ?[.ord, ?C.ord],
|
data/lib/rawline/terminal.rb
CHANGED
data/lib/rawline.rb
CHANGED
data/lib/tasks/gem.rake
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
namespace :bump do
|
2
|
+
namespace :version do
|
3
|
+
class ProjectVersion
|
4
|
+
FILE = File.dirname(__FILE__) + '/../rawline/version.rb'
|
5
|
+
PATTERN = /VERSION\s*=\s*"(\d+)\.(\d+)\.(\d+)"/m
|
6
|
+
|
7
|
+
def initialize(file=FILE, pattern=PATTERN)
|
8
|
+
@file = file
|
9
|
+
@pattern = pattern
|
10
|
+
end
|
11
|
+
|
12
|
+
def bump(major:nil, minor:nil, patch:nil)
|
13
|
+
version = nil
|
14
|
+
contents.sub!(@pattern) do
|
15
|
+
_major = major.call($1) if major
|
16
|
+
_minor = minor.call($2) if minor
|
17
|
+
_patch = patch.call($3) if patch
|
18
|
+
version = "#{_major}.#{_minor}.#{_patch}"
|
19
|
+
results = %|VERSION = "#{version}"|
|
20
|
+
end
|
21
|
+
File.write(@file, contents)
|
22
|
+
system "bundle"
|
23
|
+
system "git add #{ProjectVersion::FILE} && git commit -m 'Bumping version to #{version}'"
|
24
|
+
system "git tag v#{version}"
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def contents
|
30
|
+
@contents ||= File.read(@file)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Increments the patch number by 1 for the project"
|
35
|
+
task :patch do
|
36
|
+
ProjectVersion.new.bump(
|
37
|
+
major: ->(major){ major },
|
38
|
+
minor: ->(minor){ minor },
|
39
|
+
patch: ->(patch){ patch.succ }
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Increments the minor number by 1 for the project"
|
44
|
+
task :minor do
|
45
|
+
ProjectVersion.new.bump(
|
46
|
+
major: ->(major){ major },
|
47
|
+
minor: ->(minor){ minor.succ },
|
48
|
+
patch: ->(patch){ 0 }
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Increments the major number by 1 for the project"
|
53
|
+
task :major do
|
54
|
+
ProjectVersion.new.bump(
|
55
|
+
major: ->(major){ major.succ },
|
56
|
+
minor: ->(minor){ 0 },
|
57
|
+
patch: ->(patch){ 0 }
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
data/spec/editor_spec.rb
CHANGED
@@ -132,7 +132,7 @@ describe RawLine::Editor do
|
|
132
132
|
it "moves the line and cursor position to left by 1 character" do
|
133
133
|
@editor.event_loop.tick
|
134
134
|
expect(@editor.line.position).to eq(3)
|
135
|
-
expect(@editor.input_box.
|
135
|
+
expect(@editor.input_box.position).to eq(3)
|
136
136
|
|
137
137
|
input.clear
|
138
138
|
input << arrow_key_left_ansi
|
@@ -142,7 +142,7 @@ describe RawLine::Editor do
|
|
142
142
|
@editor.event_loop.tick
|
143
143
|
|
144
144
|
expect(@editor.line.position).to eq(2)
|
145
|
-
expect(@editor.input_box.
|
145
|
+
expect(@editor.input_box.position).to eq(2)
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
@@ -150,7 +150,7 @@ describe RawLine::Editor do
|
|
150
150
|
it "doesnt move the line and cursor position" do
|
151
151
|
@editor.event_loop.tick
|
152
152
|
expect(@editor.line.position).to eq(3)
|
153
|
-
expect(@editor.input_box.
|
153
|
+
expect(@editor.input_box.position).to eq(3)
|
154
154
|
|
155
155
|
input.clear
|
156
156
|
input << arrow_key_right_ansi
|
@@ -160,7 +160,7 @@ describe RawLine::Editor do
|
|
160
160
|
@editor.event_loop.tick
|
161
161
|
|
162
162
|
expect(@editor.line.position).to eq(3)
|
163
|
-
expect(@editor.input_box.
|
163
|
+
expect(@editor.input_box.position).to eq(3)
|
164
164
|
end
|
165
165
|
end
|
166
166
|
|
@@ -204,12 +204,77 @@ describe RawLine::Editor do
|
|
204
204
|
|
205
205
|
it "correctly sets the line and cursor position" do
|
206
206
|
expect(@editor.line.position).to eq(3)
|
207
|
-
expect(@editor.input_box.
|
207
|
+
expect(@editor.input_box.position).to eq(3)
|
208
208
|
end
|
209
209
|
end
|
210
210
|
end
|
211
211
|
end
|
212
212
|
|
213
|
+
describe "#insert" do
|
214
|
+
before do
|
215
|
+
input << "test #5"
|
216
|
+
input.rewind
|
217
|
+
@editor.event_loop.tick
|
218
|
+
expect(@editor.line.position).to eq(7)
|
219
|
+
end
|
220
|
+
|
221
|
+
it "inserts the given string at the current line position" do
|
222
|
+
@editor.insert "ABC"
|
223
|
+
expect(@editor.line.text).to eq("test #5ABC")
|
224
|
+
end
|
225
|
+
|
226
|
+
it "increments the line position the length of the inserted string" do
|
227
|
+
@editor.insert "ABC"
|
228
|
+
expect(@editor.line.position).to eq(10)
|
229
|
+
end
|
230
|
+
|
231
|
+
it "shifts characters not at the end of the string" do
|
232
|
+
@editor.move_left
|
233
|
+
@editor.insert "931"
|
234
|
+
expect(@editor.line.text).to eq("test #9315")
|
235
|
+
expect(@editor.line.position).to eq(9)
|
236
|
+
end
|
237
|
+
|
238
|
+
it "updates the DOM's input_box and position" do
|
239
|
+
@editor.insert "hello"
|
240
|
+
expect(dom.input_box.content).to eq("test #5hello")
|
241
|
+
expect(dom.input_box.position).to eq(12)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe "#write" do
|
246
|
+
before do
|
247
|
+
input << "test #5"
|
248
|
+
input.rewind
|
249
|
+
@editor.event_loop.tick
|
250
|
+
expect(@editor.line.position).to eq(7)
|
251
|
+
end
|
252
|
+
|
253
|
+
it "writes the given string at the current line position" do
|
254
|
+
@editor.write "ABC"
|
255
|
+
expect(@editor.line.text).to eq("test #5ABC")
|
256
|
+
end
|
257
|
+
|
258
|
+
it "increments the line position the length of the written string" do
|
259
|
+
@editor.write "ABC"
|
260
|
+
expect(@editor.line.position).to eq(10)
|
261
|
+
end
|
262
|
+
|
263
|
+
it "overwrites any character at the current position" do
|
264
|
+
@editor.move_left
|
265
|
+
@editor.write "931"
|
266
|
+
expect(@editor.line.text).to eq("test #931")
|
267
|
+
expect(@editor.line.position).to eq(9)
|
268
|
+
end
|
269
|
+
|
270
|
+
it "updates the DOM's input_box and position" do
|
271
|
+
@editor.move_left
|
272
|
+
@editor.write "hello"
|
273
|
+
expect(dom.input_box.content).to eq("test #hello")
|
274
|
+
expect(dom.input_box.position).to eq(11)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
213
278
|
it "can delete characters" do
|
214
279
|
input << "test #5"
|
215
280
|
input.rewind
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yap-rawline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fabio Cevasco
|
@@ -104,6 +104,8 @@ files:
|
|
104
104
|
- lib/rawline/terminal.rb
|
105
105
|
- lib/rawline/terminal/vt220_terminal.rb
|
106
106
|
- lib/rawline/terminal/windows_terminal.rb
|
107
|
+
- lib/rawline/version.rb
|
108
|
+
- lib/tasks/gem.rake
|
107
109
|
- spec/editor_spec.rb
|
108
110
|
- spec/history_buffer_spec.rb
|
109
111
|
- spec/keycode_parser_spec.rb
|