rufio 0.30.0 → 0.32.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 +109 -12
- data/README.md +76 -3
- data/README_EN.md +30 -2
- data/bin/rufio +80 -9
- data/docs/CHANGELOG_v0.31.0.md +125 -0
- data/docs/CHANGELOG_v0.32.0.md +288 -0
- data/{CHANGELOG_v0.4.0.md → docs/CHANGELOG_v0.4.0.md} +2 -2
- data/{CHANGELOG_v0.5.0.md → docs/CHANGELOG_v0.5.0.md} +3 -0
- data/{CHANGELOG_v0.7.0.md → docs/CHANGELOG_v0.7.0.md} +1 -1
- data/{CHANGELOG_v0.8.0.md → docs/CHANGELOG_v0.8.0.md} +1 -1
- data/{CHANGELOG_v0.9.0.md → docs/CHANGELOG_v0.9.0.md} +1 -1
- data/lib/rufio/command_completion.rb +101 -0
- data/lib/rufio/command_history.rb +109 -0
- data/lib/rufio/command_mode.rb +35 -0
- data/lib/rufio/command_mode_ui.rb +48 -15
- data/lib/rufio/config_loader.rb +9 -0
- data/lib/rufio/plugins/hello.rb +30 -0
- data/lib/rufio/shell_command_completion.rb +120 -0
- data/lib/rufio/terminal_ui.rb +89 -4
- data/lib/rufio/version.rb +1 -1
- data/lib/rufio.rb +6 -0
- data/retag.sh +55 -0
- metadata +23 -16
- data/docs/PLUGIN_GUIDE.md +0 -431
- data/docs/plugin_example.rb +0 -119
- data/rufio.gemspec +0 -40
- /data/{CHANGELOG_v0.10.0.md → docs/CHANGELOG_v0.10.0.md} +0 -0
- /data/{CHANGELOG_v0.20.0.md → docs/CHANGELOG_v0.20.0.md} +0 -0
- /data/{CHANGELOG_v0.21.0.md → docs/CHANGELOG_v0.21.0.md} +0 -0
- /data/{CHANGELOG_v0.30.0.md → docs/CHANGELOG_v0.30.0.md} +0 -0
- /data/{CHANGELOG_v0.6.0.md → docs/CHANGELOG_v0.6.0.md} +0 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# rufio v0.32.0 - Command Mode Enhancements
|
|
2
|
+
|
|
3
|
+
**Release Date**: 2026-01-02
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Version 0.32.0 introduces comprehensive command mode enhancements, including shell command execution, command history, intelligent Tab completion, and the plugin system foundation with a sample Hello plugin. This release focuses on making command mode a powerful interface for daily operations.
|
|
8
|
+
|
|
9
|
+
## 🎯 Major Features
|
|
10
|
+
|
|
11
|
+
### 1. Shell Command Execution
|
|
12
|
+
|
|
13
|
+
Execute shell commands directly from command mode using the `!` prefix.
|
|
14
|
+
|
|
15
|
+
**Usage:**
|
|
16
|
+
```
|
|
17
|
+
:!ls -la # List files with details
|
|
18
|
+
:!git status # Check git status
|
|
19
|
+
:!grep pattern * # Search for patterns
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Features:**
|
|
23
|
+
- ✅ Safe execution with `Open3.capture3`
|
|
24
|
+
- ✅ Separate stdout and stderr display
|
|
25
|
+
- ✅ Exit code tracking and error handling
|
|
26
|
+
- ✅ Result display in floating window
|
|
27
|
+
|
|
28
|
+
**Implementation:**
|
|
29
|
+
- `lib/rufio/command_mode.rb`: Added `execute_shell_command` method
|
|
30
|
+
- `lib/rufio/command_mode_ui.rb`: Hash-based result formatting
|
|
31
|
+
|
|
32
|
+
### 2. Command History
|
|
33
|
+
|
|
34
|
+
Navigate through previously executed commands using arrow keys.
|
|
35
|
+
|
|
36
|
+
**Usage:**
|
|
37
|
+
- `↑` (Up Arrow): Previous command
|
|
38
|
+
- `↓` (Down Arrow): Next command
|
|
39
|
+
|
|
40
|
+
**Features:**
|
|
41
|
+
- ✅ File persistence (`~/.rufio/command_history.txt`)
|
|
42
|
+
- ✅ Duplicate filtering
|
|
43
|
+
- ✅ Configurable history size (default: 1000)
|
|
44
|
+
- ✅ Automatic save on command execution
|
|
45
|
+
|
|
46
|
+
**Configuration:**
|
|
47
|
+
```ruby
|
|
48
|
+
# ~/.config/rufio/config.rb
|
|
49
|
+
COMMAND_HISTORY_SIZE = 500 # Default: 1000
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Implementation:**
|
|
53
|
+
- `lib/rufio/command_history.rb`: History management class
|
|
54
|
+
- `lib/rufio/config_loader.rb`: Configuration support
|
|
55
|
+
- `lib/rufio/terminal_ui.rb`: Integration with command mode
|
|
56
|
+
|
|
57
|
+
### 3. Intelligent Tab Completion
|
|
58
|
+
|
|
59
|
+
Smart Tab completion with multiple behavior modes.
|
|
60
|
+
|
|
61
|
+
**Behavior:**
|
|
62
|
+
|
|
63
|
+
1. **Single candidate**: Auto-complete
|
|
64
|
+
```
|
|
65
|
+
Input: !lsbo [Tab]
|
|
66
|
+
Result: !lsbom
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
2. **Multiple candidates with common prefix**: Complete to common prefix
|
|
70
|
+
```
|
|
71
|
+
Input: !lsap [Tab]
|
|
72
|
+
Result: !lsappinfo
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
3. **Multiple candidates, no common prefix**: Display candidate list
|
|
76
|
+
```
|
|
77
|
+
Input: !l [Tab]
|
|
78
|
+
Result: Shows list of 115 commands starting with 'l'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Features:**
|
|
82
|
+
- ✅ Internal command completion
|
|
83
|
+
- ✅ Shell command completion (PATH-based)
|
|
84
|
+
- ✅ File path completion with tilde expansion
|
|
85
|
+
- ✅ History-based completion
|
|
86
|
+
- ✅ Case-insensitive matching
|
|
87
|
+
- ✅ Candidate list display (max 20 items)
|
|
88
|
+
|
|
89
|
+
**Implementation:**
|
|
90
|
+
- `lib/rufio/command_completion.rb`: Main completion logic
|
|
91
|
+
- `lib/rufio/shell_command_completion.rb`: Shell-specific completion
|
|
92
|
+
- `lib/rufio/terminal_ui.rb`: Tab key handling with candidate display
|
|
93
|
+
|
|
94
|
+
### 4. Hello Plugin (Ruby Command Example)
|
|
95
|
+
|
|
96
|
+
Simple example plugin demonstrating how to create custom Ruby commands.
|
|
97
|
+
|
|
98
|
+
**Usage:**
|
|
99
|
+
```
|
|
100
|
+
:hello # Execute the hello command
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Output:**
|
|
104
|
+
```
|
|
105
|
+
Hello, World! 🌍
|
|
106
|
+
|
|
107
|
+
このコマンドはRubyで実装されています。
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Features:**
|
|
111
|
+
- ✅ Automatic plugin loading from `lib/rufio/plugins/`
|
|
112
|
+
- ✅ Tab completion support
|
|
113
|
+
- ✅ Command history integration
|
|
114
|
+
- ✅ Comprehensive test coverage
|
|
115
|
+
|
|
116
|
+
**Creating Your Own Plugin:**
|
|
117
|
+
```ruby
|
|
118
|
+
# lib/rufio/plugins/my_plugin.rb
|
|
119
|
+
module Rufio
|
|
120
|
+
module Plugins
|
|
121
|
+
class MyPlugin < Plugin
|
|
122
|
+
def name
|
|
123
|
+
"MyPlugin"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def description
|
|
127
|
+
"Description of my plugin"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def commands
|
|
131
|
+
{
|
|
132
|
+
mycommand: method(:execute_command)
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
def execute_command
|
|
139
|
+
"Command result"
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Implementation:**
|
|
147
|
+
- `lib/rufio/plugins/hello.rb`: Hello plugin
|
|
148
|
+
- `lib/rufio.rb`: Automatic plugin loading via `PluginManager.load_all`
|
|
149
|
+
- `test/test_plugins_hello.rb`: Plugin tests
|
|
150
|
+
|
|
151
|
+
### 5. Command Mode UI Improvements
|
|
152
|
+
|
|
153
|
+
Cleaner and more intuitive command mode interface.
|
|
154
|
+
|
|
155
|
+
**Changes:**
|
|
156
|
+
- ✅ Removed "補完候補:" label (candidates shown only on Tab)
|
|
157
|
+
- ✅ Floating window for candidate display
|
|
158
|
+
- ✅ Better visual feedback for Tab completion
|
|
159
|
+
- ✅ Color-coded windows (blue for input, yellow for candidates, green/red for results)
|
|
160
|
+
|
|
161
|
+
## 📊 Technical Details
|
|
162
|
+
|
|
163
|
+
### File Changes
|
|
164
|
+
|
|
165
|
+
**New Files:**
|
|
166
|
+
- `lib/rufio/command_history.rb` - Command history management
|
|
167
|
+
- `lib/rufio/command_completion.rb` - Command completion logic
|
|
168
|
+
- `lib/rufio/shell_command_completion.rb` - Shell command completion
|
|
169
|
+
- `lib/rufio/plugins/hello.rb` - Hello plugin example
|
|
170
|
+
- `test/test_command_history.rb` - Command history tests
|
|
171
|
+
- `test/test_command_completion.rb` - Completion tests
|
|
172
|
+
- `test/test_shell_command_completion.rb` - Shell completion tests
|
|
173
|
+
- `test/test_plugins_hello.rb` - Hello plugin tests
|
|
174
|
+
|
|
175
|
+
**Modified Files:**
|
|
176
|
+
- `lib/rufio.rb` - Added plugin loading
|
|
177
|
+
- `lib/rufio/command_mode.rb` - Shell command execution
|
|
178
|
+
- `lib/rufio/command_mode_ui.rb` - UI improvements, Hash result formatting
|
|
179
|
+
- `lib/rufio/terminal_ui.rb` - History and completion integration
|
|
180
|
+
- `lib/rufio/config_loader.rb` - Command history size configuration
|
|
181
|
+
|
|
182
|
+
### Test Coverage
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
390 runs, 1663 assertions, 0 failures, 0 errors, 1 skips
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
All features are fully tested with comprehensive test coverage.
|
|
189
|
+
|
|
190
|
+
### Performance
|
|
191
|
+
|
|
192
|
+
- Command history: O(1) access for previous/next
|
|
193
|
+
- Tab completion: O(n) where n = number of PATH commands
|
|
194
|
+
- File path completion: Uses efficient Dir.glob with patterns
|
|
195
|
+
- Shell execution: Non-blocking with Open3.capture3
|
|
196
|
+
|
|
197
|
+
## 🔧 Configuration
|
|
198
|
+
|
|
199
|
+
### Command History Size
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
# ~/.config/rufio/config.rb
|
|
203
|
+
COMMAND_HISTORY_SIZE = 1000 # Default: 1000
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### History File Location
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
~/.rufio/command_history.txt
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## 🎓 Usage Examples
|
|
213
|
+
|
|
214
|
+
### Shell Command Execution
|
|
215
|
+
```
|
|
216
|
+
:!ls # List files
|
|
217
|
+
:!pwd # Print working directory
|
|
218
|
+
:!git log --oneline # Git log
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Tab Completion
|
|
222
|
+
```
|
|
223
|
+
:h[Tab] # Complete to 'hello'
|
|
224
|
+
:!l[Tab] # Show list of commands starting with 'l'
|
|
225
|
+
:!ls /tm[Tab] # Complete to '!ls /tmp'
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Command History
|
|
229
|
+
```
|
|
230
|
+
:[↑] # Previous command
|
|
231
|
+
:[↓] # Next command
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Ruby Commands
|
|
235
|
+
```
|
|
236
|
+
:hello # Execute hello plugin
|
|
237
|
+
:copy # File operations (future)
|
|
238
|
+
:move # File operations (future)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## 🐛 Bug Fixes
|
|
242
|
+
|
|
243
|
+
- Fixed Tab completion not working for shell commands
|
|
244
|
+
- Fixed command input display showing candidates unnecessarily
|
|
245
|
+
- Fixed ConfigLoader method access (class method vs instance method)
|
|
246
|
+
|
|
247
|
+
## 🔄 Migration Guide
|
|
248
|
+
|
|
249
|
+
No breaking changes. All existing functionality remains compatible.
|
|
250
|
+
|
|
251
|
+
**New users:**
|
|
252
|
+
- Command history will be automatically created on first command execution
|
|
253
|
+
- No configuration required for basic usage
|
|
254
|
+
|
|
255
|
+
**Existing users:**
|
|
256
|
+
- Command history feature works automatically
|
|
257
|
+
- Previous command mode behavior preserved
|
|
258
|
+
- New Tab completion enhances existing workflow
|
|
259
|
+
|
|
260
|
+
## 📝 Known Limitations
|
|
261
|
+
|
|
262
|
+
- Command arguments not yet supported for internal commands
|
|
263
|
+
- Shell command completion limited to PATH commands
|
|
264
|
+
- History limited to command strings (no metadata)
|
|
265
|
+
|
|
266
|
+
## 🚀 Future Enhancements
|
|
267
|
+
|
|
268
|
+
- Command arguments support
|
|
269
|
+
- Command aliases
|
|
270
|
+
- Custom keybindings for command mode
|
|
271
|
+
- Command history search (Ctrl+R style)
|
|
272
|
+
- More built-in plugins
|
|
273
|
+
- Plugin dependency management
|
|
274
|
+
|
|
275
|
+
## 👏 Credits
|
|
276
|
+
|
|
277
|
+
Implemented following TDD (Test-Driven Development) methodology:
|
|
278
|
+
1. Write tests first
|
|
279
|
+
2. Run tests to confirm failures
|
|
280
|
+
3. Implement features
|
|
281
|
+
4. Verify all tests pass
|
|
282
|
+
5. Commit
|
|
283
|
+
|
|
284
|
+
All features developed with comprehensive test coverage and documentation.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
For the main changelog, see [CHANGELOG.md](../CHANGELOG.md)
|
|
@@ -126,7 +126,7 @@ This release establishes rufio as a modern, English-focused file manager with:
|
|
|
126
126
|
|
|
127
127
|
---
|
|
128
128
|
|
|
129
|
-
**Release Date**: 2025-
|
|
129
|
+
**Release Date**: 2025-09-13
|
|
130
130
|
**Version**: 0.4.0
|
|
131
131
|
**Previous Version**: 0.3.0
|
|
132
132
|
**Compatibility**: Ruby 2.7.0+
|
|
@@ -143,4 +143,4 @@ Please report issues at: https://github.com/masisz/rufio/issues
|
|
|
143
143
|
|
|
144
144
|
---
|
|
145
145
|
|
|
146
|
-
*This release represents a significant step forward in rufio's evolution, focusing on modern UI patterns, safety, and maintainability while streamlining the user experience.*
|
|
146
|
+
*This release represents a significant step forward in rufio's evolution, focusing on modern UI patterns, safety, and maintainability while streamlining the user experience.*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# rufio v0.5.0 - Release Notes
|
|
2
2
|
|
|
3
3
|
## Added
|
|
4
|
+
|
|
4
5
|
- **Bookmark System**: Complete bookmark functionality for quick directory navigation
|
|
5
6
|
- **Interactive Bookmark Menu**: Floating dialog accessed via `b` key with Add/List/Remove operations
|
|
6
7
|
- **Quick Navigation**: Number keys (1-9) for instant bookmark jumping
|
|
@@ -12,6 +13,7 @@
|
|
|
12
13
|
- **Error Handling**: Graceful handling of non-existent paths, permission errors, and invalid inputs
|
|
13
14
|
|
|
14
15
|
## Changed
|
|
16
|
+
|
|
15
17
|
- **Help Messages Updated**: Latest keybinding information including bookmark operations in footer
|
|
16
18
|
- **KeybindHandler Enhanced**: Integrated bookmark menu and direct navigation functionality
|
|
17
19
|
- **DirectoryListing Improved**: Added `navigate_to_path` method for bookmark-based navigation
|
|
@@ -19,6 +21,7 @@
|
|
|
19
21
|
- **Documentation Updated**: Comprehensive README updates with bookmark usage examples and workflows
|
|
20
22
|
|
|
21
23
|
## Technical Implementation
|
|
24
|
+
|
|
22
25
|
- New `Bookmark` class with full CRUD operations and JSON persistence
|
|
23
26
|
- Floating window system for bookmark management dialogs
|
|
24
27
|
- Integration with existing terminal UI components and color system
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rufio
|
|
4
|
+
# コマンド補完機能を提供するクラス
|
|
5
|
+
class CommandCompletion
|
|
6
|
+
# 初期化
|
|
7
|
+
# @param history [CommandHistory, nil] コマンド履歴(オプション)
|
|
8
|
+
def initialize(history = nil)
|
|
9
|
+
@command_mode = CommandMode.new
|
|
10
|
+
@shell_completion = ShellCommandCompletion.new
|
|
11
|
+
@history = history
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# コマンドの補完候補を取得
|
|
15
|
+
# @param input [String] 入力されたテキスト
|
|
16
|
+
# @return [Array<String>] 補完候補のリスト
|
|
17
|
+
def complete(input)
|
|
18
|
+
# 入力が空の場合は内部コマンドを返す
|
|
19
|
+
if input.nil? || input.strip.empty?
|
|
20
|
+
return @command_mode.available_commands.map(&:to_s)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# シェルコマンド補完(!で始まる場合)
|
|
24
|
+
if input.strip.start_with?('!')
|
|
25
|
+
return complete_shell_command(input.strip)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# 通常のコマンド補完(内部コマンド)
|
|
29
|
+
available_commands = @command_mode.available_commands.map(&:to_s)
|
|
30
|
+
input_lower = input.downcase
|
|
31
|
+
candidates = available_commands.select do |command|
|
|
32
|
+
command.downcase.start_with?(input_lower)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
candidates
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# 補完候補の共通プレフィックスを取得
|
|
39
|
+
# @param input [String] 入力されたテキスト
|
|
40
|
+
# @return [String] 共通プレフィックス
|
|
41
|
+
def common_prefix(input)
|
|
42
|
+
candidates = complete(input)
|
|
43
|
+
|
|
44
|
+
# 候補がない場合は元の入力を返す
|
|
45
|
+
return input if candidates.empty?
|
|
46
|
+
|
|
47
|
+
# 候補が1つの場合はそのコマンド名を返す
|
|
48
|
+
return candidates.first if candidates.size == 1
|
|
49
|
+
|
|
50
|
+
# 複数の候補がある場合、共通プレフィックスを計算
|
|
51
|
+
min_candidate = candidates.min
|
|
52
|
+
max_candidate = candidates.max
|
|
53
|
+
|
|
54
|
+
min_candidate.chars.zip(max_candidate.chars).each_with_index do |(char_min, char_max), index|
|
|
55
|
+
return min_candidate[0...index] if char_min != char_max
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# すべての文字が一致した場合は最小の候補を返す
|
|
59
|
+
min_candidate
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
# シェルコマンドの補完
|
|
65
|
+
# @param input [String] ! で始まる入力
|
|
66
|
+
# @return [Array<String>] 補完候補のリスト
|
|
67
|
+
def complete_shell_command(input)
|
|
68
|
+
# ! を除去
|
|
69
|
+
command_part = input[1..-1]
|
|
70
|
+
|
|
71
|
+
# スペースが含まれる場合、コマンドと引数に分離
|
|
72
|
+
if command_part.include?(' ')
|
|
73
|
+
parts = command_part.split(' ', 2)
|
|
74
|
+
cmd = parts[0]
|
|
75
|
+
arg = parts[1] || ''
|
|
76
|
+
|
|
77
|
+
# 引数部分がパスっぽい場合、ファイルパス補完
|
|
78
|
+
if arg.include?('/') || arg.start_with?('~')
|
|
79
|
+
path_candidates = @shell_completion.complete_path(arg)
|
|
80
|
+
return path_candidates.map { |path| "!#{cmd} #{path}" }
|
|
81
|
+
else
|
|
82
|
+
# 引数部分のファイル補完(カレントディレクトリ)
|
|
83
|
+
path_candidates = @shell_completion.complete_path(arg)
|
|
84
|
+
return path_candidates.map { |path| "!#{cmd} #{path}" }
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
# コマンド名の補完
|
|
88
|
+
cmd_candidates = @shell_completion.complete_command(command_part)
|
|
89
|
+
|
|
90
|
+
# 履歴からの補完も追加
|
|
91
|
+
if @history
|
|
92
|
+
history_candidates = @shell_completion.complete_from_history(command_part, @history)
|
|
93
|
+
cmd_candidates += history_candidates
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# ! を付けて返す
|
|
97
|
+
cmd_candidates.uniq.map { |cmd| "!#{cmd}" }
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rufio
|
|
4
|
+
# コマンド履歴管理クラス
|
|
5
|
+
class CommandHistory
|
|
6
|
+
DEFAULT_MAX_SIZE = 1000
|
|
7
|
+
|
|
8
|
+
attr_reader :size
|
|
9
|
+
|
|
10
|
+
# 初期化
|
|
11
|
+
# @param history_file [String] 履歴ファイルのパス
|
|
12
|
+
# @param max_size [Integer] 履歴の最大保存数
|
|
13
|
+
def initialize(history_file, max_size: DEFAULT_MAX_SIZE)
|
|
14
|
+
@history_file = history_file
|
|
15
|
+
@max_size = max_size
|
|
16
|
+
@history = []
|
|
17
|
+
@position = -1 # -1 = 最新の位置(履歴の外)
|
|
18
|
+
|
|
19
|
+
load_from_file if File.exist?(@history_file)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# コマンドを履歴に追加
|
|
23
|
+
# @param command [String] 追加するコマンド
|
|
24
|
+
def add(command)
|
|
25
|
+
# 空のコマンドは無視
|
|
26
|
+
return if command.nil? || command.strip.empty?
|
|
27
|
+
|
|
28
|
+
# 連続する重複は無視
|
|
29
|
+
return if !@history.empty? && @history.last == command
|
|
30
|
+
|
|
31
|
+
@history << command
|
|
32
|
+
|
|
33
|
+
# 最大サイズを超えたら古いものを削除
|
|
34
|
+
@history.shift if @history.size > @max_size
|
|
35
|
+
|
|
36
|
+
# 位置をリセット
|
|
37
|
+
reset_position
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# 前のコマンドを取得(上矢印キー相当)
|
|
41
|
+
# @return [String, nil] 前のコマンド、存在しない場合はnil
|
|
42
|
+
def previous
|
|
43
|
+
return nil if @history.empty?
|
|
44
|
+
|
|
45
|
+
# 初回は最後のコマンドを返す
|
|
46
|
+
if @position == -1
|
|
47
|
+
@position = @history.size - 1
|
|
48
|
+
return @history[@position]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# これ以上前がない場合
|
|
52
|
+
return nil if @position <= 0
|
|
53
|
+
|
|
54
|
+
# 一つ前に移動
|
|
55
|
+
@position -= 1
|
|
56
|
+
@history[@position]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# 次のコマンドを取得(下矢印キー相当)
|
|
60
|
+
# @return [String] 次のコマンド、最新位置の場合は空文字列
|
|
61
|
+
def next
|
|
62
|
+
return "" if @history.empty? || @position == -1
|
|
63
|
+
|
|
64
|
+
# 一つ次に移動
|
|
65
|
+
@position += 1
|
|
66
|
+
|
|
67
|
+
# 最新位置を超えた場合は空文字列を返す
|
|
68
|
+
if @position >= @history.size
|
|
69
|
+
@position = -1
|
|
70
|
+
return ""
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
@history[@position]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# 履歴をファイルに保存
|
|
77
|
+
def save
|
|
78
|
+
File.write(@history_file, @history.join("\n") + "\n")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# 位置をリセット(新しいコマンド入力時などに使用)
|
|
82
|
+
def reset_position
|
|
83
|
+
@position = -1
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# 履歴のサイズを取得
|
|
87
|
+
def size
|
|
88
|
+
@history.size
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
# ファイルから履歴を読み込む
|
|
94
|
+
def load_from_file
|
|
95
|
+
return unless File.exist?(@history_file)
|
|
96
|
+
|
|
97
|
+
File.readlines(@history_file, chomp: true).each do |line|
|
|
98
|
+
next if line.strip.empty?
|
|
99
|
+
|
|
100
|
+
@history << line
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# 最大サイズを超えている場合は調整
|
|
104
|
+
while @history.size > @max_size
|
|
105
|
+
@history.shift
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
data/lib/rufio/command_mode.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'open3'
|
|
4
|
+
|
|
3
5
|
module Rufio
|
|
4
6
|
# コマンドモード - プラグインコマンドを実行するためのインターフェース
|
|
5
7
|
class CommandMode
|
|
@@ -13,6 +15,11 @@ module Rufio
|
|
|
13
15
|
# 空のコマンドは無視
|
|
14
16
|
return nil if command_string.nil? || command_string.strip.empty?
|
|
15
17
|
|
|
18
|
+
# シェルコマンドの実行 (! で始まる場合)
|
|
19
|
+
if command_string.strip.start_with?('!')
|
|
20
|
+
return execute_shell_command(command_string.strip[1..-1])
|
|
21
|
+
end
|
|
22
|
+
|
|
16
23
|
# コマンド名を取得 (前後の空白を削除)
|
|
17
24
|
command_name = command_string.strip.to_sym
|
|
18
25
|
|
|
@@ -48,6 +55,34 @@ module Rufio
|
|
|
48
55
|
|
|
49
56
|
private
|
|
50
57
|
|
|
58
|
+
# シェルコマンドを実行する
|
|
59
|
+
def execute_shell_command(shell_command)
|
|
60
|
+
# コマンドが空の場合
|
|
61
|
+
return { success: false, error: "コマンドが指定されていません" } if shell_command.strip.empty?
|
|
62
|
+
|
|
63
|
+
begin
|
|
64
|
+
# Open3を使って標準出力と標準エラーを分離して取得
|
|
65
|
+
stdout, stderr, status = Open3.capture3(shell_command)
|
|
66
|
+
|
|
67
|
+
result = {
|
|
68
|
+
success: status.success?,
|
|
69
|
+
output: stdout.strip,
|
|
70
|
+
stderr: stderr.strip
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# コマンドが失敗した場合、エラーメッセージを追加
|
|
74
|
+
unless status.success?
|
|
75
|
+
result[:error] = "コマンドが失敗しました (終了コード: #{status.exitstatus})"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
result
|
|
79
|
+
rescue Errno::ENOENT => e
|
|
80
|
+
{ success: false, error: "コマンドが見つかりません: #{e.message}" }
|
|
81
|
+
rescue StandardError => e
|
|
82
|
+
{ success: false, error: "コマンド実行エラー: #{e.message}" }
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
51
86
|
# プラグインからコマンドを読み込む
|
|
52
87
|
def load_plugin_commands
|
|
53
88
|
# 有効なプラグインを取得
|
|
@@ -51,16 +51,6 @@ module Rufio
|
|
|
51
51
|
content_lines = [""]
|
|
52
52
|
content_lines << "#{input}_" # カーソルを_で表現
|
|
53
53
|
content_lines << ""
|
|
54
|
-
|
|
55
|
-
# 補完候補がある場合は表示
|
|
56
|
-
unless suggestions.empty?
|
|
57
|
-
content_lines << "補完候補:"
|
|
58
|
-
suggestions.each do |suggestion|
|
|
59
|
-
content_lines << " #{suggestion}"
|
|
60
|
-
end
|
|
61
|
-
content_lines << ""
|
|
62
|
-
end
|
|
63
|
-
|
|
64
54
|
content_lines << "Tab: 補完 | Enter: 実行 | ESC: キャンセル"
|
|
65
55
|
|
|
66
56
|
# ウィンドウの色設定(青)
|
|
@@ -87,16 +77,23 @@ module Rufio
|
|
|
87
77
|
end
|
|
88
78
|
|
|
89
79
|
# コマンド実行結果をフローティングウィンドウで表示
|
|
90
|
-
# @param result [String, nil] コマンド実行結果
|
|
80
|
+
# @param result [String, Hash, nil] コマンド実行結果
|
|
91
81
|
def show_result(result)
|
|
92
82
|
# nil または空文字列の場合は何も表示しない
|
|
93
83
|
return if result.nil? || result.empty?
|
|
94
84
|
|
|
95
|
-
#
|
|
96
|
-
|
|
85
|
+
# Hash形式の結果を処理
|
|
86
|
+
if result.is_a?(Hash)
|
|
87
|
+
result_text = format_hash_result(result)
|
|
88
|
+
is_error = !result[:success]
|
|
89
|
+
else
|
|
90
|
+
# 文字列形式の結果(従来の動作)
|
|
91
|
+
result_text = result
|
|
92
|
+
is_error = result.include?("⚠️") || result.include?("エラー")
|
|
93
|
+
end
|
|
97
94
|
|
|
98
|
-
#
|
|
99
|
-
|
|
95
|
+
# 結果を行に分割
|
|
96
|
+
result_lines = result_text.split("\n")
|
|
100
97
|
|
|
101
98
|
# ウィンドウの色設定
|
|
102
99
|
if is_error
|
|
@@ -164,5 +161,41 @@ module Rufio
|
|
|
164
161
|
|
|
165
162
|
strings.first[0...common_length]
|
|
166
163
|
end
|
|
164
|
+
|
|
165
|
+
# Hash形式の結果を文字列に変換
|
|
166
|
+
# @param result [Hash] コマンド実行結果
|
|
167
|
+
# @return [String] フォーマットされた結果
|
|
168
|
+
def format_hash_result(result)
|
|
169
|
+
lines = []
|
|
170
|
+
|
|
171
|
+
# エラーメッセージがある場合
|
|
172
|
+
if result[:error]
|
|
173
|
+
lines << result[:error]
|
|
174
|
+
lines << ""
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# 標準出力
|
|
178
|
+
if result[:output] && !result[:output].empty?
|
|
179
|
+
lines << result[:output]
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# 標準エラー出力(空でない場合のみ)
|
|
183
|
+
if result[:stderr] && !result[:stderr].empty?
|
|
184
|
+
lines << "" if lines.any?
|
|
185
|
+
lines << "--- stderr ---"
|
|
186
|
+
lines << result[:stderr]
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# 何も出力がない場合
|
|
190
|
+
if lines.empty?
|
|
191
|
+
if result[:success]
|
|
192
|
+
lines << "コマンドが正常に実行されました"
|
|
193
|
+
else
|
|
194
|
+
lines << "コマンドが失敗しました"
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
lines.join("\n")
|
|
199
|
+
end
|
|
167
200
|
end
|
|
168
201
|
end
|