textbringer 22 → 23

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75bc23a6bf83f87be572ca81acfb29c2171d99d07d0fc48c5a50fac711b12ecb
4
- data.tar.gz: 5811dd657e36666831c26b9212494138c815629fe24997bb939c375c6d4a7944
3
+ metadata.gz: 0fe4d897c03de987989c81559c4c7d354f9d2afd9ec8cc7ff819c5da0a2c1bb4
4
+ data.tar.gz: c687cc3726ea8d9ccfd9efcb235590f9d4d447145cb9a0a6eaeb103b133f671f
5
5
  SHA512:
6
- metadata.gz: a3b91ec8b00442665b7060840b1e7a43be4193f887b0d9bc6925e1eb528b8b7e6dd173e2ba2c453b11ab8d56a248a4ef875ba760427a06d27de5dea5c58b19e8
7
- data.tar.gz: 0abd782f34b8ebc44391a86bc6074e8369773de886738681d025bfafe22f01d357889c54dd8fb8b20a1d321f4789dd590793d32c9d1ddb82d28228c29b8c4d33
6
+ metadata.gz: c1885974de9ae18238d0a49f436e3300d5971c06b7d3b16fb9c21cfc36c42b15e1beb22ee4608a80252100e202cef01d0943fb8d68a3db6ec9884773aff02093
7
+ data.tar.gz: 75bdc11e89da85249a54568e8d23ecd0979934143604918b292c01f4630a59386fd2965c7a260d9fc9b05c8a5f81695ecf23e9306fcb5df04535f97d65a927b7
data/CLAUDE.md CHANGED
@@ -35,12 +35,6 @@ txtb
35
35
  # Run all tests
36
36
  bundle exec rake test
37
37
 
38
- # Or simply (default task)
39
- bundle exec rake
40
-
41
- # On Ubuntu/Linux (for CI)
42
- xvfb-run bundle exec rake test
43
-
44
38
  # Run a single test file
45
39
  ruby -Ilib:test test/textbringer/test_buffer.rb
46
40
  ```
@@ -112,11 +112,13 @@ module Textbringer
112
112
  end
113
113
 
114
114
  def self.current=(buffer)
115
+ @@current&.input_method&.on_deactivate
115
116
  if buffer && buffer.name && @@table.key?(buffer.name)
116
117
  @@list.delete(buffer)
117
118
  @@list.unshift(buffer)
118
119
  end
119
120
  @@current = buffer
121
+ @@current&.input_method&.on_activate
120
122
  end
121
123
 
122
124
  def self.minibuffer
@@ -36,6 +36,12 @@ module Textbringer
36
36
  @enabled = false
37
37
  end
38
38
 
39
+ def on_activate
40
+ end
41
+
42
+ def on_deactivate
43
+ end
44
+
39
45
  def enabled?
40
46
  @enabled
41
47
  end
@@ -1,8 +1,12 @@
1
1
  require "open-uri"
2
2
  require "fileutils"
3
+ require "socket"
4
+ require "timeout"
3
5
 
4
6
  module Textbringer
5
7
  CONFIG[:skk_dictionary_path] = File.expand_path("~/.textbringer/skk/SKK-JISYO.L")
8
+ CONFIG[:skk_server_host] = nil # nil = disabled (default)
9
+ CONFIG[:skk_server_port] = 1178
6
10
 
7
11
  class SkkInputMethod < InputMethod
8
12
  HIRAGANA_TABLE = {
@@ -46,7 +50,11 @@ module Textbringer
46
50
  "xtu" => "っ", "xtsu" => "っ",
47
51
  "xya" => "ゃ", "xyu" => "ゅ", "xyo" => "ょ",
48
52
  "xa" => "ぁ", "xi" => "ぃ", "xu" => "ぅ", "xe" => "ぇ", "xo" => "ぉ",
49
- "," => "、", "." => "。",
53
+ "-" => "ー", "," => "、", "." => "。", "[" => "「", "]" => "」",
54
+ "z-" => "~", "z." => "…", "z/" => "・", "z," => "‥",
55
+ "z(" => "(", "z)" => ")", "z[" => "『", "z]" => "』",
56
+ "zh" => "←", "zj" => "↓", "zk" => "↑", "zl" => "→", "zL" => "⇒",
57
+ "z " => " ",
50
58
  }
51
59
 
52
60
  HIRAGANA_PREFIXES = HIRAGANA_TABLE.keys.flat_map { |s|
@@ -99,6 +107,14 @@ module Textbringer
99
107
  (s.size - 1).times.map { |i| s[0, i + 1] }
100
108
  }.uniq
101
109
 
110
+ STATUS_NAMES = {
111
+ hiragana: "かな",
112
+ katakana: "カナ",
113
+ hankaku_katakana: "半カナ",
114
+ zenkaku_ascii: "全英",
115
+ ascii: "SKK:"
116
+ }
117
+
102
118
  DEFAULT_CURSOR_COLORS = {
103
119
  hiragana: "pink",
104
120
  katakana: "green",
@@ -120,6 +136,7 @@ module Textbringer
120
136
  @marker_pos = nil
121
137
  @okuriiari = nil
122
138
  @okurinasi = nil
139
+ @skk_server_socket = nil
123
140
  end
124
141
 
125
142
  def toggle
@@ -128,22 +145,26 @@ module Textbringer
128
145
  update_cursor_color
129
146
  else
130
147
  reset_cursor_color
148
+ close_skk_server
131
149
  end
132
150
  end
133
151
 
134
152
  def disable
135
153
  super
136
154
  reset_cursor_color
155
+ close_skk_server
156
+ end
157
+
158
+ def on_activate
159
+ update_cursor_color if @enabled
160
+ end
161
+
162
+ def on_deactivate
163
+ reset_cursor_color if @enabled
137
164
  end
138
165
 
139
166
  def status
140
- case @phase
141
- when :converting then "▽"
142
- when :selecting then "▼"
143
- else
144
- { hiragana: "あ", katakana: "ア", hankaku_katakana: "ア",
145
- zenkaku_ascii: "A", ascii: "A" }[@mode]
146
- end
167
+ STATUS_NAMES[@mode]
147
168
  end
148
169
 
149
170
  def handle_event(event)
@@ -201,7 +222,7 @@ module Textbringer
201
222
  process_romaji(event)
202
223
  end
203
224
  when "l"
204
- if [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
225
+ if @roman_buffer != "z" && [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
205
226
  @roman_buffer = +""
206
227
  @mode = :ascii
207
228
  Window.redisplay
@@ -211,7 +232,7 @@ module Textbringer
211
232
  process_romaji(event)
212
233
  end
213
234
  when "L"
214
- if [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
235
+ if @roman_buffer != "z" && [:hiragana, :katakana, :hankaku_katakana].include?(@mode)
215
236
  @roman_buffer = +""
216
237
  @mode = :zenkaku_ascii
217
238
  Window.redisplay
@@ -389,8 +410,8 @@ module Textbringer
389
410
  if kana
390
411
  @roman_buffer = +""
391
412
  if @okuri_roman
392
- # Completing okurigana
393
- @okuri_kana = kana
413
+ # Completing okurigana (accumulate in case a vowel kana was already prepended)
414
+ @okuri_kana = (@okuri_kana || "") + kana
394
415
  with_target_buffer do |buffer|
395
416
  buffer.insert(kana)
396
417
  end
@@ -429,7 +450,14 @@ module Textbringer
429
450
  first_char = @roman_buffer[0]
430
451
  last_char = @roman_buffer[-1]
431
452
  @roman_buffer = +""
432
- append_yomi_kana(first_char)
453
+ if @okuri_roman && (kana = HIRAGANA_TABLE[first_char])
454
+ # Vowel starts okurigana: accumulate kana and continue buffering the rest
455
+ @okuri_kana = (@okuri_kana || "") + kana
456
+ with_target_buffer { |b| b.insert(kana) }
457
+ Window.redisplay
458
+ else
459
+ append_yomi_kana(first_char)
460
+ end
433
461
  process_converting_romaji(last_char)
434
462
  end
435
463
 
@@ -457,9 +485,20 @@ module Textbringer
457
485
  nil
458
486
  end
459
487
 
460
- def start_okurigana(consonant)
461
- @okuri_roman = consonant.dup
462
- @roman_buffer = consonant.dup
488
+ def start_okurigana(c)
489
+ @okuri_roman = c.dup
490
+ kana = HIRAGANA_TABLE[c]
491
+ if kana
492
+ # Vowel okurigana: insert the kana immediately and record it in @okuri_kana.
493
+ # (A vowel is never a prefix of a longer romaji sequence, so it's always complete.)
494
+ @okuri_kana = kana
495
+ @roman_buffer = +""
496
+ with_target_buffer { |b| b.insert(kana) }
497
+ Window.redisplay
498
+ start_selecting
499
+ else
500
+ @roman_buffer = c.dup
501
+ end
463
502
  end
464
503
 
465
504
  def cancel_converting
@@ -492,16 +531,19 @@ module Textbringer
492
531
  end
493
532
 
494
533
  def start_selecting
495
- ensure_dictionary_loaded
496
-
497
534
  lookup_key = if @okuri_roman
498
535
  @yomi + @okuri_roman
499
536
  else
500
537
  @yomi
501
538
  end
502
539
 
503
- dict = @okuri_roman ? @okuriiari : @okurinasi
504
- candidates = dict[lookup_key]
540
+ candidates = if CONFIG[:skk_server_host]
541
+ skk_server_lookup(lookup_key)
542
+ else
543
+ ensure_dictionary_loaded
544
+ dict = @okuri_roman ? @okuriiari : @okurinasi
545
+ dict[lookup_key]
546
+ end
505
547
 
506
548
  if candidates.nil? || candidates.empty?
507
549
  message("No conversion: #{@yomi}")
@@ -750,6 +792,49 @@ module Textbringer
750
792
  STDOUT.write("\e]112\a")
751
793
  STDOUT.flush
752
794
  end
795
+
796
+ SKK_SERVER_TIMEOUT = 3 # seconds
797
+
798
+ def close_skk_server
799
+ return unless @skk_server_socket
800
+ begin
801
+ @skk_server_socket.write("0\n")
802
+ rescue IOError, Errno::EPIPE
803
+ end
804
+ @skk_server_socket.close rescue nil
805
+ @skk_server_socket = nil
806
+ end
807
+
808
+ def skk_server_connect
809
+ return true if @skk_server_socket && !@skk_server_socket.closed?
810
+ host = CONFIG[:skk_server_host]
811
+ return false unless host
812
+ port = CONFIG[:skk_server_port] || 1178
813
+ Timeout.timeout(SKK_SERVER_TIMEOUT) do
814
+ @skk_server_socket = TCPSocket.new(host, port)
815
+ end
816
+ true
817
+ end
818
+
819
+ def skk_server_lookup(lookup_key)
820
+ skk_server_connect
821
+ begin
822
+ Timeout.timeout(SKK_SERVER_TIMEOUT) do
823
+ @skk_server_socket.write("1#{lookup_key} \n".encode("EUC-JP"))
824
+ response = @skk_server_socket.gets("\n")
825
+ return nil unless response
826
+ response = response.encode("UTF-8", "EUC-JP", invalid: :replace, undef: :replace).chomp
827
+ return nil unless response.start_with?("1/")
828
+ body = response[2..]
829
+ candidates = body.split("/").map { |c| c.split(";").first&.strip }.compact.reject(&:empty?)
830
+ candidates.empty? ? nil : candidates
831
+ end
832
+ rescue Timeout::Error, IOError, Errno::EPIPE, Errno::ECONNRESET
833
+ @skk_server_socket.close rescue nil
834
+ @skk_server_socket = nil
835
+ nil
836
+ end
837
+ end
753
838
  end
754
839
 
755
840
  SKK_DICTIONARY_URL = "https://github.com/skk-dev/dict/raw/090619ac57ef230a0506c191b569fc8c82b1025b/SKK-JISYO.L"
@@ -1,3 +1,3 @@
1
1
  module Textbringer
2
- VERSION = "22"
2
+ VERSION = "23"
3
3
  end
@@ -175,6 +175,7 @@ module Textbringer
175
175
  @@started = true
176
176
  yield
177
177
  ensure
178
+ Buffer.current&.input_method&.on_deactivate
178
179
  @@list.each do |win|
179
180
  win.close
180
181
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: textbringer
3
3
  version: !ruby/object:Gem::Version
4
- version: '22'
4
+ version: '23'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shugo Maeda