rufio 0.80.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 +18 -0
- data/README.md +1 -1
- data/README_ja.md +2 -0
- data/lib/rufio/keybind_handler.rb +15 -0
- data/lib/rufio/tab_mode_manager.rb +12 -0
- data/lib/rufio/terminal_ui.rb +177 -68
- data/lib/rufio/version.rb +1 -1
- data/lib/rufio/zoxide_integration.rb +11 -5
- metadata +2 -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,24 @@ 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
|
+
|
|
10
28
|
## [0.80.0] - 2026-02-21
|
|
11
29
|
|
|
12
30
|
### Added
|
data/README.md
CHANGED
|
@@ -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
|
data/README_ja.md
CHANGED
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -13,6 +13,13 @@ module Rufio
|
|
|
13
13
|
help: 'Help'
|
|
14
14
|
}.freeze
|
|
15
15
|
|
|
16
|
+
MODE_KEYS = {
|
|
17
|
+
files: nil,
|
|
18
|
+
logs: 'L',
|
|
19
|
+
jobs: 'J',
|
|
20
|
+
help: '?'
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
16
23
|
attr_reader :current_mode
|
|
17
24
|
|
|
18
25
|
def initialize
|
|
@@ -30,6 +37,11 @@ module Rufio
|
|
|
30
37
|
MODE_LABELS
|
|
31
38
|
end
|
|
32
39
|
|
|
40
|
+
# モードのキーバインド一覧
|
|
41
|
+
def mode_keys
|
|
42
|
+
MODE_KEYS
|
|
43
|
+
end
|
|
44
|
+
|
|
33
45
|
# 次のモードに切り替え
|
|
34
46
|
def next_mode
|
|
35
47
|
current_index = MODES.index(@current_mode)
|
data/lib/rufio/terminal_ui.rb
CHANGED
|
@@ -6,9 +6,9 @@ require_relative 'text_utils'
|
|
|
6
6
|
module Rufio
|
|
7
7
|
class TerminalUI
|
|
8
8
|
# Layout constants
|
|
9
|
-
HEADER_HEIGHT =
|
|
9
|
+
HEADER_HEIGHT = 1 # Header占有行数(モードタブ+パス+バージョン 1行に統合)
|
|
10
10
|
FOOTER_HEIGHT = 1 # Footer占有行数(ブックマーク一覧 + ステータス情報)
|
|
11
|
-
HEADER_FOOTER_MARGIN =
|
|
11
|
+
HEADER_FOOTER_MARGIN = 2 # Header(1行) + Footer(1行)分のマージン
|
|
12
12
|
|
|
13
13
|
# Panel layout ratios
|
|
14
14
|
LEFT_PANEL_RATIO = 0.5 # 左パネルの幅比率
|
|
@@ -19,6 +19,7 @@ module Rufio
|
|
|
19
19
|
DEFAULT_SCREEN_HEIGHT = 24 # デフォルト画面高さ
|
|
20
20
|
HEADER_PADDING = 2 # ヘッダーのパディング
|
|
21
21
|
FILTER_TEXT_RESERVED = 15 # フィルタテキスト表示の予約幅
|
|
22
|
+
TAB_SEPARATOR = ">" # タブ間セパレータ
|
|
22
23
|
|
|
23
24
|
# File display constants
|
|
24
25
|
ICON_SIZE_PADDING = 12 # アイコン、選択マーク、サイズ情報分
|
|
@@ -29,8 +30,11 @@ module Rufio
|
|
|
29
30
|
MEGABYTE = KILOBYTE * 1024
|
|
30
31
|
GIGABYTE = MEGABYTE * 1024
|
|
31
32
|
|
|
33
|
+
# Bookmark highlight duration (seconds)
|
|
34
|
+
BOOKMARK_HIGHLIGHT_DURATION = 0.5
|
|
35
|
+
|
|
32
36
|
# Line offsets
|
|
33
|
-
CONTENT_START_LINE =
|
|
37
|
+
CONTENT_START_LINE = 1 # コンテンツ開始行(フッタ1行: Y=0)
|
|
34
38
|
|
|
35
39
|
def initialize(test_mode: false)
|
|
36
40
|
console = IO.console
|
|
@@ -76,6 +80,10 @@ module Rufio
|
|
|
76
80
|
@cached_bookmark_time = nil
|
|
77
81
|
@bookmark_cache_ttl = 1.0 # 1秒間キャッシュ
|
|
78
82
|
|
|
83
|
+
# Bookmark highlight (Tab ジャンプ時に 500ms ハイライト)
|
|
84
|
+
@highlighted_bookmark_index = nil # 1-based display index (0=start_dir, 1..9=bookmarks)
|
|
85
|
+
@highlighted_bookmark_time = nil
|
|
86
|
+
|
|
79
87
|
# Command execution lamp (footer indicator)
|
|
80
88
|
@completion_lamp_message = nil
|
|
81
89
|
@completion_lamp_time = nil
|
|
@@ -158,6 +166,14 @@ module Rufio
|
|
|
158
166
|
|
|
159
167
|
private
|
|
160
168
|
|
|
169
|
+
# ブックマークハイライトが期限切れかどうか
|
|
170
|
+
# @return [Boolean] true=期限切れ or ハイライト中でない, false=ハイライト中
|
|
171
|
+
def bookmark_highlight_expired?
|
|
172
|
+
return false unless @highlighted_bookmark_index && @highlighted_bookmark_time
|
|
173
|
+
|
|
174
|
+
(Time.now - @highlighted_bookmark_time) >= BOOKMARK_HIGHLIGHT_DURATION
|
|
175
|
+
end
|
|
176
|
+
|
|
161
177
|
def setup_terminal
|
|
162
178
|
# terminal setup
|
|
163
179
|
system('tput smcup') # alternate screen
|
|
@@ -309,6 +325,13 @@ module Rufio
|
|
|
309
325
|
needs_redraw = true
|
|
310
326
|
end
|
|
311
327
|
|
|
328
|
+
# ブックマークハイライトのタイムアウトチェック(500ms 後に自動消去)
|
|
329
|
+
if bookmark_highlight_expired?
|
|
330
|
+
@highlighted_bookmark_index = nil
|
|
331
|
+
@highlighted_bookmark_time = nil
|
|
332
|
+
needs_redraw = true
|
|
333
|
+
end
|
|
334
|
+
|
|
312
335
|
# DRAW & RENDER phase - 変更があった場合のみ描画
|
|
313
336
|
if needs_redraw
|
|
314
337
|
# Screenバッファに描画(clearは呼ばない。必要な部分だけ更新)
|
|
@@ -396,19 +419,18 @@ module Rufio
|
|
|
396
419
|
|
|
397
420
|
# Phase 3: Screenバッファに描画する新しいメソッド
|
|
398
421
|
def draw_screen_to_buffer(screen, notification_message = nil, fps = nil)
|
|
399
|
-
# header (2 lines) - y=0, y=1(全モード共通)
|
|
400
|
-
draw_header_to_buffer(screen, 0)
|
|
401
|
-
draw_mode_tabs_to_buffer(screen, 1)
|
|
402
|
-
|
|
403
422
|
# calculate height with header and footer margin
|
|
404
423
|
content_height = @screen_height - HEADER_FOOTER_MARGIN
|
|
405
424
|
|
|
406
425
|
if @in_job_mode
|
|
407
|
-
# ジョブモード:
|
|
426
|
+
# ジョブモード: フッタ y=0(上部)、コンテンツ y=1〜h-2、統合行 y=h-1(下部)
|
|
427
|
+
draw_job_footer_to_buffer(screen, 0)
|
|
408
428
|
draw_job_list_to_buffer(screen, content_height)
|
|
409
|
-
|
|
429
|
+
draw_mode_tabs_to_buffer(screen, @screen_height - 1)
|
|
410
430
|
else
|
|
411
|
-
# 通常モード:
|
|
431
|
+
# 通常モード: フッタ y=0(上部)、コンテンツ y=1〜h-2、統合行 y=h-1(下部)
|
|
432
|
+
draw_footer_to_buffer(screen, 0, fps)
|
|
433
|
+
|
|
412
434
|
entries = get_display_entries
|
|
413
435
|
selected_entry = entries[@keybind_handler.current_index]
|
|
414
436
|
|
|
@@ -421,8 +443,7 @@ module Rufio
|
|
|
421
443
|
draw_directory_list_to_buffer(screen, entries, left_width, content_height)
|
|
422
444
|
draw_file_preview_to_buffer(screen, selected_entry, right_width, content_height, left_width)
|
|
423
445
|
|
|
424
|
-
|
|
425
|
-
draw_footer_to_buffer(screen, @screen_height - 1, fps)
|
|
446
|
+
draw_mode_tabs_to_buffer(screen, @screen_height - 1)
|
|
426
447
|
end
|
|
427
448
|
|
|
428
449
|
# 通知メッセージがある場合は表示
|
|
@@ -543,24 +564,40 @@ module Rufio
|
|
|
543
564
|
header += filter_text
|
|
544
565
|
end
|
|
545
566
|
|
|
546
|
-
# abbreviate if path is too long
|
|
547
|
-
if header
|
|
567
|
+
# abbreviate if path is too long (use visual width to account for wide chars like emoji)
|
|
568
|
+
if TextUtils.display_width(header) > @screen_width - HEADER_PADDING
|
|
569
|
+
prefix = "💎 rufio v#{VERSION} - ..."
|
|
570
|
+
prefix_width = TextUtils.display_width(prefix)
|
|
548
571
|
if @keybind_handler.help_mode?
|
|
549
572
|
# prioritize showing help mode indicator
|
|
550
573
|
help_text = " [Help Mode - Press ESC to exit]"
|
|
551
|
-
|
|
552
|
-
header = "
|
|
574
|
+
available = [@screen_width - prefix_width - help_text.length, 0].max
|
|
575
|
+
header = "#{prefix}#{current_path[-available..-1]}#{help_text}"
|
|
553
576
|
elsif @keybind_handler.filter_active?
|
|
554
577
|
# prioritize showing filter when active
|
|
555
578
|
filter_text = " [Filter: #{@keybind_handler.filter_query}]"
|
|
556
|
-
|
|
557
|
-
header = "
|
|
579
|
+
available = [@screen_width - prefix_width - filter_text.length, 0].max
|
|
580
|
+
header = "#{prefix}#{current_path[-available..-1]}#{filter_text}"
|
|
558
581
|
else
|
|
559
|
-
|
|
582
|
+
available = [@screen_width - prefix_width, 0].max
|
|
583
|
+
header = "#{prefix}#{current_path[-available..-1]}"
|
|
560
584
|
end
|
|
561
585
|
end
|
|
562
586
|
|
|
563
|
-
|
|
587
|
+
# モードタブと同じ表示方法: グレー文字で1文字ずつ描画
|
|
588
|
+
# current_x は表示幅(カラム数)で管理(絵文字等の全角文字対応)
|
|
589
|
+
current_x = 0
|
|
590
|
+
header.each_char do |char|
|
|
591
|
+
char_width = TextUtils.display_width(char)
|
|
592
|
+
break if current_x + char_width > @screen_width
|
|
593
|
+
screen.put(current_x, y, char, fg: "\e[90m")
|
|
594
|
+
current_x += char_width
|
|
595
|
+
end
|
|
596
|
+
# 残りをスペースで埋める
|
|
597
|
+
while current_x < @screen_width
|
|
598
|
+
screen.put(current_x, y, ' ')
|
|
599
|
+
current_x += 1
|
|
600
|
+
end
|
|
564
601
|
end
|
|
565
602
|
|
|
566
603
|
# Phase 3: Screenバッファにモードタブを描画
|
|
@@ -571,10 +608,12 @@ module Rufio
|
|
|
571
608
|
current_x = 0
|
|
572
609
|
modes = @tab_mode_manager.available_modes
|
|
573
610
|
labels = @tab_mode_manager.mode_labels
|
|
611
|
+
keys = @tab_mode_manager.mode_keys
|
|
574
612
|
current_mode = @tab_mode_manager.current_mode
|
|
575
613
|
|
|
576
614
|
modes.each_with_index do |mode, index|
|
|
577
|
-
|
|
615
|
+
key = keys[mode]
|
|
616
|
+
label = key ? " #{key}:#{labels[mode]} " : " #{labels[mode]} "
|
|
578
617
|
|
|
579
618
|
if mode == current_mode
|
|
580
619
|
# 現在のモード: シアン背景 + 黒文字 + 太字
|
|
@@ -590,9 +629,57 @@ module Rufio
|
|
|
590
629
|
end
|
|
591
630
|
end
|
|
592
631
|
|
|
593
|
-
#
|
|
632
|
+
# セパレータ: アクティブタブの後はPowerline塗りつぶし三角、それ以外は >
|
|
594
633
|
if index < modes.length - 1
|
|
595
|
-
|
|
634
|
+
if mode == current_mode
|
|
635
|
+
screen.put(current_x, y, "\uE0B0", fg: "\e[36m")
|
|
636
|
+
else
|
|
637
|
+
screen.put(current_x, y, TAB_SEPARATOR, fg: "\e[90m")
|
|
638
|
+
end
|
|
639
|
+
current_x += 1
|
|
640
|
+
end
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
# パスとバージョン情報を行末に追加
|
|
644
|
+
current_path = @directory_listing.current_path
|
|
645
|
+
version_str = " rufio v#{VERSION}"
|
|
646
|
+
version_w = version_str.length # ASCII-only
|
|
647
|
+
|
|
648
|
+
remaining_w = @screen_width - current_x
|
|
649
|
+
# 必要な最小幅: (1) + " x " (3) + (1) + version_w
|
|
650
|
+
path_display_w = remaining_w - 2 - version_w
|
|
651
|
+
|
|
652
|
+
if path_display_w >= 3
|
|
653
|
+
# 最後のタブ→パスの区切り(最後のモードがアクティブかで色が変わる)
|
|
654
|
+
arrow_fg = modes.last == current_mode ? "\e[36m" : "\e[90m"
|
|
655
|
+
screen.put(current_x, y, TAB_SEPARATOR, fg: arrow_fg)
|
|
656
|
+
current_x += 1
|
|
657
|
+
|
|
658
|
+
# パスを描画(path_end までの領域)
|
|
659
|
+
path_end = @screen_width - 1 - version_w
|
|
660
|
+
path_str = " #{current_path} "
|
|
661
|
+
path_str.each_char do |char|
|
|
662
|
+
break if current_x >= path_end
|
|
663
|
+
char_w = TextUtils.display_width(char)
|
|
664
|
+
break if current_x + char_w > path_end
|
|
665
|
+
screen.put(current_x, y, char, fg: "\e[90m")
|
|
666
|
+
current_x += char_w
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
# path_end まで空白で埋める
|
|
670
|
+
while current_x < path_end
|
|
671
|
+
screen.put(current_x, y, ' ')
|
|
672
|
+
current_x += 1
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
# バージョンセパレータ(左向き三角、シアン色でシアン背景に遷移)
|
|
676
|
+
screen.put(current_x, y, "\uE0B2", fg: "\e[36m")
|
|
677
|
+
current_x += 1
|
|
678
|
+
|
|
679
|
+
# バージョン描画(シアン背景+黒太字)
|
|
680
|
+
version_str.each_char do |char|
|
|
681
|
+
break if current_x >= @screen_width
|
|
682
|
+
screen.put(current_x, y, char, fg: "\e[30m\e[1m", bg: "\e[46m")
|
|
596
683
|
current_x += 1
|
|
597
684
|
end
|
|
598
685
|
end
|
|
@@ -608,12 +695,12 @@ module Rufio
|
|
|
608
695
|
def sync_tab_mode_with_keybind_handler
|
|
609
696
|
return unless @keybind_handler
|
|
610
697
|
|
|
611
|
-
current_mode = if @keybind_handler.
|
|
698
|
+
current_mode = if @in_job_mode || @keybind_handler.in_job_mode?
|
|
699
|
+
:jobs
|
|
700
|
+
elsif @keybind_handler.help_mode?
|
|
612
701
|
:help
|
|
613
702
|
elsif @keybind_handler.log_viewer_mode?
|
|
614
703
|
:logs
|
|
615
|
-
elsif @keybind_handler.in_job_mode?
|
|
616
|
-
:jobs
|
|
617
704
|
else
|
|
618
705
|
:files
|
|
619
706
|
end
|
|
@@ -636,20 +723,23 @@ module Rufio
|
|
|
636
723
|
header += filter_text
|
|
637
724
|
end
|
|
638
725
|
|
|
639
|
-
# abbreviate if path is too long
|
|
640
|
-
if header
|
|
726
|
+
# abbreviate if path is too long (use visual width to account for wide chars like emoji)
|
|
727
|
+
if TextUtils.display_width(header) > @screen_width - HEADER_PADDING
|
|
728
|
+
prefix = "💎 rufio v#{VERSION} - ..."
|
|
729
|
+
prefix_width = TextUtils.display_width(prefix)
|
|
641
730
|
if @keybind_handler.help_mode?
|
|
642
731
|
# prioritize showing help mode indicator
|
|
643
732
|
help_text = " [Help Mode - Press ESC to exit]"
|
|
644
|
-
|
|
645
|
-
header = "
|
|
733
|
+
available = [@screen_width - prefix_width - help_text.length, 0].max
|
|
734
|
+
header = "#{prefix}#{current_path[-available..-1]}#{help_text}"
|
|
646
735
|
elsif @keybind_handler.filter_active?
|
|
647
736
|
# prioritize showing filter when active
|
|
648
737
|
filter_text = " [Filter: #{@keybind_handler.filter_query}]"
|
|
649
|
-
|
|
650
|
-
header = "
|
|
738
|
+
available = [@screen_width - prefix_width - filter_text.length, 0].max
|
|
739
|
+
header = "#{prefix}#{current_path[-available..-1]}#{filter_text}"
|
|
651
740
|
else
|
|
652
|
-
|
|
741
|
+
available = [@screen_width - prefix_width, 0].max
|
|
742
|
+
header = "#{prefix}#{current_path[-available..-1]}"
|
|
653
743
|
end
|
|
654
744
|
end
|
|
655
745
|
|
|
@@ -1164,7 +1254,7 @@ module Rufio
|
|
|
1164
1254
|
unless bookmarks.empty?
|
|
1165
1255
|
bookmark_parts.concat(bookmarks.take(9).map.with_index(1) { |bm, idx| "#{idx}.#{bm[:name]}" })
|
|
1166
1256
|
end
|
|
1167
|
-
bookmark_text = bookmark_parts.join(" ")
|
|
1257
|
+
bookmark_text = bookmark_parts.join(" │ ")
|
|
1168
1258
|
|
|
1169
1259
|
# 右側の情報: ジョブ数 | コマンド実行ランプ | FPS(test modeの時のみ)| ?:help
|
|
1170
1260
|
right_parts = []
|
|
@@ -1197,24 +1287,43 @@ module Rufio
|
|
|
1197
1287
|
right_parts << "#{fps.round(1)} FPS"
|
|
1198
1288
|
end
|
|
1199
1289
|
|
|
1200
|
-
# ヘルプ表示
|
|
1201
|
-
right_parts << "?:help"
|
|
1202
|
-
|
|
1203
1290
|
right_info = right_parts.join(" | ")
|
|
1204
1291
|
|
|
1205
1292
|
# ブックマーク一覧を利用可能な幅に収める
|
|
1206
|
-
|
|
1293
|
+
if right_info.empty?
|
|
1294
|
+
available_width = @screen_width
|
|
1295
|
+
else
|
|
1296
|
+
available_width = @screen_width - right_info.length - 3
|
|
1297
|
+
end
|
|
1207
1298
|
if bookmark_text.length > available_width && available_width > 3
|
|
1208
1299
|
bookmark_text = bookmark_text[0...available_width - 3] + "..."
|
|
1209
1300
|
elsif available_width <= 3
|
|
1210
1301
|
bookmark_text = ""
|
|
1211
1302
|
end
|
|
1212
1303
|
|
|
1213
|
-
#
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1304
|
+
# フッタ全体を構築(左にブックマーク、右に情報がある場合のみ右寄せ)
|
|
1305
|
+
if right_info.empty?
|
|
1306
|
+
footer_content = bookmark_text.ljust(@screen_width)[0...@screen_width]
|
|
1307
|
+
else
|
|
1308
|
+
padding = @screen_width - bookmark_text.length - right_info.length
|
|
1309
|
+
footer_content = "#{bookmark_text}#{' ' * padding}#{right_info}"
|
|
1310
|
+
footer_content = footer_content.ljust(@screen_width)[0...@screen_width]
|
|
1311
|
+
end
|
|
1312
|
+
screen.put_string(0, y, footer_content, fg: "\e[90m")
|
|
1313
|
+
|
|
1314
|
+
# Tab ジャンプ時:対象ブックマークを 500ms ハイライト(セカンドパス)
|
|
1315
|
+
if @highlighted_bookmark_index && !bookmark_highlight_expired? && available_width > 3
|
|
1316
|
+
highlight_idx = @highlighted_bookmark_index
|
|
1317
|
+
if highlight_idx < bookmark_parts.length
|
|
1318
|
+
separator_len = 3 # " │ "
|
|
1319
|
+
x_pos = bookmark_parts[0...highlight_idx].sum { |p| p.length + separator_len }
|
|
1320
|
+
part_text = bookmark_parts[highlight_idx]
|
|
1321
|
+
if x_pos < available_width
|
|
1322
|
+
visible_len = [part_text.length, available_width - x_pos].min
|
|
1323
|
+
screen.put_string(x_pos, y, part_text[0...visible_len], fg: "\e[1;36m")
|
|
1324
|
+
end
|
|
1325
|
+
end
|
|
1326
|
+
end
|
|
1218
1327
|
end
|
|
1219
1328
|
end
|
|
1220
1329
|
|
|
@@ -1257,27 +1366,11 @@ module Rufio
|
|
|
1257
1366
|
unless bookmarks.empty?
|
|
1258
1367
|
bookmark_parts.concat(bookmarks.take(9).map.with_index(1) { |bm, idx| "#{idx}.#{bm[:name]}" })
|
|
1259
1368
|
end
|
|
1260
|
-
bookmark_text = bookmark_parts.join(" ")
|
|
1261
|
-
|
|
1262
|
-
# ステータス情報を作成
|
|
1263
|
-
time_info = render_time ? "#{(render_time * 1000).round(1)}ms" : "-ms"
|
|
1369
|
+
bookmark_text = bookmark_parts.join(" │ ")
|
|
1264
1370
|
|
|
1265
|
-
#
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
# ブックマーク一覧を利用可能な幅に収める
|
|
1269
|
-
available_width = @screen_width - right_info.length - 3
|
|
1270
|
-
if bookmark_text.length > available_width && available_width > 3
|
|
1271
|
-
bookmark_text = bookmark_text[0...available_width - 3] + "..."
|
|
1272
|
-
elsif available_width <= 3
|
|
1273
|
-
bookmark_text = ""
|
|
1274
|
-
end
|
|
1275
|
-
|
|
1276
|
-
# フッタ全体を構築
|
|
1277
|
-
padding = @screen_width - bookmark_text.length - right_info.length
|
|
1278
|
-
footer_content = "#{bookmark_text}#{' ' * padding}#{right_info}"
|
|
1279
|
-
footer_content = footer_content.ljust(@screen_width)[0...@screen_width]
|
|
1280
|
-
print "\e[7m#{footer_content}\e[0m"
|
|
1371
|
+
# フッタ全体を構築(ブックマーク左寄せ)
|
|
1372
|
+
footer_content = bookmark_text.ljust(@screen_width)[0...@screen_width]
|
|
1373
|
+
print "\e[90m#{footer_content}\e[0m"
|
|
1281
1374
|
end
|
|
1282
1375
|
end
|
|
1283
1376
|
|
|
@@ -1333,12 +1426,21 @@ module Rufio
|
|
|
1333
1426
|
end
|
|
1334
1427
|
end
|
|
1335
1428
|
|
|
1336
|
-
# Tab
|
|
1337
|
-
if input == "\t"
|
|
1429
|
+
# TabキーはFilesモードの時のみブックマーク循環移動
|
|
1430
|
+
if input == "\t" && @tab_mode_manager.current_mode == :files
|
|
1338
1431
|
handle_tab_key
|
|
1339
1432
|
return true
|
|
1340
1433
|
end
|
|
1341
1434
|
|
|
1435
|
+
# Jobsモード中のモード切替キーをインターセプト(L:Logs, ?:Help, J:Files復帰)
|
|
1436
|
+
if @in_job_mode
|
|
1437
|
+
case input
|
|
1438
|
+
when 'L' then apply_mode_change(:logs); return true
|
|
1439
|
+
when '?' then apply_mode_change(:help); return true
|
|
1440
|
+
when 'J' then apply_mode_change(:files); return true
|
|
1441
|
+
end
|
|
1442
|
+
end
|
|
1443
|
+
|
|
1342
1444
|
# キーバインドハンドラーに処理を委譲
|
|
1343
1445
|
result = @keybind_handler.handle_key(input) if input
|
|
1344
1446
|
|
|
@@ -1422,10 +1524,17 @@ module Rufio
|
|
|
1422
1524
|
end
|
|
1423
1525
|
end
|
|
1424
1526
|
|
|
1425
|
-
# Tab
|
|
1527
|
+
# Tabキー: 次のブックマークへ循環移動
|
|
1426
1528
|
def handle_tab_key
|
|
1427
|
-
@
|
|
1428
|
-
|
|
1529
|
+
next_idx = @keybind_handler.goto_next_bookmark
|
|
1530
|
+
if next_idx
|
|
1531
|
+
# display_index: 0=start_dir, 1..9=bookmarks(next_idx は 0-based bookmarks 配列)
|
|
1532
|
+
@highlighted_bookmark_index = next_idx + 1
|
|
1533
|
+
@highlighted_bookmark_time = Time.now
|
|
1534
|
+
# ブックマークキャッシュを即時クリア(移動先を反映させる)
|
|
1535
|
+
@cached_bookmarks = nil
|
|
1536
|
+
@cached_bookmark_time = nil
|
|
1537
|
+
end
|
|
1429
1538
|
end
|
|
1430
1539
|
|
|
1431
1540
|
# Shift+Tabによる逆順モード切り替え
|
data/lib/rufio/version.rb
CHANGED
|
@@ -219,12 +219,18 @@ module Rufio
|
|
|
219
219
|
# Max 2 digits
|
|
220
220
|
input_buffer = input_buffer[-2..-1] if input_buffer.length > 2
|
|
221
221
|
|
|
222
|
-
# If number is within range, select immediately
|
|
223
222
|
number = input_buffer.to_i
|
|
224
|
-
if number > 0 && number <= display_history.length
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
223
|
+
if number > 0 && number <= display_history.length
|
|
224
|
+
if input_buffer.length >= 2
|
|
225
|
+
# 2桁入力: 即時選択
|
|
226
|
+
selected_path = display_history[number - 1][:path]
|
|
227
|
+
break
|
|
228
|
+
elsif number * 10 > display_history.length
|
|
229
|
+
# 1桁入力: この数字を先頭とする2桁の有効な番号が存在しない → 即時選択
|
|
230
|
+
selected_path = display_history[number - 1][:path]
|
|
231
|
+
break
|
|
232
|
+
end
|
|
233
|
+
# else: number*10 以下のアイテムが存在しうるので次の入力を待つ
|
|
228
234
|
end
|
|
229
235
|
end
|
|
230
236
|
end
|
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.81.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-02-
|
|
11
|
+
date: 2026-02-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: io-console
|