rufio 0.65.0 → 0.70.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c80ee03ac65fdfbf06623c7702795bdbaced929d40e72739f599d43eb8d240ef
4
- data.tar.gz: 8bc1a41cd84d762923e6f4785542c8ad4de418c804d0b30150d4217dac0168bd
3
+ metadata.gz: f7c56fe39c80425ba94128d7e8531584e1d7530d9eb78d323b59d34563df1fe3
4
+ data.tar.gz: 659fe182e9aace392e902151caac5a289b969db060f31f7176c2545e22d452c8
5
5
  SHA512:
6
- metadata.gz: c42bffef8f63ed300ef17a960625e0e5b5b20735e1f326fba26691e7731c37a0f24a09194b2c51d10e758e4c44710f0e938781e47e0662ba63a1b7afce760195
7
- data.tar.gz: 7033a73f5a0c124eb9fa722e614a7a28f17972872a4cbe8d7682558ba7760852c3c10db6226e5771222ddb94e1f9a68dbe686f1b621c0dee6ae45073aae47a2a
6
+ metadata.gz: 01fe9fe08f1e494eafcfc18aeb1a8b208c6406b60525d81a6b0ebebe3131fa8388f3b86631d7ae2ea15ec02f20eaf21d3daaa01eec6a011174050750b5f51fb4
7
+ data.tar.gz: 4920c3320a0df0d87b0af4b410b59722efce3163f53f5098c5ceadcb45f5124b49f4c0774d9e22daef1d293f3417a1fa397977932946a776210f4452bf141ecb
data/CHANGELOG.md CHANGED
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.70.0] - 2026-02-14
11
+
12
+ ### Added
13
+ - **Local Script Scanning**: Automatically detect script files (`.sh`, `.rb`, `.py`, `.pl`, `.js`, `.ts`, `.ps1`) in the currently browsed directory
14
+ - Displayed and executable as `@script.sh` format in command mode
15
+ - Falls back to local scripts when not found in registered script paths
16
+ - Cached per directory with automatic invalidation on directory change
17
+ - **Rakefile Task Execution**: Parse Rakefile to extract task names and execute them
18
+ - `rake:task_name` format in command mode (e.g., `:rake:test`, `:rake:build`)
19
+ - Supports `Rakefile`, `rakefile`, `Rakefile.rb`
20
+ - Recognizes symbol, string, and hash-style task definitions
21
+ - **Rake Task Tab Completion**: Full Tab completion support for rake tasks
22
+ - `rake:` prefix triggers task-specific completion
23
+ - Partial input (`r`, `rak`, `rake`) also suggests matching `rake:xxx` commands
24
+ - Common prefix completion (e.g., `rak` → `rake:`)
25
+ - **New classes**: `LocalScriptScanner`, `RakefileParser`
26
+ - **New tests**: `test_local_script_scanner.rb` (16 tests), `test_rakefile_parser.rb` (19 tests), `test_command_mode_local.rb` (11 tests), `test_command_completion_local.rb` (13 tests), `test_overlay_clearing.rb` (2 tests)
27
+
28
+ ### Fixed
29
+ - **Floating window border remnants**: Fixed old dialog borders remaining when switching between overlay dialogs (e.g., command prompt → completion list)
30
+ - Added `@screen.clear_overlay` in `show_overlay_dialog` before drawing new dialog
31
+ - Added overlay clearing before each frame's `draw_command_mode_to_overlay` in main loop
32
+ - **CommandResult display artifact**: Fixed command window top border remaining visible when showing command execution results
33
+ - Root cause: `execute_command` called legacy `draw_screen` (direct terminal print) which has a coordinate offset from the overlay-based rendering system
34
+ - Removed `draw_screen` call from `execute_command`, letting the main loop handle re-rendering via the buffer system
35
+
36
+ ### Changed
37
+ - **CommandMode**: Added `update_browsing_directory` method, `rake:` routing, local script fallback
38
+ - **CommandCompletion**: Added rake task and local script completion integration
39
+ - **TerminalUI**: `activate_command_mode` now notifies `CommandMode` of current browsing directory
40
+
41
+ ### Technical Details
42
+ - **New files**: `lib/rufio/local_script_scanner.rb`, `lib/rufio/rakefile_parser.rb`, 5 test files
43
+ - **Modified files**: `lib/rufio.rb`, `lib/rufio/command_mode.rb`, `lib/rufio/command_completion.rb`, `lib/rufio/terminal_ui.rb`
44
+ - **Test coverage**: 821 runs, 2816 assertions, 0 failures
45
+
10
46
  ## [0.65.0] - 2026-02-14
11
47
 
12
48
  ### Changed
data/README.md CHANGED
@@ -145,8 +145,18 @@ Press `:` to enter command mode and execute various commands.
145
145
  ```
146
146
  :@build # @ prefix triggers script completion
147
147
  :@deploy.rb # Execute registered script
148
+ :@local.sh # Scripts in current directory are also available
148
149
  ```
149
150
 
151
+ ### Rake Task Execution
152
+
153
+ ```
154
+ :rake:test # Execute rake task
155
+ :rake:build # Tab completion supported
156
+ ```
157
+
158
+ Rakefile in the current directory is automatically parsed. Supports `Rakefile`, `rakefile`, `Rakefile.rb`.
159
+
150
160
  ### Shell Commands
151
161
 
152
162
  ```
@@ -182,8 +192,11 @@ Press `B` → `3` to open the script path management menu:
182
192
  |-----------|----------|
183
193
  | `.rb` | Ruby |
184
194
  | `.py` | Python |
185
- | `.ps1` | PowerShell |
186
195
  | `.sh` | Shell (bash/zsh) |
196
+ | `.js` | JavaScript (Node.js) |
197
+ | `.ts` | TypeScript (ts-node/deno) |
198
+ | `.pl` | Perl |
199
+ | `.ps1` | PowerShell |
187
200
 
188
201
  ## DSL Commands
189
202
 
data/info/help.md CHANGED
@@ -1,16 +1,17 @@
1
1
  # rufio Help
2
2
 
3
- **rufio** is a terminal-based file manager inspired by Yazi.
3
+ **rufio** is a terminal-based file manager and tool runtime environment.
4
4
 
5
5
  ## Table of Contents
6
6
 
7
7
  - [Basic Operations](#basic-operations)
8
- - [Navigation](#navigation)
9
8
  - [File Operations](#file-operations)
10
9
  - [File Selection & Bulk Operations](#file-selection--bulk-operations)
11
10
  - [Filtering & Search](#filtering--search)
12
- - [Bookmarks](#bookmarks)
13
- - [Other Features](#other-features)
11
+ - [Bookmarks & Navigation](#bookmarks--navigation)
12
+ - [Command Mode](#command-mode)
13
+ - [Tool Runtime](#tool-runtime)
14
+ - [Mode Switching](#mode-switching)
14
15
 
15
16
  ---
16
17
 
@@ -20,10 +21,10 @@
20
21
 
21
22
  | Key | Action |
22
23
  |-----|--------|
23
- | `j` or `↓` | Move down one item |
24
- | `k` or `↑` | Move up one item |
25
- | `h` or `←` | Go to parent directory |
26
- | `l`, `Enter`, or `→` | Enter directory / Select file |
24
+ | `j` or `Down` | Move down one item |
25
+ | `k` or `Up` | Move up one item |
26
+ | `h` or `Left` | Go to parent directory |
27
+ | `l`, `Enter`, or `Right` | Enter directory / Open file |
27
28
  | `g` | Jump to top of list |
28
29
  | `G` | Jump to bottom of list |
29
30
 
@@ -61,33 +62,78 @@
61
62
  - Press `Enter` to apply filter and exit filter mode
62
63
  - Press `ESC` to cancel and clear filter
63
64
 
64
- ### Bookmarks
65
+ ### Bookmarks & Navigation
65
66
 
66
67
  | Key | Action |
67
68
  |-----|--------|
68
69
  | `b` | Add current directory to bookmarks |
70
+ | `B` | Bookmark menu (view/add/remove/script paths) |
69
71
  | `0` | Jump to startup directory |
70
72
  | `1-9` | Jump to bookmark 1-9 |
71
- | `p` | Enter project mode (browse bookmarks) |
73
+ | `z` | Navigate using zoxide history |
74
+
75
+ ---
76
+
77
+ ## Command Mode
78
+
79
+ Press `:` to enter command mode. Available prefixes:
80
+
81
+ | Prefix | Function | Example |
82
+ |--------|----------|---------|
83
+ | `@` | Execute script | `:@build.sh` |
84
+ | `rake:` | Execute rake task | `:rake:test` |
85
+ | `!` | Shell command | `:!git status` |
86
+ | (none) | Built-in command | `:hello` |
72
87
 
73
- **Project Mode:**
74
- - Browse all bookmarks with normal navigation keys
75
- - Press `Space` to select a bookmark and jump to it
76
- - Press `ESC` to exit project mode
88
+ ### Features
77
89
 
78
- ### Other Features
90
+ - **Tab completion**: Press `Tab` to auto-complete commands, scripts, and rake tasks
91
+ - **Command history**: Use `Up/Down` arrows to navigate previous commands
92
+ - **Local scripts**: Scripts in the current directory are automatically available with `@` prefix
93
+ - **Rakefile parsing**: Tasks from `Rakefile` in the current directory are available as `rake:task_name`
94
+
95
+ ---
96
+
97
+ ## Tool Runtime
79
98
 
80
99
  | Key | Action |
81
100
  |-----|--------|
82
- | `z` | Navigate using zoxide history |
83
101
  | `:` | Enter command mode |
84
- | `?` | Enter help mode (this mode) |
85
- | `ESC` | Exit help mode / Cancel filter |
86
- | `q` | Quit rufio |
102
+ | `J` | Job mode (view background jobs) |
103
+ | `L` | View execution logs |
104
+
105
+ ### Script Path Management
106
+
107
+ Press `B` then select script path management to:
108
+ - View registered script directories
109
+ - Add/remove script paths
110
+ - Jump to script directories
111
+
112
+ ### Supported Script Types
113
+
114
+ | Extension | Language |
115
+ |-----------|----------|
116
+ | `.rb` | Ruby |
117
+ | `.py` | Python |
118
+ | `.sh` | Shell (bash/zsh) |
119
+ | `.js` | JavaScript |
120
+ | `.ts` | TypeScript |
121
+ | `.pl` | Perl |
122
+ | `.ps1` | PowerShell |
87
123
 
88
124
  ---
89
125
 
90
- ## Help Mode
126
+ ## Mode Switching
127
+
128
+ | Key | Action |
129
+ |-----|--------|
130
+ | `Tab` | Switch mode: Files -> Logs -> Jobs -> Help |
131
+ | `Shift+Tab` | Switch mode (reverse) |
132
+ | `?` | Enter help mode (this mode) |
133
+ | `ESC` | Exit current mode |
134
+ | `q` | Quit rufio |
135
+
136
+ ### Help Mode
91
137
 
92
138
  You are currently in **Help Mode**. In this mode:
93
139
 
@@ -104,7 +150,8 @@ You are currently in **Help Mode**. In this mode:
104
150
  2. **Bulk operations**: Select multiple files with `Space`, then use `m/c/x`
105
151
  3. **Filter + Search**: Use `f` for real-time filtering, `s` for fuzzy search
106
152
  4. **Bookmarks**: Save frequently used directories with `b`, access with `1-9`
107
- 5. **Project mode**: Press `p` to see all bookmarks at once
153
+ 5. **Rake tasks**: If your project has a Rakefile, use `:rake:` with Tab completion
154
+ 6. **Background jobs**: Long-running commands execute in background, view with `J`
108
155
 
109
156
  ---
110
157
 
data/info/keybindings.md CHANGED
@@ -6,10 +6,10 @@ Complete reference of all keyboard shortcuts in **rufio**.
6
6
 
7
7
  | Key | Action |
8
8
  |-----|--------|
9
- | `j` / `↓` | Move down |
10
- | `k` / `↑` | Move up |
11
- | `h` / `←` | Go to parent directory |
12
- | `l` / `→` / `Enter` | Enter directory or select file |
9
+ | `j` / `Down` | Move down |
10
+ | `k` / `Up` | Move up |
11
+ | `h` / `Left` | Go to parent directory |
12
+ | `l` / `Right` / `Enter` | Enter directory or open file |
13
13
  | `g` | Jump to top of list |
14
14
  | `G` | Jump to bottom of list |
15
15
 
@@ -42,31 +42,32 @@ Complete reference of all keyboard shortcuts in **rufio**.
42
42
  | `s` | Search file names with fzf |
43
43
  | `F` | Search file contents with rga |
44
44
 
45
- ## Bookmarks
45
+ ## Bookmarks & Navigation
46
46
 
47
47
  | Key | Action |
48
48
  |-----|--------|
49
49
  | `b` | Add current directory to bookmarks |
50
+ | `B` | Bookmark menu (view/add/remove/script paths) |
50
51
  | `0` | Jump to startup directory |
51
- | `1` | Jump to bookmark 1 |
52
- | `2` | Jump to bookmark 2 |
53
- | `3` | Jump to bookmark 3 |
54
- | `4` | Jump to bookmark 4 |
55
- | `5` | Jump to bookmark 5 |
56
- | `6` | Jump to bookmark 6 |
57
- | `7` | Jump to bookmark 7 |
58
- | `8` | Jump to bookmark 8 |
59
- | `9` | Jump to bookmark 9 |
60
- | `p` | Enter project mode (browse all bookmarks) |
61
-
62
- ## Other
52
+ | `1-9` | Jump to bookmark 1-9 |
53
+ | `z` | Navigate using zoxide history |
54
+
55
+ ## Command Mode & Tool Runtime
63
56
 
64
57
  | Key | Action |
65
58
  |-----|--------|
66
- | `z` | Navigate using zoxide history |
67
59
  | `:` | Enter command mode |
60
+ | `J` | Job mode (view background jobs) |
61
+ | `L` | View execution logs |
62
+
63
+ ## Mode Switching
64
+
65
+ | Key | Action |
66
+ |-----|--------|
67
+ | `Tab` | Switch mode: Files -> Logs -> Jobs -> Help |
68
+ | `Shift+Tab` | Switch mode (reverse direction) |
68
69
  | `?` | Enter help mode |
69
- | `ESC` | Exit current mode (help/filter/project) |
70
+ | `ESC` | Exit current mode (help/filter/command) |
70
71
  | `q` | Quit rufio |
71
72
 
72
73
  ---
@@ -79,15 +80,28 @@ Complete reference of all keyboard shortcuts in **rufio**.
79
80
  - **Enter**: Apply filter and exit filter mode
80
81
  - **ESC**: Cancel filter and exit filter mode
81
82
 
82
- ### Project Mode
83
- - **j/k**: Navigate through bookmarks
84
- - **Space**: Select bookmark and jump to directory
85
- - **ESC**: Exit project mode
83
+ ### Command Mode
84
+ - **Any character**: Add to command input
85
+ - **Tab**: Auto-complete (scripts, rake tasks, commands)
86
+ - **Up/Down**: Navigate command history
87
+ - **Enter**: Execute command
88
+ - **Backspace**: Remove last character
89
+ - **ESC**: Cancel and exit command mode
90
+
91
+ ### Command Mode Prefixes
92
+ - `@script` - Execute a registered or local script
93
+ - `rake:task` - Execute a Rakefile task
94
+ - `!command` - Execute a shell command
95
+ - `command` - Execute a built-in or plugin command
86
96
 
87
97
  ### Help Mode
88
98
  - **j/k/h/l**: Navigate help files
89
99
  - **ESC**: Exit help mode and return to previous directory
90
100
 
101
+ ### Job Mode
102
+ - **j/k**: Navigate through jobs
103
+ - **ESC**: Exit job mode
104
+
91
105
  ---
92
106
 
93
107
  ## Tips
@@ -96,6 +110,8 @@ Complete reference of all keyboard shortcuts in **rufio**.
96
110
  - **Selection**: Use `Space` to mark multiple files, then operate on all at once
97
111
  - **Quick access**: Number keys `1-9` provide instant access to bookmarks
98
112
  - **Filtering**: Press `f` and start typing for real-time filtering
113
+ - **Rake tasks**: Type `:rake:` then `Tab` to see available tasks
114
+ - **Local scripts**: Scripts in the current directory are auto-detected with `@` prefix
99
115
 
100
116
  ---
101
117
 
data/info/welcome.md CHANGED
@@ -1,15 +1,18 @@
1
- # Welcome to rufio! 🚀
1
+ # Welcome to rufio!
2
2
 
3
- Thank you for using **rufio** - a terminal-based file manager inspired by [Yazi](https://github.com/sxyazi/yazi).
3
+ **Runtime Unified Flow I/O Operator**
4
+
5
+ A TUI file manager that executes and coordinates tools and scripts from files.
4
6
 
5
7
  ## Key Features
6
8
 
7
- - **Vim-like keybindings** - Navigate with `j/k/h/l` keys
8
- - **Real-time filtering** - Press `f` to filter files instantly
9
- - **Advanced search** - Use `fzf` for file names and `rga` for content search
10
- - **Bookmark support** - Quick access to favorite directories with number keys
11
- - **Project mode** - Manage multiple projects efficiently
12
- - **Plugin system** - Extend functionality with custom plugins
9
+ - **Tool Runtime** - Execute scripts and rake tasks from command mode
10
+ - **Vim-like Keybindings** - Navigate with `j/k/h/l` keys
11
+ - **Real-time Filtering** - Press `f` to filter files instantly
12
+ - **Advanced Search** - Use `fzf` for file names and `rga` for content search
13
+ - **Bookmark Support** - Quick access to favorite directories
14
+ - **Job Management** - Run commands in the background
15
+ - **Plugin System** - Extend functionality with custom plugins
13
16
 
14
17
  ## Quick Start
15
18
 
@@ -18,12 +21,25 @@ Thank you for using **rufio** - a terminal-based file manager inspired by [Yazi]
18
21
  | `j/k` | Move down/up |
19
22
  | `h/l` | Go to parent / Enter directory |
20
23
  | `f` | Filter files |
24
+ | `s` | Search with fzf |
21
25
  | `b` | Add bookmark |
22
- | `p` | Project mode |
23
- | `?` | Help mode |
26
+ | `B` | Bookmark menu |
27
+ | `z` | zoxide history |
24
28
  | `:` | Command mode |
29
+ | `J` | Job mode |
30
+ | `?` | Help mode |
31
+ | `Tab` | Switch mode (Files / Logs / Jobs / Help) |
25
32
  | `q` | Quit |
26
33
 
34
+ ## Command Mode
35
+
36
+ Press `:` to enter command mode:
37
+
38
+ - `@script.sh` - Execute a script
39
+ - `rake:test` - Execute a rake task
40
+ - `!git status` - Run a shell command
41
+ - `Tab` - Auto-complete commands
42
+
27
43
  ## Getting Help
28
44
 
29
45
  Press `?` to enter **Help Mode** where you can browse all documentation files.
@@ -37,4 +53,4 @@ Visit the GitHub repository for detailed documentation:
37
53
 
38
54
  ---
39
55
 
40
- *Happy file managing! 📁*
56
+ *Happy file managing!*
@@ -16,9 +16,11 @@ module Rufio
16
16
  # @param input [String] 入力されたテキスト
17
17
  # @return [Array<String>] 補完候補のリスト
18
18
  def complete(input)
19
- # 入力が空の場合は内部コマンドとスクリプトを返す
19
+ # 入力が空の場合は内部コマンド + スクリプト + rakeタスクを返す
20
20
  if input.nil? || input.strip.empty?
21
- return @command_mode.available_commands.map(&:to_s) + script_candidates('')
21
+ return @command_mode.available_commands.map(&:to_s) +
22
+ script_candidates('') +
23
+ rake_candidates('')
22
24
  end
23
25
 
24
26
  # シェルコマンド補完(!で始まる場合)
@@ -31,13 +33,23 @@ module Rufio
31
33
  return @command_mode.complete_script(input.strip)
32
34
  end
33
35
 
34
- # 通常のコマンド補完(内部コマンド + スクリプト)
36
+ # rakeタスク補完(rake:で始まる場合)
37
+ if input.strip.start_with?('rake:')
38
+ prefix = input.strip[5..-1]
39
+ return @command_mode.complete_rake_task(prefix)
40
+ end
41
+
42
+ # 通常のコマンド補完(内部コマンド + rakeタスク)
35
43
  available_commands = @command_mode.available_commands.map(&:to_s)
36
44
  input_lower = input.downcase
37
45
  candidates = available_commands.select do |command|
38
46
  command.downcase.start_with?(input_lower)
39
47
  end
40
48
 
49
+ # rakeタスクも候補に追加("r", "ra", "rak", "rake" 等にマッチ)
50
+ rake_tasks = rake_candidates('')
51
+ candidates += rake_tasks.select { |task| task.downcase.start_with?(input_lower) }
52
+
41
53
  candidates
42
54
  end
43
55
 
@@ -67,15 +79,20 @@ module Rufio
67
79
 
68
80
  private
69
81
 
70
- # スクリプト候補を取得
82
+ # スクリプト候補を取得(ScriptRunner + ローカルスクリプト)
71
83
  # @param prefix [String] 入力中の文字列
72
84
  # @return [Array<String>] スクリプト候補(@付き)
73
85
  def script_candidates(prefix)
74
- return [] unless @command_mode&.script_runner
75
-
76
86
  @command_mode.complete_script("@#{prefix}")
77
87
  end
78
88
 
89
+ # rakeタスク候補を取得
90
+ # @param prefix [String] 入力中の文字列
91
+ # @return [Array<String>] rakeタスク候補(rake:付き)
92
+ def rake_candidates(prefix)
93
+ @command_mode.complete_rake_task(prefix)
94
+ end
95
+
79
96
  # シェルコマンドの補完
80
97
  # @param input [String] ! で始まる入力
81
98
  # @return [Array<String>] 補完候補のリスト
@@ -15,6 +15,8 @@ module Rufio
15
15
  @script_runner = nil
16
16
  @script_path_manager = nil
17
17
  @job_manager = nil
18
+ @local_script_scanner = LocalScriptScanner.new
19
+ @rakefile_parser = RakefileParser.new
18
20
  load_builtin_commands
19
21
  load_dsl_commands
20
22
  end
@@ -43,6 +45,13 @@ module Rufio
43
45
  )
44
46
  end
45
47
 
48
+ # 閲覧中ディレクトリを更新
49
+ # @param directory [String] 現在の閲覧ディレクトリ
50
+ def update_browsing_directory(directory)
51
+ @local_script_scanner.update_directory(directory)
52
+ @rakefile_parser.update_directory(directory)
53
+ end
54
+
46
55
  # コマンドを実行する
47
56
  # @param command_string [String] コマンド文字列
48
57
  # @param working_dir [String, nil] 作業ディレクトリ(スクリプト実行時に使用)
@@ -55,6 +64,12 @@ module Rufio
55
64
  return execute_script(command_string.strip[1..-1], working_dir)
56
65
  end
57
66
 
67
+ # rakeタスク実行 (rake: で始まる場合)
68
+ if command_string.strip.start_with?('rake:')
69
+ task_name = command_string.strip[5..-1]
70
+ return execute_rake_task(task_name, working_dir)
71
+ end
72
+
58
73
  # シェルコマンドの実行 (! で始まる場合)
59
74
  if command_string.strip.start_with?('!')
60
75
  shell_command = command_string.strip[1..-1]
@@ -132,11 +147,28 @@ module Rufio
132
147
  # @param prefix [String] 入力中の文字列(@を含む)
133
148
  # @return [Array<String>] 補完候補(@付き)
134
149
  def complete_script(prefix)
135
- return [] unless @script_runner
136
-
137
150
  # @を除去して検索
138
151
  search_prefix = prefix.sub(/^@/, '')
139
- @script_runner.complete(search_prefix).map { |name| "@#{name}" }
152
+
153
+ candidates = []
154
+
155
+ # ScriptRunnerからの候補
156
+ if @script_runner
157
+ candidates += @script_runner.complete(search_prefix)
158
+ end
159
+
160
+ # ローカルスクリプトからの候補
161
+ candidates += @local_script_scanner.complete(search_prefix)
162
+
163
+ # 重複排除してソート、@付きで返す
164
+ candidates.uniq.sort.map { |name| "@#{name}" }
165
+ end
166
+
167
+ # rakeタスク名を補完する
168
+ # @param prefix [String] 入力中の文字列(rake:を含まない)
169
+ # @return [Array<String>] 補完候補(rake:付き)
170
+ def complete_rake_task(prefix)
171
+ @rakefile_parser.complete(prefix).map { |name| "rake:#{name}" }
140
172
  end
141
173
 
142
174
  private
@@ -204,22 +236,143 @@ module Rufio
204
236
  end
205
237
 
206
238
  # スクリプトを実行する(@プレフィックス用)
239
+ # ScriptRunner → LocalScriptScanner の順にフォールバック
207
240
  # @param script_name [String] スクリプト名
208
241
  # @param working_dir [String, nil] 作業ディレクトリ
209
242
  # @return [String] 実行結果メッセージ
210
243
  def execute_script(script_name, working_dir)
211
- unless @script_runner
212
- return "⚠️ スクリプトランナーが設定されていません"
244
+ working_dir ||= Dir.pwd
245
+
246
+ # ScriptRunnerで検索
247
+ if @script_runner
248
+ job = @script_runner.run(script_name, working_dir: working_dir)
249
+ return "🚀 ジョブを開始: #{script_name}" if job
213
250
  end
214
251
 
215
- working_dir ||= Dir.pwd
252
+ # LocalScriptScannerにフォールバック
253
+ local_script = @local_script_scanner.find_script(script_name)
254
+ if local_script
255
+ return execute_local_script(local_script, working_dir)
256
+ end
216
257
 
217
- job = @script_runner.run(script_name, working_dir: working_dir)
258
+ # どちらにも見つからない
259
+ if @script_runner
260
+ "⚠️ スクリプトが見つかりません: #{script_name}"
261
+ else
262
+ "⚠️ スクリプトランナーが設定されていません"
263
+ end
264
+ end
218
265
 
219
- if job
220
- "🚀 ジョブを開始: #{script_name}"
266
+ # ローカルスクリプトを実行する
267
+ # @param script [Hash] スクリプト情報 { name:, path:, dir: }
268
+ # @param working_dir [String] 作業ディレクトリ
269
+ # @return [String] 実行結果メッセージ
270
+ def execute_local_script(script, working_dir)
271
+ if @job_manager
272
+ job = @job_manager.add_job(
273
+ name: script[:name],
274
+ path: working_dir,
275
+ command: build_script_command(script)
276
+ )
277
+ job.start
278
+
279
+ Thread.new do
280
+ execute_script_in_background(job, script, working_dir)
281
+ end
282
+
283
+ "🚀 ジョブを開始: #{script[:name]}"
221
284
  else
222
- "⚠️ スクリプトが見つかりません: #{script_name}"
285
+ # 同期実行
286
+ command = build_script_command(script)
287
+ stdout, stderr, status = Open3.capture3(command, chdir: working_dir)
288
+ {
289
+ success: status.success?,
290
+ output: stdout.strip,
291
+ stderr: stderr.strip
292
+ }
293
+ end
294
+ end
295
+
296
+ # スクリプトの実行コマンドを構築
297
+ # @param script [Hash] スクリプト情報
298
+ # @return [String] 実行コマンド
299
+ def build_script_command(script)
300
+ path = script[:path]
301
+ ext = File.extname(path).downcase
302
+
303
+ case ext
304
+ when '.rb'
305
+ "ruby #{path.shellescape}"
306
+ when '.py'
307
+ "python3 #{path.shellescape}"
308
+ when '.js'
309
+ "node #{path.shellescape}"
310
+ when '.ts'
311
+ "ts-node #{path.shellescape}"
312
+ when '.pl'
313
+ "perl #{path.shellescape}"
314
+ when '.ps1'
315
+ "pwsh #{path.shellescape}"
316
+ else
317
+ path.shellescape
318
+ end
319
+ end
320
+
321
+ # ローカルスクリプトをバックグラウンドで実行
322
+ def execute_script_in_background(job, script, working_dir)
323
+ command = build_script_command(script)
324
+ stdout, stderr, status = Open3.capture3(command, chdir: working_dir)
325
+
326
+ job.append_log(stdout) unless stdout.empty?
327
+ job.append_log(stderr) unless stderr.empty?
328
+
329
+ if status.success?
330
+ job.complete(exit_code: status.exitstatus)
331
+ else
332
+ job.fail(exit_code: status.exitstatus)
333
+ end
334
+
335
+ @job_manager&.notify_completion(job)
336
+ rescue StandardError => e
337
+ job.append_log("Error: #{e.message}")
338
+ job.fail(exit_code: -1)
339
+ @job_manager&.notify_completion(job)
340
+ end
341
+
342
+ # rakeタスクを実行する
343
+ # @param task_name [String] タスク名
344
+ # @param working_dir [String, nil] 作業ディレクトリ
345
+ # @return [String, Hash] 実行結果
346
+ def execute_rake_task(task_name, working_dir)
347
+ unless @rakefile_parser.rakefile_exists?
348
+ return "⚠️ Rakefileが見つかりません"
349
+ end
350
+
351
+ unless @rakefile_parser.tasks.include?(task_name)
352
+ return "⚠️ rakeタスクが見つかりません: #{task_name}"
353
+ end
354
+
355
+ working_dir ||= Dir.pwd
356
+ shell_command = "rake #{task_name.shellescape}"
357
+
358
+ begin
359
+ stdout, stderr, status = Open3.capture3(shell_command, chdir: working_dir)
360
+
361
+ result = {
362
+ success: status.success?,
363
+ output: stdout.strip,
364
+ stderr: stderr.strip
365
+ }
366
+
367
+ unless status.success?
368
+ result[:error] = "コマンドが失敗しました (終了コード: #{status.exitstatus})"
369
+ end
370
+
371
+ result
372
+ rescue Errno::ENOENT => e
373
+ { success: false, error: "rakeが見つかりません: #{e.message}" }
374
+ rescue StandardError => e
375
+ { success: false, error: "rake実行エラー: #{e.message}" }
223
376
  end
224
377
  end
225
378
 
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rufio
4
+ # 閲覧中ディレクトリのスクリプトファイルを検出するスキャナー
5
+ # カレントディレクトリ直下のスクリプトファイル(.sh, .rb, .py等)を検出し、
6
+ # コマンドモードから @script.sh 形式で実行可能にする
7
+ class LocalScriptScanner
8
+ # サポートするスクリプト拡張子
9
+ SUPPORTED_EXTENSIONS = %w[.sh .rb .py .pl .js .ts .ps1].freeze
10
+
11
+ # @param directory [String, nil] スキャン対象ディレクトリ
12
+ def initialize(directory = nil)
13
+ @directory = directory
14
+ @scripts_cache = nil
15
+ end
16
+
17
+ # ディレクトリ変更時にキャッシュを無効化
18
+ # @param directory [String] 新しいディレクトリ
19
+ def update_directory(directory)
20
+ return if @directory == directory
21
+
22
+ @directory = directory
23
+ @scripts_cache = nil
24
+ end
25
+
26
+ # 利用可能なスクリプト一覧を取得
27
+ # @return [Array<Hash>] スクリプト情報の配列 [{ name:, path:, dir: }, ...]
28
+ def available_scripts
29
+ @scripts_cache ||= scan_scripts
30
+ end
31
+
32
+ # 名前でスクリプトを検索
33
+ # @param name [String] スクリプト名(拡張子あり/なし)
34
+ # @return [Hash, nil] スクリプト情報 { name:, path:, dir: } または nil
35
+ def find_script(name)
36
+ # 完全一致を優先
37
+ script = available_scripts.find { |s| s[:name] == name }
38
+ return script if script
39
+
40
+ # 拡張子なしで検索
41
+ SUPPORTED_EXTENSIONS.each do |ext|
42
+ script = available_scripts.find { |s| s[:name] == "#{name}#{ext}" }
43
+ return script if script
44
+ end
45
+
46
+ nil
47
+ end
48
+
49
+ # Tab補完候補を取得
50
+ # @param prefix [String] 入力中の文字列
51
+ # @return [Array<String>] 補完候補のスクリプト名
52
+ def complete(prefix)
53
+ available_scripts
54
+ .map { |s| s[:name] }
55
+ .select { |name| name.start_with?(prefix) }
56
+ .sort
57
+ end
58
+
59
+ private
60
+
61
+ # ディレクトリをスキャンしてスクリプトファイルを収集
62
+ # @return [Array<Hash>] スクリプト情報の配列
63
+ def scan_scripts
64
+ return [] unless @directory && Dir.exist?(@directory)
65
+
66
+ scripts = []
67
+
68
+ Dir.foreach(@directory) do |entry|
69
+ next if entry.start_with?('.')
70
+ path = File.join(@directory, entry)
71
+ next unless File.file?(path)
72
+ next unless script_file?(entry)
73
+
74
+ scripts << {
75
+ name: entry,
76
+ path: path,
77
+ dir: @directory
78
+ }
79
+ end
80
+
81
+ scripts.sort_by { |s| s[:name] }
82
+ end
83
+
84
+ # スクリプトファイルかどうかを判定
85
+ # @param filename [String] ファイル名
86
+ # @return [Boolean]
87
+ def script_file?(filename)
88
+ ext = File.extname(filename).downcase
89
+ SUPPORTED_EXTENSIONS.include?(ext)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rufio
4
+ # Rakefileをパースしてタスク名を抽出するパーサー
5
+ # 正規表現ベースでtask定義を検出し、コマンドモードから
6
+ # rake:task_name 形式で実行可能にする
7
+ class RakefileParser
8
+ RAKEFILE_NAMES = %w[Rakefile rakefile Rakefile.rb].freeze
9
+ TASK_PATTERN = /^\s*task\s+[:'"]?(\w+)/.freeze
10
+
11
+ # @param directory [String, nil] スキャン対象ディレクトリ
12
+ def initialize(directory = nil)
13
+ @directory = directory
14
+ @tasks_cache = nil
15
+ end
16
+
17
+ # ディレクトリ変更時にキャッシュを無効化
18
+ # @param directory [String] 新しいディレクトリ
19
+ def update_directory(directory)
20
+ return if @directory == directory
21
+
22
+ @directory = directory
23
+ @tasks_cache = nil
24
+ end
25
+
26
+ # Rakefileが存在するかどうか
27
+ # @return [Boolean]
28
+ def rakefile_exists?
29
+ !!find_rakefile
30
+ end
31
+
32
+ # Rakefileからタスク名を抽出
33
+ # @return [Array<String>] タスク名の配列(ソート済み・ユニーク)
34
+ def tasks
35
+ @tasks_cache ||= parse_tasks
36
+ end
37
+
38
+ # Tab補完候補を取得
39
+ # @param prefix [String] 入力中の文字列
40
+ # @return [Array<String>] 補完候補のタスク名
41
+ def complete(prefix)
42
+ tasks.select { |name| name.start_with?(prefix) }
43
+ end
44
+
45
+ private
46
+
47
+ # Rakefileのパスを検索
48
+ # @return [String, nil] Rakefileのパス、見つからない場合nil
49
+ def find_rakefile
50
+ return nil unless @directory && Dir.exist?(@directory)
51
+
52
+ RAKEFILE_NAMES.each do |name|
53
+ path = File.join(@directory, name)
54
+ return path if File.file?(path)
55
+ end
56
+
57
+ nil
58
+ end
59
+
60
+ # Rakefileをパースしてタスク名を抽出
61
+ # @return [Array<String>] タスク名の配列
62
+ def parse_tasks
63
+ rakefile = find_rakefile
64
+ return [] unless rakefile
65
+
66
+ content = File.read(rakefile)
67
+ task_names = []
68
+
69
+ content.each_line do |line|
70
+ match = line.match(TASK_PATTERN)
71
+ task_names << match[1] if match
72
+ end
73
+
74
+ task_names.uniq.sort
75
+ end
76
+ end
77
+ end
@@ -305,6 +305,8 @@ module Rufio
305
305
 
306
306
  # コマンドモードがアクティブな場合はオーバーレイにダイアログを描画
307
307
  if @command_mode_active
308
+ # 前回のオーバーレイ残留を防ぐためクリアしてから描画
309
+ @screen.clear_overlay if @screen.overlay_enabled?
308
310
  draw_command_mode_to_overlay
309
311
  else
310
312
  # コマンドモードでない場合はオーバーレイをクリア
@@ -1370,6 +1372,9 @@ module Rufio
1370
1372
  def activate_command_mode
1371
1373
  @command_mode_active = true
1372
1374
  @command_input = ""
1375
+ # 閲覧中ディレクトリをコマンドモードに通知(ローカルスクリプト・Rakefileの検出用)
1376
+ browsing_dir = @directory_listing&.current_path || Dir.pwd
1377
+ @command_mode.update_browsing_directory(browsing_dir)
1373
1378
  end
1374
1379
 
1375
1380
  # コマンドモードを終了
@@ -1476,8 +1481,9 @@ module Rufio
1476
1481
  @command_mode_ui.show_result(result)
1477
1482
  end
1478
1483
 
1479
- # 画面を再描画
1480
- draw_screen
1484
+ # メインループの次フレームで再描画される(draw_screenは使わない)
1485
+ # draw_screen(レガシー直接出力)はバッファベースのオーバーレイと座標系が異なるため、
1486
+ # 使用するとコマンドプロンプトの枠線が残る不具合が発生する
1481
1487
  end
1482
1488
 
1483
1489
  # Tab補完を処理
@@ -1697,8 +1703,9 @@ module Rufio
1697
1703
  def show_overlay_dialog(title, content_lines, options = {}, &block)
1698
1704
  return nil unless @screen && @renderer
1699
1705
 
1700
- # オーバーレイを有効化
1706
+ # オーバーレイを有効化し、前回のダイアログ残留を除去
1701
1707
  @screen.enable_overlay
1708
+ @screen.clear_overlay
1702
1709
 
1703
1710
  # ウィンドウサイズを計算
1704
1711
  if options[:width] && options[:height]
data/lib/rufio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rufio
4
- VERSION = '0.65.0'
4
+ VERSION = '0.70.0'
5
5
  end
data/lib/rufio.rb CHANGED
@@ -53,6 +53,8 @@ require_relative 'rufio/job_mode'
53
53
  require_relative 'rufio/script_runner'
54
54
  require_relative 'rufio/script_path_manager'
55
55
  require_relative 'rufio/script_config_loader'
56
+ require_relative 'rufio/local_script_scanner'
57
+ require_relative 'rufio/rakefile_parser'
56
58
 
57
59
  module Rufio
58
60
  class Error < StandardError; 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.65.0
4
+ version: 0.70.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-14 00:00:00.000000000 Z
11
+ date: 2026-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -175,12 +175,14 @@ files:
175
175
  - lib/rufio/job_manager.rb
176
176
  - lib/rufio/job_mode.rb
177
177
  - lib/rufio/keybind_handler.rb
178
+ - lib/rufio/local_script_scanner.rb
178
179
  - lib/rufio/logger.rb
179
180
  - lib/rufio/native/rufio_zig.bundle
180
181
  - lib/rufio/native_scanner.rb
181
182
  - lib/rufio/native_scanner_zig.rb
182
183
  - lib/rufio/notification_manager.rb
183
184
  - lib/rufio/parallel_scanner.rb
185
+ - lib/rufio/rakefile_parser.rb
184
186
  - lib/rufio/renderer.rb
185
187
  - lib/rufio/screen.rb
186
188
  - lib/rufio/script_config_loader.rb