rufio 0.71.0 → 0.81.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 +45 -0
- data/README.md +30 -11
- data/README_ja.md +32 -10
- data/docs/CHANGELOG_v0.80.0.md +189 -0
- data/lib/rufio/ansi_line_parser.rb +103 -0
- data/lib/rufio/config.rb +2 -0
- data/lib/rufio/file_preview.rb +26 -1
- data/lib/rufio/health_checker.rb +22 -0
- data/lib/rufio/keybind_handler.rb +15 -0
- data/lib/rufio/renderer.rb +11 -4
- data/lib/rufio/screen.rb +3 -2
- data/lib/rufio/syntax_highlighter.rb +111 -0
- data/lib/rufio/tab_mode_manager.rb +12 -0
- data/lib/rufio/terminal_ui.rb +306 -96
- data/lib/rufio/version.rb +1 -1
- data/lib/rufio/zoxide_integration.rb +11 -5
- data/lib/rufio.rb +2 -0
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 533e0a5b32ced89d9d65bfd1abaafee73bada752cc24848538abc05e878a3f41
|
|
4
|
+
data.tar.gz: f614bb8ee10f320c3b8e3387f5374b5c1bc2c2b9299112f0640061dffcb47b05
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a0f9f950cfa19fc467fe220614f298ac35473aa8e9112e7776b683b9414e39436f4cce7bf5f5d3cf3a481dbf48545e2e971a9773e3e68bc11bfae53c6b63fc13
|
|
7
|
+
data.tar.gz: cff712ea8904a749d0d3f646bc0b9a016c085a043bf08bc6cf304d1f1bbbc5a4e94daf7e05464334f6da56c0bdcf32f6411e8d0787a7763b303428bde0993f65
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Added
|
|
11
|
+
- **Bookmark Jump Highlight**: When cycling bookmarks with `Tab`, the target bookmark in the top bar is highlighted in cyan for 500ms, then automatically fades back to gray
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **UI Layout**: Merged mode tabs and title bar into a single combined bottom row
|
|
15
|
+
- **Top bar (y=0)**: Bookmark list `0.start │ 1.name │ 2.name ...`, job status, FPS (test mode)
|
|
16
|
+
- **Bottom bar (y=h-1)**: Mode tabs + current path + version — all in one line
|
|
17
|
+
- Powerline-style separators: active tab gets a `\uE0B0` cyan exit arrow; version section uses `\uE0B2` cyan entry arrow with cyan background and black bold text
|
|
18
|
+
- **`Tab` key**: Changed from mode cycling to **bookmark cycling** (Files mode only)
|
|
19
|
+
- In Files mode: jump to next registered bookmark in sequence (wraps to first)
|
|
20
|
+
- In other modes (Logs / Jobs / Help): no action
|
|
21
|
+
- Mode switching is done via `J` / `L` / `?` keys and `Shift+Tab`
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- **zoxide 2-digit input**: Fixed a bug where pressing a single digit in the zoxide history dialog immediately navigated, making it impossible to enter 2-digit numbers (e.g., `12`)
|
|
25
|
+
- **Jobs mode tab highlight**: Fixed active tab not highlighting when entering Jobs mode from Logs or Help mode
|
|
26
|
+
- **Jobs mode navigation**: Fixed inability to switch away from Jobs mode using `L`, `?` keys
|
|
27
|
+
|
|
28
|
+
## [0.80.0] - 2026-02-21
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **Syntax Highlighting**: File preview now supports syntax highlighting via `bat`
|
|
32
|
+
- 19 languages supported: Ruby, Python, JS, TS, Go, Rust, Shell, C, C++, Java, SQL, TOML, YAML, JSON, HTML, CSS, Markdown, Dockerfile, Makefile
|
|
33
|
+
- Graceful fallback to plain text when `bat` is not installed
|
|
34
|
+
- mtime-based cache for instant re-display of previously viewed files
|
|
35
|
+
- Health check support (`rufio -c`) now reports `bat` availability
|
|
36
|
+
- **New classes**: `AnsiLineParser`, `SyntaxHighlighter`
|
|
37
|
+
- **New tests**: `test_ansi_line_parser.rb` (25 tests), `test_syntax_highlighter.rb` (+7 async tests)
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
- **Cursor flickering** when navigating source directories: Changed `Renderer#render` from per-line `print` (immediate flush) to a single buffered `write` call — terminal updates are now atomic
|
|
41
|
+
- **Navigation lag** when moving between source files: `bat` is now executed asynchronously in a background thread; the current frame immediately falls back to plain text, then re-renders with highlighting on completion
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- **`Renderer#render`**: Replaced row-by-row `print` with single `write(buf)` + `flush` for atomic output
|
|
45
|
+
- **`SyntaxHighlighter`**: Added `highlight_async` (Thread + Mutex + pending guard) alongside existing `highlight`
|
|
46
|
+
- **`TerminalUI`**: Preview caching extended with `highlighted` / `highlighted_wrapped` keys; `@highlight_updated` flag added for async re-render notification
|
|
47
|
+
- **`FilePreview#determine_file_type`**: Added Go, Rust, Shell, TOML, SQL, C, C++, Java, Dockerfile, Makefile language detection
|
|
48
|
+
|
|
49
|
+
### Technical Details
|
|
50
|
+
- **New files**: `lib/rufio/ansi_line_parser.rb`, `lib/rufio/syntax_highlighter.rb`
|
|
51
|
+
- **Modified files**: `lib/rufio/renderer.rb`, `lib/rufio/terminal_ui.rb`, `lib/rufio/file_preview.rb`, `lib/rufio/health_checker.rb`, `lib/rufio/config.rb`, `lib/rufio.rb`
|
|
52
|
+
- **For details**: [CHANGELOG_v0.80.0.md](./docs/CHANGELOG_v0.80.0.md)
|
|
53
|
+
|
|
10
54
|
## [0.71.0] - 2026-02-16
|
|
11
55
|
|
|
12
56
|
### Added
|
|
@@ -611,6 +655,7 @@ For detailed information, see [CHANGELOG_v0.4.0.md](./docs/CHANGELOG_v0.4.0.md)
|
|
|
611
655
|
|
|
612
656
|
### Detailed Release Notes
|
|
613
657
|
|
|
658
|
+
- [v0.80.0](./docs/CHANGELOG_v0.80.0.md) - Syntax Highlighting & Rendering Fixes
|
|
614
659
|
- [v0.31.0](./docs/CHANGELOG_v0.31.0.md) - Experimental Native Scanner Implementation
|
|
615
660
|
- [v0.30.0](./docs/CHANGELOG_v0.30.0.md) - Help System Overhaul
|
|
616
661
|
- [v0.21.0](./docs/CHANGELOG_v0.21.0.md) - Copy Feature & Code Refactoring
|
data/README.md
CHANGED
|
@@ -40,7 +40,7 @@ rufio is not just a file manager. It's a **tool runtime execution environment**.
|
|
|
40
40
|
### As a File Manager
|
|
41
41
|
|
|
42
42
|
- **Vim-like Key Bindings**: Intuitive navigation
|
|
43
|
-
- **Real-time Preview**: Instantly display file contents
|
|
43
|
+
- **Real-time Preview**: Instantly display file contents with syntax highlighting (via `bat`)
|
|
44
44
|
- **Fast Search**: Integration with fzf/rga
|
|
45
45
|
- **Bookmarks**: Quick access to frequently used directories
|
|
46
46
|
- **zoxide Integration**: Smart directory history
|
|
@@ -123,6 +123,7 @@ rufio /path/to # Launch in specified directory
|
|
|
123
123
|
| `B` | Bookmark menu |
|
|
124
124
|
| `0` | Return to startup directory |
|
|
125
125
|
| `1-9` | Jump to bookmark |
|
|
126
|
+
| `Tab` | Cycle to next bookmark (Files mode only) |
|
|
126
127
|
| `z` | zoxide history |
|
|
127
128
|
|
|
128
129
|
### Tool Runtime
|
|
@@ -133,7 +134,6 @@ rufio /path/to # Launch in specified directory
|
|
|
133
134
|
| `J` | Job mode |
|
|
134
135
|
| `L` | View execution logs |
|
|
135
136
|
| `?` | Help |
|
|
136
|
-
| `Tab` | Switch mode (Files → Logs → Jobs → Help) |
|
|
137
137
|
| `Shift+Tab` | Switch mode (reverse) |
|
|
138
138
|
|
|
139
139
|
## Command Mode
|
|
@@ -290,22 +290,41 @@ script_paths:
|
|
|
290
290
|
|
|
291
291
|
## External Tool Integration
|
|
292
292
|
|
|
293
|
-
rufio integrates with the following external tools to extend functionality
|
|
293
|
+
rufio integrates with the following external tools to extend functionality.
|
|
294
|
+
All tools are **optional** — rufio works without them, falling back to built-in behavior.
|
|
294
295
|
|
|
295
|
-
| Tool | Purpose | Key |
|
|
296
|
-
|
|
297
|
-
| fzf | File name search | `s` |
|
|
298
|
-
| rga | File content search | `F` |
|
|
299
|
-
| zoxide | Directory history | `z` |
|
|
296
|
+
| Tool | Purpose | Key | Required? |
|
|
297
|
+
|------|---------|-----|-----------|
|
|
298
|
+
| fzf | File name search | `s` | Optional |
|
|
299
|
+
| rga | File content search | `F` | Optional |
|
|
300
|
+
| zoxide | Directory history | `z` | Optional |
|
|
301
|
+
| bat | Syntax highlighting in preview | — | Optional |
|
|
300
302
|
|
|
301
|
-
###
|
|
303
|
+
### bat — Syntax Highlighting
|
|
304
|
+
|
|
305
|
+
When `bat` is installed, code files in the preview pane are displayed with full syntax
|
|
306
|
+
highlighting (Ruby, Python, Go, Rust, TypeScript, and 15+ more languages).
|
|
307
|
+
|
|
308
|
+
Highlighting is loaded asynchronously — navigation stays fast even on large source trees.
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
# macOS
|
|
312
|
+
brew install bat
|
|
313
|
+
|
|
314
|
+
# Ubuntu/Debian
|
|
315
|
+
apt install bat
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Run `rufio -c` to verify bat is detected correctly.
|
|
319
|
+
|
|
320
|
+
### Installation (all tools)
|
|
302
321
|
|
|
303
322
|
```bash
|
|
304
323
|
# macOS
|
|
305
|
-
brew install fzf rga zoxide
|
|
324
|
+
brew install fzf bat rga zoxide
|
|
306
325
|
|
|
307
326
|
# Ubuntu/Debian
|
|
308
|
-
apt install fzf zoxide
|
|
327
|
+
apt install fzf bat zoxide
|
|
309
328
|
# rga requires separate installation: https://github.com/phiresky/ripgrep-all
|
|
310
329
|
```
|
|
311
330
|
|
data/README_ja.md
CHANGED
|
@@ -42,7 +42,7 @@ rufioは単なるファイルマネージャーではありません。**ツー
|
|
|
42
42
|
### ファイルマネージャーとして
|
|
43
43
|
|
|
44
44
|
- **Vimライクなキーバインド**: 直感的なナビゲーション
|
|
45
|
-
- **リアルタイムプレビュー**:
|
|
45
|
+
- **リアルタイムプレビュー**: ファイル内容を即座に表示(`bat` によるシンタックスハイライト対応)
|
|
46
46
|
- **高速検索**: fzf/rgaとの連携
|
|
47
47
|
- **ブックマーク**: よく使うディレクトリに素早くアクセス
|
|
48
48
|
- **zoxide連携**: スマートなディレクトリ履歴
|
|
@@ -125,6 +125,7 @@ rufio /path/to # 指定したディレクトリで起動
|
|
|
125
125
|
| `B` | ブックマークメニュー |
|
|
126
126
|
| `0` | 起動ディレクトリに戻る |
|
|
127
127
|
| `1-9` | ブックマークにジャンプ |
|
|
128
|
+
| `Tab` | 次のブックマークへ循環移動(Filesモード限定) |
|
|
128
129
|
| `z` | zoxide履歴 |
|
|
129
130
|
|
|
130
131
|
### ツールランタイム
|
|
@@ -135,6 +136,7 @@ rufio /path/to # 指定したディレクトリで起動
|
|
|
135
136
|
| `J` | ジョブモード |
|
|
136
137
|
| `L` | 実行ログ表示 |
|
|
137
138
|
| `?` | ヘルプ |
|
|
139
|
+
| `Shift+Tab` | モード切り替え(逆順) |
|
|
138
140
|
|
|
139
141
|
## コマンドモード
|
|
140
142
|
|
|
@@ -255,22 +257,42 @@ SCRIPT_PATHS = [
|
|
|
255
257
|
|
|
256
258
|
## 外部ツール連携
|
|
257
259
|
|
|
258
|
-
rufio
|
|
260
|
+
rufioは以下の外部ツールと連携して機能を拡張します。
|
|
261
|
+
すべて**オプション**です。インストールなしでも rufio は正常動作します。
|
|
259
262
|
|
|
260
|
-
| ツール | 用途 | キー |
|
|
261
|
-
|
|
262
|
-
| fzf | ファイル名検索 | `s` |
|
|
263
|
-
| rga | ファイル内容検索 | `F` |
|
|
264
|
-
| zoxide | ディレクトリ履歴 | `z` |
|
|
263
|
+
| ツール | 用途 | キー | 必須 |
|
|
264
|
+
|--------|------|------|------|
|
|
265
|
+
| fzf | ファイル名検索 | `s` | オプション |
|
|
266
|
+
| rga | ファイル内容検索 | `F` | オプション |
|
|
267
|
+
| zoxide | ディレクトリ履歴 | `z` | オプション |
|
|
268
|
+
| bat | プレビューのシンタックスハイライト | — | オプション |
|
|
265
269
|
|
|
266
|
-
###
|
|
270
|
+
### bat — シンタックスハイライト
|
|
271
|
+
|
|
272
|
+
`bat` をインストールすると、プレビューペインでコードファイルを開いた際に
|
|
273
|
+
シンタックスハイライトが表示されます(Ruby、Python、Go、Rust、TypeScript など15言語以上対応)。
|
|
274
|
+
|
|
275
|
+
ハイライトはバックグラウンドで非同期に読み込まれるため、大きなソースツリーでも
|
|
276
|
+
カーソル移動が重くなりません。
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# macOS
|
|
280
|
+
brew install bat
|
|
281
|
+
|
|
282
|
+
# Ubuntu/Debian
|
|
283
|
+
apt install bat
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
`rufio -c` を実行すると bat が正しく認識されているか確認できます。
|
|
287
|
+
|
|
288
|
+
### インストール(全ツール)
|
|
267
289
|
|
|
268
290
|
```bash
|
|
269
291
|
# macOS
|
|
270
|
-
brew install fzf rga zoxide
|
|
292
|
+
brew install fzf bat rga zoxide
|
|
271
293
|
|
|
272
294
|
# Ubuntu/Debian
|
|
273
|
-
apt install fzf zoxide
|
|
295
|
+
apt install fzf bat zoxide
|
|
274
296
|
# rgaは別途インストール: https://github.com/phiresky/ripgrep-all
|
|
275
297
|
```
|
|
276
298
|
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# CHANGELOG v0.80.0
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Adds syntax highlighting to the file preview pane. When `bat` is installed, code files
|
|
6
|
+
are displayed with full ANSI color highlighting. Environments without `bat` fall back
|
|
7
|
+
silently to plain text display.
|
|
8
|
+
|
|
9
|
+
Also fixes **cursor flickering** and **navigation lag** that occurred when browsing
|
|
10
|
+
source code directories with highlighting active.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## New Features
|
|
15
|
+
|
|
16
|
+
### Syntax Highlighting (via `bat`)
|
|
17
|
+
|
|
18
|
+
The preview pane now renders code files with syntax highlighting using `bat`'s ANSI
|
|
19
|
+
color output.
|
|
20
|
+
|
|
21
|
+
**Supported languages:**
|
|
22
|
+
|
|
23
|
+
| Language | Extensions |
|
|
24
|
+
|----------|------------|
|
|
25
|
+
| Ruby | `.rb` |
|
|
26
|
+
| Python | `.py` |
|
|
27
|
+
| JavaScript | `.js`, `.mjs` |
|
|
28
|
+
| TypeScript | `.ts` |
|
|
29
|
+
| HTML | `.html`, `.htm` |
|
|
30
|
+
| CSS | `.css` |
|
|
31
|
+
| JSON | `.json` |
|
|
32
|
+
| YAML | `.yml`, `.yaml` |
|
|
33
|
+
| Markdown | `.md`, `.markdown` |
|
|
34
|
+
| Go | `.go` |
|
|
35
|
+
| Rust | `.rs` |
|
|
36
|
+
| Shell | `.sh`, `.bash`, `.zsh` |
|
|
37
|
+
| TOML | `.toml` |
|
|
38
|
+
| SQL | `.sql` |
|
|
39
|
+
| C | `.c`, `.h` |
|
|
40
|
+
| C++ | `.cpp`, `.cc`, `.cxx`, `.hpp` |
|
|
41
|
+
| Java | `.java` |
|
|
42
|
+
| Dockerfile | `Dockerfile`, `Dockerfile.*` |
|
|
43
|
+
| Makefile | `Makefile`, `GNUmakefile` |
|
|
44
|
+
|
|
45
|
+
**Behavior:**
|
|
46
|
+
- Graceful degradation — plain text display when `bat` is not installed
|
|
47
|
+
- Non-UTF-8 files (e.g. Shift_JIS) skip highlighting automatically
|
|
48
|
+
- mtime-based cache: second visit to the same file is instant (0 ms)
|
|
49
|
+
- Run `rufio -c` to verify `bat` is detected by the health checker
|
|
50
|
+
|
|
51
|
+
**Installation:**
|
|
52
|
+
```bash
|
|
53
|
+
# macOS
|
|
54
|
+
brew install bat
|
|
55
|
+
|
|
56
|
+
# Ubuntu/Debian
|
|
57
|
+
apt install bat
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Bug Fixes
|
|
63
|
+
|
|
64
|
+
### Fix 1: Cursor Flickering (Renderer Atomic Output)
|
|
65
|
+
|
|
66
|
+
**Symptom:** The preview pane flickered briefly when moving the cursor in source
|
|
67
|
+
code directories.
|
|
68
|
+
|
|
69
|
+
**Root cause:** `Renderer#render` called `print` once per dirty row. With
|
|
70
|
+
`STDOUT sync=true`, each `print` flushes immediately, so intermediate states
|
|
71
|
+
(highlighted color removed, new color not yet drawn) were visible in the terminal.
|
|
72
|
+
|
|
73
|
+
**Fix:** All dirty row output is now accumulated into a single string buffer, then
|
|
74
|
+
written with one `write` + `flush` call — guaranteeing an atomic terminal update.
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
Before: print row0 → flush → print row1 → flush → ... (intermediate states visible)
|
|
78
|
+
After: buf = row0 + row1 + ... → write(buf) + flush (single atomic update)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Fix 2: Navigation Lag (Async bat Execution)
|
|
82
|
+
|
|
83
|
+
**Symptom:** Moving the cursor to a new file in a source directory caused 10–30 ms
|
|
84
|
+
of lag, making navigation feel sluggish.
|
|
85
|
+
|
|
86
|
+
**Root cause:** `SyntaxHighlighter#highlight` called `IO.popen(['bat', ...])` synchronously
|
|
87
|
+
inside the main loop. The bat process startup cost blocked the frame on every new file visit.
|
|
88
|
+
|
|
89
|
+
**Fix:** Added `highlight_async` which runs `bat` in a background Thread.
|
|
90
|
+
|
|
91
|
+
- The frame immediately after moving to a new file displays plain text (instant fallback)
|
|
92
|
+
- When the background thread completes, it sets `@highlight_updated = true`
|
|
93
|
+
- The main loop detects the flag and triggers a re-render with highlighting
|
|
94
|
+
- A pending guard prevents duplicate threads for the same file path
|
|
95
|
+
- A `Mutex` protects all cache reads/writes for thread safety
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Technical Details
|
|
100
|
+
|
|
101
|
+
### New Files
|
|
102
|
+
|
|
103
|
+
| File | Description |
|
|
104
|
+
|------|-------------|
|
|
105
|
+
| `lib/rufio/ansi_line_parser.rb` | Parses ANSI SGR escape sequences into token arrays. Full-width character-aware wrapping |
|
|
106
|
+
| `lib/rufio/syntax_highlighter.rb` | Wraps the `bat` command. mtime cache, async execution, Mutex protection |
|
|
107
|
+
| `test/test_ansi_line_parser.rb` | Unit tests for AnsiLineParser (25 tests) |
|
|
108
|
+
| `test/test_syntax_highlighter.rb` | Unit tests for SyntaxHighlighter (16 tests) |
|
|
109
|
+
|
|
110
|
+
### Modified Files
|
|
111
|
+
|
|
112
|
+
| File | Change |
|
|
113
|
+
|------|--------|
|
|
114
|
+
| `lib/rufio/renderer.rb` | Per-line `print` → single `write(buf)` + `flush` |
|
|
115
|
+
| `lib/rufio/terminal_ui.rb` | Added `@syntax_highlighter`, highlighting branch in `draw_file_preview_to_buffer`, `@highlight_updated` check in main loop |
|
|
116
|
+
| `lib/rufio/file_preview.rb` | Extended `determine_file_type` with Go, Rust, Shell, TOML, SQL, C, C++, Java, Dockerfile, Makefile |
|
|
117
|
+
| `lib/rufio/health_checker.rb` | Added `check_bat` method |
|
|
118
|
+
| `lib/rufio/config.rb` | Added `health.bat` message key (EN + JA) |
|
|
119
|
+
| `lib/rufio.rb` | Added `require` for `ansi_line_parser` and `syntax_highlighter` |
|
|
120
|
+
| `test/test_renderer.rb` | Added `OutputSpy` helper, 2 new atomic output tests |
|
|
121
|
+
|
|
122
|
+
### Architecture
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
bat (external process)
|
|
126
|
+
↓ IO.popen — background Thread
|
|
127
|
+
SyntaxHighlighter#highlight_async
|
|
128
|
+
↓ callback on completion
|
|
129
|
+
@preview_cache[path][:highlighted] = lines # store ANSI line array
|
|
130
|
+
@highlight_updated = true # notify main loop
|
|
131
|
+
↓ next frame
|
|
132
|
+
AnsiLineParser.parse(line) # ANSI → token array
|
|
133
|
+
AnsiLineParser.wrap(tokens, width) # full-width-aware wrapping
|
|
134
|
+
draw_highlighted_line_to_buffer(screen, ...) # per-char fg: color drawing
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Preview Cache Structure
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
@preview_cache[file_path] = {
|
|
141
|
+
content: Array<String>, # plain text lines
|
|
142
|
+
preview_data: Hash, # type, encoding, etc.
|
|
143
|
+
highlighted: nil | false | Array<String>,
|
|
144
|
+
# nil = not yet requested
|
|
145
|
+
# false = requested, awaiting background result
|
|
146
|
+
# Array = ANSI lines ready to render
|
|
147
|
+
wrapped: Hash, # width => wrapped plain lines
|
|
148
|
+
highlighted_wrapped: Hash # width => wrapped token arrays
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Tests
|
|
155
|
+
|
|
156
|
+
All tests pass (pre-existing TestUISnapshot / TestBufferParity snapshot mismatches excluded):
|
|
157
|
+
|
|
158
|
+
| Test file | Tests | Status |
|
|
159
|
+
|-----------|-------|--------|
|
|
160
|
+
| `test_ansi_line_parser.rb` | 25 | new |
|
|
161
|
+
| `test_syntax_highlighter.rb` | 16 (9 existing + 7 new) | pass |
|
|
162
|
+
| `test_renderer.rb` | 12 (10 existing + 2 new) | pass |
|
|
163
|
+
|
|
164
|
+
**34 new tests** added in this release.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Dependencies
|
|
169
|
+
|
|
170
|
+
### New Optional External Tool
|
|
171
|
+
|
|
172
|
+
| Tool | Purpose | Install |
|
|
173
|
+
|------|---------|---------|
|
|
174
|
+
| `bat` | Syntax highlighting | `brew install bat` / `apt install bat` |
|
|
175
|
+
|
|
176
|
+
rufio works normally without `bat` — plain text preview is always available as a fallback.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Health Check
|
|
181
|
+
|
|
182
|
+
Use `rufio -c` to verify `bat` installation:
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
rufio Health Check
|
|
186
|
+
✓ bat (syntax highlight): bat 0.25.0 (2024-...)
|
|
187
|
+
✗ bat (syntax highlight): not found
|
|
188
|
+
brew install bat # optional: enables syntax highlighting
|
|
189
|
+
```
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rufio
|
|
4
|
+
# ANSI エスケープコード付きの行をトークン列に分解するモジュール。
|
|
5
|
+
# bat --color=always の出力をシンタックスハイライト表示するために使用する。
|
|
6
|
+
module AnsiLineParser
|
|
7
|
+
# SGR (Select Graphic Rendition) ANSI エスケープシーケンスにマッチするパターン
|
|
8
|
+
ANSI_SGR_PATTERN = /\e\[[0-9;]*m/
|
|
9
|
+
|
|
10
|
+
# ANSI 付き行を {text: String, fg: String|nil} のトークン配列に分解する。
|
|
11
|
+
#
|
|
12
|
+
# @param line [String] ANSI コードを含む可能性がある行
|
|
13
|
+
# @return [Array<Hash>] {text:, fg:} のトークン配列
|
|
14
|
+
def self.parse(line)
|
|
15
|
+
tokens = []
|
|
16
|
+
current_fg = nil
|
|
17
|
+
|
|
18
|
+
# ANSI SGR シーケンス、非エスケープ文字列、孤立エスケープの順にスキャン
|
|
19
|
+
line.scan(/#{ANSI_SGR_PATTERN}|[^\e]+|\e(?!\[)/) do |part|
|
|
20
|
+
if part.start_with?("\e[")
|
|
21
|
+
current_fg = apply_ansi_sequence(current_fg, part)
|
|
22
|
+
else
|
|
23
|
+
tokens << { text: part, fg: current_fg }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
tokens
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# トークン配列の表示幅(ANSI コードを除く)を計算する。
|
|
31
|
+
#
|
|
32
|
+
# @param tokens [Array<Hash>] parse が返したトークン配列
|
|
33
|
+
# @return [Integer] 表示幅
|
|
34
|
+
def self.display_width(tokens)
|
|
35
|
+
tokens.sum { |t| TextUtils.display_width(t[:text]) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# トークン配列を max_width で折り返し、行ごとのトークン配列の配列を返す。
|
|
39
|
+
# 全角文字(日本語等)は幅2として扱う。
|
|
40
|
+
#
|
|
41
|
+
# @param tokens [Array<Hash>] parse が返したトークン配列
|
|
42
|
+
# @param max_width [Integer] 折り返し幅(表示幅基準)
|
|
43
|
+
# @return [Array<Array<Hash>>] 行ごとのトークン配列
|
|
44
|
+
def self.wrap(tokens, max_width)
|
|
45
|
+
return [] if tokens.empty? || max_width <= 0
|
|
46
|
+
|
|
47
|
+
lines = []
|
|
48
|
+
current_line = []
|
|
49
|
+
current_width = 0
|
|
50
|
+
|
|
51
|
+
tokens.each do |token|
|
|
52
|
+
fg = token[:fg]
|
|
53
|
+
current_text = String.new
|
|
54
|
+
|
|
55
|
+
token[:text].each_char do |char|
|
|
56
|
+
char_w = TextUtils.char_width(char)
|
|
57
|
+
|
|
58
|
+
if current_width + char_w > max_width
|
|
59
|
+
# 折り返し: 現在のテキストをトークンとして確定
|
|
60
|
+
current_line << { text: current_text, fg: fg } unless current_text.empty?
|
|
61
|
+
lines << current_line
|
|
62
|
+
current_line = []
|
|
63
|
+
current_text = String.new
|
|
64
|
+
current_width = 0
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
current_text << char
|
|
68
|
+
current_width += char_w
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
current_line << { text: current_text, fg: fg } unless current_text.empty?
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
lines << current_line unless current_line.empty?
|
|
75
|
+
lines
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# private helper: ANSI シーケンスを適用して新しい fg 状態を返す。
|
|
79
|
+
# リセットシーケンスは nil を返す。
|
|
80
|
+
# 複合シーケンス(例: \e[0;32m)はリセット後の色だけを返す。
|
|
81
|
+
def self.apply_ansi_sequence(current_fg, seq)
|
|
82
|
+
# \e[ と m の間のコード文字列を取り出す
|
|
83
|
+
codes_str = seq[2..-2]
|
|
84
|
+
codes = codes_str.split(';')
|
|
85
|
+
|
|
86
|
+
# すべてのコードがリセット("0" or "")ならリセット
|
|
87
|
+
if codes.empty? || codes.all? { |c| c.empty? || c == '0' }
|
|
88
|
+
return nil
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# 先頭がリセットコードで後続に色指定がある場合(例: \e[0;32m)
|
|
92
|
+
if codes.first.empty? || codes.first == '0'
|
|
93
|
+
remaining = codes.drop_while { |c| c.empty? || c == '0' }
|
|
94
|
+
return remaining.empty? ? nil : "\e[#{remaining.join(';')}m"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# 通常の色/属性コード → そのまま使用
|
|
98
|
+
seq
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private_class_method :apply_ansi_sequence
|
|
102
|
+
end
|
|
103
|
+
end
|
data/lib/rufio/config.rb
CHANGED
|
@@ -66,6 +66,7 @@ module Rufio
|
|
|
66
66
|
'health.fzf' => 'fzf (file search)',
|
|
67
67
|
'health.rga' => 'rga (content search)',
|
|
68
68
|
'health.zoxide' => 'zoxide (directory history)',
|
|
69
|
+
'health.bat' => 'bat (syntax highlight)',
|
|
69
70
|
'health.file_opener' => 'System file opener',
|
|
70
71
|
'health.summary' => 'Summary:',
|
|
71
72
|
'health.ok' => 'OK',
|
|
@@ -135,6 +136,7 @@ module Rufio
|
|
|
135
136
|
'health.fzf' => 'fzf (file search)',
|
|
136
137
|
'health.rga' => 'rga (content search)',
|
|
137
138
|
'health.zoxide' => 'zoxide (directory history)',
|
|
139
|
+
'health.bat' => 'bat (syntax highlight)',
|
|
138
140
|
'health.file_opener' => 'System file opener',
|
|
139
141
|
'health.summary' => 'Summary:',
|
|
140
142
|
'health.ok' => 'OK',
|
data/lib/rufio/file_preview.rb
CHANGED
|
@@ -127,7 +127,16 @@ module Rufio
|
|
|
127
127
|
|
|
128
128
|
def determine_file_type(file_path)
|
|
129
129
|
extension = File.extname(file_path).downcase
|
|
130
|
-
|
|
130
|
+
basename = File.basename(file_path)
|
|
131
|
+
|
|
132
|
+
# 拡張子なしファイル名での判定(Dockerfile 等)
|
|
133
|
+
case basename
|
|
134
|
+
when "Dockerfile", /\ADockerfile\./
|
|
135
|
+
return { type: "code", language: "dockerfile" }
|
|
136
|
+
when "Makefile", "GNUmakefile"
|
|
137
|
+
return { type: "code", language: "makefile" }
|
|
138
|
+
end
|
|
139
|
+
|
|
131
140
|
case extension
|
|
132
141
|
when ".rb"
|
|
133
142
|
{ type: "code", language: "ruby" }
|
|
@@ -147,6 +156,22 @@ module Rufio
|
|
|
147
156
|
{ type: "code", language: "yaml" }
|
|
148
157
|
when ".md", ".markdown"
|
|
149
158
|
{ type: "code", language: "markdown" }
|
|
159
|
+
when ".go"
|
|
160
|
+
{ type: "code", language: "go" }
|
|
161
|
+
when ".rs"
|
|
162
|
+
{ type: "code", language: "rust" }
|
|
163
|
+
when ".sh", ".bash", ".zsh"
|
|
164
|
+
{ type: "code", language: "shell" }
|
|
165
|
+
when ".toml"
|
|
166
|
+
{ type: "code", language: "toml" }
|
|
167
|
+
when ".sql"
|
|
168
|
+
{ type: "code", language: "sql" }
|
|
169
|
+
when ".c", ".h"
|
|
170
|
+
{ type: "code", language: "c" }
|
|
171
|
+
when ".cpp", ".cc", ".cxx", ".hpp"
|
|
172
|
+
{ type: "code", language: "cpp" }
|
|
173
|
+
when ".java"
|
|
174
|
+
{ type: "code", language: "java" }
|
|
150
175
|
when ".txt", ".log"
|
|
151
176
|
{ type: "text", language: nil }
|
|
152
177
|
when ".zip", ".tar", ".gz", ".bz2", ".xz", ".7z"
|
data/lib/rufio/health_checker.rb
CHANGED
|
@@ -21,6 +21,7 @@ module Rufio
|
|
|
21
21
|
{ name: ConfigLoader.message('health.fzf'), method: :check_fzf },
|
|
22
22
|
{ name: ConfigLoader.message('health.rga'), method: :check_rga },
|
|
23
23
|
{ name: ConfigLoader.message('health.zoxide'), method: :check_zoxide },
|
|
24
|
+
{ name: ConfigLoader.message('health.bat'), method: :check_bat },
|
|
24
25
|
{ name: ConfigLoader.message('health.file_opener'), method: :check_file_opener }
|
|
25
26
|
]
|
|
26
27
|
|
|
@@ -136,6 +137,23 @@ module Rufio
|
|
|
136
137
|
end
|
|
137
138
|
end
|
|
138
139
|
|
|
140
|
+
def check_bat
|
|
141
|
+
if system("which bat > /dev/null 2>&1")
|
|
142
|
+
version = `bat --version 2>/dev/null`.strip
|
|
143
|
+
{
|
|
144
|
+
status: :ok,
|
|
145
|
+
message: version,
|
|
146
|
+
details: nil
|
|
147
|
+
}
|
|
148
|
+
else
|
|
149
|
+
{
|
|
150
|
+
status: :warning,
|
|
151
|
+
message: "bat #{ConfigLoader.message('health.tool_not_found')}",
|
|
152
|
+
details: install_instruction_for('bat')
|
|
153
|
+
}
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
139
157
|
def check_file_opener
|
|
140
158
|
case RUBY_PLATFORM
|
|
141
159
|
when /darwin/
|
|
@@ -180,6 +198,8 @@ module Rufio
|
|
|
180
198
|
"#{ConfigLoader.message('health.install_brew')} rga"
|
|
181
199
|
when 'zoxide'
|
|
182
200
|
"#{ConfigLoader.message('health.install_brew')} zoxide"
|
|
201
|
+
when 'bat'
|
|
202
|
+
"#{ConfigLoader.message('health.install_brew')} bat # optional: syntax highlight"
|
|
183
203
|
end
|
|
184
204
|
when /linux/
|
|
185
205
|
case tool
|
|
@@ -189,6 +209,8 @@ module Rufio
|
|
|
189
209
|
ConfigLoader.message('health.rga_releases')
|
|
190
210
|
when 'zoxide'
|
|
191
211
|
"#{ConfigLoader.message('health.install_apt')} zoxide (Ubuntu/Debian) or check your package manager"
|
|
212
|
+
when 'bat'
|
|
213
|
+
"#{ConfigLoader.message('health.install_apt')} bat (Ubuntu/Debian) or check your package manager # optional: syntax highlight"
|
|
192
214
|
end
|
|
193
215
|
else
|
|
194
216
|
ConfigLoader.message('health.install_guide')
|
|
@@ -436,6 +436,20 @@ module Rufio
|
|
|
436
436
|
@preview_scroll_offset = 0
|
|
437
437
|
end
|
|
438
438
|
|
|
439
|
+
# Tabキー: 次のブックマークへ循環移動
|
|
440
|
+
def goto_next_bookmark
|
|
441
|
+
bookmarks = @bookmark_manager.list
|
|
442
|
+
return nil unless bookmarks&.any?
|
|
443
|
+
|
|
444
|
+
current_path = @directory_listing.current_path
|
|
445
|
+
current_idx = bookmarks.find_index { |bm| bm[:path] == current_path }
|
|
446
|
+
|
|
447
|
+
next_idx = current_idx ? (current_idx + 1) % bookmarks.length : 0
|
|
448
|
+
next_bookmark = bookmarks[next_idx]
|
|
449
|
+
navigate_to_directory(next_bookmark[:path])
|
|
450
|
+
next_idx
|
|
451
|
+
end
|
|
452
|
+
|
|
439
453
|
private
|
|
440
454
|
|
|
441
455
|
# オーバーレイダイアログを表示してキー入力を待つヘルパーメソッド
|
|
@@ -1388,6 +1402,7 @@ module Rufio
|
|
|
1388
1402
|
navigate_to_directory(bookmark[:path])
|
|
1389
1403
|
end
|
|
1390
1404
|
|
|
1405
|
+
|
|
1391
1406
|
def add_bookmark
|
|
1392
1407
|
current_path = @directory_listing&.current_path || Dir.pwd
|
|
1393
1408
|
|