rufio 1.0.3 → 1.0.4

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: 247130c9fd76d05ed1ca70b859ea587e0b42f82ca7491fdc8b1ebea80d0257d4
4
- data.tar.gz: 0122c547241cbd60c870798324b9cddaef6a3767a3153f52ca3b6b6cee3efa07
3
+ metadata.gz: 431baab2112b7382ee6b9aeb19a17f7cbc0133adc8d76e349ac614827908234b
4
+ data.tar.gz: ffe6479dc44a44869dbd56a67af086cfda84164cacb6b3b8334e0d691f24a706
5
5
  SHA512:
6
- metadata.gz: 6ef019b2c59bc7bea03293c837ca7ff1f40cb4015e585056c9d12628dd552e33533a6ab3e6d012473110ebac0456978d1bb5c762b6192f13d7d8a269fd0826a9
7
- data.tar.gz: 75138dbdeb740c137045ef17ba6ede44a8a4b2aa85450618e457b3e8d04ca0d5d6157622aadccb9abb934e4c60b4c5a830923406d9854d02128c5f65e4c19e53
6
+ metadata.gz: 92038826f2b9ba53ba7c2e329c835ba92f99e9678151805faadbdc23f32f7fe6b4bcb4cb8394855ef1ddb01a96ce1abc4ee12ffbf0f1b71672b2148ba7692daa
7
+ data.tar.gz: e7dfbeba635500c59b6fbd2c3b17efdd4b17c24c6bcac9af7d95bb6ebc7ef38b59ce55be6206dd42ceb49b2531728a21cd8c1876a44189371be6f3621ac7c2fc
data/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ 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
+ ## [1.0.4] - 2026-10-25
9
+
10
+ ### Changed
11
+ - Replace directory-based Help with a floating menu containing Controls, Modes, and Scripts sections. Switch sections with 1/2/3 or Tab, scroll with j/k, and close with ESC while preserving the current mode, directory, and preview focus
12
+ - Show mode shortcuts as `[L] Logs`, `[J] Jobs`, and `[?] Help` in the bottom bar
13
+
14
+ ### Fixed
15
+ - Show `ESC: Back to files` below the file name in Preview mode
16
+ - Preserve the original return directory when entering Logs repeatedly and prevent overlapping Help and Logs states
17
+ - Keep mouse interactions inside the floating Help window from affecting the underlying file list
18
+
8
19
  ## [1.0.3] - 2026-10-23
9
20
 
10
21
  ### Security
data/README.md CHANGED
@@ -2,34 +2,26 @@
2
2
 
3
3
  **Runtime Unified Flow I/O Operator**
4
4
 
5
- A TUI file manager that executes and coordinates tools and scripts from files.
6
- Supports Ruby/Python/PowerShell and integrates your development workflow in one place.
5
+ A terminal file manager that keeps your everyday script workflow close at hand.
6
+ Find files, run Ruby, Python, or PowerShell scripts in the current directory, and check jobs and logs.
7
+ Add your own actions in Ruby.
7
8
 
8
9
  [日本語](./README_ja.md) | **English**
9
10
 
10
- ## Concept
11
+ ## What Makes rufio Different
11
12
 
12
- rufio is not just a file manager. It's a **tool runtime execution environment**.
13
+ rufio brings finding files, running scripts, and checking results together in one interface.
13
14
 
14
- ```
15
- ┌─────────────────────────────────────────────────────────┐
16
- │ rufio │
17
- │ Runtime Unified Flow I/O Operator │
18
- ├─────────────────────────────────────────────────────────┤
19
- │ Files ──→ Scripts ──→ Tools ──→ Output │
20
- │ ↑ │ │
21
- │ └───────────── Feedback ────────────┘ │
22
- └─────────────────────────────────────────────────────────┘
23
- ```
24
-
25
- - **File Operations**: Traditional file manager functionality
26
- - **Script Execution**: Run Ruby/Python/PowerShell scripts in file context
27
- - **Tool Integration**: Seamless integration with external tools (git, fzf, rga, etc.)
28
- - **Unified I/O**: Manage all input/output in a single flow
15
+ - **Run scripts where your files are**: Register your script directories, then press `:`, type `@` + part of a script name, press `Tab`, and hit `Enter`. Run Ruby, Python, or PowerShell scripts in the directory you are browsing
16
+ - **Follow jobs and execution logs**: Keep browsing while scripts run in the background. Press `J` to check jobs and `L` to view execution logs
17
+ - **Add your own actions in Ruby**: Define custom commands with a small Ruby DSL in `~/.config/rufio/commands.rb`. `~/.rufio/commands.rb` is also supported
18
+ - **Use installed tools without extra configuration**: Search file names with fzf, search contents with rga, highlight previews with bat, and navigate directory history with zoxide
19
+ - **Windows support**: Run PowerShell scripts with keyboard input handling adapted to Windows terminals
20
+ - **Trace behavior in the source**: The implementation is primarily Ruby, so you can inspect and change the parts you need. Security design is documented in [SECURITY.md](./SECURITY.md)
29
21
 
30
22
  ## Features
31
23
 
32
- ### As a Tool Runtime
24
+ ### For Script Workflows
33
25
 
34
26
  - **Multi-language Script Support**: Ruby, Python, PowerShell
35
27
  - **Script Path Management**: Register and manage multiple script directories
data/README_ja.md CHANGED
@@ -2,36 +2,26 @@
2
2
 
3
3
  **Runtime Unified Flow I/O Operator**
4
4
 
5
- ファイルを起点に、ツールとスクリプトを実行・連携させるTUIファイルマネージャー。
6
- Ruby/Python/PowerShellに対応し、開発ワークフローを一箇所に統合します。
7
-
8
- A TUI file manager as a unified runtime environment for tools and scripts.
5
+ 日々のスクリプト作業を手元にまとめるターミナルファイラ。
6
+ ファイルを探し、その場所で Ruby・Python・PowerShell を実行し、ジョブとログを確認できます。
7
+ 自分用の操作は Ruby で追加できます。
9
8
 
10
9
  **日本語** | [English](./README.md)
11
10
 
12
- ## コンセプト
13
-
14
- rufioは単なるファイルマネージャーではありません。**ツールランタイム実行環境**です。
11
+ ## rufioならではの点
15
12
 
16
- ```
17
- ┌─────────────────────────────────────────────────────────┐
18
- │ rufio │
19
- │ Runtime Unified Flow I/O Operator │
20
- ├─────────────────────────────────────────────────────────┤
21
- │ Files ──→ Scripts ──→ Tools ──→ Output │
22
- │ ↑ │ │
23
- │ └───────────── Feedback ────────────┘ │
24
- └─────────────────────────────────────────────────────────┘
25
- ```
13
+ rufio は、ファイルを探すところからスクリプトの実行、結果の確認までを一つの画面にまとめます。
26
14
 
27
- - **ファイル操作**: 従来のファイルマネージャー機能
28
- - **スクリプト実行**: Ruby/Python/PowerShellスクリプトをファイルコンテキストで実行
29
- - **ツール連携**: 外部ツール(git, fzf, rga等)とのシームレスな統合
30
- - **統一I/O**: すべての入出力を単一のフローで管理
15
+ - **ファイルのある場所からスクリプトを実行**: スクリプトのディレクトリを登録し、`:` → `@` + スクリプト名の一部 → `Tab` → `Enter` で呼び出せます。Ruby・Python・PowerShell を、いま開いているディレクトリで実行できます
16
+ - **ジョブとログで実行結果を追える**: バックグラウンドで実行しながらファイル操作を続け、`J` でジョブ、`L` で実行ログを確認できます
17
+ - **自分用の操作を Ruby で追加**: `~/.config/rufio/commands.rb` に小さな Ruby DSL で独自コマンドを定義できます。`~/.rufio/commands.rb` にも対応しています
18
+ - **インストール済みのツールと追加設定なしで連携**: fzf でファイル名検索、rga で内容検索、bat でプレビューのシンタックスハイライト、zoxide でディレクトリ履歴から移動できます
19
+ - **Windows にも対応**: PowerShell スクリプトの実行に対応し、Windows のターミナルに合わせたキー入力処理を備えています
20
+ - **挙動をソースで追いやすい**: Ruby を中心とした実装で、必要な処理を自分で確認・修正できます。セキュリティに関する設計は [SECURITY.md](./SECURITY.md) にまとめています
31
21
 
32
22
  ## 特徴
33
23
 
34
- ### ツールランタイムとして
24
+ ### スクリプト作業のために
35
25
 
36
26
  - **マルチ言語スクリプト対応**: Ruby, Python, PowerShell
37
27
  - **スクリプトパス管理**: 複数のスクリプトディレクトリを登録・管理
data/SECURITY.md ADDED
@@ -0,0 +1,95 @@
1
+ # Security Policy / セキュリティポリシー
2
+
3
+ [English](#english) | [日本語](#日本語)
4
+
5
+ ## English
6
+
7
+ ### Supported versions
8
+
9
+ Only the latest released version receives security fixes. Please upgrade with `gem update rufio` before reporting.
10
+
11
+ ### Reporting a vulnerability
12
+
13
+ Please **do not open a public issue** for security problems.
14
+
15
+ - Use GitHub's private reporting: [Security → Report a vulnerability](https://github.com/masisz/rufio/security/advisories/new)
16
+ - Or email masisz.1567@gmail.com
17
+
18
+ Include the rufio version, OS, steps to reproduce, and the impact you expect. This is a personal project, so responses are best-effort, but reports are taken seriously and fixes are noted in [CHANGELOG.md](./CHANGELOG.md) under `Security`.
19
+
20
+ ### Threat model
21
+
22
+ rufio is a local TUI tool run by you, on files you can already access.
23
+
24
+ **In scope** (treated as vulnerabilities):
25
+ - Names or contents of files, directories, archives, or tool output causing unintended command execution (e.g. shell metacharacters in file names)
26
+ - Escape sequences in file contents or names that manipulate the terminal in harmful ways
27
+ - Unsafe handling of paths that lets an operation affect files outside what the user selected
28
+ - Secrets exposed through logs or temporary files
29
+
30
+ **Out of scope** (by design):
31
+ - Commands you type yourself in command mode (`:`, `!`) — they are executed as shell commands
32
+ - Code in your own configuration: `~/.rufio/commands.rb` and `~/.config/rufio/commands.rb` are **evaluated as Ruby**. Keep them writable only by you
33
+ - Scripts you register under script paths — they run with your privileges
34
+ - Vulnerabilities in external tools (fzf, rga, bat, zoxide, editors)
35
+
36
+ ### Design practices
37
+
38
+ - Files and scripts are launched in array form (`system(*argv)`), never through a shell string; paths beginning with `-` are prefixed with `./`
39
+ - Search queries are passed to rga after `--`
40
+ - YAML is loaded with `YAML.safe_load`
41
+ - Command execution logs are written with `0600` permissions
42
+ - Runtime dependencies are limited to `io-console`, `pastel`, `tty-cursor`, `tty-screen`
43
+ - Gems are published from tagged commits via RubyGems Trusted Publishing (no long-lived API key); CI runs the test suite before publishing
44
+
45
+ ### Known limitations
46
+
47
+ - Text previews only detect binary files (by control-character ratio); terminal escape sequences inside otherwise-textual files are not explicitly stripped. Avoid previewing untrusted files in a terminal you do not trust
48
+ - The optional native extension under `lib_zig` is not shipped in the gem and has not been independently audited
49
+
50
+ ---
51
+
52
+ ## 日本語
53
+
54
+ ### サポート対象バージョン
55
+
56
+ セキュリティ修正は最新のリリースにのみ行います。報告の前に `gem update rufio` で更新してください。
57
+
58
+ ### 脆弱性の報告
59
+
60
+ セキュリティ上の問題は**公開Issueに書かない**でください。
61
+
62
+ - GitHubの非公開報告: [Security → Report a vulnerability](https://github.com/masisz/rufio/security/advisories/new)
63
+ - またはメール: masisz.1567@gmail.com
64
+
65
+ rufioのバージョン、OS、再現手順、想定される影響を添えてください。個人プロジェクトのため対応はベストエフォートですが、報告は真剣に扱い、修正は [CHANGELOG.md](./CHANGELOG.md) の `Security` に記載します。
66
+
67
+ ### 脅威モデル
68
+
69
+ rufioは、あなた自身がアクセスできるファイルに対して、ローカルで実行するTUIツールです。
70
+
71
+ **対象(脆弱性として扱う)**:
72
+ - ファイル名・ディレクトリ名・アーカイブ・ツール出力の内容によって、意図しないコマンドが実行されること(例: ファイル名中のシェルメタ文字)
73
+ - ファイル内容や名前に含まれるエスケープシーケンスによる、有害なターミナル操作
74
+ - パスの扱いの不備により、ユーザーが選択した範囲外のファイルに操作が及ぶこと
75
+ - ログや一時ファイルを通じた機密情報の漏えい
76
+
77
+ **対象外(設計上の仕様)**:
78
+ - コマンドモード(`:`、`!`)で自分で入力したコマンド — シェルコマンドとして実行されます
79
+ - 自分の設定ファイル内のコード — `~/.rufio/commands.rb` と `~/.config/rufio/commands.rb` は**Rubyとして評価**されます。書き込み権限は自分だけにしてください
80
+ - スクリプトパスに登録したスクリプト — あなたの権限で実行されます
81
+ - 外部ツール(fzf、rga、bat、zoxide、エディタ)自体の脆弱性
82
+
83
+ ### 設計上の方針
84
+
85
+ - ファイルやスクリプトは配列形式(`system(*argv)`)で起動し、シェル文字列を介しません。`-` で始まるパスには `./` を付与します
86
+ - rga には `--` を挟んで検索語を渡します
87
+ - YAML は `YAML.safe_load` で読み込みます
88
+ - コマンド実行ログは `0600` で保存します
89
+ - 実行時依存gemは `io-console`、`pastel`、`tty-cursor`、`tty-screen` のみです
90
+ - gemはタグ付きコミットからRubyGemsのTrusted Publishingで公開します(長期APIキーなし)。公開前にCIでテストを実行します
91
+
92
+ ### 既知の制約
93
+
94
+ - テキストのプレビューはバイナリ判定(制御文字の比率)のみで、テキストとして扱われるファイル内のエスケープシーケンスは明示的に除去していません。信頼できないファイルを、信頼できないターミナルでプレビューするのは避けてください
95
+ - `lib_zig` のネイティブ拡張(任意機能)はgemに同梱しておらず、第三者による監査も受けていません
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'text_utils'
4
+ require_relative 'dialog_renderer'
5
+ require_relative 'config_loader'
6
+
7
+ module Rufio
8
+ # メインループを止めずに表示するヘルプメニュー。
9
+ class HelpMenu
10
+ SECTIONS = %w[Controls Modes Scripts].freeze
11
+ attr_reader :scroll_offset
12
+
13
+ def initialize
14
+ @active = false
15
+ @section_index = 0
16
+ @scroll_offset = 0
17
+ @max_scroll = 0
18
+ end
19
+
20
+ def open
21
+ @active = true
22
+ @section_index = 0
23
+ @scroll_offset = 0
24
+ end
25
+
26
+ def active?
27
+ @active
28
+ end
29
+
30
+ def section
31
+ SECTIONS[@section_index]
32
+ end
33
+
34
+ def handle_key(key)
35
+ case key
36
+ when "\e", 'q', '?' then @active = false
37
+ when '1', '2', '3' then select_section(key.to_i - 1)
38
+ when "\t", 'l' then select_section((@section_index + 1) % SECTIONS.length)
39
+ when 'h', "\e[Z" then select_section((@section_index - 1) % SECTIONS.length)
40
+ when 'j' then @scroll_offset = [@scroll_offset + 1, @max_scroll].min
41
+ when 'k' then @scroll_offset = [@scroll_offset - 1, 0].max
42
+ when "\x04" then @scroll_offset = [@scroll_offset + @page_size.to_i, @max_scroll].min
43
+ when "\x15" then @scroll_offset = [@scroll_offset - @page_size.to_i, 0].max
44
+ when 'g' then @scroll_offset = 0
45
+ when 'G' then @scroll_offset = @max_scroll
46
+ end
47
+ true
48
+ end
49
+
50
+ def content
51
+ case section
52
+ when 'Controls'
53
+ [
54
+ 'Navigation',
55
+ "#{key(:move_down)}/#{key(:move_up)} or arrows: Move down/up",
56
+ "#{key(:navigate_parent)}/#{key(:navigate_enter)}: Parent / enter directory",
57
+ 'Enter: Open file preview | ESC: Back to file list',
58
+ 'Preview: j/k scroll, Ctrl+D/U page down/up',
59
+ "#{key(:top)}/#{key(:bottom)}: First / last entry",
60
+ "#{key(:open_file)}: Open in external editor",
61
+ "#{key(:refresh)}: Refresh directory",
62
+ '', 'Selection and file operations',
63
+ "#{key(:select)}: Select / unselect file",
64
+ "#{key(:copy_selected)}/#{key(:move_selected)}/#{key(:delete_selected)}: Copy / move / delete selected files",
65
+ "#{key(:rename)}/#{key(:delete)}: Rename / delete current file",
66
+ "#{key(:create_file)}/#{key(:create_dir)}: Create file / directory",
67
+ '', 'Search and bookmarks',
68
+ "#{key(:filter)}: Filter | Enter: Apply | ESC: Clear",
69
+ "#{key(:fzf_search)}: Filename search (fzf)",
70
+ "#{key(:rga_search)}: Content search (rga)",
71
+ "#{key(:add_bookmark)}/#{key(:bookmark_menu)}: Add / manage bookmarks",
72
+ 'Tab / Shift+Tab: Next / previous bookmark',
73
+ "1-9: Jump to bookmark | #{key(:start_dir)}: Start directory",
74
+ "#{key(:zoxide)}: Directory history (zoxide)",
75
+ "#{key(:quit)}: Quit (with confirmation)"
76
+ ]
77
+ when 'Modes'
78
+ [
79
+ 'Files', 'Browse directories, select files and view previews.',
80
+ '', "[#{key(:log_viewer)}] Logs",
81
+ 'Browse command logs. Enter opens a preview.',
82
+ 'ESC: Leave preview; ESC again: Return to Files.',
83
+ '', "[#{key(:job_mode)}] Jobs",
84
+ 'View background commands and their status.',
85
+ 'Space: View log | x: Cancel job | ESC: Back',
86
+ '', "[#{key(:help)}] Help",
87
+ 'This floating menu keeps your current mode and directory.',
88
+ '1/2/3 or Tab: Select section | ESC: Close',
89
+ '', "[#{key(:command_mode)}] Command",
90
+ 'Type a command, then Enter to run it.',
91
+ 'Tab: Complete | Up/Down: History | ESC: Cancel',
92
+ ':!git status: Run a shell command',
93
+ ':@hello.rb: Run a script in the current directory'
94
+ ]
95
+ when 'Scripts'
96
+ [
97
+ '1. Personal scripts',
98
+ 'Place scripts in ~/.config/rufio/scripts/',
99
+ 'Example: ~/.config/rufio/scripts/hello.rb',
100
+ 'Press : and type hello, then Enter (:hello).',
101
+ '', '2. Additional script folders',
102
+ 'List folders in ~/.config/rufio/script_paths.yml:',
103
+ '- ~/.config/rufio/scripts', '- ~/my-scripts',
104
+ 'Folders are searched in order. First matching name wins.',
105
+ '', '3. Project scripts',
106
+ 'Place hello.rb or hello.sh in the directory you browse.',
107
+ 'Run it with :@hello.rb or :@hello.sh.',
108
+ 'Project search paths: ./rufio.yml, script_paths list.',
109
+ '', '4. Run and monitor',
110
+ 'Tab completes script names. Up/Down recalls commands.',
111
+ "#{key(:job_mode)}: Background jobs | #{key(:log_viewer)}: Execution logs",
112
+ 'Supported: Ruby, shell, Python and other script types.'
113
+ ]
114
+ end
115
+ end
116
+
117
+ def draw(screen)
118
+ width = [screen.width, 78].min
119
+ height = [screen.height, 26].min
120
+ return if width < 8 || height < 8
121
+
122
+ @page_size = height - 7
123
+ lines = content.flat_map { |line| line.empty? ? [''] : TextUtils.wrap_preview_lines([line], width - 4) }
124
+ @max_scroll = [lines.length - @page_size, 0].max
125
+ @scroll_offset = [@scroll_offset, @max_scroll].min
126
+ tabs = SECTIONS.each_with_index.map do |name, index|
127
+ index == @section_index ? "[#{index + 1}:#{name}]" : " #{index + 1}:#{name} "
128
+ end.join(' ')
129
+ visible = [TextUtils.truncate_to_width(tabs, width - 2), '']
130
+ visible.concat(lines.slice(@scroll_offset, @page_size) || [])
131
+ visible << '' while visible.length < height - 5
132
+ visible << TextUtils.truncate_to_width('ESC: Close | Tab: Menu | j/k: Scroll', width - 2)
133
+ screen.enable_overlay
134
+ screen.clear_overlay
135
+ title = "Help - #{section} (#{@scroll_offset + 1}/#{@max_scroll + 1})"
136
+ DialogRenderer.new.draw_floating_window_to_overlay(
137
+ screen, (screen.width - width) / 2, (screen.height - height) / 2,
138
+ width, height, TextUtils.truncate_to_width(title, width - 2), visible,
139
+ border_color: "\e[36m", title_color: "\e[1;36m"
140
+ )
141
+ end
142
+
143
+ private
144
+
145
+ def select_section(index)
146
+ @section_index = index
147
+ @scroll_offset = 0
148
+ end
149
+
150
+ def key(action)
151
+ value = ConfigLoader.keybinds[action]
152
+ value == ' ' ? 'Space' : value.to_s
153
+ end
154
+ end
155
+ end
@@ -130,6 +130,10 @@ module Rufio
130
130
  def handle_key(key)
131
131
  return false unless @directory_listing
132
132
 
133
+ if @key_map[key] == :help && !@filter_manager.filter_mode
134
+ return show_help_dialog
135
+ end
136
+
133
137
  # ジョブモード中の特別処理
134
138
  if @job_mode.active?
135
139
  return handle_job_mode_key(key)
@@ -217,6 +221,9 @@ module Rufio
217
221
  # ヘルプモードに入る
218
222
  def enter_help_mode
219
223
  return false unless @directory_listing
224
+ return true if @in_help_mode
225
+
226
+ exit_log_viewer_mode if @in_log_viewer_mode
220
227
 
221
228
  # 現在のディレクトリを保存
222
229
  @pre_help_directory = @directory_listing.current_path
@@ -264,6 +271,9 @@ module Rufio
264
271
  # ログビューワモードに入る
265
272
  def enter_log_viewer_mode
266
273
  return false unless @directory_listing
274
+ return true if @in_log_viewer_mode
275
+
276
+ exit_help_mode if @in_help_mode
267
277
 
268
278
  # 現在のディレクトリを保存
269
279
  @pre_log_viewer_directory = @directory_listing.current_path
@@ -488,7 +498,7 @@ module Rufio
488
498
  when :zoxide then show_zoxide_menu
489
499
  when :start_dir then goto_start_directory
490
500
  when :job_mode then enter_job_mode
491
- when :help then enter_help_mode
501
+ when :help then show_help_dialog
492
502
  when :log_viewer then enter_log_viewer_mode
493
503
  when :command_mode then activate_command_mode
494
504
  when :quit then exit_request
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'io/console'
4
4
  require_relative 'text_utils'
5
+ require_relative 'help_menu'
5
6
 
6
7
  module Rufio
7
8
  class TerminalUI
@@ -51,6 +52,7 @@ module Rufio
51
52
  @input_queue = nil
52
53
  @input_thread = nil
53
54
  @command_mode_active = false
55
+ @help_menu = HelpMenu.new
54
56
  @command_input = ""
55
57
  @command_mode = CommandMode.new
56
58
  @dialog_renderer = DialogRenderer.new
@@ -494,8 +496,10 @@ module Rufio
494
496
  draw_screen_to_buffer(@screen, nil, current_fps)
495
497
  end
496
498
 
497
- # コマンドモードがアクティブな場合はオーバーレイにダイアログを描画
498
- if @command_mode_active
499
+ # ヘルプまたはコマンドモードのダイアログをオーバーレイに描画
500
+ if help_dialog_active?
501
+ @help_menu.draw(@screen)
502
+ elsif @command_mode_active
499
503
  # 前回のオーバーレイ残留を防ぐためクリアしてから描画
500
504
  @screen.clear_overlay if @screen.overlay_enabled?
501
505
  draw_command_mode_to_overlay
@@ -598,7 +602,13 @@ module Rufio
598
602
  when 'B' then 'j' # Down arrow
599
603
  when 'C' then 'l' # Right arrow
600
604
  when 'D' then 'h' # Left arrow
601
- when 'Z' then handle_shift_tab; return true # Shift+Tab
605
+ when 'Z'
606
+ if help_dialog_active?
607
+ handle_help_input("\e[Z")
608
+ else
609
+ handle_shift_tab
610
+ end
611
+ return true # Shift+Tab
602
612
  else
603
613
  # 未知の CSI シーケンス(\e[27;1u 等): 残りバイトを読み捨てて
604
614
  # パイプを汚染しないようにする
@@ -610,6 +620,8 @@ module Rufio
610
620
  end
611
621
  end
612
622
 
623
+ return handle_help_input(input) if help_dialog_active?
624
+
613
625
  # TabキーはFilesモードの時のみブックマーク循環移動(ジョブモード中は無効)
614
626
  if input == "\t" && @tab_mode_manager.current_mode == :files && !@in_job_mode
615
627
  handle_tab_key
@@ -692,6 +704,12 @@ module Rufio
692
704
  # @param row [Integer] クリック行(1-indexed)
693
705
  # @param press [Boolean] true=押下, false=解放
694
706
  def handle_mouse_event(btn, col, row, press)
707
+ if help_dialog_active?
708
+ handle_help_input('k') if btn == 64
709
+ handle_help_input('j') if btn == 65
710
+ return
711
+ end
712
+
695
713
  case btn
696
714
  when 0 # 左クリック(押下のみ処理)
697
715
  handle_mouse_left_click(col, row) if press
@@ -784,12 +802,7 @@ module Rufio
784
802
  @keybind_handler.send(:exit_job_mode)
785
803
  end
786
804
  when :help
787
- # ヘルプモードに入る
788
- unless @keybind_handler.help_mode?
789
- @keybind_handler.send(:exit_log_viewer_mode) if @keybind_handler.log_viewer_mode?
790
- @keybind_handler.send(:exit_job_mode) if @keybind_handler.in_job_mode?
791
- @keybind_handler.send(:enter_help_mode)
792
- end
805
+ show_help_dialog
793
806
  when :logs
794
807
  # ログビューワモードに入る
795
808
  unless @keybind_handler.log_viewer_mode?
@@ -1191,61 +1204,19 @@ module Rufio
1191
1204
  # Screen と Renderer のアクセサ(他のクラスから利用可能に)
1192
1205
  attr_reader :screen, :renderer
1193
1206
 
1194
- # ヘルプダイアログを表示
1207
+ # ヘルプは非同期オーバーレイとして表示し、元のモードを保持する。
1195
1208
  def show_help_dialog
1196
- content_lines = [
1197
- '',
1198
- "rufio v#{VERSION}",
1199
- '',
1200
- 'Key Bindings:',
1201
- '',
1202
- 'j/k - Move up/down',
1203
- 'h/l - Navigate back/enter',
1204
- 'g/G - Go to top/bottom',
1205
- 'o - Open file',
1206
- 'f - Filter files',
1207
- 's - Search with fzf',
1208
- 'F - Content search (rga)',
1209
- 'a/A - Create file/directory',
1210
- 'm/c/x - Move/Copy/Delete',
1211
- 'b - Add bookmark',
1212
- 'z - Zoxide navigation',
1213
- '0 - Go to start directory',
1214
- '1-9 - Go to bookmark',
1215
- 'J - Job mode',
1216
- ': - Command mode',
1217
- 'q - Quit',
1218
- ''
1219
- ]
1220
-
1221
- # お知らせ情報を追加
1222
- require_relative 'info_notice'
1223
- info_notice = InfoNotice.new
1224
- all_notices = Dir.glob(File.join(info_notice.info_dir, '*.txt'))
1225
-
1226
- if !all_notices.empty?
1227
- content_lines << 'Recent Updates:'
1228
- content_lines << ''
1229
- all_notices.take(3).each do |file|
1230
- title = info_notice.extract_title(file)
1231
- content_lines << " • #{title}"
1232
- end
1233
- content_lines << ''
1234
- end
1235
-
1236
- content_lines << 'Press any key to continue...'
1209
+ @help_menu.open
1210
+ true
1211
+ end
1237
1212
 
1238
- width = 60
1239
- height = [content_lines.length + 4, @screen_height - 4].min
1213
+ def help_dialog_active?
1214
+ @help_menu.active?
1215
+ end
1240
1216
 
1241
- # オーバーレイダイアログを表示
1242
- show_overlay_dialog('rufio - Help', content_lines, {
1243
- width: width,
1244
- height: height,
1245
- border_color: "\e[36m", # Cyan
1246
- title_color: "\e[1;36m", # Bold cyan
1247
- content_color: "\e[37m" # White
1248
- })
1217
+ def handle_help_input(input)
1218
+ @help_menu.handle_key(input)
1219
+ true
1249
1220
  end
1250
1221
 
1251
1222
  # 未知の CSI シーケンス(\e[X...)の残りバイトを終端アルファベットまで読み捨てる。
@@ -401,6 +401,10 @@ module Rufio
401
401
  header += ' ' * remaining_space if remaining_space > 0
402
402
  screen.put_string(content_x, line_num, header)
403
403
 
404
+ elsif i == 1 && @keybind_handler&.preview_focused?
405
+ hint = TextUtils.truncate_to_width(' ESC: Back to files', safe_width)
406
+ screen.put_string(content_x, line_num, hint + ' ' * (safe_width - TextUtils.display_width(hint)))
407
+
404
408
  elsif i >= 2 && highlighted_wrapped_lines
405
409
  # シンタックスハイライト付きコンテンツ
406
410
  scroll_offset = @keybind_handler&.preview_scroll_offset || 0
@@ -583,7 +587,7 @@ module Rufio
583
587
 
584
588
  modes.each_with_index do |mode, index|
585
589
  key = keys[mode]
586
- label = key ? " #{key}:#{labels[mode]} " : " #{labels[mode]} "
590
+ label = key ? " [#{key}] #{labels[mode]} " : " #{labels[mode]} "
587
591
 
588
592
  if mode == current_mode
589
593
  label.each_char do |char|
data/lib/rufio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rufio
4
- VERSION = '1.0.3'
4
+ VERSION = '1.0.4'
5
5
  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: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - masisz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-23 00:00:00.000000000 Z
11
+ date: 2026-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -121,6 +121,7 @@ files:
121
121
  - README.md
122
122
  - README_ja.md
123
123
  - Rakefile
124
+ - SECURITY.md
124
125
  - bin/rufio
125
126
  - docs/CHANGELOG_v0.10.0.md
126
127
  - docs/CHANGELOG_v0.20.0.md
@@ -175,6 +176,7 @@ files:
175
176
  - lib/rufio/file_preview.rb
176
177
  - lib/rufio/filter_manager.rb
177
178
  - lib/rufio/health_checker.rb
179
+ - lib/rufio/help_menu.rb
178
180
  - lib/rufio/info_notice.rb
179
181
  - lib/rufio/interpreter_resolver.rb
180
182
  - lib/rufio/job_manager.rb