reline 0.5.12 → 0.6.1
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.
- checksums.yaml +4 -4
- data/lib/reline/io/ansi.rb +44 -36
- data/lib/reline/io/dumb.rb +11 -0
- data/lib/reline/io/windows.rb +11 -1
- data/lib/reline/io.rb +14 -0
- data/lib/reline/key_actor/base.rb +10 -4
- data/lib/reline/key_actor/emacs.rb +96 -96
- data/lib/reline/key_actor/vi_command.rb +182 -182
- data/lib/reline/key_actor/vi_insert.rb +137 -137
- data/lib/reline/key_stroke.rb +10 -11
- data/lib/reline/line_editor.rb +153 -250
- data/lib/reline/unicode/east_asian_width.rb +41 -15
- data/lib/reline/unicode.rb +102 -348
- data/lib/reline/version.rb +1 -1
- data/lib/reline.rb +34 -25
- metadata +3 -4
@@ -1,6 +1,6 @@
|
|
1
1
|
class Reline::Unicode::EastAsianWidth
|
2
2
|
# This is based on EastAsianWidth.txt
|
3
|
-
# UNICODE_VERSION = '
|
3
|
+
# UNICODE_VERSION = '16.0.0'
|
4
4
|
|
5
5
|
CHUNK_LAST, CHUNK_WIDTH = [
|
6
6
|
[0x1f, 2],
|
@@ -174,7 +174,7 @@ class Reline::Unicode::EastAsianWidth
|
|
174
174
|
[0x82d, 0],
|
175
175
|
[0x858, 1],
|
176
176
|
[0x85b, 0],
|
177
|
-
[
|
177
|
+
[0x896, 1],
|
178
178
|
[0x89f, 0],
|
179
179
|
[0x8c9, 1],
|
180
180
|
[0x8e1, 0],
|
@@ -646,6 +646,8 @@ class Reline::Unicode::EastAsianWidth
|
|
646
646
|
[0x261c, -1],
|
647
647
|
[0x261d, 1],
|
648
648
|
[0x261e, -1],
|
649
|
+
[0x262f, 1],
|
650
|
+
[0x2637, 2],
|
649
651
|
[0x263f, 1],
|
650
652
|
[0x2640, -1],
|
651
653
|
[0x2641, 1],
|
@@ -664,6 +666,8 @@ class Reline::Unicode::EastAsianWidth
|
|
664
666
|
[0x266f, -1],
|
665
667
|
[0x267e, 1],
|
666
668
|
[0x267f, 2],
|
669
|
+
[0x2689, 1],
|
670
|
+
[0x268f, 2],
|
667
671
|
[0x2692, 1],
|
668
672
|
[0x2693, 2],
|
669
673
|
[0x269d, 1],
|
@@ -753,14 +757,12 @@ class Reline::Unicode::EastAsianWidth
|
|
753
757
|
[0x3130, 1],
|
754
758
|
[0x318e, 2],
|
755
759
|
[0x318f, 1],
|
756
|
-
[
|
760
|
+
[0x31e5, 2],
|
757
761
|
[0x31ee, 1],
|
758
762
|
[0x321e, 2],
|
759
763
|
[0x321f, 1],
|
760
764
|
[0x3247, 2],
|
761
765
|
[0x324f, -1],
|
762
|
-
[0x4dbf, 2],
|
763
|
-
[0x4dff, 1],
|
764
766
|
[0xa48c, 2],
|
765
767
|
[0xa48f, 1],
|
766
768
|
[0xa4c6, 2],
|
@@ -879,9 +881,11 @@ class Reline::Unicode::EastAsianWidth
|
|
879
881
|
[0x10ae6, 0],
|
880
882
|
[0x10d23, 1],
|
881
883
|
[0x10d27, 0],
|
884
|
+
[0x10d68, 1],
|
885
|
+
[0x10d6d, 0],
|
882
886
|
[0x10eaa, 1],
|
883
887
|
[0x10eac, 0],
|
884
|
-
[
|
888
|
+
[0x10efb, 1],
|
885
889
|
[0x10eff, 0],
|
886
890
|
[0x10f45, 1],
|
887
891
|
[0x10f50, 0],
|
@@ -943,6 +947,16 @@ class Reline::Unicode::EastAsianWidth
|
|
943
947
|
[0x1136c, 0],
|
944
948
|
[0x1136f, 1],
|
945
949
|
[0x11374, 0],
|
950
|
+
[0x113ba, 1],
|
951
|
+
[0x113c0, 0],
|
952
|
+
[0x113cd, 1],
|
953
|
+
[0x113ce, 0],
|
954
|
+
[0x113cf, 1],
|
955
|
+
[0x113d0, 0],
|
956
|
+
[0x113d1, 1],
|
957
|
+
[0x113d2, 0],
|
958
|
+
[0x113e0, 1],
|
959
|
+
[0x113e2, 0],
|
946
960
|
[0x11437, 1],
|
947
961
|
[0x1143f, 0],
|
948
962
|
[0x11441, 1],
|
@@ -982,6 +996,8 @@ class Reline::Unicode::EastAsianWidth
|
|
982
996
|
[0x116b6, 1],
|
983
997
|
[0x116b7, 0],
|
984
998
|
[0x1171c, 1],
|
999
|
+
[0x1171d, 0],
|
1000
|
+
[0x1171e, 1],
|
985
1001
|
[0x1171f, 0],
|
986
1002
|
[0x11721, 1],
|
987
1003
|
[0x11725, 0],
|
@@ -1059,10 +1075,16 @@ class Reline::Unicode::EastAsianWidth
|
|
1059
1075
|
[0x11f40, 0],
|
1060
1076
|
[0x11f41, 1],
|
1061
1077
|
[0x11f42, 0],
|
1078
|
+
[0x11f59, 1],
|
1079
|
+
[0x11f5a, 0],
|
1062
1080
|
[0x1343f, 1],
|
1063
1081
|
[0x13440, 0],
|
1064
1082
|
[0x13446, 1],
|
1065
1083
|
[0x13455, 0],
|
1084
|
+
[0x1611d, 1],
|
1085
|
+
[0x16129, 0],
|
1086
|
+
[0x1612c, 1],
|
1087
|
+
[0x1612f, 0],
|
1066
1088
|
[0x16aef, 1],
|
1067
1089
|
[0x16af4, 0],
|
1068
1090
|
[0x16b2f, 1],
|
@@ -1080,7 +1102,7 @@ class Reline::Unicode::EastAsianWidth
|
|
1080
1102
|
[0x187f7, 2],
|
1081
1103
|
[0x187ff, 1],
|
1082
1104
|
[0x18cd5, 2],
|
1083
|
-
[
|
1105
|
+
[0x18cfe, 1],
|
1084
1106
|
[0x18d08, 2],
|
1085
1107
|
[0x1afef, 1],
|
1086
1108
|
[0x1aff3, 2],
|
@@ -1116,6 +1138,10 @@ class Reline::Unicode::EastAsianWidth
|
|
1116
1138
|
[0x1d1ad, 0],
|
1117
1139
|
[0x1d241, 1],
|
1118
1140
|
[0x1d244, 0],
|
1141
|
+
[0x1d2ff, 1],
|
1142
|
+
[0x1d356, 2],
|
1143
|
+
[0x1d35f, 1],
|
1144
|
+
[0x1d376, 2],
|
1119
1145
|
[0x1d9ff, 1],
|
1120
1146
|
[0x1da36, 0],
|
1121
1147
|
[0x1da3a, 1],
|
@@ -1148,6 +1174,8 @@ class Reline::Unicode::EastAsianWidth
|
|
1148
1174
|
[0x1e2ef, 0],
|
1149
1175
|
[0x1e4eb, 1],
|
1150
1176
|
[0x1e4ef, 0],
|
1177
|
+
[0x1e5ed, 1],
|
1178
|
+
[0x1e5ef, 0],
|
1151
1179
|
[0x1e8cf, 1],
|
1152
1180
|
[0x1e8d6, 0],
|
1153
1181
|
[0x1e943, 1],
|
@@ -1241,15 +1269,13 @@ class Reline::Unicode::EastAsianWidth
|
|
1241
1269
|
[0x1fa6f, 1],
|
1242
1270
|
[0x1fa7c, 2],
|
1243
1271
|
[0x1fa7f, 1],
|
1244
|
-
[
|
1245
|
-
[
|
1246
|
-
[
|
1247
|
-
[0x1fabe, 1],
|
1248
|
-
[0x1fac5, 2],
|
1272
|
+
[0x1fa89, 2],
|
1273
|
+
[0x1fa8e, 1],
|
1274
|
+
[0x1fac6, 2],
|
1249
1275
|
[0x1facd, 1],
|
1250
|
-
[
|
1251
|
-
[
|
1252
|
-
[
|
1276
|
+
[0x1fadc, 2],
|
1277
|
+
[0x1fade, 1],
|
1278
|
+
[0x1fae9, 2],
|
1253
1279
|
[0x1faef, 1],
|
1254
1280
|
[0x1faf8, 2],
|
1255
1281
|
[0x1ffff, 1],
|
data/lib/reline/unicode.rb
CHANGED
@@ -28,12 +28,12 @@ class Reline::Unicode
|
|
28
28
|
0x19 => '^Y',
|
29
29
|
0x1A => '^Z', # C-z
|
30
30
|
0x1B => '^[', # C-[ C-3
|
31
|
+
0x1C => '^\\', # C-\
|
31
32
|
0x1D => '^]', # C-]
|
32
33
|
0x1E => '^^', # C-~ C-6
|
33
34
|
0x1F => '^_', # C-_ C-7
|
34
35
|
0x7F => '^?', # C-? C-8
|
35
36
|
}
|
36
|
-
EscapedChars = EscapedPairs.keys.map(&:chr)
|
37
37
|
|
38
38
|
NON_PRINTING_START = "\1"
|
39
39
|
NON_PRINTING_END = "\2"
|
@@ -61,7 +61,7 @@ class Reline::Unicode
|
|
61
61
|
|
62
62
|
# This code is essentially doing the same thing as
|
63
63
|
# `str.encode(utf8, **replace_options).encode(encoding, **replace_options)`
|
64
|
-
# but also avoids
|
64
|
+
# but also avoids unnecessary irreversible encoding conversion.
|
65
65
|
converted.gsub(/\X/) do |c|
|
66
66
|
c.encode(Encoding::UTF_8)
|
67
67
|
c
|
@@ -262,375 +262,126 @@ class Reline::Unicode
|
|
262
262
|
end
|
263
263
|
|
264
264
|
def self.em_forward_word(line, byte_pointer)
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
|
270
|
-
byte_size += size
|
271
|
-
end
|
272
|
-
while line.bytesize > (byte_pointer + byte_size)
|
273
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
274
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
275
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
|
276
|
-
byte_size += size
|
277
|
-
end
|
278
|
-
byte_size
|
265
|
+
gcs = line.byteslice(byte_pointer..).grapheme_clusters
|
266
|
+
nonwords = gcs.take_while { |c| !word_character?(c) }
|
267
|
+
words = gcs.drop(nonwords.size).take_while { |c| word_character?(c) }
|
268
|
+
nonwords.sum(&:bytesize) + words.sum(&:bytesize)
|
279
269
|
end
|
280
270
|
|
281
271
|
def self.em_forward_word_with_capitalization(line, byte_pointer)
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
287
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
|
288
|
-
new_str += mbchar
|
289
|
-
byte_size += size
|
290
|
-
end
|
291
|
-
first = true
|
292
|
-
while line.bytesize > (byte_pointer + byte_size)
|
293
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
294
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
295
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
|
296
|
-
if first
|
297
|
-
new_str += mbchar.upcase
|
298
|
-
first = false
|
299
|
-
else
|
300
|
-
new_str += mbchar.downcase
|
301
|
-
end
|
302
|
-
byte_size += size
|
303
|
-
end
|
304
|
-
[byte_size, new_str]
|
272
|
+
gcs = line.byteslice(byte_pointer..).grapheme_clusters
|
273
|
+
nonwords = gcs.take_while { |c| !word_character?(c) }
|
274
|
+
words = gcs.drop(nonwords.size).take_while { |c| word_character?(c) }
|
275
|
+
[nonwords.sum(&:bytesize) + words.sum(&:bytesize), nonwords.join + words.join.capitalize]
|
305
276
|
end
|
306
277
|
|
307
278
|
def self.em_backward_word(line, byte_pointer)
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
|
313
|
-
byte_size += size
|
314
|
-
end
|
315
|
-
while 0 < (byte_pointer - byte_size)
|
316
|
-
size = get_prev_mbchar_size(line, byte_pointer - byte_size)
|
317
|
-
mbchar = line.byteslice(byte_pointer - byte_size - size, size)
|
318
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
|
319
|
-
byte_size += size
|
320
|
-
end
|
321
|
-
byte_size
|
279
|
+
gcs = line.byteslice(0, byte_pointer).grapheme_clusters.reverse
|
280
|
+
nonwords = gcs.take_while { |c| !word_character?(c) }
|
281
|
+
words = gcs.drop(nonwords.size).take_while { |c| word_character?(c) }
|
282
|
+
nonwords.sum(&:bytesize) + words.sum(&:bytesize)
|
322
283
|
end
|
323
284
|
|
324
285
|
def self.em_big_backward_word(line, byte_pointer)
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
break if mbchar =~ /\S/
|
330
|
-
byte_size += size
|
331
|
-
end
|
332
|
-
while 0 < (byte_pointer - byte_size)
|
333
|
-
size = get_prev_mbchar_size(line, byte_pointer - byte_size)
|
334
|
-
mbchar = line.byteslice(byte_pointer - byte_size - size, size)
|
335
|
-
break if mbchar =~ /\s/
|
336
|
-
byte_size += size
|
337
|
-
end
|
338
|
-
byte_size
|
286
|
+
gcs = line.byteslice(0, byte_pointer).grapheme_clusters.reverse
|
287
|
+
spaces = gcs.take_while { |c| space_character?(c) }
|
288
|
+
nonspaces = gcs.drop(spaces.size).take_while { |c| !space_character?(c) }
|
289
|
+
spaces.sum(&:bytesize) + nonspaces.sum(&:bytesize)
|
339
290
|
end
|
340
291
|
|
341
292
|
def self.ed_transpose_words(line, byte_pointer)
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
while line.bytesize > (byte_pointer + byte_size)
|
363
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
364
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
365
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
|
366
|
-
byte_size += size
|
367
|
-
end
|
368
|
-
after_start = byte_pointer + byte_size
|
369
|
-
elsif mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
|
370
|
-
# ' aaa bb[cursor]b'
|
371
|
-
byte_size = 0
|
372
|
-
while 0 < (byte_pointer + byte_size)
|
373
|
-
size = get_prev_mbchar_size(line, byte_pointer + byte_size)
|
374
|
-
mbchar = line.byteslice(byte_pointer + byte_size - size, size)
|
375
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
|
376
|
-
byte_size -= size
|
377
|
-
end
|
378
|
-
right_word_start = byte_pointer + byte_size
|
379
|
-
byte_size = 0
|
380
|
-
while line.bytesize > (byte_pointer + byte_size)
|
381
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
382
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
383
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
|
384
|
-
byte_size += size
|
385
|
-
end
|
386
|
-
after_start = byte_pointer + byte_size
|
387
|
-
else
|
388
|
-
byte_size = 0
|
389
|
-
while (line.bytesize - 1) > (byte_pointer + byte_size)
|
390
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
391
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
392
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
|
393
|
-
byte_size += size
|
394
|
-
end
|
395
|
-
if (byte_pointer + byte_size) == (line.bytesize - 1)
|
396
|
-
# ' aaa bbb [cursor] '
|
397
|
-
after_start = line.bytesize
|
398
|
-
while 0 < (byte_pointer + byte_size)
|
399
|
-
size = get_prev_mbchar_size(line, byte_pointer + byte_size)
|
400
|
-
mbchar = line.byteslice(byte_pointer + byte_size - size, size)
|
401
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
|
402
|
-
byte_size -= size
|
403
|
-
end
|
404
|
-
while 0 < (byte_pointer + byte_size)
|
405
|
-
size = get_prev_mbchar_size(line, byte_pointer + byte_size)
|
406
|
-
mbchar = line.byteslice(byte_pointer + byte_size - size, size)
|
407
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
|
408
|
-
byte_size -= size
|
409
|
-
end
|
410
|
-
right_word_start = byte_pointer + byte_size
|
411
|
-
else
|
412
|
-
# ' aaa [cursor] bbb '
|
413
|
-
right_word_start = byte_pointer + byte_size
|
414
|
-
while line.bytesize > (byte_pointer + byte_size)
|
415
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
416
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
417
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
|
418
|
-
byte_size += size
|
419
|
-
end
|
420
|
-
after_start = byte_pointer + byte_size
|
421
|
-
end
|
422
|
-
end
|
423
|
-
byte_size = right_word_start - byte_pointer
|
424
|
-
while 0 < (byte_pointer + byte_size)
|
425
|
-
size = get_prev_mbchar_size(line, byte_pointer + byte_size)
|
426
|
-
mbchar = line.byteslice(byte_pointer + byte_size - size, size)
|
427
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\p{Word}/
|
428
|
-
byte_size -= size
|
429
|
-
end
|
430
|
-
middle_start = byte_pointer + byte_size
|
431
|
-
byte_size = middle_start - byte_pointer
|
432
|
-
while 0 < (byte_pointer + byte_size)
|
433
|
-
size = get_prev_mbchar_size(line, byte_pointer + byte_size)
|
434
|
-
mbchar = line.byteslice(byte_pointer + byte_size - size, size)
|
435
|
-
break if mbchar.encode(Encoding::UTF_8) =~ /\P{Word}/
|
436
|
-
byte_size -= size
|
293
|
+
gcs = line.byteslice(0, byte_pointer).grapheme_clusters
|
294
|
+
pos = gcs.size
|
295
|
+
gcs += line.byteslice(byte_pointer..).grapheme_clusters
|
296
|
+
pos += 1 while pos < gcs.size && !word_character?(gcs[pos])
|
297
|
+
if pos == gcs.size # 'aaa bbb [cursor] '
|
298
|
+
pos -= 1 while pos > 0 && !word_character?(gcs[pos - 1])
|
299
|
+
second_word_end = gcs.size
|
300
|
+
else # 'aaa [cursor]bbb'
|
301
|
+
pos += 1 while pos < gcs.size && word_character?(gcs[pos])
|
302
|
+
second_word_end = pos
|
303
|
+
end
|
304
|
+
pos -= 1 while pos > 0 && word_character?(gcs[pos - 1])
|
305
|
+
second_word_start = pos
|
306
|
+
pos -= 1 while pos > 0 && !word_character?(gcs[pos - 1])
|
307
|
+
first_word_end = pos
|
308
|
+
pos -= 1 while pos > 0 && word_character?(gcs[pos - 1])
|
309
|
+
first_word_start = pos
|
310
|
+
|
311
|
+
[first_word_start, first_word_end, second_word_start, second_word_end].map do |idx|
|
312
|
+
gcs.take(idx).sum(&:bytesize)
|
437
313
|
end
|
438
|
-
left_word_start = byte_pointer + byte_size
|
439
|
-
[left_word_start, middle_start, right_word_start, after_start]
|
440
314
|
end
|
441
315
|
|
442
316
|
def self.vi_big_forward_word(line, byte_pointer)
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
break if mbchar =~ /\s/
|
448
|
-
byte_size += size
|
449
|
-
end
|
450
|
-
while (line.bytesize - 1) > (byte_pointer + byte_size)
|
451
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
452
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
453
|
-
break if mbchar =~ /\S/
|
454
|
-
byte_size += size
|
455
|
-
end
|
456
|
-
byte_size
|
317
|
+
gcs = line.byteslice(byte_pointer..).grapheme_clusters
|
318
|
+
nonspaces = gcs.take_while { |c| !space_character?(c) }
|
319
|
+
spaces = gcs.drop(nonspaces.size).take_while { |c| space_character?(c) }
|
320
|
+
nonspaces.sum(&:bytesize) + spaces.sum(&:bytesize)
|
457
321
|
end
|
458
322
|
|
459
323
|
def self.vi_big_forward_end_word(line, byte_pointer)
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
468
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
469
|
-
break if mbchar =~ /\S/
|
470
|
-
byte_size += size
|
471
|
-
end
|
472
|
-
prev_byte_size = byte_size
|
473
|
-
while line.bytesize > (byte_pointer + byte_size)
|
474
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
475
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
476
|
-
break if mbchar =~ /\s/
|
477
|
-
prev_byte_size = byte_size
|
478
|
-
byte_size += size
|
479
|
-
end
|
480
|
-
prev_byte_size
|
324
|
+
gcs = line.byteslice(byte_pointer..).grapheme_clusters
|
325
|
+
first = gcs.shift(1)
|
326
|
+
spaces = gcs.take_while { |c| space_character?(c) }
|
327
|
+
nonspaces = gcs.drop(spaces.size).take_while { |c| !space_character?(c) }
|
328
|
+
matched = spaces + nonspaces
|
329
|
+
matched.pop
|
330
|
+
first.sum(&:bytesize) + matched.sum(&:bytesize)
|
481
331
|
end
|
482
332
|
|
483
333
|
def self.vi_big_backward_word(line, byte_pointer)
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
break if mbchar =~ /\S/
|
489
|
-
byte_size += size
|
490
|
-
end
|
491
|
-
while 0 < (byte_pointer - byte_size)
|
492
|
-
size = get_prev_mbchar_size(line, byte_pointer - byte_size)
|
493
|
-
mbchar = line.byteslice(byte_pointer - byte_size - size, size)
|
494
|
-
break if mbchar =~ /\s/
|
495
|
-
byte_size += size
|
496
|
-
end
|
497
|
-
byte_size
|
334
|
+
gcs = line.byteslice(0, byte_pointer).grapheme_clusters.reverse
|
335
|
+
spaces = gcs.take_while { |c| space_character?(c) }
|
336
|
+
nonspaces = gcs.drop(spaces.size).take_while { |c| !space_character?(c) }
|
337
|
+
spaces.sum(&:bytesize) + nonspaces.sum(&:bytesize)
|
498
338
|
end
|
499
339
|
|
500
340
|
def self.vi_forward_word(line, byte_pointer, drop_terminate_spaces = false)
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
341
|
+
gcs = line.byteslice(byte_pointer..).grapheme_clusters
|
342
|
+
return 0 if gcs.empty?
|
343
|
+
|
344
|
+
c = gcs.first
|
345
|
+
matched =
|
346
|
+
if word_character?(c)
|
347
|
+
gcs.take_while { |c| word_character?(c) }
|
348
|
+
elsif space_character?(c)
|
349
|
+
gcs.take_while { |c| space_character?(c) }
|
508
350
|
else
|
509
|
-
|
510
|
-
end
|
511
|
-
byte_size = size
|
512
|
-
else
|
513
|
-
return 0
|
514
|
-
end
|
515
|
-
while line.bytesize > (byte_pointer + byte_size)
|
516
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
517
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
518
|
-
case started_by
|
519
|
-
when :word
|
520
|
-
break if mbchar =~ /\W/
|
521
|
-
when :space
|
522
|
-
break if mbchar =~ /\S/
|
523
|
-
when :non_word_printable
|
524
|
-
break if mbchar =~ /\w|\s/
|
351
|
+
gcs.take_while { |c| !word_character?(c) && !space_character?(c) }
|
525
352
|
end
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
532
|
-
break if mbchar =~ /\S/
|
533
|
-
byte_size += size
|
534
|
-
end
|
535
|
-
byte_size
|
353
|
+
|
354
|
+
return matched.sum(&:bytesize) if drop_terminate_spaces
|
355
|
+
|
356
|
+
spaces = gcs.drop(matched.size).take_while { |c| space_character?(c) }
|
357
|
+
matched.sum(&:bytesize) + spaces.sum(&:bytesize)
|
536
358
|
end
|
537
359
|
|
538
360
|
def self.vi_forward_end_word(line, byte_pointer)
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
555
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
556
|
-
if mbchar =~ /\w/
|
557
|
-
second = :word
|
558
|
-
elsif mbchar =~ /\s/
|
559
|
-
second = :space
|
560
|
-
else
|
561
|
-
second = :non_word_printable
|
562
|
-
end
|
563
|
-
second_byte_size = size
|
564
|
-
else
|
565
|
-
return byte_size
|
566
|
-
end
|
567
|
-
if second == :space
|
568
|
-
byte_size += second_byte_size
|
569
|
-
while (line.bytesize - 1) > (byte_pointer + byte_size)
|
570
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
571
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
572
|
-
if mbchar =~ /\S/
|
573
|
-
if mbchar =~ /\w/
|
574
|
-
started_by = :word
|
575
|
-
else
|
576
|
-
started_by = :non_word_printable
|
577
|
-
end
|
578
|
-
break
|
579
|
-
end
|
580
|
-
byte_size += size
|
581
|
-
end
|
582
|
-
else
|
583
|
-
case [started_by, second]
|
584
|
-
when [:word, :non_word_printable], [:non_word_printable, :word]
|
585
|
-
started_by = second
|
586
|
-
else
|
587
|
-
byte_size += second_byte_size
|
588
|
-
started_by = second
|
589
|
-
end
|
590
|
-
end
|
591
|
-
prev_byte_size = byte_size
|
592
|
-
while line.bytesize > (byte_pointer + byte_size)
|
593
|
-
size = get_next_mbchar_size(line, byte_pointer + byte_size)
|
594
|
-
mbchar = line.byteslice(byte_pointer + byte_size, size)
|
595
|
-
case started_by
|
596
|
-
when :word
|
597
|
-
break if mbchar =~ /\W/
|
598
|
-
when :non_word_printable
|
599
|
-
break if mbchar =~ /[\w\s]/
|
600
|
-
end
|
601
|
-
prev_byte_size = byte_size
|
602
|
-
byte_size += size
|
603
|
-
end
|
604
|
-
prev_byte_size
|
361
|
+
gcs = line.byteslice(byte_pointer..).grapheme_clusters
|
362
|
+
return 0 if gcs.empty?
|
363
|
+
return gcs.first.bytesize if gcs.size == 1
|
364
|
+
|
365
|
+
start = gcs.shift
|
366
|
+
skips = [start]
|
367
|
+
if space_character?(start) || space_character?(gcs.first)
|
368
|
+
spaces = gcs.take_while { |c| space_character?(c) }
|
369
|
+
skips += spaces
|
370
|
+
gcs.shift(spaces.size)
|
371
|
+
end
|
372
|
+
start_with_word = word_character?(gcs.first)
|
373
|
+
matched = gcs.take_while { |c| start_with_word ? word_character?(c) : !word_character?(c) && !space_character?(c) }
|
374
|
+
matched.pop
|
375
|
+
skips.sum(&:bytesize) + matched.sum(&:bytesize)
|
605
376
|
end
|
606
377
|
|
607
378
|
def self.vi_backward_word(line, byte_pointer)
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
started_by = :word
|
615
|
-
else
|
616
|
-
started_by = :non_word_printable
|
617
|
-
end
|
618
|
-
break
|
619
|
-
end
|
620
|
-
byte_size += size
|
621
|
-
end
|
622
|
-
while 0 < (byte_pointer - byte_size)
|
623
|
-
size = get_prev_mbchar_size(line, byte_pointer - byte_size)
|
624
|
-
mbchar = line.byteslice(byte_pointer - byte_size - size, size)
|
625
|
-
case started_by
|
626
|
-
when :word
|
627
|
-
break if mbchar =~ /\W/
|
628
|
-
when :non_word_printable
|
629
|
-
break if mbchar =~ /[\w\s]/
|
630
|
-
end
|
631
|
-
byte_size += size
|
632
|
-
end
|
633
|
-
byte_size
|
379
|
+
gcs = line.byteslice(0, byte_pointer).grapheme_clusters.reverse
|
380
|
+
spaces = gcs.take_while { |c| space_character?(c) }
|
381
|
+
gcs.shift(spaces.size)
|
382
|
+
start_with_word = word_character?(gcs.first)
|
383
|
+
matched = gcs.take_while { |c| start_with_word ? word_character?(c) : !word_character?(c) && !space_character?(c) }
|
384
|
+
spaces.sum(&:bytesize) + matched.sum(&:bytesize)
|
634
385
|
end
|
635
386
|
|
636
387
|
def self.common_prefix(list, ignore_case: false)
|
@@ -647,15 +398,18 @@ class Reline::Unicode
|
|
647
398
|
end
|
648
399
|
|
649
400
|
def self.vi_first_print(line)
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
401
|
+
gcs = line.grapheme_clusters
|
402
|
+
spaces = gcs.take_while { |c| space_character?(c) }
|
403
|
+
spaces.sum(&:bytesize)
|
404
|
+
end
|
405
|
+
|
406
|
+
def self.word_character?(s)
|
407
|
+
s.encode(Encoding::UTF_8).match?(/\p{Word}/) if s
|
408
|
+
rescue Encoding::UndefinedConversionError
|
409
|
+
false
|
410
|
+
end
|
411
|
+
|
412
|
+
def self.space_character?(s)
|
413
|
+
s.match?(/\s/) if s
|
660
414
|
end
|
661
415
|
end
|
data/lib/reline/version.rb
CHANGED