textbringer 17 → 19
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/exe/txtb +1 -1
- data/lib/textbringer/buffer.rb +37 -3
- data/lib/textbringer/commands/buffers.rb +4 -2
- data/lib/textbringer/commands/clipboard.rb +21 -6
- data/lib/textbringer/commands/completion.rb +133 -0
- data/lib/textbringer/commands/ctags.rb +1 -1
- data/lib/textbringer/commands/files.rb +11 -1
- data/lib/textbringer/commands/help.rb +1 -1
- data/lib/textbringer/commands/isearch.rb +4 -10
- data/lib/textbringer/commands/ispell.rb +0 -2
- data/lib/textbringer/commands/lsp.rb +389 -0
- data/lib/textbringer/commands/misc.rb +2 -1
- data/lib/textbringer/commands.rb +7 -3
- data/lib/textbringer/completion_popup.rb +188 -0
- data/lib/textbringer/faces/basic.rb +3 -1
- data/lib/textbringer/faces/completion.rb +4 -0
- data/lib/textbringer/floating_window.rb +327 -0
- data/lib/textbringer/input_methods/skk_input_method.rb +751 -0
- data/lib/textbringer/lsp/client.rb +568 -0
- data/lib/textbringer/lsp/server_registry.rb +138 -0
- data/lib/textbringer/mode.rb +3 -1
- data/lib/textbringer/modes/programming_mode.rb +17 -8
- data/lib/textbringer/modes/transient_mark_mode.rb +9 -2
- data/lib/textbringer/utils.rb +14 -10
- data/lib/textbringer/version.rb +1 -1
- data/lib/textbringer/window.rb +116 -19
- data/lib/textbringer.rb +7 -0
- data/sig/lib/textbringer/buffer.rbs +483 -0
- data/sig/lib/textbringer/color.rbs +9 -0
- data/sig/lib/textbringer/commands/buffers.rbs +93 -0
- data/sig/lib/textbringer/commands/clipboard.rbs +17 -0
- data/sig/lib/textbringer/commands/completion.rbs +20 -0
- data/sig/lib/textbringer/commands/ctags.rbs +11 -0
- data/sig/lib/textbringer/commands/dabbrev.rbs +4 -0
- data/sig/lib/textbringer/commands/files.rbs +29 -0
- data/sig/lib/textbringer/commands/fill.rbs +5 -0
- data/sig/lib/textbringer/commands/help.rbs +28 -0
- data/sig/lib/textbringer/commands/input_method.rbs +6 -0
- data/sig/lib/textbringer/commands/isearch.rbs +38 -0
- data/sig/lib/textbringer/commands/ispell.rbs +39 -0
- data/sig/lib/textbringer/commands/keyboard_macro.rbs +25 -0
- data/sig/lib/textbringer/commands/lsp.rbs +8 -0
- data/sig/lib/textbringer/commands/misc.rbs +74 -0
- data/sig/lib/textbringer/commands/rectangle.rbs +19 -0
- data/sig/lib/textbringer/commands/register.rbs +31 -0
- data/sig/lib/textbringer/commands/replace.rbs +17 -0
- data/sig/lib/textbringer/commands/server.rbs +31 -0
- data/sig/lib/textbringer/commands/ucs_normalize.rbs +9 -0
- data/sig/lib/textbringer/commands/windows.rbs +45 -0
- data/sig/lib/textbringer/commands.rbs +21 -0
- data/sig/lib/textbringer/completion_popup.rbs +40 -0
- data/sig/lib/textbringer/controller.rbs +58 -0
- data/sig/lib/textbringer/default_output.rbs +7 -0
- data/sig/lib/textbringer/errors.rbs +3 -0
- data/sig/lib/textbringer/face.rbs +19 -0
- data/sig/lib/textbringer/floating_window.rbs +42 -0
- data/sig/lib/textbringer/global_minor_mode.rbs +7 -0
- data/sig/lib/textbringer/input_method.rbs +28 -0
- data/sig/lib/textbringer/input_methods/hangul_input_method.rbs +12 -0
- data/sig/lib/textbringer/input_methods/hiragana_input_method.rbs +12 -0
- data/sig/lib/textbringer/input_methods/t_code_input_method.rbs +49 -0
- data/sig/lib/textbringer/keymap.rbs +33 -0
- data/sig/lib/textbringer/lsp/client.rbs +21 -0
- data/sig/lib/textbringer/lsp/server_registry.rbs +23 -0
- data/sig/lib/textbringer/minor_mode.rbs +12 -0
- data/sig/lib/textbringer/mode.rbs +70 -0
- data/sig/lib/textbringer/modes/backtrace_mode.rbs +8 -0
- data/sig/lib/textbringer/modes/buffer_list_mode.rbs +5 -0
- data/sig/lib/textbringer/modes/c_mode.rbs +21 -0
- data/sig/lib/textbringer/modes/completion_list_mode.rbs +5 -0
- data/sig/lib/textbringer/modes/fundamental_mode.rbs +3 -0
- data/sig/lib/textbringer/modes/help_mode.rbs +7 -0
- data/sig/lib/textbringer/modes/overwrite_mode.rbs +15 -0
- data/sig/lib/textbringer/modes/programming_mode.rbs +14 -0
- data/sig/lib/textbringer/modes/ruby_mode.rbs +57 -0
- data/sig/lib/textbringer/plugin.rbs +3 -0
- data/sig/lib/textbringer/ring.rbs +36 -0
- data/sig/lib/textbringer/utils.rbs +95 -0
- data/sig/lib/textbringer/window.rbs +183 -0
- data/textbringer.gemspec +1 -0
- metadata +76 -2
|
@@ -0,0 +1,751 @@
|
|
|
1
|
+
module Textbringer
|
|
2
|
+
class SkkInputMethod < InputMethod
|
|
3
|
+
HIRAGANA_TABLE = {
|
|
4
|
+
"a" => "あ", "i" => "い", "u" => "う", "e" => "え", "o" => "お",
|
|
5
|
+
"ka" => "か", "ki" => "き", "ku" => "く", "ke" => "け", "ko" => "こ",
|
|
6
|
+
"ga" => "が", "gi" => "ぎ", "gu" => "ぐ", "ge" => "げ", "go" => "ご",
|
|
7
|
+
"sa" => "さ", "si" => "し", "su" => "す", "se" => "せ", "so" => "そ",
|
|
8
|
+
"za" => "ざ", "zi" => "じ", "zu" => "ず", "ze" => "ぜ", "zo" => "ぞ",
|
|
9
|
+
"sha" => "しゃ", "shi" => "し", "shu" => "しゅ", "she" => "しぇ", "sho" => "しょ",
|
|
10
|
+
"ja" => "じゃ", "ji" => "じ", "ju" => "じゅ", "je" => "じぇ", "jo" => "じょ",
|
|
11
|
+
"ta" => "た", "ti" => "ち", "tu" => "つ", "te" => "て", "to" => "と",
|
|
12
|
+
"da" => "だ", "di" => "ぢ", "du" => "づ", "de" => "で", "do" => "ど",
|
|
13
|
+
"cha" => "ちゃ", "chi" => "ち", "chu" => "ちゅ", "che" => "ちぇ", "cho" => "ちょ",
|
|
14
|
+
"na" => "な", "ni" => "に", "nu" => "ぬ", "ne" => "ね", "no" => "の",
|
|
15
|
+
"ha" => "は", "hi" => "ひ", "hu" => "ふ", "he" => "へ", "ho" => "ほ",
|
|
16
|
+
"ba" => "ば", "bi" => "び", "bu" => "ぶ", "be" => "べ", "bo" => "ぼ",
|
|
17
|
+
"pa" => "ぱ", "pi" => "ぴ", "pu" => "ぷ", "pe" => "ぺ", "po" => "ぽ",
|
|
18
|
+
"ma" => "ま", "mi" => "み", "mu" => "む", "me" => "め", "mo" => "も",
|
|
19
|
+
"ya" => "や", "yi" => "い", "yu" => "ゆ", "ye" => "いぇ", "yo" => "よ",
|
|
20
|
+
"ra" => "ら", "ri" => "り", "ru" => "る", "re" => "れ", "ro" => "ろ",
|
|
21
|
+
"wa" => "わ", "wi" => "ゐ", "wu" => "う", "we" => "ゑ", "wo" => "を",
|
|
22
|
+
"nn" => "ん",
|
|
23
|
+
"kya" => "きゃ", "kyi" => "きぃ", "kyu" => "きゅ", "kye" => "きぇ", "kyo" => "きょ",
|
|
24
|
+
"gya" => "ぎゃ", "gyi" => "ぎぃ", "gyu" => "ぎゅ", "gye" => "ぎぇ", "gyo" => "ぎょ",
|
|
25
|
+
"sya" => "しゃ", "syi" => "しぃ", "syu" => "しゅ", "sye" => "しぇ", "syo" => "しょ",
|
|
26
|
+
"zya" => "じゃ", "zyi" => "じぃ", "zyu" => "じゅ", "zye" => "じぇ", "zyo" => "じょ",
|
|
27
|
+
"tya" => "ちゃ", "tyi" => "ちぃ", "tyu" => "ちゅ", "tye" => "ちぇ", "tyo" => "ちょ",
|
|
28
|
+
"dya" => "ぢゃ", "dyi" => "ぢぃ", "dyu" => "ぢゅ", "dye" => "ぢぇ", "dyo" => "ぢょ",
|
|
29
|
+
"nya" => "にゃ", "nyi" => "にぃ", "nyu" => "にゅ", "nye" => "にぇ", "nyo" => "にょ",
|
|
30
|
+
"hya" => "ひゃ", "hyi" => "ひぃ", "hyu" => "ひゅ", "hye" => "ひぇ", "hyo" => "ひょ",
|
|
31
|
+
"bya" => "びゃ", "byi" => "びぃ", "byu" => "びゅ", "bye" => "びぇ", "byo" => "びょ",
|
|
32
|
+
"pya" => "ぴゃ", "pyi" => "ぴぃ", "pyu" => "ぴゅ", "pye" => "ぴぇ", "pyo" => "ぴょ",
|
|
33
|
+
"mya" => "みゃ", "myi" => "みぃ", "myu" => "みゅ", "mye" => "みぇ", "myo" => "みょ",
|
|
34
|
+
"rya" => "りゃ", "ryi" => "りぃ", "ryu" => "りゅ", "rye" => "りぇ", "ryo" => "りょ",
|
|
35
|
+
"fa" => "ふぁ", "fi" => "ふぃ", "fu" => "ふ", "fe" => "ふぇ", "fo" => "ふぉ",
|
|
36
|
+
"va" => "ヴぁ", "vi" => "ヴぃ", "vu" => "ヴ", "ve" => "ヴぇ", "vo" => "ヴぉ",
|
|
37
|
+
"tsa" => "つぁ", "tsi" => "つぃ", "tse" => "つぇ", "tso" => "つぉ",
|
|
38
|
+
"la" => "ぁ", "li" => "ぃ", "lu" => "ぅ", "le" => "ぇ", "lo" => "ぉ",
|
|
39
|
+
"lya" => "ゃ", "lyu" => "ゅ", "lyo" => "ょ",
|
|
40
|
+
"lka" => "ヵ", "lke" => "ヶ",
|
|
41
|
+
"xtu" => "っ", "xtsu" => "っ",
|
|
42
|
+
"xya" => "ゃ", "xyu" => "ゅ", "xyo" => "ょ",
|
|
43
|
+
"xa" => "ぁ", "xi" => "ぃ", "xu" => "ぅ", "xe" => "ぇ", "xo" => "ぉ",
|
|
44
|
+
"," => "、", "." => "。",
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
HIRAGANA_PREFIXES = HIRAGANA_TABLE.keys.flat_map { |s|
|
|
48
|
+
(s.size - 1).times.map { |i| s[0, i + 1] }
|
|
49
|
+
}.uniq
|
|
50
|
+
|
|
51
|
+
KATAKANA_TABLE = HIRAGANA_TABLE.transform_values { |v|
|
|
52
|
+
v.chars.map { |c|
|
|
53
|
+
c.ord.between?(0x3041, 0x3096) ? (c.ord + 0x60).chr("UTF-8") : c
|
|
54
|
+
}.join
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
HANKAKU_KATAKANA_TABLE = {
|
|
58
|
+
"a" => "ア", "i" => "イ", "u" => "ウ", "e" => "エ", "o" => "オ",
|
|
59
|
+
"ka" => "カ", "ki" => "キ", "ku" => "ク", "ke" => "ケ", "ko" => "コ",
|
|
60
|
+
"ga" => "ガ", "gi" => "ギ", "gu" => "グ", "ge" => "ゲ", "go" => "ゴ",
|
|
61
|
+
"sa" => "サ", "si" => "シ", "su" => "ス", "se" => "セ", "so" => "ソ",
|
|
62
|
+
"za" => "ザ", "zi" => "ジ", "zu" => "ズ", "ze" => "ゼ", "zo" => "ゾ",
|
|
63
|
+
"sha" => "シャ", "shi" => "シ", "shu" => "シュ", "she" => "シェ", "sho" => "ショ",
|
|
64
|
+
"ja" => "ジャ", "ji" => "ジ", "ju" => "ジュ", "je" => "ジェ", "jo" => "ジョ",
|
|
65
|
+
"ta" => "タ", "ti" => "チ", "tu" => "ツ", "te" => "テ", "to" => "ト",
|
|
66
|
+
"da" => "ダ", "di" => "ヂ", "du" => "ヅ", "de" => "デ", "do" => "ド",
|
|
67
|
+
"cha" => "チャ", "chi" => "チ", "chu" => "チュ", "che" => "チェ", "cho" => "チョ",
|
|
68
|
+
"na" => "ナ", "ni" => "ニ", "nu" => "ヌ", "ne" => "ネ", "no" => "ノ",
|
|
69
|
+
"ha" => "ハ", "hi" => "ヒ", "hu" => "フ", "he" => "ヘ", "ho" => "ホ",
|
|
70
|
+
"ba" => "バ", "bi" => "ビ", "bu" => "ブ", "be" => "ベ", "bo" => "ボ",
|
|
71
|
+
"pa" => "パ", "pi" => "ピ", "pu" => "プ", "pe" => "ペ", "po" => "ポ",
|
|
72
|
+
"ma" => "マ", "mi" => "ミ", "mu" => "ム", "me" => "メ", "mo" => "モ",
|
|
73
|
+
"ya" => "ヤ", "yu" => "ユ", "yo" => "ヨ",
|
|
74
|
+
"ra" => "ラ", "ri" => "リ", "ru" => "ル", "re" => "レ", "ro" => "ロ",
|
|
75
|
+
"wa" => "ワ", "wo" => "ヲ",
|
|
76
|
+
"nn" => "ン",
|
|
77
|
+
"kya" => "キャ", "kyu" => "キュ", "kyo" => "キョ",
|
|
78
|
+
"gya" => "ギャ", "gyu" => "ギュ", "gyo" => "ギョ",
|
|
79
|
+
"sya" => "シャ", "syu" => "シュ", "syo" => "ショ",
|
|
80
|
+
"zya" => "ジャ", "zyu" => "ジュ", "zyo" => "ジョ",
|
|
81
|
+
"tya" => "チャ", "tyu" => "チュ", "tyo" => "チョ",
|
|
82
|
+
"dya" => "ヂャ", "dyu" => "ヂュ", "dyo" => "ヂョ",
|
|
83
|
+
"nya" => "ニャ", "nyu" => "ニュ", "nyo" => "ニョ",
|
|
84
|
+
"hya" => "ヒャ", "hyu" => "ヒュ", "hyo" => "ヒョ",
|
|
85
|
+
"bya" => "ビャ", "byu" => "ビュ", "byo" => "ビョ",
|
|
86
|
+
"pya" => "ピャ", "pyu" => "ピュ", "pyo" => "ピョ",
|
|
87
|
+
"mya" => "ミャ", "myu" => "ミュ", "myo" => "ミョ",
|
|
88
|
+
"rya" => "リャ", "ryu" => "リュ", "ryo" => "リョ",
|
|
89
|
+
"fa" => "ファ", "fi" => "フィ", "fu" => "フ", "fe" => "フェ", "fo" => "フォ",
|
|
90
|
+
"," => "、", "." => "。",
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
HANKAKU_KATAKANA_PREFIXES = HANKAKU_KATAKANA_TABLE.keys.flat_map { |s|
|
|
94
|
+
(s.size - 1).times.map { |i| s[0, i + 1] }
|
|
95
|
+
}.uniq
|
|
96
|
+
|
|
97
|
+
DICTIONARY_PATH = File.expand_path("~/.textbringer/skk/SKK-JISYO.L")
|
|
98
|
+
|
|
99
|
+
DEFAULT_CURSOR_COLORS = {
|
|
100
|
+
hiragana: "pink",
|
|
101
|
+
katakana: "green",
|
|
102
|
+
hankaku_katakana: "blue",
|
|
103
|
+
zenkaku_ascii: "yellow",
|
|
104
|
+
ascii: nil, # nil = reset to terminal default
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
def initialize
|
|
108
|
+
super
|
|
109
|
+
@mode = :hiragana # :hiragana | :katakana | :hankaku_katakana | :zenkaku_ascii | :ascii
|
|
110
|
+
@phase = :normal # :normal | :converting | :selecting
|
|
111
|
+
@roman_buffer = +""
|
|
112
|
+
@yomi = +""
|
|
113
|
+
@okuri_roman = nil
|
|
114
|
+
@okuri_kana = nil
|
|
115
|
+
@candidates = []
|
|
116
|
+
@candidate_index = 0
|
|
117
|
+
@marker_pos = nil
|
|
118
|
+
@okuriiari = nil
|
|
119
|
+
@okurinasi = nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def toggle
|
|
123
|
+
super
|
|
124
|
+
if @enabled
|
|
125
|
+
update_cursor_color
|
|
126
|
+
else
|
|
127
|
+
reset_cursor_color
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def disable
|
|
132
|
+
super
|
|
133
|
+
reset_cursor_color
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def status
|
|
137
|
+
case @phase
|
|
138
|
+
when :converting then "▽"
|
|
139
|
+
when :selecting then "▼"
|
|
140
|
+
else
|
|
141
|
+
{ hiragana: "あ", katakana: "ア", hankaku_katakana: "ア",
|
|
142
|
+
zenkaku_ascii: "A", ascii: "A" }[@mode]
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def handle_event(event)
|
|
147
|
+
case @phase
|
|
148
|
+
when :normal then handle_normal(event)
|
|
149
|
+
when :converting then handle_converting(event)
|
|
150
|
+
when :selecting then handle_selecting(event)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
private
|
|
155
|
+
|
|
156
|
+
def handle_normal(event)
|
|
157
|
+
unless event.is_a?(String)
|
|
158
|
+
@roman_buffer = +""
|
|
159
|
+
return event
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
case event
|
|
163
|
+
when "\C-j"
|
|
164
|
+
@roman_buffer = +""
|
|
165
|
+
@mode = :hiragana
|
|
166
|
+
Window.redisplay
|
|
167
|
+
update_cursor_color
|
|
168
|
+
nil
|
|
169
|
+
when "\C-q"
|
|
170
|
+
if [:hiragana, :katakana].include?(@mode)
|
|
171
|
+
@roman_buffer = +""
|
|
172
|
+
@mode = :hankaku_katakana
|
|
173
|
+
Window.redisplay
|
|
174
|
+
update_cursor_color
|
|
175
|
+
elsif @mode == :hankaku_katakana
|
|
176
|
+
@roman_buffer = +""
|
|
177
|
+
@mode = :hiragana
|
|
178
|
+
Window.redisplay
|
|
179
|
+
update_cursor_color
|
|
180
|
+
else
|
|
181
|
+
return process_romaji(event)
|
|
182
|
+
end
|
|
183
|
+
nil
|
|
184
|
+
when "q"
|
|
185
|
+
if @mode == :hiragana
|
|
186
|
+
@roman_buffer = +""
|
|
187
|
+
@mode = :katakana
|
|
188
|
+
Window.redisplay
|
|
189
|
+
update_cursor_color
|
|
190
|
+
nil
|
|
191
|
+
elsif @mode == :katakana || @mode == :hankaku_katakana
|
|
192
|
+
@roman_buffer = +""
|
|
193
|
+
@mode = :hiragana
|
|
194
|
+
Window.redisplay
|
|
195
|
+
update_cursor_color
|
|
196
|
+
nil
|
|
197
|
+
else
|
|
198
|
+
process_romaji(event)
|
|
199
|
+
end
|
|
200
|
+
when "l"
|
|
201
|
+
if [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
|
|
202
|
+
@roman_buffer = +""
|
|
203
|
+
@mode = :ascii
|
|
204
|
+
Window.redisplay
|
|
205
|
+
update_cursor_color
|
|
206
|
+
nil
|
|
207
|
+
else
|
|
208
|
+
process_romaji(event)
|
|
209
|
+
end
|
|
210
|
+
when "L"
|
|
211
|
+
if [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
|
|
212
|
+
@roman_buffer = +""
|
|
213
|
+
@mode = :zenkaku_ascii
|
|
214
|
+
Window.redisplay
|
|
215
|
+
update_cursor_color
|
|
216
|
+
nil
|
|
217
|
+
else
|
|
218
|
+
process_romaji(event)
|
|
219
|
+
end
|
|
220
|
+
when /\A[A-Z]\z/
|
|
221
|
+
if [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
|
|
222
|
+
start_converting(event.downcase)
|
|
223
|
+
else
|
|
224
|
+
process_romaji(event)
|
|
225
|
+
end
|
|
226
|
+
when /\A[\x00-\x09\x0b-\x1f\x7f]\z/
|
|
227
|
+
# Control characters other than C-j and C-q pass through unchanged
|
|
228
|
+
@roman_buffer = +""
|
|
229
|
+
event
|
|
230
|
+
else
|
|
231
|
+
process_romaji(event)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def handle_converting(event)
|
|
236
|
+
unless event.is_a?(String)
|
|
237
|
+
commit_converting
|
|
238
|
+
return event
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Control characters not handled below: commit conversion and pass through
|
|
242
|
+
if event.bytesize == 1 && (event.ord < 0x20 || event.ord == 0x7f) &&
|
|
243
|
+
event != "\C-g" && event != "\C-j"
|
|
244
|
+
commit_converting
|
|
245
|
+
return event
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
case event
|
|
249
|
+
when "\C-g"
|
|
250
|
+
cancel_converting
|
|
251
|
+
nil
|
|
252
|
+
when "\C-j"
|
|
253
|
+
commit_converting
|
|
254
|
+
nil
|
|
255
|
+
when " "
|
|
256
|
+
start_selecting
|
|
257
|
+
nil
|
|
258
|
+
when /\A[A-Z]\z/
|
|
259
|
+
if @okuri_roman.nil?
|
|
260
|
+
start_okurigana(event.downcase)
|
|
261
|
+
else
|
|
262
|
+
process_converting_romaji(event.downcase)
|
|
263
|
+
end
|
|
264
|
+
nil
|
|
265
|
+
else
|
|
266
|
+
process_converting_romaji(event)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def handle_selecting(event)
|
|
271
|
+
unless event.is_a?(String)
|
|
272
|
+
confirm_selecting
|
|
273
|
+
return event
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
case event
|
|
277
|
+
when "\C-g"
|
|
278
|
+
cancel_selecting
|
|
279
|
+
nil
|
|
280
|
+
when " "
|
|
281
|
+
next_candidate
|
|
282
|
+
nil
|
|
283
|
+
when "x"
|
|
284
|
+
prev_candidate
|
|
285
|
+
nil
|
|
286
|
+
when "\C-m", "\r", "\n"
|
|
287
|
+
confirm_selecting
|
|
288
|
+
nil
|
|
289
|
+
else
|
|
290
|
+
confirm_selecting
|
|
291
|
+
handle_event(event)
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def process_romaji(event)
|
|
296
|
+
case @mode
|
|
297
|
+
when :ascii
|
|
298
|
+
return event
|
|
299
|
+
when :zenkaku_ascii
|
|
300
|
+
if event.ord.between?(0x21, 0x7E)
|
|
301
|
+
return (event.ord + 0xFEE0).chr("UTF-8")
|
|
302
|
+
else
|
|
303
|
+
return event
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# Special "n" handling: flush "ん" before appending if next char won't extend "n"
|
|
308
|
+
if @roman_buffer == "n" && !%w[n y a i u e o].include?(event)
|
|
309
|
+
kana = kana_for_mode("ん")
|
|
310
|
+
@roman_buffer = +""
|
|
311
|
+
insert_kana(kana)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
@roman_buffer << event
|
|
315
|
+
|
|
316
|
+
table = current_table
|
|
317
|
+
prefixes = current_prefixes
|
|
318
|
+
|
|
319
|
+
kana = table[@roman_buffer]
|
|
320
|
+
if kana
|
|
321
|
+
@roman_buffer = +""
|
|
322
|
+
insert_kana(kana_for_mode(kana))
|
|
323
|
+
return nil
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
if prefixes.include?(@roman_buffer)
|
|
327
|
+
return nil
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Double consonant: e.g. "kk" → っ + keep second "k"
|
|
331
|
+
if @roman_buffer.size >= 2
|
|
332
|
+
first = @roman_buffer[0]
|
|
333
|
+
rest = @roman_buffer[1..]
|
|
334
|
+
if first == rest[0] && first =~ /[bcdfghjklmnpqrstvwxyz]/
|
|
335
|
+
geminate = kana_for_mode("っ")
|
|
336
|
+
@roman_buffer = +rest
|
|
337
|
+
insert_kana(geminate)
|
|
338
|
+
# Now check if rest completes a kana
|
|
339
|
+
kana2 = table[@roman_buffer]
|
|
340
|
+
if kana2
|
|
341
|
+
@roman_buffer = +""
|
|
342
|
+
insert_kana(kana_for_mode(kana2))
|
|
343
|
+
end
|
|
344
|
+
return nil
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# No match: if single char, return it to let the controller handle it
|
|
349
|
+
# (consistent with HiraganaInputMethod#flush for unrecognized chars)
|
|
350
|
+
if @roman_buffer.size == 1
|
|
351
|
+
char = @roman_buffer
|
|
352
|
+
@roman_buffer = +""
|
|
353
|
+
return char
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Multi-char: flush first char as-is, retry with last char
|
|
357
|
+
first_char = @roman_buffer[0]
|
|
358
|
+
last_char = @roman_buffer[-1]
|
|
359
|
+
@roman_buffer = +""
|
|
360
|
+
with_target_buffer { |b| b.insert(first_char) }
|
|
361
|
+
Window.redisplay
|
|
362
|
+
process_romaji(last_char)
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def insert_kana(kana)
|
|
366
|
+
with_target_buffer do |buffer|
|
|
367
|
+
buffer.insert(kana)
|
|
368
|
+
end
|
|
369
|
+
Window.redisplay
|
|
370
|
+
nil
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def process_converting_romaji(event)
|
|
374
|
+
# Special "n" handling: flush "ん" before appending if next char won't extend "n"
|
|
375
|
+
if @roman_buffer == "n" && !%w[n y a i u e o].include?(event)
|
|
376
|
+
@roman_buffer = +""
|
|
377
|
+
append_yomi_kana("ん")
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
@roman_buffer << event
|
|
381
|
+
|
|
382
|
+
table = hiragana_table_for_converting
|
|
383
|
+
prefixes = hiragana_prefixes_for_converting
|
|
384
|
+
|
|
385
|
+
kana = table[@roman_buffer]
|
|
386
|
+
if kana
|
|
387
|
+
@roman_buffer = +""
|
|
388
|
+
if @okuri_roman
|
|
389
|
+
# Completing okurigana
|
|
390
|
+
@okuri_kana = kana
|
|
391
|
+
with_target_buffer do |buffer|
|
|
392
|
+
buffer.insert(kana)
|
|
393
|
+
end
|
|
394
|
+
Window.redisplay
|
|
395
|
+
start_selecting
|
|
396
|
+
else
|
|
397
|
+
append_yomi_kana(kana)
|
|
398
|
+
end
|
|
399
|
+
return
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
if prefixes.include?(@roman_buffer)
|
|
403
|
+
return
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# Double consonant handling
|
|
407
|
+
if @roman_buffer.size >= 2
|
|
408
|
+
first = @roman_buffer[0]
|
|
409
|
+
rest = @roman_buffer[1..]
|
|
410
|
+
if first == rest[0] && first =~ /[bcdfghjklmnpqrstvwxyz]/
|
|
411
|
+
append_yomi_kana("っ")
|
|
412
|
+
@roman_buffer = +rest # Keep the second consonant buffered
|
|
413
|
+
return
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
# No match: if single char, insert as-is
|
|
418
|
+
if @roman_buffer.size == 1
|
|
419
|
+
char = @roman_buffer
|
|
420
|
+
@roman_buffer = +""
|
|
421
|
+
append_yomi_kana(char)
|
|
422
|
+
return
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
# Multi-char: flush first char as-is, retry with last char
|
|
426
|
+
first_char = @roman_buffer[0]
|
|
427
|
+
last_char = @roman_buffer[-1]
|
|
428
|
+
@roman_buffer = +""
|
|
429
|
+
append_yomi_kana(first_char)
|
|
430
|
+
process_converting_romaji(last_char)
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def append_yomi_kana(kana)
|
|
434
|
+
@yomi << kana
|
|
435
|
+
with_target_buffer do |buffer|
|
|
436
|
+
buffer.insert(kana)
|
|
437
|
+
end
|
|
438
|
+
Window.redisplay
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def start_converting(first_char)
|
|
442
|
+
@phase = :converting
|
|
443
|
+
@yomi = +""
|
|
444
|
+
@okuri_roman = nil
|
|
445
|
+
@okuri_kana = nil
|
|
446
|
+
@roman_buffer = +""
|
|
447
|
+
with_target_buffer do |buffer|
|
|
448
|
+
@marker_pos = buffer.point
|
|
449
|
+
buffer.insert("▽")
|
|
450
|
+
end
|
|
451
|
+
Window.redisplay
|
|
452
|
+
update_cursor_color
|
|
453
|
+
process_converting_romaji(first_char)
|
|
454
|
+
nil
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def start_okurigana(consonant)
|
|
458
|
+
@okuri_roman = consonant.dup
|
|
459
|
+
@roman_buffer = consonant.dup
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def cancel_converting
|
|
463
|
+
with_target_buffer do |buffer|
|
|
464
|
+
buffer.delete_region(@marker_pos, buffer.point)
|
|
465
|
+
end
|
|
466
|
+
@phase = :normal
|
|
467
|
+
@yomi = +""
|
|
468
|
+
@roman_buffer = +""
|
|
469
|
+
@okuri_roman = nil
|
|
470
|
+
@okuri_kana = nil
|
|
471
|
+
@marker_pos = nil
|
|
472
|
+
Window.redisplay
|
|
473
|
+
update_cursor_color
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
def commit_converting
|
|
477
|
+
with_target_buffer do |buffer|
|
|
478
|
+
# Remove the ▽ marker (3 bytes for ▽ in UTF-8)
|
|
479
|
+
marker_end = @marker_pos + "▽".bytesize
|
|
480
|
+
buffer.delete_region(@marker_pos, marker_end)
|
|
481
|
+
end
|
|
482
|
+
@phase = :normal
|
|
483
|
+
@roman_buffer = +""
|
|
484
|
+
@okuri_roman = nil
|
|
485
|
+
@okuri_kana = nil
|
|
486
|
+
@marker_pos = nil
|
|
487
|
+
Window.redisplay
|
|
488
|
+
update_cursor_color
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
def start_selecting
|
|
492
|
+
ensure_dictionary_loaded
|
|
493
|
+
|
|
494
|
+
lookup_key = if @okuri_roman
|
|
495
|
+
@yomi + @okuri_roman
|
|
496
|
+
else
|
|
497
|
+
@yomi
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
dict = @okuri_roman ? @okuriiari : @okurinasi
|
|
501
|
+
candidates = dict[lookup_key]
|
|
502
|
+
|
|
503
|
+
if candidates.nil? || candidates.empty?
|
|
504
|
+
message("No conversion: #{@yomi}")
|
|
505
|
+
return
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
@candidates = candidates
|
|
509
|
+
@candidate_index = 0
|
|
510
|
+
@phase = :selecting
|
|
511
|
+
|
|
512
|
+
with_target_buffer do |buffer|
|
|
513
|
+
buffer.delete_region(@marker_pos, buffer.point)
|
|
514
|
+
buffer.insert("▼" + @candidates[0] + (@okuri_kana || ""))
|
|
515
|
+
end
|
|
516
|
+
Window.redisplay
|
|
517
|
+
update_cursor_color
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
def next_candidate
|
|
521
|
+
@candidate_index = (@candidate_index + 1) % @candidates.size
|
|
522
|
+
replace_candidate
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
def prev_candidate
|
|
526
|
+
@candidate_index = (@candidate_index - 1 + @candidates.size) % @candidates.size
|
|
527
|
+
replace_candidate
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
def replace_candidate
|
|
531
|
+
with_target_buffer do |buffer|
|
|
532
|
+
buffer.delete_region(@marker_pos, buffer.point)
|
|
533
|
+
buffer.insert("▼" + @candidates[@candidate_index] + (@okuri_kana || ""))
|
|
534
|
+
end
|
|
535
|
+
Window.redisplay
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
def confirm_selecting
|
|
539
|
+
candidate = @candidates[@candidate_index]
|
|
540
|
+
with_target_buffer do |buffer|
|
|
541
|
+
buffer.delete_region(@marker_pos, buffer.point)
|
|
542
|
+
buffer.insert(candidate + (@okuri_kana || ""))
|
|
543
|
+
end
|
|
544
|
+
@phase = :normal
|
|
545
|
+
@yomi = +""
|
|
546
|
+
@roman_buffer = +""
|
|
547
|
+
@okuri_roman = nil
|
|
548
|
+
@okuri_kana = nil
|
|
549
|
+
@candidates = []
|
|
550
|
+
@candidate_index = 0
|
|
551
|
+
@marker_pos = nil
|
|
552
|
+
Window.redisplay
|
|
553
|
+
update_cursor_color
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
def cancel_selecting
|
|
557
|
+
with_target_buffer do |buffer|
|
|
558
|
+
buffer.delete_region(@marker_pos, buffer.point)
|
|
559
|
+
buffer.insert("▽" + @yomi + (@okuri_kana || ""))
|
|
560
|
+
end
|
|
561
|
+
@phase = :converting
|
|
562
|
+
@roman_buffer = +""
|
|
563
|
+
@candidates = []
|
|
564
|
+
@candidate_index = 0
|
|
565
|
+
Window.redisplay
|
|
566
|
+
update_cursor_color
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
def ensure_dictionary_loaded
|
|
570
|
+
return if @okuriiari
|
|
571
|
+
|
|
572
|
+
path = CONFIG[:skk_dictionary] || DICTIONARY_PATH
|
|
573
|
+
@okuriiari = {}
|
|
574
|
+
@okurinasi = {}
|
|
575
|
+
section = :okuriiari
|
|
576
|
+
|
|
577
|
+
File.foreach(path, encoding: "EUC-JP:UTF-8") do |line|
|
|
578
|
+
line.chomp!
|
|
579
|
+
if line == ";; okuri-nasi entries."
|
|
580
|
+
section = :okurinasi
|
|
581
|
+
next
|
|
582
|
+
end
|
|
583
|
+
next if line.start_with?(";") || line.empty?
|
|
584
|
+
|
|
585
|
+
key, rest = line.split(" /", 2)
|
|
586
|
+
next unless key && rest
|
|
587
|
+
|
|
588
|
+
candidates = rest.split("/").map { |c| c.split(";").first&.strip }.compact.reject(&:empty?)
|
|
589
|
+
next if candidates.empty?
|
|
590
|
+
|
|
591
|
+
if section == :okuriiari
|
|
592
|
+
@okuriiari[key] = candidates
|
|
593
|
+
else
|
|
594
|
+
@okurinasi[key] = candidates
|
|
595
|
+
end
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
def kana_for_mode(hiragana_kana)
|
|
600
|
+
case @mode
|
|
601
|
+
when :hiragana
|
|
602
|
+
hiragana_kana
|
|
603
|
+
when :katakana
|
|
604
|
+
hiragana_to_katakana(hiragana_kana)
|
|
605
|
+
when :hankaku_katakana
|
|
606
|
+
hiragana_to_hankaku_katakana(hiragana_kana)
|
|
607
|
+
else
|
|
608
|
+
hiragana_kana
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
def hiragana_to_katakana(kana)
|
|
613
|
+
kana.chars.map { |c|
|
|
614
|
+
c.ord.between?(0x3041, 0x3096) ? (c.ord + 0x60).chr("UTF-8") : c
|
|
615
|
+
}.join
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
def hiragana_to_hankaku_katakana(kana)
|
|
619
|
+
kana.chars.map { |c|
|
|
620
|
+
case c.ord
|
|
621
|
+
when 0x3041 then "ァ"
|
|
622
|
+
when 0x3042 then "ア"
|
|
623
|
+
when 0x3043 then "ィ"
|
|
624
|
+
when 0x3044 then "イ"
|
|
625
|
+
when 0x3045 then "ゥ"
|
|
626
|
+
when 0x3046 then "ウ"
|
|
627
|
+
when 0x3047 then "ェ"
|
|
628
|
+
when 0x3048 then "エ"
|
|
629
|
+
when 0x3049 then "ォ"
|
|
630
|
+
when 0x304a then "オ"
|
|
631
|
+
when 0x304b then "カ"
|
|
632
|
+
when 0x304c then "ガ"
|
|
633
|
+
when 0x304d then "キ"
|
|
634
|
+
when 0x304e then "ギ"
|
|
635
|
+
when 0x304f then "ク"
|
|
636
|
+
when 0x3050 then "グ"
|
|
637
|
+
when 0x3051 then "ケ"
|
|
638
|
+
when 0x3052 then "ゲ"
|
|
639
|
+
when 0x3053 then "コ"
|
|
640
|
+
when 0x3054 then "ゴ"
|
|
641
|
+
when 0x3055 then "サ"
|
|
642
|
+
when 0x3056 then "ザ"
|
|
643
|
+
when 0x3057 then "シ"
|
|
644
|
+
when 0x3058 then "ジ"
|
|
645
|
+
when 0x3059 then "ス"
|
|
646
|
+
when 0x305a then "ズ"
|
|
647
|
+
when 0x305b then "セ"
|
|
648
|
+
when 0x305c then "ゼ"
|
|
649
|
+
when 0x305d then "ソ"
|
|
650
|
+
when 0x305e then "ゾ"
|
|
651
|
+
when 0x305f then "タ"
|
|
652
|
+
when 0x3060 then "ダ"
|
|
653
|
+
when 0x3061 then "チ"
|
|
654
|
+
when 0x3062 then "ヂ"
|
|
655
|
+
when 0x3063 then "ッ"
|
|
656
|
+
when 0x3064 then "ツ"
|
|
657
|
+
when 0x3065 then "ヅ"
|
|
658
|
+
when 0x3066 then "テ"
|
|
659
|
+
when 0x3067 then "デ"
|
|
660
|
+
when 0x3068 then "ト"
|
|
661
|
+
when 0x3069 then "ド"
|
|
662
|
+
when 0x306a then "ナ"
|
|
663
|
+
when 0x306b then "ニ"
|
|
664
|
+
when 0x306c then "ヌ"
|
|
665
|
+
when 0x306d then "ネ"
|
|
666
|
+
when 0x306e then "ノ"
|
|
667
|
+
when 0x306f then "ハ"
|
|
668
|
+
when 0x3070 then "バ"
|
|
669
|
+
when 0x3071 then "パ"
|
|
670
|
+
when 0x3072 then "ヒ"
|
|
671
|
+
when 0x3073 then "ビ"
|
|
672
|
+
when 0x3074 then "ピ"
|
|
673
|
+
when 0x3075 then "フ"
|
|
674
|
+
when 0x3076 then "ブ"
|
|
675
|
+
when 0x3077 then "プ"
|
|
676
|
+
when 0x3078 then "ヘ"
|
|
677
|
+
when 0x3079 then "ベ"
|
|
678
|
+
when 0x307a then "ペ"
|
|
679
|
+
when 0x307b then "ホ"
|
|
680
|
+
when 0x307c then "ボ"
|
|
681
|
+
when 0x307d then "ポ"
|
|
682
|
+
when 0x307e then "マ"
|
|
683
|
+
when 0x307f then "ミ"
|
|
684
|
+
when 0x3080 then "ム"
|
|
685
|
+
when 0x3081 then "メ"
|
|
686
|
+
when 0x3082 then "モ"
|
|
687
|
+
when 0x3083 then "ャ"
|
|
688
|
+
when 0x3084 then "ヤ"
|
|
689
|
+
when 0x3085 then "ュ"
|
|
690
|
+
when 0x3086 then "ユ"
|
|
691
|
+
when 0x3087 then "ョ"
|
|
692
|
+
when 0x3088 then "ヨ"
|
|
693
|
+
when 0x3089 then "ラ"
|
|
694
|
+
when 0x308a then "リ"
|
|
695
|
+
when 0x308b then "ル"
|
|
696
|
+
when 0x308c then "レ"
|
|
697
|
+
when 0x308d then "ロ"
|
|
698
|
+
when 0x308e then "ワ"
|
|
699
|
+
when 0x308f then "ワ"
|
|
700
|
+
when 0x3090 then "イ"
|
|
701
|
+
when 0x3091 then "エ"
|
|
702
|
+
when 0x3092 then "ヲ"
|
|
703
|
+
when 0x3093 then "ン"
|
|
704
|
+
else c
|
|
705
|
+
end
|
|
706
|
+
}.join
|
|
707
|
+
end
|
|
708
|
+
|
|
709
|
+
def current_table
|
|
710
|
+
case @mode
|
|
711
|
+
when :katakana then KATAKANA_TABLE
|
|
712
|
+
when :hankaku_katakana then HANKAKU_KATAKANA_TABLE
|
|
713
|
+
else HIRAGANA_TABLE
|
|
714
|
+
end
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
def current_prefixes
|
|
718
|
+
case @mode
|
|
719
|
+
when :hankaku_katakana then HANKAKU_KATAKANA_PREFIXES
|
|
720
|
+
else HIRAGANA_PREFIXES
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
# During converting phase, always use hiragana for yomi tracking
|
|
725
|
+
def hiragana_table_for_converting
|
|
726
|
+
HIRAGANA_TABLE
|
|
727
|
+
end
|
|
728
|
+
|
|
729
|
+
def hiragana_prefixes_for_converting
|
|
730
|
+
HIRAGANA_PREFIXES
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
def update_cursor_color
|
|
734
|
+
return unless STDOUT.tty?
|
|
735
|
+
colors = CONFIG[:skk_cursor_colors] || DEFAULT_CURSOR_COLORS
|
|
736
|
+
color = colors[@mode]
|
|
737
|
+
if color
|
|
738
|
+
STDOUT.write("\e]12;#{color}\a")
|
|
739
|
+
else
|
|
740
|
+
reset_cursor_color
|
|
741
|
+
end
|
|
742
|
+
STDOUT.flush
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
def reset_cursor_color
|
|
746
|
+
return unless STDOUT.tty?
|
|
747
|
+
STDOUT.write("\e]112\a")
|
|
748
|
+
STDOUT.flush
|
|
749
|
+
end
|
|
750
|
+
end
|
|
751
|
+
end
|