textbringer 1.4.0 → 2
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/push_gem.yml +48 -0
- data/lib/textbringer/buffer.rb +68 -44
- data/lib/textbringer/commands/buffers.rb +33 -0
- data/lib/textbringer/commands/files.rb +1 -1
- data/lib/textbringer/commands/help.rb +44 -2
- data/lib/textbringer/commands/misc.rb +25 -0
- data/lib/textbringer/commands/register.rb +4 -1
- data/lib/textbringer/commands/ucs_normalize.rb +39 -0
- data/lib/textbringer/default_output.rb +12 -4
- data/lib/textbringer/input_method.rb +22 -0
- data/lib/textbringer/input_methods/hangul_input_method.rb +73 -0
- data/lib/textbringer/input_methods/hiragana_input_method.rb +0 -2
- data/lib/textbringer/input_methods/t_code_input_method.rb +0 -19
- data/lib/textbringer/keymap.rb +5 -0
- data/lib/textbringer/mode.rb +1 -1
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window/fallback_characters.rb +81 -0
- data/lib/textbringer/window.rb +140 -47
- data/lib/textbringer.rb +2 -0
- data/textbringer.gemspec +9 -0
- metadata +133 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a7815997c04d50a71d83ccb13cc2b2ec378679b26e74d6a2add40635d033c7ad
|
4
|
+
data.tar.gz: 82193a90e99ba1d56df8c1f6cfde23ae6560585273e3c25777d55f3f7fa3c78a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6bc44799c79165fee0acf71efedd019692432da5a3b6f6c005a485587e7aecd44e2a82ba380272f42fa51a4519e1d461c9f1cdcb5f2f25f76a62029dff0358ca
|
7
|
+
data.tar.gz: 21ae07326bfbb38398950efcf5d0f0e9abea6195aafa26430691d2879d9e92ff3f4d50a4be5f77ed1d5082fbe776724c737ec7103d7ccd2d977638c3e160be81
|
@@ -0,0 +1,48 @@
|
|
1
|
+
name: Publish gem to rubygems.org
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- 'v*'
|
7
|
+
|
8
|
+
permissions:
|
9
|
+
contents: read
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
push:
|
13
|
+
if: github.repository == 'shugo/textbringer'
|
14
|
+
runs-on: ubuntu-latest
|
15
|
+
|
16
|
+
environment:
|
17
|
+
name: rubygems.org
|
18
|
+
url: https://rubygems.org/gems/textbringer
|
19
|
+
|
20
|
+
permissions:
|
21
|
+
contents: write
|
22
|
+
id-token: write
|
23
|
+
|
24
|
+
steps:
|
25
|
+
# Set up
|
26
|
+
- name: Harden Runner
|
27
|
+
uses: step-security/harden-runner@v2
|
28
|
+
with:
|
29
|
+
egress-policy: audit
|
30
|
+
|
31
|
+
- uses: actions/checkout@v4
|
32
|
+
|
33
|
+
- name: Set up Ruby
|
34
|
+
uses: ruby/setup-ruby@v1
|
35
|
+
with:
|
36
|
+
bundler-cache: true
|
37
|
+
ruby-version: ruby
|
38
|
+
|
39
|
+
# Release
|
40
|
+
- name: Publish to RubyGems
|
41
|
+
uses: rubygems/release-gem@v1
|
42
|
+
|
43
|
+
- name: Create GitHub release
|
44
|
+
run: |
|
45
|
+
tag_name="$(git describe --tags --abbrev=0)"
|
46
|
+
gh release create "${tag_name}" --verify-tag --draft --generate-notes
|
47
|
+
env:
|
48
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
data/lib/textbringer/buffer.rb
CHANGED
@@ -71,6 +71,8 @@ module Textbringer
|
|
71
71
|
false
|
72
72
|
end
|
73
73
|
|
74
|
+
WORD_COMPONENT_REGEXP = /\p{Letter}|\p{Number}|\p{M}/
|
75
|
+
|
74
76
|
if !defined?(@@detect_encoding_proc)
|
75
77
|
@@detect_encoding_proc = DEFAULT_DETECT_ENCODING
|
76
78
|
|
@@ -187,7 +189,7 @@ module Textbringer
|
|
187
189
|
|
188
190
|
def self.new_buffer_name(name)
|
189
191
|
if @@table.key?(name)
|
190
|
-
(2..
|
192
|
+
(2..).lazy.map { |i|
|
191
193
|
"#{name}<#{i}>"
|
192
194
|
}.find { |i| !@@table.key?(i) }
|
193
195
|
else
|
@@ -683,7 +685,8 @@ module Textbringer
|
|
683
685
|
forward_char(-n)
|
684
686
|
end
|
685
687
|
|
686
|
-
def forward_word(n = 1, regexp:
|
688
|
+
def forward_word(n = 1, regexp: WORD_COMPONENT_REGEXP)
|
689
|
+
return backward_word(-n) if n < 0
|
687
690
|
n.times do
|
688
691
|
while !end_of_buffer? && regexp !~ char_after
|
689
692
|
forward_char
|
@@ -694,7 +697,8 @@ module Textbringer
|
|
694
697
|
end
|
695
698
|
end
|
696
699
|
|
697
|
-
def backward_word(n = 1, regexp:
|
700
|
+
def backward_word(n = 1, regexp: WORD_COMPONENT_REGEXP)
|
701
|
+
return forward_word(-n) if n < 0
|
698
702
|
n.times do
|
699
703
|
break if beginning_of_buffer?
|
700
704
|
backward_char
|
@@ -820,6 +824,10 @@ module Textbringer
|
|
820
824
|
@point > mark.location
|
821
825
|
end
|
822
826
|
|
827
|
+
def point_compare_mark(mark)
|
828
|
+
@point - mark.location
|
829
|
+
end
|
830
|
+
|
823
831
|
def exchange_point_and_mark(mark = @mark)
|
824
832
|
if mark.nil?
|
825
833
|
raise EditorError, "The mark is not set"
|
@@ -989,14 +997,23 @@ module Textbringer
|
|
989
997
|
end
|
990
998
|
end
|
991
999
|
|
992
|
-
def replace(str, start: point_min, end: point_max)
|
1000
|
+
def replace(str = nil, start: point_min, end: point_max, &block)
|
1001
|
+
end_pos = binding.local_variable_get(:end)
|
1002
|
+
if str.nil?
|
1003
|
+
str = block.call(substring(start, end_pos))
|
1004
|
+
end
|
993
1005
|
composite_edit do
|
994
|
-
delete_region(start,
|
1006
|
+
delete_region(start, end_pos)
|
995
1007
|
goto_char(start)
|
996
1008
|
insert(str)
|
997
1009
|
end
|
998
1010
|
end
|
999
1011
|
|
1012
|
+
def replace_region(str = nil, &block)
|
1013
|
+
s, e = Buffer.region_boundaries(@point, mark)
|
1014
|
+
replace(str, start: s, end: e, &block)
|
1015
|
+
end
|
1016
|
+
|
1000
1017
|
def clear
|
1001
1018
|
check_read_only_flag
|
1002
1019
|
@contents = String.new
|
@@ -1040,6 +1057,27 @@ module Textbringer
|
|
1040
1057
|
end
|
1041
1058
|
end
|
1042
1059
|
|
1060
|
+
def convert_word(n = 1, &block)
|
1061
|
+
s = point
|
1062
|
+
forward_word(n)
|
1063
|
+
e = point
|
1064
|
+
s, e = Buffer.region_boundaries(s, e)
|
1065
|
+
str = substring(s, e).gsub(/[\p{Letter}\p{Number}]+/, &block)
|
1066
|
+
replace(str, start: s, end: e)
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
def downcase_word(n = 1)
|
1070
|
+
convert_word(n, &:downcase)
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
def upcase_word(n = 1)
|
1074
|
+
convert_word(n, &:upcase)
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
def capitalize_word(n = 1)
|
1078
|
+
convert_word(n, &:capitalize)
|
1079
|
+
end
|
1080
|
+
|
1043
1081
|
def insert_for_yank(s)
|
1044
1082
|
if @mark.nil? || !point_at_mark?(@mark)
|
1045
1083
|
push_mark
|
@@ -1057,47 +1095,11 @@ module Textbringer
|
|
1057
1095
|
end
|
1058
1096
|
|
1059
1097
|
def undo
|
1060
|
-
|
1061
|
-
if @undo_stack.empty?
|
1062
|
-
raise EditorError, "No further undo information"
|
1063
|
-
end
|
1064
|
-
action = @undo_stack.pop
|
1065
|
-
@undoing = true
|
1066
|
-
begin
|
1067
|
-
was_modified = @modified
|
1068
|
-
action.undo
|
1069
|
-
if action.version == @version
|
1070
|
-
@modified = false
|
1071
|
-
action.version = nil
|
1072
|
-
elsif !was_modified
|
1073
|
-
action.version = @version
|
1074
|
-
end
|
1075
|
-
@redo_stack.push(action)
|
1076
|
-
ensure
|
1077
|
-
@undoing = false
|
1078
|
-
end
|
1098
|
+
undo_or_redo(:undo, @undo_stack, @redo_stack)
|
1079
1099
|
end
|
1080
1100
|
|
1081
1101
|
def redo
|
1082
|
-
|
1083
|
-
if @redo_stack.empty?
|
1084
|
-
raise EditorError, "No further redo information"
|
1085
|
-
end
|
1086
|
-
action = @redo_stack.pop
|
1087
|
-
@undoing = true
|
1088
|
-
begin
|
1089
|
-
was_modified = @modified
|
1090
|
-
action.redo
|
1091
|
-
if action.version == @version
|
1092
|
-
@modified = false
|
1093
|
-
action.version = nil
|
1094
|
-
elsif !was_modified
|
1095
|
-
action.version = @version
|
1096
|
-
end
|
1097
|
-
@undo_stack.push(action)
|
1098
|
-
ensure
|
1099
|
-
@undoing = false
|
1100
|
-
end
|
1102
|
+
undo_or_redo(:redo, @redo_stack, @undo_stack)
|
1101
1103
|
end
|
1102
1104
|
|
1103
1105
|
def re_search_forward(s, raise_error: true, count: 1)
|
@@ -1477,7 +1479,7 @@ module Textbringer
|
|
1477
1479
|
def set_contents(s, enc)
|
1478
1480
|
case s.encoding
|
1479
1481
|
when Encoding::UTF_8, Encoding::ASCII_8BIT
|
1480
|
-
@contents = s
|
1482
|
+
@contents = +s
|
1481
1483
|
else
|
1482
1484
|
@contents = s.encode(Encoding::UTF_8)
|
1483
1485
|
end
|
@@ -1713,6 +1715,28 @@ module Textbringer
|
|
1713
1715
|
end
|
1714
1716
|
end
|
1715
1717
|
|
1718
|
+
def undo_or_redo(op, from_stack, to_stack)
|
1719
|
+
check_read_only_flag
|
1720
|
+
if from_stack.empty?
|
1721
|
+
raise EditorError, "No further #{op} information"
|
1722
|
+
end
|
1723
|
+
action = from_stack.pop
|
1724
|
+
@undoing = true
|
1725
|
+
begin
|
1726
|
+
was_modified = @modified
|
1727
|
+
action.send(op)
|
1728
|
+
if action.version == @version
|
1729
|
+
@modified = false
|
1730
|
+
action.version = nil
|
1731
|
+
elsif !was_modified
|
1732
|
+
action.version = @version
|
1733
|
+
end
|
1734
|
+
to_stack.push(action)
|
1735
|
+
ensure
|
1736
|
+
@undoing = false
|
1737
|
+
end
|
1738
|
+
end
|
1739
|
+
|
1716
1740
|
def new_regexp(s)
|
1717
1741
|
if s.is_a?(Regexp)
|
1718
1742
|
s
|
@@ -264,5 +264,38 @@ module Textbringer
|
|
264
264
|
e = buffer.re_search_forward(Regexp.quote(char), count: count)
|
265
265
|
buffer.kill_region(s, e)
|
266
266
|
end
|
267
|
+
|
268
|
+
define_command(:downcase_word,
|
269
|
+
doc: <<~EOD) do
|
270
|
+
Convert to lower case from point to end of word, moving over.
|
271
|
+
EOD
|
272
|
+
|n = number_prefix_arg|
|
273
|
+
Buffer.current.downcase_word(n)
|
274
|
+
end
|
275
|
+
|
276
|
+
define_command(:upcase_word,
|
277
|
+
doc: <<~EOD) do
|
278
|
+
Convert to upper case from point to end of word, moving over.
|
279
|
+
EOD
|
280
|
+
|n = number_prefix_arg|
|
281
|
+
Buffer.current.upcase_word(n)
|
282
|
+
end
|
283
|
+
|
284
|
+
define_command(:capitalize_word,
|
285
|
+
doc: <<~EOD) do
|
286
|
+
Capitalize from point to the end of word, moving over.
|
287
|
+
EOD
|
288
|
+
|n = number_prefix_arg|
|
289
|
+
Buffer.current.capitalize_word(n)
|
290
|
+
end
|
291
|
+
|
292
|
+
define_command(:insert_char,
|
293
|
+
doc: <<~EOD) do
|
294
|
+
Insert character.
|
295
|
+
EOD
|
296
|
+
|c = read_from_minibuffer("Insert character (hex): "),
|
297
|
+
n = number_prefix_arg|
|
298
|
+
Buffer.current.insert(c.hex.chr(Encoding::UTF_8) * n)
|
299
|
+
end
|
267
300
|
end
|
268
301
|
end
|
@@ -128,7 +128,7 @@ module Textbringer
|
|
128
128
|
|dir_name = read_file_name("Change directory: ",
|
129
129
|
default: Buffer.current.file_name &&
|
130
130
|
File.dirname(Buffer.current.file_name))|
|
131
|
-
Dir.chdir(dir_name)
|
131
|
+
Dir.chdir(File.expand_path(dir_name))
|
132
132
|
end
|
133
133
|
|
134
134
|
define_command(:find_alternate_file, doc: "Find an alternate file.") do
|
@@ -18,9 +18,14 @@ module Textbringer
|
|
18
18
|
help.clear
|
19
19
|
yield(help)
|
20
20
|
help.beginning_of_buffer
|
21
|
-
|
22
|
-
help_mode
|
21
|
+
help.apply_mode(HelpMode)
|
23
22
|
end
|
23
|
+
if Window.list.size == 1
|
24
|
+
split_window
|
25
|
+
end
|
26
|
+
windows = Window.list
|
27
|
+
i = (windows.index(Window.current) + 1) % windows.size
|
28
|
+
windows[i].buffer = help
|
24
29
|
end
|
25
30
|
private :show_help
|
26
31
|
|
@@ -143,6 +148,43 @@ module Textbringer
|
|
143
148
|
push_help_command([:describe_method, name])
|
144
149
|
end
|
145
150
|
|
151
|
+
define_command(:describe_char,
|
152
|
+
doc: "Describe the char after point") do
|
153
|
+
require "unicode/name"
|
154
|
+
require "unicode/categories"
|
155
|
+
require "unicode/blocks"
|
156
|
+
require "unicode/scripts"
|
157
|
+
require "unicode/types"
|
158
|
+
|
159
|
+
show_help do |help|
|
160
|
+
buffer = Buffer.current
|
161
|
+
c = buffer.char_after
|
162
|
+
if c.nil?
|
163
|
+
raise "No character follows specified position"
|
164
|
+
end
|
165
|
+
percent = (100.0 * buffer.point / buffer.bytesize).to_i
|
166
|
+
char = /[\0-\x20\x7f]/.match?(c) ? Keymap.key_name(c) : c
|
167
|
+
codepoint = "U+%04X" % c.ord
|
168
|
+
name = Unicode::Name.readable(c)
|
169
|
+
category = Unicode::Categories.category(c)
|
170
|
+
category_long = Unicode::Categories.category(c, format: :long)
|
171
|
+
script = Unicode::Scripts.script(c)
|
172
|
+
block = Unicode::Blocks.block(c)
|
173
|
+
type = Unicode::Types.type(c)
|
174
|
+
help.insert(<<EOF)
|
175
|
+
position: #{buffer.point} of #{buffer.bytesize} (#{percent}%), column: #{buffer.current_column}
|
176
|
+
character: #{char}
|
177
|
+
codepoint: #{codepoint}
|
178
|
+
name: #{name}
|
179
|
+
category: #{category} (#{category_long})
|
180
|
+
script: #{script}
|
181
|
+
block: #{block}
|
182
|
+
type: #{type}
|
183
|
+
EOF
|
184
|
+
end
|
185
|
+
push_help_command([:describe_char])
|
186
|
+
end
|
187
|
+
|
146
188
|
define_command(:help_go_back, doc: "Go back to the previous help.") do
|
147
189
|
if !HELP_RING.empty?
|
148
190
|
HELP_RING.rotate(1)
|
@@ -353,5 +353,30 @@ module Textbringer
|
|
353
353
|
define_command(:jit_resume) do
|
354
354
|
RubyVM::MJIT.resume
|
355
355
|
end
|
356
|
+
|
357
|
+
define_command(:what_cursor_position,
|
358
|
+
doc: "Print info on cursor position.") do
|
359
|
+
|arg = current_prefix_arg|
|
360
|
+
|
361
|
+
buffer = Buffer.current
|
362
|
+
c = buffer.char_after
|
363
|
+
if c
|
364
|
+
char = format("Char: %s (U+%04X) ",
|
365
|
+
/[\0-\x20\x7f]/.match?(c) ? Keymap.key_name(c) : c,
|
366
|
+
c.ord)
|
367
|
+
else
|
368
|
+
char = ""
|
369
|
+
end
|
370
|
+
if buffer.bytesize == 0
|
371
|
+
percent = "EOB"
|
372
|
+
else
|
373
|
+
percent = (100.0 * buffer.point / buffer.bytesize).to_i
|
374
|
+
end
|
375
|
+
column = buffer.current_column
|
376
|
+
message("#{char}point=#{buffer.point} of #{buffer.bytesize} (#{percent}%) column=#{column}")
|
377
|
+
if arg && c
|
378
|
+
describe_char
|
379
|
+
end
|
380
|
+
end
|
356
381
|
end
|
357
382
|
end
|
@@ -88,7 +88,10 @@ module Textbringer
|
|
88
88
|
|
89
89
|
define_command(:insert_register) do
|
90
90
|
|register = read_register("Insert register:"),
|
91
|
-
arg =
|
91
|
+
arg = nil|
|
92
|
+
if arg.nil? && Controller.current.this_command == :insert_register
|
93
|
+
arg = !current_prefix_arg
|
94
|
+
end
|
92
95
|
buffer = Buffer.current
|
93
96
|
str = REGISTERS[register]
|
94
97
|
if arg
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Textbringer
|
2
|
+
module Commands
|
3
|
+
define_command(:ucs_normalize_nfc_region,
|
4
|
+
doc: <<~EOD) do
|
5
|
+
Compose the region according to the Unicode NFC.
|
6
|
+
EOD
|
7
|
+
Buffer.current.replace_region do |s|
|
8
|
+
s.unicode_normalize(:nfc)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
define_command(:ucs_normalize_nfd_region,
|
13
|
+
doc: <<~EOD) do
|
14
|
+
Decompose the region according to the Unicode NFD.
|
15
|
+
EOD
|
16
|
+
Buffer.current.replace_region do |s|
|
17
|
+
s.unicode_normalize(:nfd)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
define_command(:ucs_normalize_nfkc_region,
|
22
|
+
doc: <<~EOD) do
|
23
|
+
Compose the region according to the Unicode NFKC.
|
24
|
+
EOD
|
25
|
+
Buffer.current.replace_region do |s|
|
26
|
+
s.unicode_normalize(:nfkc)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
define_command(:ucs_normalize_nfkd_region,
|
31
|
+
doc: <<~EOD) do
|
32
|
+
Decompose the region according to the Unicode NFKD.
|
33
|
+
EOD
|
34
|
+
Buffer.current.replace_region do |s|
|
35
|
+
s.unicode_normalize(:nfkd)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -9,10 +9,18 @@ module Textbringer
|
|
9
9
|
def flush
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
[
|
13
|
+
:print,
|
14
|
+
:printf,
|
15
|
+
:putc,
|
16
|
+
:puts,
|
17
|
+
:"<<"
|
18
|
+
].each do |mid|
|
19
|
+
define_method(mid) do |*args|
|
20
|
+
buffer = StringIO.new
|
21
|
+
buffer.send(mid, *args)
|
22
|
+
write(buffer.string)
|
23
|
+
end
|
16
24
|
end
|
17
25
|
end
|
18
26
|
end
|
@@ -59,5 +59,27 @@ module Textbringer
|
|
59
59
|
def handle_event(event)
|
60
60
|
raise EditorError, "subclass must override InputMethod#handle_event"
|
61
61
|
end
|
62
|
+
|
63
|
+
def with_target_buffer(&block)
|
64
|
+
if isearch_mode?
|
65
|
+
@isearch_buffer ||= Buffer.new
|
66
|
+
if @isearch_buffer.to_s != ISEARCH_STATUS[:string]
|
67
|
+
@isearch_buffer.replace(ISEARCH_STATUS[:string])
|
68
|
+
end
|
69
|
+
@isearch_buffer.modified = false
|
70
|
+
begin
|
71
|
+
block.call(@isearch_buffer)
|
72
|
+
ensure
|
73
|
+
ISEARCH_STATUS[:string] = @isearch_buffer.to_s
|
74
|
+
isearch_search if @isearch_buffer.modified?
|
75
|
+
if Buffer.current != Buffer.minibuffer
|
76
|
+
message(isearch_prompt + ISEARCH_STATUS[:string], log: false)
|
77
|
+
end
|
78
|
+
Window.redisplay
|
79
|
+
end
|
80
|
+
else
|
81
|
+
block.call(Buffer.current)
|
82
|
+
end
|
83
|
+
end
|
62
84
|
end
|
63
85
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Textbringer
|
2
|
+
class HangulInputMethod < InputMethod
|
3
|
+
KEY_TO_COMPATIBILITY_JAMO = {
|
4
|
+
"q" => "ㅂ", "w" => "ㅈ", "e" => "ㄷ", "r" => "ㄱ", "t" => "ㅅ",
|
5
|
+
"y" => "ㅛ", "u" => "ㅕ", "i" => "ㅑ", "o" => "ㅐ", "p" => "ㅔ",
|
6
|
+
"a" => "ㅁ", "s" => "ㄴ", "d" => "ㅇ", "f" => "ㄹ", "g" => "ㅎ",
|
7
|
+
"h" => "ㅗ", "j" => "ㅓ", "k" => "ㅏ", "l" => "ㅣ",
|
8
|
+
"z" => "ㅋ", "x" => "ㅌ", "c" => "ㅊ", "v" => "ㅍ", "b" => "ㅠ",
|
9
|
+
"n" => "ㅜ", "m" => "ㅡ",
|
10
|
+
"Q" => "ㅃ", "W" => "ㅉ", "E" => "ㄸ", "R" => "ㄲ", "T" => "ㅆ",
|
11
|
+
"O" => "ㅒ", "P" => "ㅖ"
|
12
|
+
}
|
13
|
+
|
14
|
+
COMPATIBILITY_JAMO_TO_FINAL = {
|
15
|
+
"ㄱ" => "ᆨ", "ㄲ" => "ᆩ", "ㄳ" => "ᆪ", "ㄴ" => "ᆫ",
|
16
|
+
"ㄵ" => "ᆬ", "ㄶ" => "ᆭ", "ㄷ" => "ᆮ", "ㄹ" => "ᆯ",
|
17
|
+
"ㄺ" => "ᆰ", "ㄻ" => "ᆱ", "ㄼ" => "ᆲ", "ㄽ" => "ᆳ",
|
18
|
+
"ㄾ" => "ᆴ", "ㄿ" => "ᆵ", "ㅀ" => "ᆶ", "ㅁ" => "ᆷ",
|
19
|
+
"ㅂ" => "ᆸ", "ㅄ" => "ᆹ", "ㅅ" => "ᆺ", "ㅆ" => "ᆻ",
|
20
|
+
"ㅇ" => "ᆼ", "ㅈ" => "ᆽ", "ㅊ" => "ᆾ", "ㅋ" => "ᆿ",
|
21
|
+
"ㅌ" => "ᇀ", "ㅍ" => "ᇁ", "ㅎ" => "ᇂ"
|
22
|
+
}
|
23
|
+
|
24
|
+
FINAL_TO_INITIAL = {
|
25
|
+
"ᆨ" => "ᄀ", "ᆩ" => "ᄁ", "ᆫ" => "ᄂ", "ᆮ" => "ᄃ",
|
26
|
+
"ᆯ" => "ᄅ", "ᆷ" => "ᄆ", "ᆸ" => "ᄇ", "ᆺ" => "ᄉ",
|
27
|
+
"ᆻ" => "ᄊ", "ᆼ" => "ᄋ", "ᆽ" => "ᄌ", "ᆾ" => "ᄎ",
|
28
|
+
"ᆿ" => "ᄏ", "ᇀ" => "ᄐ", "ᇁ" => "ᄑ", "ᇂ" => "ᄒ"
|
29
|
+
}
|
30
|
+
|
31
|
+
def status
|
32
|
+
"한"
|
33
|
+
end
|
34
|
+
|
35
|
+
def handle_event(event)
|
36
|
+
return event if !event.is_a?(String)
|
37
|
+
jamo = KEY_TO_COMPATIBILITY_JAMO[event]
|
38
|
+
return event if jamo.nil?
|
39
|
+
with_target_buffer do |buffer|
|
40
|
+
prev = buffer.char_before
|
41
|
+
if /[\u{3131}-\u{3183}\u{ac00}-\u{d7a3}]/.match?(prev) # jamo or syllables
|
42
|
+
decomposed_prev, prev = decompose_prev(prev, jamo)
|
43
|
+
if c = compose_hangul(prev, jamo)
|
44
|
+
buffer.backward_delete_char
|
45
|
+
c = decomposed_prev + c if decomposed_prev
|
46
|
+
buffer.insert(c)
|
47
|
+
Window.redisplay
|
48
|
+
return nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
jamo
|
53
|
+
end
|
54
|
+
|
55
|
+
def decompose_prev(prev, jamo)
|
56
|
+
if /[\u{ac00}-\u{d7a3}]/.match?(prev) && # syllables
|
57
|
+
/[\u{314f}-\u{3163}]/.match?(jamo) # vowels
|
58
|
+
s = prev.unicode_normalize(:nfd)
|
59
|
+
if s.size == 3 && (initial = FINAL_TO_INITIAL[s[2]])
|
60
|
+
return s[0, 2].unicode_normalize(:nfc), initial
|
61
|
+
end
|
62
|
+
end
|
63
|
+
return nil, prev
|
64
|
+
end
|
65
|
+
|
66
|
+
def compose_hangul(prev, jamo)
|
67
|
+
# Use NFKC for compatibility jamo
|
68
|
+
c = (prev + (COMPATIBILITY_JAMO_TO_FINAL[jamo] || jamo)).
|
69
|
+
unicode_normalize(:nfkc)
|
70
|
+
c.size == 1 ? c : nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -86,23 +86,6 @@ module Textbringer
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
-
def with_target_buffer(&block)
|
90
|
-
if isearch_mode?
|
91
|
-
@isearch_buffer ||= Buffer.new
|
92
|
-
if @isearch_buffer.to_s != ISEARCH_STATUS[:string]
|
93
|
-
@isearch_buffer.replace(ISEARCH_STATUS[:string])
|
94
|
-
end
|
95
|
-
block.call(@isearch_buffer)
|
96
|
-
ISEARCH_STATUS[:string] = @isearch_buffer.to_s
|
97
|
-
if Buffer.current != Buffer.minibuffer
|
98
|
-
message(isearch_prompt + ISEARCH_STATUS[:string], log: false)
|
99
|
-
Window.redisplay
|
100
|
-
end
|
101
|
-
else
|
102
|
-
block.call(Buffer.current)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
89
|
def bushu_compose
|
107
90
|
with_target_buffer do |buffer|
|
108
91
|
pos = buffer.point
|
@@ -117,7 +100,6 @@ module Textbringer
|
|
117
100
|
buffer.goto_char(pos)
|
118
101
|
end
|
119
102
|
end
|
120
|
-
isearch_search if isearch_mode?
|
121
103
|
Window.redisplay
|
122
104
|
nil
|
123
105
|
end
|
@@ -276,7 +258,6 @@ module Textbringer
|
|
276
258
|
buffer.insert(s + @mazegaki_suffix)
|
277
259
|
end
|
278
260
|
end
|
279
|
-
isearch_search if isearch_mode?
|
280
261
|
end
|
281
262
|
|
282
263
|
def hide_help_window
|
data/lib/textbringer/keymap.rb
CHANGED
@@ -215,6 +215,11 @@ module Textbringer
|
|
215
215
|
GLOBAL_MAP.define_key([:f1, "m"], :describe_method)
|
216
216
|
GLOBAL_MAP.define_key("\C-x#", :server_edit_done)
|
217
217
|
GLOBAL_MAP.define_key("\C-\\", :toggle_input_method)
|
218
|
+
GLOBAL_MAP.define_key("\M-l", :downcase_word)
|
219
|
+
GLOBAL_MAP.define_key("\M-u", :upcase_word)
|
220
|
+
GLOBAL_MAP.define_key("\M-c", :capitalize_word)
|
221
|
+
GLOBAL_MAP.define_key("\C-x8\C-m", :insert_char)
|
222
|
+
GLOBAL_MAP.define_key("\C-x=", :what_cursor_position)
|
218
223
|
GLOBAL_MAP.handle_undefined_key do |key|
|
219
224
|
if key.is_a?(String) && /[\0-\x7f]/ !~ key
|
220
225
|
:self_insert
|
data/lib/textbringer/mode.rb
CHANGED
data/lib/textbringer/version.rb
CHANGED
@@ -0,0 +1,81 @@
|
|
1
|
+
module Textbringer
|
2
|
+
class Window
|
3
|
+
FALLBACK_CHARACTERS = {
|
4
|
+
# Hiragana
|
5
|
+
"゙" => "゛",
|
6
|
+
"゚" => "゜",
|
7
|
+
|
8
|
+
# Hangul jamo
|
9
|
+
## initial
|
10
|
+
"ᄀ" => "ㄱ",
|
11
|
+
"ᄁ" => "ㄲ",
|
12
|
+
"ᄂ" => "ㄴ",
|
13
|
+
"ᄃ" => "ㄷ",
|
14
|
+
"ᄄ" => "ㄸ",
|
15
|
+
"ᄅ" => "ㄹ",
|
16
|
+
"ᄆ" => "ㅁ",
|
17
|
+
"ᄇ" => "ㅂ",
|
18
|
+
"ᄈ" => "ㅃ",
|
19
|
+
"ᄉ" => "ㅅ",
|
20
|
+
"ᄊ" => "ㅆ",
|
21
|
+
"ᄋ" => "ㅇ",
|
22
|
+
"ᄌ" => "ㅈ",
|
23
|
+
"ᄍ" => "ㅉ",
|
24
|
+
"ᄎ" => "ㅊ",
|
25
|
+
"ᄏ" => "ㅋ",
|
26
|
+
"ᄐ" => "ㅌ",
|
27
|
+
"ᄑ" => "ㅍ",
|
28
|
+
"ᄒ" => "ㅎ",
|
29
|
+
## medial
|
30
|
+
"ᅡ" => "ㅏ",
|
31
|
+
"ᅢ" => "ㅐ",
|
32
|
+
"ᅣ" => "ㅑ",
|
33
|
+
"ᅤ" => "ㅒ",
|
34
|
+
"ᅥ" => "ㅓ",
|
35
|
+
"ᅦ" => "ㅔ",
|
36
|
+
"ᅧ" => "ㅕ",
|
37
|
+
"ᅨ" => "ㅖ",
|
38
|
+
"ᅩ" => "ㅗ",
|
39
|
+
"ᅪ" => "ㅘ",
|
40
|
+
"ᅫ" => "ㅙ",
|
41
|
+
"ᅬ" => "ㅚ",
|
42
|
+
"ᅭ" => "ㅛ",
|
43
|
+
"ᅮ" => "ㅜ",
|
44
|
+
"ᅯ" => "ㅝ",
|
45
|
+
"ᅰ" => "ㅞ",
|
46
|
+
"ᅱ" => "ㅟ",
|
47
|
+
"ᅲ" => "ㅠ",
|
48
|
+
"ᅳ" => "ㅡ",
|
49
|
+
"ᅴ" => "ㅢ",
|
50
|
+
"ᅵ" => "ㅣ",
|
51
|
+
## final
|
52
|
+
"ᆨ" => "ㄱ",
|
53
|
+
"ᆩ" => "ㄲ",
|
54
|
+
"ᆪ" => "ㄳ",
|
55
|
+
"ᆫ" => "ㄴ",
|
56
|
+
"ᆬ" => "ㄵ",
|
57
|
+
"ᆭ" => "ㄶ",
|
58
|
+
"ᆮ" => "ㄷ",
|
59
|
+
"ᆯ" => "ㄹ",
|
60
|
+
"ᆰ" => "ㄺ",
|
61
|
+
"ᆱ" => "ㄻ",
|
62
|
+
"ᆲ" => "ㄼ",
|
63
|
+
"ᆳ" => "ㄽ",
|
64
|
+
"ᆴ" => "ㄾ",
|
65
|
+
"ᆵ" => "ㄿ",
|
66
|
+
"ᆶ" => "ㅀ",
|
67
|
+
"ᆷ" => "ㅁ",
|
68
|
+
"ᆸ" => "ㅂ",
|
69
|
+
"ᆹ" => "ㅄ",
|
70
|
+
"ᆺ" => "ㅅ",
|
71
|
+
"ᆻ" => "ㅆ",
|
72
|
+
"ᆼ" => "ㅇ",
|
73
|
+
"ᆽ" => "ㅈ",
|
74
|
+
"ᆾ" => "ㅊ",
|
75
|
+
"ᆿ" => "ㅋ",
|
76
|
+
"ᇀ" => "ㅌ",
|
77
|
+
"ᇁ" => "ㅍ",
|
78
|
+
"ᇂ" => "ㅎ"
|
79
|
+
}
|
80
|
+
end
|
81
|
+
end
|
data/lib/textbringer/window.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require "curses"
|
2
|
+
require_relative "window/fallback_characters"
|
2
3
|
|
3
4
|
module Textbringer
|
4
5
|
class Window
|
6
|
+
Cursor = Struct.new(:y, :x)
|
7
|
+
|
5
8
|
KEY_NAMES = {}
|
6
9
|
Curses.constants.grep(/\AKEY_/).each do |name|
|
7
10
|
KEY_NAMES[Curses.const_get(name)] =
|
@@ -232,6 +235,7 @@ module Textbringer
|
|
232
235
|
@deleted = false
|
233
236
|
@raw_key_buffer = []
|
234
237
|
@key_buffer = []
|
238
|
+
@cursor = Cursor.new(0, 0)
|
235
239
|
end
|
236
240
|
|
237
241
|
def echo_area?
|
@@ -395,7 +399,7 @@ module Textbringer
|
|
395
399
|
@buffer.point_to_mark(@point_mark)
|
396
400
|
end
|
397
401
|
framer
|
398
|
-
y = x = 0
|
402
|
+
@cursor.y = @cursor.x = 0
|
399
403
|
@buffer.point_to_mark(@top_of_window)
|
400
404
|
highlight
|
401
405
|
@window.erase
|
@@ -406,25 +410,9 @@ module Textbringer
|
|
406
410
|
@window.attron(Curses::A_REVERSE)
|
407
411
|
end
|
408
412
|
while !@buffer.end_of_buffer?
|
409
|
-
cury
|
410
|
-
|
411
|
-
|
412
|
-
if current? && @buffer.visible_mark
|
413
|
-
if @buffer.point_after_mark?(@buffer.visible_mark)
|
414
|
-
@window.attroff(Curses::A_REVERSE)
|
415
|
-
elsif @buffer.point_before_mark?(@buffer.visible_mark)
|
416
|
-
@window.attron(Curses::A_REVERSE)
|
417
|
-
end
|
418
|
-
end
|
419
|
-
end
|
420
|
-
if current? && @buffer.visible_mark &&
|
421
|
-
@buffer.point_at_mark?(@buffer.visible_mark)
|
422
|
-
if @buffer.point_after_mark?(point)
|
423
|
-
@window.attroff(Curses::A_REVERSE)
|
424
|
-
elsif @buffer.point_before_mark?(point)
|
425
|
-
@window.attron(Curses::A_REVERSE)
|
426
|
-
end
|
427
|
-
end
|
413
|
+
cury = @window.cury
|
414
|
+
curx = @window.curx
|
415
|
+
update_cursor_and_attr(point, cury, curx)
|
428
416
|
if attrs = @highlight_off[@buffer.point]
|
429
417
|
@window.attroff(attrs)
|
430
418
|
end
|
@@ -442,12 +430,13 @@ module Textbringer
|
|
442
430
|
n = calc_tab_width(curx)
|
443
431
|
c = " " * n
|
444
432
|
else
|
445
|
-
c =
|
433
|
+
c = compose_character(point, cury, curx, c)
|
446
434
|
end
|
435
|
+
s = escape(c)
|
447
436
|
if curx < columns - 4
|
448
437
|
newx = nil
|
449
438
|
else
|
450
|
-
newx = curx + Buffer.display_width(
|
439
|
+
newx = curx + Buffer.display_width(s)
|
451
440
|
if newx > columns
|
452
441
|
if cury == lines - 2
|
453
442
|
break
|
@@ -457,12 +446,7 @@ module Textbringer
|
|
457
446
|
end
|
458
447
|
end
|
459
448
|
end
|
460
|
-
|
461
|
-
# ncurses on macOS prints U+FEFF, U+FE0F etc. as space,
|
462
|
-
# so ignore it
|
463
|
-
else
|
464
|
-
@window.addstr(c)
|
465
|
-
end
|
449
|
+
@window.addstr(s)
|
466
450
|
break if newx == columns && cury == lines - 2
|
467
451
|
@buffer.forward_char
|
468
452
|
end
|
@@ -471,16 +455,17 @@ module Textbringer
|
|
471
455
|
end
|
472
456
|
@buffer.mark_to_point(@bottom_of_window)
|
473
457
|
if @buffer.point_at_mark?(point)
|
474
|
-
y
|
458
|
+
@cursor.y = @window.cury
|
459
|
+
@cursor.x = @window.curx
|
475
460
|
end
|
476
|
-
if x == columns - 1
|
461
|
+
if @cursor.x == columns - 1
|
477
462
|
c = @buffer.char_after(point.location)
|
478
463
|
if c && Buffer.display_width(c) > 1
|
479
|
-
y += 1
|
480
|
-
x = 0
|
464
|
+
@cursor.y += 1
|
465
|
+
@cursor.x = 0
|
481
466
|
end
|
482
467
|
end
|
483
|
-
@window.setpos(y, x)
|
468
|
+
@window.setpos(@cursor.y, @cursor.x)
|
484
469
|
@window.noutrefresh
|
485
470
|
end
|
486
471
|
end
|
@@ -690,6 +675,86 @@ module Textbringer
|
|
690
675
|
"0x" + c.unpack("H*")[0]
|
691
676
|
end
|
692
677
|
|
678
|
+
def update_cursor_and_attr(point, cury, curx)
|
679
|
+
if @buffer.point_at_mark?(point)
|
680
|
+
@cursor.y = cury
|
681
|
+
@cursor.x = curx
|
682
|
+
if current? && @buffer.visible_mark
|
683
|
+
if @buffer.point_after_mark?(@buffer.visible_mark)
|
684
|
+
@window.attroff(Curses::A_REVERSE)
|
685
|
+
elsif @buffer.point_before_mark?(@buffer.visible_mark)
|
686
|
+
@window.attron(Curses::A_REVERSE)
|
687
|
+
end
|
688
|
+
end
|
689
|
+
end
|
690
|
+
if current? && @buffer.visible_mark &&
|
691
|
+
@buffer.point_at_mark?(@buffer.visible_mark)
|
692
|
+
if @buffer.point_after_mark?(point)
|
693
|
+
@window.attroff(Curses::A_REVERSE)
|
694
|
+
elsif @buffer.point_before_mark?(point)
|
695
|
+
@window.attron(Curses::A_REVERSE)
|
696
|
+
end
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
def compose_character(point, cury, curx, c)
|
701
|
+
return c if @buffer.binary? || c.nil? || c.match?(/\p{M}/)
|
702
|
+
if c.match?(/[\u{1100}-\u{115f}]/) # hangul initial consonants
|
703
|
+
return compose_hangul_character(point, cury, curx, c)
|
704
|
+
end
|
705
|
+
pos = @buffer.point + c.bytesize
|
706
|
+
while nextc = @buffer.char_after(pos)
|
707
|
+
case nextc
|
708
|
+
when /[\u{fe00}-\u{fe0f}\u{e0100}-\u{e01ef}]/ # variation selectors
|
709
|
+
c += nextc
|
710
|
+
when /[\p{Mn}\p{Me}]/ # nonspacing & enclosing marks
|
711
|
+
# Normalize パ (U+30CF + U+309A) to パ (U+30D1) so that curses can
|
712
|
+
# caluculate display width correctly.
|
713
|
+
# Display combining marks by codepoint when characters cannot be
|
714
|
+
# combined by NFC.
|
715
|
+
newc = (c + nextc).unicode_normalize(:nfc)
|
716
|
+
return c if newc.size != c.size
|
717
|
+
c = newc
|
718
|
+
else
|
719
|
+
return c
|
720
|
+
end
|
721
|
+
@buffer.forward_char
|
722
|
+
update_cursor_and_attr(point, cury, curx)
|
723
|
+
pos += nextc.bytesize
|
724
|
+
end
|
725
|
+
c
|
726
|
+
end
|
727
|
+
|
728
|
+
def compose_hangul_character(point, cury, curx, initial)
|
729
|
+
pos = @buffer.point + initial.bytesize
|
730
|
+
medial = @buffer.char_after(pos)
|
731
|
+
if !medial&.match?(/[\u{1160}-\u{11a7}]/)
|
732
|
+
return initial
|
733
|
+
end
|
734
|
+
final = @buffer.char_after(pos + medial.bytesize)
|
735
|
+
if final&.match?(/[\u{11a8}-\u{11ff}]/)
|
736
|
+
newc = (initial + medial + final).unicode_normalize(:nfc)
|
737
|
+
if newc.size == 1
|
738
|
+
2.times do
|
739
|
+
@buffer.forward_char
|
740
|
+
update_cursor_and_attr(point, cury, curx)
|
741
|
+
end
|
742
|
+
newc
|
743
|
+
else
|
744
|
+
c
|
745
|
+
end
|
746
|
+
else
|
747
|
+
newc = (initial + medial).unicode_normalize(:nfc)
|
748
|
+
if newc.size == 1
|
749
|
+
@buffer.forward_char
|
750
|
+
update_cursor_and_attr(point, cury, curx)
|
751
|
+
newc
|
752
|
+
else
|
753
|
+
c
|
754
|
+
end
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
693
758
|
def escape(s)
|
694
759
|
if !s.valid_encoding?
|
695
760
|
s = s.b
|
@@ -701,8 +766,23 @@ module Textbringer
|
|
701
766
|
"<%02X>" % c.ord
|
702
767
|
}
|
703
768
|
else
|
704
|
-
s.gsub(/
|
705
|
-
|
769
|
+
s.gsub(/
|
770
|
+
(?<ascii_control>[\0-\b\v-\x1f\x7f])
|
771
|
+
| (?<nonascii_control>\p{C})
|
772
|
+
| (?<combining_diacritical_mark>[\u{0300}-\u{036f}])
|
773
|
+
| (?<other_special_char>[\p{M}\u{1100}-\u{11ff}])
|
774
|
+
/x) { |c|
|
775
|
+
if $~[:ascii_control]
|
776
|
+
"^" + (c.ord ^ 0x40).chr
|
777
|
+
elsif $~[:nonascii_control]
|
778
|
+
"<%04x>" % c.ord
|
779
|
+
elsif $~[:combining_diacritical_mark]
|
780
|
+
# Use U+00A0 as the base character, following the convention
|
781
|
+
# described in section 2.11.4 of Unicode Standard 16.0.0
|
782
|
+
"\u{00a0}#{c}"
|
783
|
+
elsif $~[:other_special_char]
|
784
|
+
FALLBACK_CHARACTERS[c] || c
|
785
|
+
end
|
706
786
|
}
|
707
787
|
end
|
708
788
|
end
|
@@ -836,8 +916,12 @@ module Textbringer
|
|
836
916
|
|
837
917
|
def redisplay
|
838
918
|
return if @buffer.nil?
|
839
|
-
@buffer.save_point do |
|
919
|
+
@buffer.save_point do |point|
|
840
920
|
@window.erase
|
921
|
+
if @buffer.input_method_status != "--"
|
922
|
+
@window.setpos(@window.cury, editable_columns + 1)
|
923
|
+
@window.addstr(@buffer.input_method_status)
|
924
|
+
end
|
841
925
|
@window.setpos(0, 0)
|
842
926
|
if @message
|
843
927
|
@window.addstr(escape(@message))
|
@@ -846,29 +930,30 @@ module Textbringer
|
|
846
930
|
@window.addstr(prompt)
|
847
931
|
framer
|
848
932
|
@buffer.point_to_mark(@top_of_window)
|
849
|
-
y = x = 0
|
933
|
+
@cursor.y = @cursor.x = 0
|
850
934
|
while !@buffer.end_of_buffer?
|
851
|
-
cury
|
852
|
-
|
853
|
-
|
854
|
-
end
|
935
|
+
cury = @window.cury
|
936
|
+
curx = @window.curx
|
937
|
+
update_cursor_and_attr(point, cury, curx)
|
855
938
|
c = @buffer.char_after
|
856
939
|
if c == "\n"
|
857
940
|
break
|
858
941
|
end
|
942
|
+
c = compose_character(point, cury, curx, c)
|
859
943
|
s = escape(c)
|
860
944
|
newx = curx + Buffer.display_width(s)
|
861
|
-
if newx >
|
945
|
+
if newx > editable_columns
|
862
946
|
break
|
863
947
|
end
|
864
948
|
@window.addstr(s)
|
865
|
-
break if newx >= @columns
|
866
949
|
@buffer.forward_char
|
950
|
+
break if newx >= editable_columns
|
867
951
|
end
|
868
|
-
if @buffer.point_at_mark?(
|
869
|
-
y
|
952
|
+
if @buffer.point_at_mark?(point)
|
953
|
+
@cursor.y = @window.cury
|
954
|
+
@cursor.x = @window.curx
|
870
955
|
end
|
871
|
-
@window.setpos(y, x)
|
956
|
+
@window.setpos(@cursor.y, @cursor.x)
|
872
957
|
end
|
873
958
|
@window.noutrefresh
|
874
959
|
end
|
@@ -890,6 +975,14 @@ module Textbringer
|
|
890
975
|
@window.resize(lines, columns)
|
891
976
|
end
|
892
977
|
|
978
|
+
def editable_columns
|
979
|
+
if @buffer.input_method_status == "--"
|
980
|
+
@columns
|
981
|
+
else
|
982
|
+
@columns - Buffer.display_width(@buffer.input_method_status) - 1
|
983
|
+
end
|
984
|
+
end
|
985
|
+
|
893
986
|
private
|
894
987
|
|
895
988
|
def initialize_window(num_lines, num_columns, y, x)
|
@@ -902,7 +995,7 @@ module Textbringer
|
|
902
995
|
|
903
996
|
def framer
|
904
997
|
@buffer.save_point do |saved|
|
905
|
-
max_width =
|
998
|
+
max_width = editable_columns - @window.curx
|
906
999
|
width = 0
|
907
1000
|
loop do
|
908
1001
|
c = @buffer.char_after
|
data/lib/textbringer.rb
CHANGED
@@ -23,6 +23,7 @@ require_relative "textbringer/commands/keyboard_macro"
|
|
23
23
|
require_relative "textbringer/commands/fill"
|
24
24
|
require_relative "textbringer/commands/server"
|
25
25
|
require_relative "textbringer/commands/input_method"
|
26
|
+
require_relative "textbringer/commands/ucs_normalize"
|
26
27
|
require_relative "textbringer/commands/help"
|
27
28
|
require_relative "textbringer/mode"
|
28
29
|
require_relative "textbringer/modes/fundamental_mode"
|
@@ -36,6 +37,7 @@ require_relative "textbringer/modes/help_mode"
|
|
36
37
|
require_relative "textbringer/input_method"
|
37
38
|
require_relative "textbringer/input_methods/t_code_input_method"
|
38
39
|
require_relative "textbringer/input_methods/hiragana_input_method"
|
40
|
+
require_relative "textbringer/input_methods/hangul_input_method"
|
39
41
|
require_relative "textbringer/plugin"
|
40
42
|
require_relative "textbringer/controller"
|
41
43
|
require_relative "textbringer/default_output"
|
data/textbringer.gemspec
CHANGED
@@ -21,14 +21,23 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.required_ruby_version = '>= 3.1'
|
23
23
|
|
24
|
+
spec.add_runtime_dependency "rdoc"
|
25
|
+
spec.add_runtime_dependency "ostruct"
|
26
|
+
spec.add_runtime_dependency "irb"
|
24
27
|
spec.add_runtime_dependency "nkf"
|
25
28
|
spec.add_runtime_dependency "drb"
|
26
29
|
spec.add_runtime_dependency "curses", ">= 1.2.7"
|
27
30
|
spec.add_runtime_dependency "unicode-display_width", ">= 1.1"
|
28
31
|
spec.add_runtime_dependency "clipboard", ">= 1.1"
|
32
|
+
spec.add_runtime_dependency "fiddle"
|
29
33
|
spec.add_runtime_dependency "fiddley", ">= 0.0.5"
|
30
34
|
spec.add_runtime_dependency "editorconfig"
|
31
35
|
spec.add_runtime_dependency "warning"
|
36
|
+
spec.add_runtime_dependency "unicode-name"
|
37
|
+
spec.add_runtime_dependency "unicode-categories"
|
38
|
+
spec.add_runtime_dependency "unicode-blocks"
|
39
|
+
spec.add_runtime_dependency "unicode-scripts"
|
40
|
+
spec.add_runtime_dependency "unicode-types"
|
32
41
|
|
33
42
|
spec.add_development_dependency "bundler"
|
34
43
|
spec.add_development_dependency "rake", ">= 12.0"
|
metadata
CHANGED
@@ -1,14 +1,56 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: textbringer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: '2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 2025-04-04 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: rdoc
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: ostruct
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: irb
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
12
54
|
- !ruby/object:Gem::Dependency
|
13
55
|
name: nkf
|
14
56
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,6 +121,20 @@ dependencies:
|
|
79
121
|
- - ">="
|
80
122
|
- !ruby/object:Gem::Version
|
81
123
|
version: '1.1'
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: fiddle
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
type: :runtime
|
132
|
+
prerelease: false
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
82
138
|
- !ruby/object:Gem::Dependency
|
83
139
|
name: fiddley
|
84
140
|
requirement: !ruby/object:Gem::Requirement
|
@@ -121,6 +177,76 @@ dependencies:
|
|
121
177
|
- - ">="
|
122
178
|
- !ruby/object:Gem::Version
|
123
179
|
version: '0'
|
180
|
+
- !ruby/object:Gem::Dependency
|
181
|
+
name: unicode-name
|
182
|
+
requirement: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
type: :runtime
|
188
|
+
prerelease: false
|
189
|
+
version_requirements: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
- !ruby/object:Gem::Dependency
|
195
|
+
name: unicode-categories
|
196
|
+
requirement: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0'
|
201
|
+
type: :runtime
|
202
|
+
prerelease: false
|
203
|
+
version_requirements: !ruby/object:Gem::Requirement
|
204
|
+
requirements:
|
205
|
+
- - ">="
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
version: '0'
|
208
|
+
- !ruby/object:Gem::Dependency
|
209
|
+
name: unicode-blocks
|
210
|
+
requirement: !ruby/object:Gem::Requirement
|
211
|
+
requirements:
|
212
|
+
- - ">="
|
213
|
+
- !ruby/object:Gem::Version
|
214
|
+
version: '0'
|
215
|
+
type: :runtime
|
216
|
+
prerelease: false
|
217
|
+
version_requirements: !ruby/object:Gem::Requirement
|
218
|
+
requirements:
|
219
|
+
- - ">="
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '0'
|
222
|
+
- !ruby/object:Gem::Dependency
|
223
|
+
name: unicode-scripts
|
224
|
+
requirement: !ruby/object:Gem::Requirement
|
225
|
+
requirements:
|
226
|
+
- - ">="
|
227
|
+
- !ruby/object:Gem::Version
|
228
|
+
version: '0'
|
229
|
+
type: :runtime
|
230
|
+
prerelease: false
|
231
|
+
version_requirements: !ruby/object:Gem::Requirement
|
232
|
+
requirements:
|
233
|
+
- - ">="
|
234
|
+
- !ruby/object:Gem::Version
|
235
|
+
version: '0'
|
236
|
+
- !ruby/object:Gem::Dependency
|
237
|
+
name: unicode-types
|
238
|
+
requirement: !ruby/object:Gem::Requirement
|
239
|
+
requirements:
|
240
|
+
- - ">="
|
241
|
+
- !ruby/object:Gem::Version
|
242
|
+
version: '0'
|
243
|
+
type: :runtime
|
244
|
+
prerelease: false
|
245
|
+
version_requirements: !ruby/object:Gem::Requirement
|
246
|
+
requirements:
|
247
|
+
- - ">="
|
248
|
+
- !ruby/object:Gem::Version
|
249
|
+
version: '0'
|
124
250
|
- !ruby/object:Gem::Dependency
|
125
251
|
name: bundler
|
126
252
|
requirement: !ruby/object:Gem::Requirement
|
@@ -205,6 +331,7 @@ files:
|
|
205
331
|
- ".editorconfig"
|
206
332
|
- ".gitattributes"
|
207
333
|
- ".github/workflows/macos.yml"
|
334
|
+
- ".github/workflows/push_gem.yml"
|
208
335
|
- ".github/workflows/ubuntu.yml"
|
209
336
|
- ".github/workflows/windows.yml"
|
210
337
|
- ".gitignore"
|
@@ -237,6 +364,7 @@ files:
|
|
237
364
|
- lib/textbringer/commands/register.rb
|
238
365
|
- lib/textbringer/commands/replace.rb
|
239
366
|
- lib/textbringer/commands/server.rb
|
367
|
+
- lib/textbringer/commands/ucs_normalize.rb
|
240
368
|
- lib/textbringer/commands/windows.rb
|
241
369
|
- lib/textbringer/config.rb
|
242
370
|
- lib/textbringer/controller.rb
|
@@ -246,6 +374,7 @@ files:
|
|
246
374
|
- lib/textbringer/faces/basic.rb
|
247
375
|
- lib/textbringer/faces/programming.rb
|
248
376
|
- lib/textbringer/input_method.rb
|
377
|
+
- lib/textbringer/input_methods/hangul_input_method.rb
|
249
378
|
- lib/textbringer/input_methods/hiragana_input_method.rb
|
250
379
|
- lib/textbringer/input_methods/t_code_input_method.rb
|
251
380
|
- lib/textbringer/input_methods/t_code_input_method/tables.rb
|
@@ -264,6 +393,7 @@ files:
|
|
264
393
|
- lib/textbringer/utils.rb
|
265
394
|
- lib/textbringer/version.rb
|
266
395
|
- lib/textbringer/window.rb
|
396
|
+
- lib/textbringer/window/fallback_characters.rb
|
267
397
|
- logo/logo.jpg
|
268
398
|
- logo/logo.png
|
269
399
|
- screenshot.png
|
@@ -286,7 +416,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
286
416
|
- !ruby/object:Gem::Version
|
287
417
|
version: '0'
|
288
418
|
requirements: []
|
289
|
-
rubygems_version: 3.6.
|
419
|
+
rubygems_version: 3.6.2
|
290
420
|
specification_version: 4
|
291
421
|
summary: An Emacs-like text editor
|
292
422
|
test_files: []
|