textbringer 3 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/macos.yml +1 -1
- data/.github/workflows/ubuntu.yml +1 -1
- data/.github/workflows/windows.yml +1 -1
- data/lib/textbringer/buffer.rb +60 -115
- data/lib/textbringer/commands/buffers.rb +1 -0
- data/lib/textbringer/keymap.rb +1 -0
- data/lib/textbringer/minor_mode.rb +35 -0
- data/lib/textbringer/modes/overwrite_mode.rb +27 -0
- data/lib/textbringer/utils.rb +22 -5
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +1 -1
- data/lib/textbringer.rb +2 -0
- data/textbringer.gemspec +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98c29dc1578dcd0acdfe058e2465e610d9803d687ac9e37ab0e2cc2935c6cc9f
|
4
|
+
data.tar.gz: 0feb32743ea8c276cb5a30e76f9725508481ca239a0f29960b8712642477ab80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d16b6eb9feb3679a1297dad604da419c3afb59a963e720d8f09c546a7accda2333732b7170edfa8db8eaef18b69d65aed87a8ed58610192fd6951021d61514b
|
7
|
+
data.tar.gz: 8b532a2c38278c08677be9bfb2cee271e0af00e832326859551d623a3daff8ad5207b4350cfe7642fbfe476fb3b7532a9671994db98355fdf8e179083c81042d
|
data/.github/workflows/macos.yml
CHANGED
data/lib/textbringer/buffer.rb
CHANGED
@@ -62,8 +62,6 @@ module Textbringer
|
|
62
62
|
end
|
63
63
|
}
|
64
64
|
|
65
|
-
HAS_BYTEINDEX = String.instance_methods.include?(:byteindex)
|
66
|
-
HAS_BYTESPLICE = String.instance_methods.include?(:bytesplice)
|
67
65
|
BYTESPLICE_SUPPORTS_PARTIAL_COPY =
|
68
66
|
begin
|
69
67
|
(+"foo").bytesplice(0, 2, "bar", 1, 2) == "aro"
|
@@ -249,6 +247,7 @@ module Textbringer
|
|
249
247
|
@version = 0
|
250
248
|
@modified = false
|
251
249
|
@mode = FundamentalMode.new(self)
|
250
|
+
@minor_modes = []
|
252
251
|
@keymap = nil
|
253
252
|
@attributes = {}
|
254
253
|
@save_point_level = 0
|
@@ -531,14 +530,10 @@ module Textbringer
|
|
531
530
|
if pos == point_min
|
532
531
|
column = 1
|
533
532
|
else
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
i = nil
|
539
|
-
end
|
540
|
-
else
|
541
|
-
i = @contents.rindex("\n", user_to_gap(pos - 1))
|
533
|
+
begin
|
534
|
+
i = @contents.byterindex("\n", user_to_gap(get_pos(pos, -1)))
|
535
|
+
rescue RangeError
|
536
|
+
i = nil
|
542
537
|
end
|
543
538
|
if i
|
544
539
|
i += 1
|
@@ -568,11 +563,7 @@ module Textbringer
|
|
568
563
|
pos = point_min
|
569
564
|
i = 1
|
570
565
|
while i < n && pos < @contents.bytesize
|
571
|
-
|
572
|
-
pos = @contents.byteindex("\n", pos)
|
573
|
-
else
|
574
|
-
pos = @contents.index("\n", pos)
|
575
|
-
end
|
566
|
+
pos = @contents.byteindex("\n", pos)
|
576
567
|
break if pos.nil?
|
577
568
|
i += 1
|
578
569
|
pos += 1
|
@@ -592,7 +583,7 @@ module Textbringer
|
|
592
583
|
pos = @point
|
593
584
|
size = s.bytesize
|
594
585
|
adjust_gap(size)
|
595
|
-
|
586
|
+
@contents.bytesplice(@point, size, s.b)
|
596
587
|
@marks.each do |m|
|
597
588
|
if m.location > @point
|
598
589
|
m.location += size
|
@@ -640,7 +631,7 @@ module Textbringer
|
|
640
631
|
if n > 0
|
641
632
|
str = substring(s, pos)
|
642
633
|
# fill the gap with NUL to avoid invalid byte sequence in UTF-8
|
643
|
-
|
634
|
+
@contents.bytesplice(@gap_end...user_to_gap(pos), "\0" * (pos - @point))
|
644
635
|
@gap_end += pos - @point
|
645
636
|
@marks.each do |m|
|
646
637
|
if m.location > pos
|
@@ -655,7 +646,7 @@ module Textbringer
|
|
655
646
|
str = substring(pos, s)
|
656
647
|
update_line_and_column(@point, pos)
|
657
648
|
# fill the gap with NUL to avoid invalid byte sequence in UTF-8
|
658
|
-
|
649
|
+
@contents.bytesplice(user_to_gap(pos)...@gap_start, "\0" * (@point - pos))
|
659
650
|
@marks.each do |m|
|
660
651
|
if m.location >= @point
|
661
652
|
m.location -= @point - pos
|
@@ -983,7 +974,7 @@ module Textbringer
|
|
983
974
|
adjust_gap
|
984
975
|
len = e - s
|
985
976
|
# fill the gap with NUL to avoid invalid byte sequence in UTF-8
|
986
|
-
|
977
|
+
@contents.bytesplice(@gap_end, len, "\0" * len)
|
987
978
|
@gap_end += len
|
988
979
|
@marks.each do |m|
|
989
980
|
if m.location > e
|
@@ -1161,72 +1152,23 @@ module Textbringer
|
|
1161
1152
|
byteindex(true, r, @point) == @point
|
1162
1153
|
end
|
1163
1154
|
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
s.force_encoding(Encoding::UTF_8)
|
1172
|
-
end
|
1173
|
-
i = s.send(method, re, pos)
|
1174
|
-
if i
|
1175
|
-
m = Regexp.last_match
|
1176
|
-
(0 .. m.size - 1).each do |j|
|
1177
|
-
@match_offsets.push(m.byteoffset(j))
|
1178
|
-
end
|
1179
|
-
i
|
1180
|
-
else
|
1181
|
-
nil
|
1182
|
-
end
|
1155
|
+
def byteindex(forward, re, pos)
|
1156
|
+
@match_offsets = []
|
1157
|
+
method = forward ? :byteindex : :byterindex
|
1158
|
+
adjust_gap(0, 0)
|
1159
|
+
s = @contents.byteslice(@gap_end..-1)
|
1160
|
+
unless binary?
|
1161
|
+
s.force_encoding(Encoding::UTF_8)
|
1183
1162
|
end
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
s = @contents[@gap_end..-1]
|
1190
|
-
if @binary
|
1191
|
-
offset = pos
|
1192
|
-
else
|
1193
|
-
offset = s.byteslice(0, pos).force_encoding(Encoding::UTF_8).size
|
1194
|
-
s.force_encoding(Encoding::UTF_8)
|
1195
|
-
end
|
1196
|
-
begin
|
1197
|
-
i = s.send(method, re, offset)
|
1198
|
-
if i
|
1199
|
-
m = Regexp.last_match
|
1200
|
-
if m.nil?
|
1201
|
-
# A bug of rindex
|
1202
|
-
@match_offsets.push([pos, pos])
|
1203
|
-
pos
|
1204
|
-
else
|
1205
|
-
b = m.pre_match.bytesize
|
1206
|
-
e = b + m.to_s.bytesize
|
1207
|
-
if e <= bytesize
|
1208
|
-
@match_offsets.push([b, e])
|
1209
|
-
match_beg = m.begin(0)
|
1210
|
-
match_str = m.to_s
|
1211
|
-
(1 .. m.size - 1).each do |j|
|
1212
|
-
cb, ce = m.offset(j)
|
1213
|
-
if cb.nil?
|
1214
|
-
@match_offsets.push([nil, nil])
|
1215
|
-
else
|
1216
|
-
bb = b + match_str[0, cb - match_beg].bytesize
|
1217
|
-
be = b + match_str[0, ce - match_beg].bytesize
|
1218
|
-
@match_offsets.push([bb, be])
|
1219
|
-
end
|
1220
|
-
end
|
1221
|
-
b
|
1222
|
-
else
|
1223
|
-
nil
|
1224
|
-
end
|
1225
|
-
end
|
1226
|
-
else
|
1227
|
-
nil
|
1228
|
-
end
|
1163
|
+
i = s.send(method, re, pos)
|
1164
|
+
if i
|
1165
|
+
m = Regexp.last_match
|
1166
|
+
(0 .. m.size - 1).each do |j|
|
1167
|
+
@match_offsets.push(m.byteoffset(j))
|
1229
1168
|
end
|
1169
|
+
i
|
1170
|
+
else
|
1171
|
+
nil
|
1230
1172
|
end
|
1231
1173
|
end
|
1232
1174
|
|
@@ -1335,6 +1277,27 @@ module Textbringer
|
|
1335
1277
|
Utils.run_hooks(mode_class.hook_name)
|
1336
1278
|
end
|
1337
1279
|
|
1280
|
+
def toggle_minor_mode(mode_class)
|
1281
|
+
mode = @minor_modes.find { |mode| mode.instance_of?(mode_class) }
|
1282
|
+
if mode
|
1283
|
+
mode.disable
|
1284
|
+
@minor_modes.delete(mode)
|
1285
|
+
else
|
1286
|
+
mode = mode_class.new(self)
|
1287
|
+
@minor_modes.push(mode)
|
1288
|
+
mode.enable
|
1289
|
+
end
|
1290
|
+
end
|
1291
|
+
|
1292
|
+
def mode_names
|
1293
|
+
names = []
|
1294
|
+
names.push(mode&.name || 'None')
|
1295
|
+
@minor_modes.each do |mode|
|
1296
|
+
names.push(mode.name)
|
1297
|
+
end
|
1298
|
+
names
|
1299
|
+
end
|
1300
|
+
|
1338
1301
|
def indent_to(column)
|
1339
1302
|
s = if self[:indent_tabs_mode]
|
1340
1303
|
"\t" * (column / self[:tab_width]) + " " * (column % self[:tab_width])
|
@@ -1503,16 +1466,6 @@ module Textbringer
|
|
1503
1466
|
end
|
1504
1467
|
end
|
1505
1468
|
|
1506
|
-
if HAS_BYTESPLICE
|
1507
|
-
def splice_contents(*args)
|
1508
|
-
@contents.bytesplice(*args)
|
1509
|
-
end
|
1510
|
-
else
|
1511
|
-
def splice_contents(*args)
|
1512
|
-
@contents.[]=(*args)
|
1513
|
-
end
|
1514
|
-
end
|
1515
|
-
|
1516
1469
|
def adjust_gap(min_size = 0, pos = @point)
|
1517
1470
|
if @gap_start < pos
|
1518
1471
|
len = user_to_gap(pos) - @gap_end
|
@@ -1526,9 +1479,9 @@ module Textbringer
|
|
1526
1479
|
"\0" * (new_gap_end - nul_filling_start))
|
1527
1480
|
else
|
1528
1481
|
s = @contents.byteslice(@gap_end, len)
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1482
|
+
@contents.bytesplice(nul_filling_start...new_gap_end,
|
1483
|
+
"\0" * (new_gap_end - nul_filling_start))
|
1484
|
+
@contents.bytesplice(@gap_start...new_gap_start, s)
|
1532
1485
|
end
|
1533
1486
|
@gap_start = new_gap_start
|
1534
1487
|
@gap_end = new_gap_end
|
@@ -1544,8 +1497,8 @@ module Textbringer
|
|
1544
1497
|
"\0" * (nul_filling_end - pos))
|
1545
1498
|
else
|
1546
1499
|
s = @contents.byteslice(pos, len)
|
1547
|
-
|
1548
|
-
|
1500
|
+
@contents.bytesplice(pos...nul_filling_end, "\0" * (nul_filling_end - pos))
|
1501
|
+
@contents.bytesplice(new_gap_end...@gap_end, s)
|
1549
1502
|
end
|
1550
1503
|
@gap_start = new_gap_start
|
1551
1504
|
@gap_end = new_gap_end
|
@@ -1553,7 +1506,7 @@ module Textbringer
|
|
1553
1506
|
if gap_size < min_size
|
1554
1507
|
new_gap_size = GAP_SIZE + min_size
|
1555
1508
|
extended_size = new_gap_size - gap_size
|
1556
|
-
|
1509
|
+
@contents.bytesplice(@gap_end, 0, "\0" * extended_size)
|
1557
1510
|
@gap_end += extended_size
|
1558
1511
|
end
|
1559
1512
|
end
|
@@ -1620,14 +1573,10 @@ module Textbringer
|
|
1620
1573
|
@current_column += substring(pos, new_pos).size
|
1621
1574
|
else
|
1622
1575
|
@current_line += n
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
i = nil
|
1628
|
-
end
|
1629
|
-
else
|
1630
|
-
i = @contents.rindex("\n", user_to_gap(new_pos - 1))
|
1576
|
+
begin
|
1577
|
+
i = @contents.byterindex("\n", user_to_gap(get_pos(new_pos, -1)))
|
1578
|
+
rescue RangeError
|
1579
|
+
i = nil
|
1631
1580
|
end
|
1632
1581
|
if i
|
1633
1582
|
i += 1
|
@@ -1642,14 +1591,10 @@ module Textbringer
|
|
1642
1591
|
@current_column -= substring(new_pos, pos).size
|
1643
1592
|
else
|
1644
1593
|
@current_line -= n
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
i = nil
|
1650
|
-
end
|
1651
|
-
else
|
1652
|
-
i = @contents.rindex("\n", user_to_gap(new_pos - 1))
|
1594
|
+
begin
|
1595
|
+
i = @contents.byterindex("\n", user_to_gap(get_pos(new_pos, - 1)))
|
1596
|
+
rescue RangeError
|
1597
|
+
i = nil
|
1653
1598
|
end
|
1654
1599
|
if i
|
1655
1600
|
i += 1
|
data/lib/textbringer/keymap.rb
CHANGED
@@ -220,6 +220,7 @@ module Textbringer
|
|
220
220
|
GLOBAL_MAP.define_key("\M-c", :capitalize_word)
|
221
221
|
GLOBAL_MAP.define_key("\C-x8\C-m", :insert_char)
|
222
222
|
GLOBAL_MAP.define_key("\C-x=", :what_cursor_position)
|
223
|
+
GLOBAL_MAP.define_key(:ic, :overwrite_mode)
|
223
224
|
GLOBAL_MAP.handle_undefined_key do |key|
|
224
225
|
if key.is_a?(String) && /[\0-\x7f]/ !~ key
|
225
226
|
:self_insert
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Textbringer
|
2
|
+
class MinorMode
|
3
|
+
extend Commands
|
4
|
+
include Commands
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :mode_name
|
8
|
+
attr_accessor :command_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.inherited(child)
|
12
|
+
base_name = child.name.slice(/[^:]*\z/)
|
13
|
+
child.mode_name = base_name.sub(/Mode\z/, "")
|
14
|
+
command_name = base_name.sub(/\A[A-Z]/) { |s| s.downcase }.
|
15
|
+
gsub(/(?<=[a-z])([A-Z])/) {
|
16
|
+
"_" + $1.downcase
|
17
|
+
}
|
18
|
+
command = command_name.intern
|
19
|
+
child.command_name = command
|
20
|
+
define_command(command) do
|
21
|
+
Buffer.current.toggle_minor_mode(child)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :buffer
|
26
|
+
|
27
|
+
def initialize(buffer)
|
28
|
+
@buffer = buffer
|
29
|
+
end
|
30
|
+
|
31
|
+
def name
|
32
|
+
self.class.mode_name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Textbringer
|
2
|
+
class OverwriteMode < MinorMode
|
3
|
+
self.mode_name = "Ovwrt"
|
4
|
+
|
5
|
+
POST_INSERT_HOOK = -> {
|
6
|
+
buffer = Buffer.current
|
7
|
+
s = Controller.current.last_key * number_prefix_arg
|
8
|
+
begin
|
9
|
+
buffer.delete_char(s.size)
|
10
|
+
rescue RangeError
|
11
|
+
buffer.save_excursion do
|
12
|
+
pos = buffer.point
|
13
|
+
buffer.end_of_buffer
|
14
|
+
buffer.delete_region(pos, buffer.point)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
}
|
18
|
+
|
19
|
+
def enable
|
20
|
+
add_hook(:post_self_insert_hook, POST_INSERT_HOOK, local: true)
|
21
|
+
end
|
22
|
+
|
23
|
+
def disable
|
24
|
+
remove_hook(:post_self_insert_hook, POST_INSERT_HOOK, local: true)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/textbringer/utils.rb
CHANGED
@@ -352,16 +352,33 @@ module Textbringer
|
|
352
352
|
|
353
353
|
HOOKS = Hash.new { |h, k| h[k] = [] }
|
354
354
|
|
355
|
-
def add_hook(name, func = nil, &block)
|
356
|
-
|
355
|
+
def add_hook(name, func = nil, local: false, &block)
|
356
|
+
hooks = get_hooks(local)
|
357
|
+
return if hooks[name].include?(func)
|
358
|
+
hooks[name].unshift(func || block)
|
357
359
|
end
|
358
360
|
|
359
|
-
def remove_hook(name, func)
|
360
|
-
|
361
|
+
def remove_hook(name, func, local: false)
|
362
|
+
hooks = get_hooks(local)
|
363
|
+
hooks[name].delete(func)
|
364
|
+
end
|
365
|
+
|
366
|
+
def get_hooks(local)
|
367
|
+
if local
|
368
|
+
Buffer.current[:hooks] ||= Hash.new { |h, k| h[k] = [] }
|
369
|
+
else
|
370
|
+
HOOKS
|
371
|
+
end
|
361
372
|
end
|
362
373
|
|
363
374
|
def run_hooks(name, remove_on_error: false)
|
364
|
-
|
375
|
+
hooks = Buffer.current[:hooks]
|
376
|
+
run_hooks_in(hooks, name, remove_on_error:) if hooks
|
377
|
+
run_hooks_in(HOOKS, name, remove_on_error:)
|
378
|
+
end
|
379
|
+
|
380
|
+
def run_hooks_in(hooks, name, remove_on_error: false)
|
381
|
+
hooks[name].delete_if do |func|
|
365
382
|
begin
|
366
383
|
case func
|
367
384
|
when Symbol
|
data/lib/textbringer/version.rb
CHANGED
data/lib/textbringer/window.rb
CHANGED
@@ -659,7 +659,7 @@ module Textbringer
|
|
659
659
|
end
|
660
660
|
@mode_line.addstr(unicode_codepoint(c))
|
661
661
|
@mode_line.addstr(" #{line},#{column}")
|
662
|
-
@mode_line.addstr(" (#{@buffer.
|
662
|
+
@mode_line.addstr(" (#{@buffer.mode_names.join(' ')})")
|
663
663
|
@mode_line.addstr(" " * (columns - @mode_line.curx))
|
664
664
|
@mode_line.attrset(0)
|
665
665
|
@mode_line.noutrefresh
|
data/lib/textbringer.rb
CHANGED
@@ -34,6 +34,8 @@ require_relative "textbringer/modes/backtrace_mode"
|
|
34
34
|
require_relative "textbringer/modes/completion_list_mode"
|
35
35
|
require_relative "textbringer/modes/buffer_list_mode"
|
36
36
|
require_relative "textbringer/modes/help_mode"
|
37
|
+
require_relative "textbringer/minor_mode"
|
38
|
+
require_relative "textbringer/modes/overwrite_mode"
|
37
39
|
require_relative "textbringer/input_method"
|
38
40
|
require_relative "textbringer/input_methods/t_code_input_method"
|
39
41
|
require_relative "textbringer/input_methods/hiragana_input_method"
|
data/textbringer.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.required_ruby_version = '>= 3.
|
22
|
+
spec.required_ruby_version = '>= 3.2'
|
23
23
|
|
24
24
|
spec.add_runtime_dependency "rdoc"
|
25
25
|
spec.add_runtime_dependency "ostruct"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: textbringer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '
|
4
|
+
version: '4'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rdoc
|
@@ -379,6 +379,7 @@ files:
|
|
379
379
|
- lib/textbringer/input_methods/t_code_input_method.rb
|
380
380
|
- lib/textbringer/input_methods/t_code_input_method/tables.rb
|
381
381
|
- lib/textbringer/keymap.rb
|
382
|
+
- lib/textbringer/minor_mode.rb
|
382
383
|
- lib/textbringer/mode.rb
|
383
384
|
- lib/textbringer/modes/backtrace_mode.rb
|
384
385
|
- lib/textbringer/modes/buffer_list_mode.rb
|
@@ -386,6 +387,7 @@ files:
|
|
386
387
|
- lib/textbringer/modes/completion_list_mode.rb
|
387
388
|
- lib/textbringer/modes/fundamental_mode.rb
|
388
389
|
- lib/textbringer/modes/help_mode.rb
|
390
|
+
- lib/textbringer/modes/overwrite_mode.rb
|
389
391
|
- lib/textbringer/modes/programming_mode.rb
|
390
392
|
- lib/textbringer/modes/ruby_mode.rb
|
391
393
|
- lib/textbringer/plugin.rb
|
@@ -409,14 +411,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
409
411
|
requirements:
|
410
412
|
- - ">="
|
411
413
|
- !ruby/object:Gem::Version
|
412
|
-
version: '3.
|
414
|
+
version: '3.2'
|
413
415
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
414
416
|
requirements:
|
415
417
|
- - ">="
|
416
418
|
- !ruby/object:Gem::Version
|
417
419
|
version: '0'
|
418
420
|
requirements: []
|
419
|
-
rubygems_version: 3.6.
|
421
|
+
rubygems_version: 3.6.7
|
420
422
|
specification_version: 4
|
421
423
|
summary: An Emacs-like text editor
|
422
424
|
test_files: []
|