rufio 0.83.0 → 0.90.0
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/CHANGELOG.md +17 -0
- data/lib/rufio/multibyte_input_reader.rb +47 -0
- data/lib/rufio/terminal_ui.rb +40 -65
- data/lib/rufio/version.rb +1 -1
- data/lib/rufio.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f01cdc5788947872cf74f4a03e33aebe5d14d8077d141a5446c22a5ec5347567
|
|
4
|
+
data.tar.gz: 88ef6deb3513d4da16c74b1397bb3d0e23063fcb6cf94cf144694e7bd2754f2a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 03be7df8ea060bde82844aaab82fddc4d7d62dc5af7db7bb4d752d012a788486a54e53fcad7a9d671d62229da01b526b3472d1777fa67beb32e28496835fb68c
|
|
7
|
+
data.tar.gz: 87ad971cd279084cc2df4c955c93948444ac6736eb0d11fc35b1984a392aa4ec5946cc58363317317c8645abcf820397f365de2a00a5df741e6e9121362df5da
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,23 @@ All notable changes to rufio will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.90.0] - 2026-03-22
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **日本語入力(マルチバイト文字)対応**: コマンドモードおよびフィルターモードでマルチバイト文字(日本語等)の入力をサポート
|
|
12
|
+
- UTF-8マルチバイトシーケンスを正しく読み取り、コマンドバッファに追加
|
|
13
|
+
- `MultibyteInputReader` クラスを実装し、マルチバイト文字の読み取り・バリデーション・エラーハンドリングを担当
|
|
14
|
+
|
|
15
|
+
## [0.83.1] - 2026-03-20
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- **Windows console input detection rewritten using Win32 API**: Replaced the background thread + Queue workaround (introduced in v0.82.1 to handle ESC key detection on Windows) with `GetNumberOfConsoleInputEvents` via the Win32 API (`fiddle` stdlib)
|
|
19
|
+
- The previous approach had a race condition where the background `STDIN.read(1)` thread competed with `STDIN.getch` calls in dialogs, potentially dropping dialog input (including multi-byte/Japanese characters)
|
|
20
|
+
- Background thread, Queue, and `windows_read_next_byte` helper are removed
|
|
21
|
+
- `read_next_input_byte` is now a single unified implementation for both Windows and Unix (`read_nonblock`)
|
|
22
|
+
- Cygwin is excluded from the Windows path since it provides POSIX-compatible `IO.select`
|
|
23
|
+
- Falls back to `read_nonblock` if `Fiddle::DLError` occurs (no extra gem required — `fiddle` is a Ruby stdlib)
|
|
24
|
+
|
|
8
25
|
## [0.83.0] - 2026-03-14
|
|
9
26
|
|
|
10
27
|
### Added
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rufio
|
|
4
|
+
# ターミナルからのマルチバイト入力(UTF-8)を読み込むクラス。
|
|
5
|
+
# read_nonblock(1) は1バイトずつしか読まないため、日本語などのマルチバイト文字が
|
|
6
|
+
# 複数のイベントに分割される問題を解決する。
|
|
7
|
+
class MultibyteInputReader
|
|
8
|
+
def initialize(io = STDIN)
|
|
9
|
+
@io = io
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# 1文字(マルチバイト対応)を読み込む。
|
|
13
|
+
# 読み込めない場合は nil を返す。
|
|
14
|
+
def read_char
|
|
15
|
+
byte = @io.read_nonblock(1)
|
|
16
|
+
return nil if byte.nil?
|
|
17
|
+
|
|
18
|
+
remaining = utf8_remaining_bytes(byte.ord)
|
|
19
|
+
return byte.force_encoding(Encoding::UTF_8) if remaining == 0
|
|
20
|
+
|
|
21
|
+
buf = byte.b
|
|
22
|
+
remaining.times do
|
|
23
|
+
next_byte = @io.read_nonblock(1)
|
|
24
|
+
return nil if next_byte.nil?
|
|
25
|
+
|
|
26
|
+
buf << next_byte.b
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
result = buf.force_encoding(Encoding::UTF_8)
|
|
30
|
+
result.valid_encoding? ? result : nil
|
|
31
|
+
rescue IO::WaitReadable, IO::EAGAINWaitReadable, EOFError
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def utf8_remaining_bytes(byte_val)
|
|
38
|
+
case byte_val
|
|
39
|
+
when 0x00..0x7F then 0 # ASCII(ESC 0x1B を含む)
|
|
40
|
+
when 0xC0..0xDF then 1 # 2バイト文字
|
|
41
|
+
when 0xE0..0xEF then 2 # 3バイト文字(日本語など)
|
|
42
|
+
when 0xF0..0xF7 then 3 # 4バイト文字(絵文字など)
|
|
43
|
+
else 0
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/rufio/terminal_ui.rb
CHANGED
|
@@ -47,6 +47,7 @@ module Rufio
|
|
|
47
47
|
end
|
|
48
48
|
@running = false
|
|
49
49
|
@test_mode = test_mode
|
|
50
|
+
@multibyte_reader = MultibyteInputReader.new(STDIN)
|
|
50
51
|
@command_mode_active = false
|
|
51
52
|
@command_input = ""
|
|
52
53
|
@command_mode = CommandMode.new
|
|
@@ -189,23 +190,6 @@ module Rufio
|
|
|
189
190
|
print "\e[?1003h\e[?1006h"
|
|
190
191
|
STDOUT.flush
|
|
191
192
|
|
|
192
|
-
# Windows: IO.select + read_nonblockはコンソールハンドルのESCキーを
|
|
193
|
-
# 検出できない場合がある。バックグラウンドスレッドでSTDINを読み取り
|
|
194
|
-
# Queueに格納することで信頼性のある入力検出を実現する。
|
|
195
|
-
if windows?
|
|
196
|
-
@windows_input_queue = Queue.new
|
|
197
|
-
@windows_input_thread = Thread.new do
|
|
198
|
-
loop do
|
|
199
|
-
begin
|
|
200
|
-
byte = STDIN.read(1)
|
|
201
|
-
@windows_input_queue << byte if byte
|
|
202
|
-
rescue
|
|
203
|
-
break
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
|
|
209
193
|
# re-acquire terminal size (just in case)
|
|
210
194
|
update_screen_size
|
|
211
195
|
end
|
|
@@ -217,31 +201,37 @@ module Rufio
|
|
|
217
201
|
@screen_width, @screen_height = console.winsize.reverse
|
|
218
202
|
end
|
|
219
203
|
|
|
204
|
+
# Cygwinは POSIX互換のIO.selectが使えるため除外
|
|
220
205
|
def windows?
|
|
221
|
-
RUBY_PLATFORM =~ /mswin|mingw
|
|
206
|
+
RUBY_PLATFORM =~ /mswin|mingw/ ? true : false
|
|
222
207
|
end
|
|
223
208
|
|
|
224
|
-
# Windows:
|
|
225
|
-
#
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
209
|
+
# Windows: GetNumberOfConsoleInputEvents でコンソール入力バッファを確認する。
|
|
210
|
+
# IO.select はWindowsコンソールハンドルでESCキーを取りこぼすため使用しない。
|
|
211
|
+
# fiddle はRuby標準ライブラリなので追加gemは不要。
|
|
212
|
+
def windows_console_input_available?
|
|
213
|
+
require 'fiddle'
|
|
214
|
+
@win32_kernel32 ||= Fiddle.dlopen('kernel32')
|
|
215
|
+
@win32_get_std_handle ||= Fiddle::Function.new(
|
|
216
|
+
@win32_kernel32['GetStdHandle'],
|
|
217
|
+
[Fiddle::TYPE_INT], Fiddle::TYPE_VOIDP
|
|
218
|
+
)
|
|
219
|
+
@win32_get_num_events ||= Fiddle::Function.new(
|
|
220
|
+
@win32_kernel32['GetNumberOfConsoleInputEvents'],
|
|
221
|
+
[Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT
|
|
222
|
+
)
|
|
223
|
+
handle = @win32_get_std_handle.call(0xFFFFFFF6) # STD_INPUT_HANDLE = (DWORD)(-10)
|
|
224
|
+
count_ptr = Fiddle::Pointer.malloc(4)
|
|
225
|
+
@win32_get_num_events.call(handle, count_ptr)
|
|
226
|
+
count_ptr[0, 4].unpack1('L') > 0
|
|
227
|
+
rescue Fiddle::DLError
|
|
228
|
+
# fiddle が使えない場合は常に入力ありとみなし read_nonblock に任せる
|
|
229
|
+
true
|
|
236
230
|
end
|
|
237
231
|
|
|
238
232
|
# エスケープシーケンスの後続バイトを読み取る(Windows/Unix共通ヘルパー)
|
|
239
233
|
def read_next_input_byte
|
|
240
|
-
|
|
241
|
-
windows_read_next_byte
|
|
242
|
-
else
|
|
243
|
-
STDIN.read_nonblock(1) rescue nil
|
|
244
|
-
end
|
|
234
|
+
STDIN.read_nonblock(1) rescue nil
|
|
245
235
|
end
|
|
246
236
|
|
|
247
237
|
def cleanup_terminal
|
|
@@ -250,13 +240,6 @@ module Rufio
|
|
|
250
240
|
STDIN.cooked!
|
|
251
241
|
end
|
|
252
242
|
|
|
253
|
-
# Windowsバックグラウンド入力スレッドを停止
|
|
254
|
-
if @windows_input_thread
|
|
255
|
-
@windows_input_thread.kill rescue nil
|
|
256
|
-
@windows_input_thread = nil
|
|
257
|
-
@windows_input_queue = nil
|
|
258
|
-
end
|
|
259
|
-
|
|
260
243
|
# マウスレポートを無効化
|
|
261
244
|
print "\e[?1003l\e[?1006l"
|
|
262
245
|
STDOUT.flush
|
|
@@ -442,31 +425,23 @@ module Rufio
|
|
|
442
425
|
private
|
|
443
426
|
|
|
444
427
|
# ノンブロッキング入力処理(ゲームループ用)
|
|
445
|
-
# Windows:
|
|
428
|
+
# Windows: GetNumberOfConsoleInputEvents で入力確認後 read_nonblock
|
|
429
|
+
# Unix: IO.select(timeout=0) で入力確認後 read_nonblock
|
|
446
430
|
def handle_input_nonblocking
|
|
447
431
|
# 入力バイトを1つ読み取る
|
|
448
|
-
if
|
|
449
|
-
# Windows:
|
|
450
|
-
|
|
451
|
-
input = @windows_input_queue.pop(true)
|
|
452
|
-
rescue ThreadError
|
|
453
|
-
return false
|
|
454
|
-
end
|
|
432
|
+
if windows?
|
|
433
|
+
# Windows: IO.selectはESCキーを取りこぼすため Win32 API で入力確認
|
|
434
|
+
return false unless windows_console_input_available?
|
|
455
435
|
else
|
|
456
436
|
# Unix: 0msタイムアウトで即座にチェック(30FPS = 33.33ms/frame)
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
return false
|
|
466
|
-
rescue Errno::ENOTTY, Errno::ENODEV
|
|
467
|
-
# ターミナルでない環境
|
|
468
|
-
return false
|
|
469
|
-
end
|
|
437
|
+
return false unless IO.select([STDIN], nil, nil, 0)
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
begin
|
|
441
|
+
input = @multibyte_reader.read_char
|
|
442
|
+
return false if input.nil?
|
|
443
|
+
rescue Errno::ENOTTY, Errno::ENODEV
|
|
444
|
+
return false
|
|
470
445
|
end
|
|
471
446
|
|
|
472
447
|
# コマンドモードがアクティブな場合は、エスケープシーケンス処理をスキップ
|
|
@@ -802,8 +777,8 @@ module Rufio
|
|
|
802
777
|
# Backspace
|
|
803
778
|
@command_input.chop! unless @command_input.empty?
|
|
804
779
|
else
|
|
805
|
-
#
|
|
806
|
-
@command_input += input
|
|
780
|
+
# 通常の文字を追加(マルチバイト文字含む)
|
|
781
|
+
@command_input += input unless input.nil? || input.empty?
|
|
807
782
|
end
|
|
808
783
|
end
|
|
809
784
|
|
data/lib/rufio/version.rb
CHANGED
data/lib/rufio.rb
CHANGED
|
@@ -47,6 +47,7 @@ require_relative 'rufio/native_scanner_zig'
|
|
|
47
47
|
require_relative 'rufio/async_scanner_promise'
|
|
48
48
|
require_relative 'rufio/async_scanner_fiber'
|
|
49
49
|
require_relative 'rufio/parallel_scanner'
|
|
50
|
+
require_relative 'rufio/multibyte_input_reader'
|
|
50
51
|
require_relative 'rufio/screen'
|
|
51
52
|
require_relative 'rufio/renderer'
|
|
52
53
|
require_relative 'rufio/tab_mode_manager'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rufio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.90.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- masisz
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: io-console
|
|
@@ -182,6 +182,7 @@ files:
|
|
|
182
182
|
- lib/rufio/keybind_handler.rb
|
|
183
183
|
- lib/rufio/local_script_scanner.rb
|
|
184
184
|
- lib/rufio/logger.rb
|
|
185
|
+
- lib/rufio/multibyte_input_reader.rb
|
|
185
186
|
- lib/rufio/native/rufio_zig.bundle
|
|
186
187
|
- lib/rufio/native_scanner.rb
|
|
187
188
|
- lib/rufio/native_scanner_zig.rb
|