rufio 0.9.0 → 0.10.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 +28 -0
- data/CHANGELOG_v0.10.0.md +145 -0
- data/lib/rufio/bookmark_manager.rb +198 -22
- data/lib/rufio/dialog_renderer.rb +106 -0
- data/lib/rufio/keybind_handler.rb +14 -5
- data/lib/rufio/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9201391f4316c4c09afabccefe7d81bb919acb11fd895981f87ebb5ad4592858
|
|
4
|
+
data.tar.gz: 0e801a038eb4c50fc170a6ce0838903cf8905b4edeb5dacbbcfaf2c04ceaf7be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9b7ab89aeed58a0af7f9d3fe617a7e71c13a9ea13f934a97ee6c607de6b30314b7ad6a769bf52d7adb617aa8be8a12f87dc674ee08d0da348c9617a24aab1521
|
|
7
|
+
data.tar.gz: 702f4a988028b4dd69f2a4610ab8393c5bd65d7eaabdaa8a6cd4432917d71a91f96179f2ba226d6a6e4a64e0bdcbed1076db6f0740296fe144fb2298332a8f86
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.10.0] - 2025-01-XX
|
|
11
|
+
|
|
12
|
+
### 🎨 Enhanced - Bookmark UI Overhaul
|
|
13
|
+
- **Floating input dialogs**: All bookmark operations now use modern floating window interface
|
|
14
|
+
- **Add Bookmark dialog**: Blue-bordered floating input with automatic whitespace trimming
|
|
15
|
+
- **List Bookmark dialog**: Interactive selection with direct navigation support
|
|
16
|
+
- **Remove Bookmark dialog**: Two-stage confirmation with color-coded warnings
|
|
17
|
+
- **Improved input handling**: Better cursor positioning, no border overlap, proper padding
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- **DialogRenderer#show_input_dialog**: Unified floating input interface with ESC support
|
|
21
|
+
- **Color-coded feedback dialogs**: 🔵 Blue (info), 🔴 Red (warning/error), 🟡 Yellow (confirm), 🟢 Green (success)
|
|
22
|
+
- **Automatic input trimming**: Leading/trailing spaces removed from bookmark names
|
|
23
|
+
- **Path truncation**: Long paths display with `~` for home directory
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **Input field positioning**: Text no longer overlaps with dialog borders
|
|
27
|
+
- **Bookmark list navigation**: Users can now navigate to bookmarks from list view
|
|
28
|
+
- **Dialog layout**: Proper spacing between all dialog elements
|
|
29
|
+
|
|
30
|
+
### Technical Details
|
|
31
|
+
- New input dialog system with multi-byte character support
|
|
32
|
+
- Enhanced BookmarkManager with private helper methods for dialogs
|
|
33
|
+
- Improved cursor positioning calculations
|
|
34
|
+
- **Detailed changelog**: [CHANGELOG_v0.10.0.md](./CHANGELOG_v0.10.0.md)
|
|
35
|
+
|
|
36
|
+
## [0.9.0] - 2025-01-XX
|
|
37
|
+
|
|
10
38
|
### Added
|
|
11
39
|
- **Escape key support for file/directory creation**: Press `Esc` to cancel file (`a`) or directory (`A`) creation prompts and return to the main view
|
|
12
40
|
- **Interactive input improvements**: Backspace support and better character handling for Japanese input
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Changelog v0.10.0 - Bookmark UI Enhancement
|
|
2
|
+
|
|
3
|
+
## [0.10.0] - 2025-01-XX
|
|
4
|
+
|
|
5
|
+
### 🎨 Enhanced - Bookmark UI Overhaul
|
|
6
|
+
|
|
7
|
+
Complete redesign of bookmark operations with modern floating window dialogs for improved user experience and consistency.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
#### Floating Input Dialog System
|
|
12
|
+
- **New `DialogRenderer#show_input_dialog` method**: Unified floating window input interface
|
|
13
|
+
- Centered floating dialog with customizable colors
|
|
14
|
+
- Real-time character input with visual feedback
|
|
15
|
+
- Multi-byte character support (Japanese, Chinese, etc.)
|
|
16
|
+
- Automatic input trimming (leading/trailing spaces)
|
|
17
|
+
- ESC key support for cancellation
|
|
18
|
+
- Input width validation to prevent overflow
|
|
19
|
+
|
|
20
|
+
#### Enhanced Bookmark Operations
|
|
21
|
+
|
|
22
|
+
**Add Bookmark (`b` → `[A]`)**
|
|
23
|
+
- Floating input dialog with blue border
|
|
24
|
+
- Clear prompt: "Enter bookmark name:"
|
|
25
|
+
- Input indicator: `> ` for better visibility
|
|
26
|
+
- Automatic whitespace trimming
|
|
27
|
+
- Success/error feedback with colored dialogs
|
|
28
|
+
- Green border for success
|
|
29
|
+
- Red border for errors
|
|
30
|
+
|
|
31
|
+
**List Bookmarks (`b` → `[L]`)**
|
|
32
|
+
- Interactive selection from floating dialog
|
|
33
|
+
- Blue-bordered bookmark list
|
|
34
|
+
- Path truncation with `~` for home directory
|
|
35
|
+
- 1-9 number key selection
|
|
36
|
+
- Direct navigation to selected bookmark
|
|
37
|
+
- ESC key to cancel
|
|
38
|
+
|
|
39
|
+
**Remove Bookmark (`b` → `[R]`)**
|
|
40
|
+
- Two-stage confirmation process for safety
|
|
41
|
+
- Red-bordered selection dialog (warning color)
|
|
42
|
+
- Yellow-bordered confirmation dialog (caution color)
|
|
43
|
+
- Displays bookmark name in confirmation
|
|
44
|
+
- Success/error feedback dialogs
|
|
45
|
+
- ESC key support at all stages
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
|
|
49
|
+
#### UI/UX Improvements
|
|
50
|
+
- **Consistent floating window interface** across all bookmark operations
|
|
51
|
+
- **Color-coded dialogs** for different operation types:
|
|
52
|
+
- 🔵 Blue: Information and input (Add, List)
|
|
53
|
+
- 🔴 Red: Warning and removal (Remove selection)
|
|
54
|
+
- 🟡 Yellow: Confirmation (Remove confirmation)
|
|
55
|
+
- 🟢 Green: Success messages
|
|
56
|
+
- 🔴 Red: Error messages
|
|
57
|
+
|
|
58
|
+
#### Input Handling
|
|
59
|
+
- **Improved cursor positioning** in input dialogs
|
|
60
|
+
- Proper padding from dialog borders
|
|
61
|
+
- Correct vertical alignment accounting for title and separators
|
|
62
|
+
- **Better input field layout**
|
|
63
|
+
- Input line positioned with `> ` prompt indicator
|
|
64
|
+
- Adequate spacing between prompt and input area
|
|
65
|
+
- No text overlapping with dialog borders
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
|
|
69
|
+
- **Input field positioning**: Text no longer overlaps with dialog borders
|
|
70
|
+
- Fixed `input_y` calculation: `y + 4` → `y + 6`
|
|
71
|
+
- Fixed `input_x` calculation: `x + 2` → `x + 4`
|
|
72
|
+
- Fixed `max_input_width`: `dialog_width - 4` → `dialog_width - 8`
|
|
73
|
+
- **Bookmark list navigation**: Users can now navigate to bookmarks from the list view
|
|
74
|
+
- **Input trimming**: Leading and trailing spaces automatically removed from bookmark names
|
|
75
|
+
- **Dialog height**: Adjusted to prevent input line from touching bottom border
|
|
76
|
+
|
|
77
|
+
### Technical Details
|
|
78
|
+
|
|
79
|
+
#### New Components
|
|
80
|
+
```ruby
|
|
81
|
+
# DialogRenderer enhancements
|
|
82
|
+
- show_input_dialog(title, prompt, options)
|
|
83
|
+
- read_input_in_dialog(x, y, width, height, input_x, input_y, options)
|
|
84
|
+
|
|
85
|
+
# BookmarkManager enhancements
|
|
86
|
+
- show_result_dialog(title, message, type)
|
|
87
|
+
- show_remove_confirmation(bookmark_name)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### Dialog Layout Improvements
|
|
91
|
+
```
|
|
92
|
+
Old layout (7 lines):
|
|
93
|
+
┌─────────────────────┐
|
|
94
|
+
│ Add Bookmark │
|
|
95
|
+
├─────────────────────┤
|
|
96
|
+
│ Enter bookmark name:│ ← overlapped with border
|
|
97
|
+
└─────────────────────┘
|
|
98
|
+
|
|
99
|
+
New layout (8 lines):
|
|
100
|
+
┌─────────────────────┐
|
|
101
|
+
│ Add Bookmark │
|
|
102
|
+
├─────────────────────┤
|
|
103
|
+
│ │
|
|
104
|
+
│ Enter bookmark name:│
|
|
105
|
+
│ │
|
|
106
|
+
│ > │ ← proper spacing
|
|
107
|
+
│ │
|
|
108
|
+
└─────────────────────┘
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### Code Quality
|
|
112
|
+
- Removed unused variable warnings
|
|
113
|
+
- Consistent error handling across all bookmark operations
|
|
114
|
+
- Proper screen refresh after dialog operations
|
|
115
|
+
- All tests passing (261 runs, 1141 assertions, 0 failures)
|
|
116
|
+
|
|
117
|
+
### Migration Notes
|
|
118
|
+
|
|
119
|
+
**User-facing changes:**
|
|
120
|
+
- All bookmark operations now use floating dialogs
|
|
121
|
+
- No more bottom-of-screen input prompts
|
|
122
|
+
- Improved visual feedback for all operations
|
|
123
|
+
- More intuitive navigation and selection
|
|
124
|
+
|
|
125
|
+
**Developer notes:**
|
|
126
|
+
- `BookmarkManager` methods now return different types:
|
|
127
|
+
- `add_interactive`: Still returns `Boolean`
|
|
128
|
+
- `list_interactive`: Now returns `Hash` (selected bookmark) or `nil`
|
|
129
|
+
- `remove_interactive`: Still returns `Boolean`
|
|
130
|
+
- `KeybindHandler` updated to handle new return types
|
|
131
|
+
- Dialog renderer supports input fields via `show_input_dialog`
|
|
132
|
+
|
|
133
|
+
### Dependencies
|
|
134
|
+
|
|
135
|
+
No new dependencies added. All changes use existing gems:
|
|
136
|
+
- `io-console` for character input
|
|
137
|
+
- Existing `dialog_renderer` infrastructure
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
**Full Diff Stats:**
|
|
142
|
+
- Modified: `lib/rufio/dialog_renderer.rb`
|
|
143
|
+
- Modified: `lib/rufio/bookmark_manager.rb`
|
|
144
|
+
- Modified: `lib/rufio/keybind_handler.rb`
|
|
145
|
+
- Tests: All passing ✅
|
|
@@ -68,15 +68,25 @@ module Rufio
|
|
|
68
68
|
# @param path [String] Path to bookmark
|
|
69
69
|
# @return [Boolean] Success status
|
|
70
70
|
def add_interactive(path)
|
|
71
|
-
|
|
72
|
-
name = STDIN.gets.chomp
|
|
73
|
-
return false if name.empty?
|
|
71
|
+
return false unless @dialog_renderer
|
|
74
72
|
|
|
73
|
+
# Show floating input dialog
|
|
74
|
+
title = 'Add Bookmark'
|
|
75
|
+
prompt = 'Enter bookmark name:'
|
|
76
|
+
name = @dialog_renderer.show_input_dialog(title, prompt, {
|
|
77
|
+
border_color: "\e[34m", # Blue
|
|
78
|
+
title_color: "\e[1;34m", # Bold blue
|
|
79
|
+
content_color: "\e[37m" # White
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
return false if name.nil? || name.empty?
|
|
83
|
+
|
|
84
|
+
# Add bookmark (name is already trimmed in show_input_dialog)
|
|
75
85
|
if @bookmark.add(path, name)
|
|
76
|
-
|
|
86
|
+
show_result_dialog('Bookmark Added', "Added: #{name}", :success)
|
|
77
87
|
true
|
|
78
88
|
else
|
|
79
|
-
|
|
89
|
+
show_result_dialog('Add Failed', 'Failed to add bookmark', :error)
|
|
80
90
|
false
|
|
81
91
|
end
|
|
82
92
|
end
|
|
@@ -87,50 +97,132 @@ module Rufio
|
|
|
87
97
|
bookmarks = @bookmark.list
|
|
88
98
|
|
|
89
99
|
if bookmarks.empty?
|
|
90
|
-
|
|
100
|
+
show_result_dialog('No Bookmarks', 'No bookmarks found', :error)
|
|
91
101
|
return false
|
|
92
102
|
end
|
|
93
103
|
|
|
94
|
-
|
|
104
|
+
return false unless @dialog_renderer
|
|
105
|
+
|
|
106
|
+
# Build content lines for bookmark selection
|
|
107
|
+
content_lines = ['', 'Select bookmark to remove:', '']
|
|
95
108
|
bookmarks.each_with_index do |bookmark, index|
|
|
96
|
-
|
|
109
|
+
# Truncate path if too long
|
|
110
|
+
display_path = bookmark[:path]
|
|
111
|
+
if display_path.start_with?(Dir.home)
|
|
112
|
+
display_path = display_path.sub(Dir.home, '~')
|
|
113
|
+
end
|
|
114
|
+
if display_path.length > 35
|
|
115
|
+
display_path = "...#{display_path[-32..]}"
|
|
116
|
+
end
|
|
117
|
+
content_lines << " #{index + 1}. #{bookmark[:name]}"
|
|
118
|
+
content_lines << " #{display_path}"
|
|
97
119
|
end
|
|
120
|
+
content_lines << ''
|
|
121
|
+
content_lines << 'Press 1-9 to select, ESC to cancel'
|
|
122
|
+
|
|
123
|
+
title = 'Remove Bookmark'
|
|
124
|
+
width = 60
|
|
125
|
+
height = [content_lines.length + 4, 20].min
|
|
126
|
+
x, y = @dialog_renderer.calculate_center(width, height)
|
|
98
127
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
128
|
+
@dialog_renderer.draw_floating_window(x, y, width, height, title, content_lines, {
|
|
129
|
+
border_color: "\e[31m", # Red (warning)
|
|
130
|
+
title_color: "\e[1;31m", # Bold red
|
|
131
|
+
content_color: "\e[37m" # White
|
|
132
|
+
})
|
|
102
133
|
|
|
103
|
-
|
|
104
|
-
|
|
134
|
+
# Wait for selection
|
|
135
|
+
selected_number = nil
|
|
136
|
+
loop do
|
|
137
|
+
input = STDIN.getch.downcase
|
|
138
|
+
|
|
139
|
+
if input >= '1' && input <= '9'
|
|
140
|
+
number = input.to_i
|
|
141
|
+
if number > 0 && number <= bookmarks.length
|
|
142
|
+
selected_number = number
|
|
143
|
+
break
|
|
144
|
+
end
|
|
145
|
+
elsif input == "\e" # ESC
|
|
146
|
+
@dialog_renderer.clear_area(x, y, width, height)
|
|
147
|
+
return false
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
@dialog_renderer.clear_area(x, y, width, height)
|
|
152
|
+
|
|
153
|
+
# Confirm deletion
|
|
154
|
+
bookmark_to_remove = bookmarks[selected_number - 1]
|
|
155
|
+
if show_remove_confirmation(bookmark_to_remove[:name])
|
|
105
156
|
if @bookmark.remove(bookmark_to_remove[:name])
|
|
106
|
-
|
|
157
|
+
show_result_dialog('Bookmark Removed', "Removed: #{bookmark_to_remove[:name]}", :success)
|
|
107
158
|
true
|
|
108
159
|
else
|
|
109
|
-
|
|
160
|
+
show_result_dialog('Remove Failed', 'Failed to remove bookmark', :error)
|
|
110
161
|
false
|
|
111
162
|
end
|
|
112
163
|
else
|
|
113
|
-
puts "\n#{ConfigLoader.message('bookmark.invalid_number') || 'Invalid number'}"
|
|
114
164
|
false
|
|
115
165
|
end
|
|
116
166
|
end
|
|
117
167
|
|
|
118
168
|
# List all bookmarks interactively
|
|
119
|
-
# @return [
|
|
169
|
+
# @return [Hash, nil] Selected bookmark path or nil
|
|
120
170
|
def list_interactive
|
|
121
171
|
bookmarks = @bookmark.list
|
|
122
172
|
|
|
123
173
|
if bookmarks.empty?
|
|
124
|
-
|
|
125
|
-
return
|
|
174
|
+
show_result_dialog('No Bookmarks', 'No bookmarks found', :error)
|
|
175
|
+
return nil
|
|
126
176
|
end
|
|
127
177
|
|
|
128
|
-
|
|
178
|
+
return nil unless @dialog_renderer
|
|
179
|
+
|
|
180
|
+
# Build content lines
|
|
181
|
+
content_lines = ['', 'Select a bookmark:','']
|
|
129
182
|
bookmarks.each_with_index do |bookmark, index|
|
|
130
|
-
|
|
183
|
+
# Truncate path if too long
|
|
184
|
+
display_path = bookmark[:path]
|
|
185
|
+
if display_path.start_with?(Dir.home)
|
|
186
|
+
display_path = display_path.sub(Dir.home, '~')
|
|
187
|
+
end
|
|
188
|
+
if display_path.length > 35
|
|
189
|
+
display_path = "...#{display_path[-32..]}"
|
|
190
|
+
end
|
|
191
|
+
content_lines << " #{index + 1}. #{bookmark[:name]}"
|
|
192
|
+
content_lines << " #{display_path}"
|
|
193
|
+
end
|
|
194
|
+
content_lines << ''
|
|
195
|
+
content_lines << 'Press 1-9 to select, ESC to cancel'
|
|
196
|
+
|
|
197
|
+
title = 'Bookmarks'
|
|
198
|
+
width = 60
|
|
199
|
+
height = [content_lines.length + 4, 20].min
|
|
200
|
+
x, y = @dialog_renderer.calculate_center(width, height)
|
|
201
|
+
|
|
202
|
+
@dialog_renderer.draw_floating_window(x, y, width, height, title, content_lines, {
|
|
203
|
+
border_color: "\e[34m", # Blue
|
|
204
|
+
title_color: "\e[1;34m", # Bold blue
|
|
205
|
+
content_color: "\e[37m" # White
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
# Wait for selection
|
|
209
|
+
selected_bookmark = nil
|
|
210
|
+
loop do
|
|
211
|
+
input = STDIN.getch.downcase
|
|
212
|
+
|
|
213
|
+
if input >= '1' && input <= '9'
|
|
214
|
+
number = input.to_i
|
|
215
|
+
if number > 0 && number <= bookmarks.length
|
|
216
|
+
selected_bookmark = bookmarks[number - 1]
|
|
217
|
+
break
|
|
218
|
+
end
|
|
219
|
+
elsif input == "\e" # ESC
|
|
220
|
+
break
|
|
221
|
+
end
|
|
131
222
|
end
|
|
132
223
|
|
|
133
|
-
|
|
224
|
+
@dialog_renderer.clear_area(x, y, width, height)
|
|
225
|
+
selected_bookmark
|
|
134
226
|
end
|
|
135
227
|
|
|
136
228
|
# Get bookmark by number
|
|
@@ -169,5 +261,89 @@ module Rufio
|
|
|
169
261
|
def remove(name)
|
|
170
262
|
@bookmark.remove(name)
|
|
171
263
|
end
|
|
264
|
+
|
|
265
|
+
private
|
|
266
|
+
|
|
267
|
+
# Show result dialog with success or error styling
|
|
268
|
+
# @param title [String] Dialog title
|
|
269
|
+
# @param message [String] Result message
|
|
270
|
+
# @param type [Symbol] :success or :error
|
|
271
|
+
def show_result_dialog(title, message, type)
|
|
272
|
+
return unless @dialog_renderer
|
|
273
|
+
|
|
274
|
+
# Set colors based on result type
|
|
275
|
+
if type == :success
|
|
276
|
+
border_color = "\e[32m" # Green
|
|
277
|
+
title_color = "\e[1;32m" # Bold green
|
|
278
|
+
else
|
|
279
|
+
border_color = "\e[31m" # Red
|
|
280
|
+
title_color = "\e[1;31m" # Bold red
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
content_lines = [
|
|
284
|
+
'',
|
|
285
|
+
message,
|
|
286
|
+
'',
|
|
287
|
+
'Press any key to continue...'
|
|
288
|
+
]
|
|
289
|
+
|
|
290
|
+
width = 50
|
|
291
|
+
height = 6
|
|
292
|
+
x, y = @dialog_renderer.calculate_center(width, height)
|
|
293
|
+
|
|
294
|
+
@dialog_renderer.draw_floating_window(x, y, width, height, title, content_lines, {
|
|
295
|
+
border_color: border_color,
|
|
296
|
+
title_color: title_color,
|
|
297
|
+
content_color: "\e[37m"
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
STDIN.getch
|
|
301
|
+
@dialog_renderer.clear_area(x, y, width, height)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# Show confirmation dialog for bookmark removal
|
|
305
|
+
# @param bookmark_name [String] Name of bookmark to remove
|
|
306
|
+
# @return [Boolean] true if confirmed, false if cancelled
|
|
307
|
+
def show_remove_confirmation(bookmark_name)
|
|
308
|
+
return false unless @dialog_renderer
|
|
309
|
+
|
|
310
|
+
content_lines = [
|
|
311
|
+
'',
|
|
312
|
+
"Remove bookmark '#{bookmark_name}'?",
|
|
313
|
+
'',
|
|
314
|
+
' [Y]es - Remove',
|
|
315
|
+
' [N]o - Cancel',
|
|
316
|
+
''
|
|
317
|
+
]
|
|
318
|
+
|
|
319
|
+
title = 'Confirm Remove'
|
|
320
|
+
width = 50
|
|
321
|
+
height = content_lines.length + 4
|
|
322
|
+
x, y = @dialog_renderer.calculate_center(width, height)
|
|
323
|
+
|
|
324
|
+
@dialog_renderer.draw_floating_window(x, y, width, height, title, content_lines, {
|
|
325
|
+
border_color: "\e[33m", # Yellow (warning)
|
|
326
|
+
title_color: "\e[1;33m", # Bold yellow
|
|
327
|
+
content_color: "\e[37m" # White
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
# Wait for confirmation
|
|
331
|
+
confirmed = false
|
|
332
|
+
loop do
|
|
333
|
+
input = STDIN.getch.downcase
|
|
334
|
+
|
|
335
|
+
case input
|
|
336
|
+
when 'y'
|
|
337
|
+
confirmed = true
|
|
338
|
+
break
|
|
339
|
+
when 'n', "\e" # n or ESC
|
|
340
|
+
confirmed = false
|
|
341
|
+
break
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
@dialog_renderer.clear_area(x, y, width, height)
|
|
346
|
+
confirmed
|
|
347
|
+
end
|
|
172
348
|
end
|
|
173
349
|
end
|
|
@@ -123,5 +123,111 @@ module Rufio
|
|
|
123
123
|
|
|
124
124
|
[width, height]
|
|
125
125
|
end
|
|
126
|
+
|
|
127
|
+
# Show a floating input dialog and get user input
|
|
128
|
+
# @param title [String] Dialog title
|
|
129
|
+
# @param prompt [String] Prompt message
|
|
130
|
+
# @param options [Hash] Customization options
|
|
131
|
+
# @option options [String] :border_color Border color ANSI code
|
|
132
|
+
# @option options [String] :title_color Title color ANSI code
|
|
133
|
+
# @option options [String] :content_color Content color ANSI code
|
|
134
|
+
# @option options [Integer] :width Dialog width (default: 50)
|
|
135
|
+
# @return [String, nil] User input (nil if cancelled)
|
|
136
|
+
def show_input_dialog(title, prompt, options = {})
|
|
137
|
+
require 'io/console'
|
|
138
|
+
|
|
139
|
+
width = options[:width] || 50
|
|
140
|
+
height = 8 # title + separator + prompt + input line + blank + ESC message + borders
|
|
141
|
+
|
|
142
|
+
x, y = calculate_center(width, height)
|
|
143
|
+
|
|
144
|
+
content_lines = [
|
|
145
|
+
'',
|
|
146
|
+
prompt,
|
|
147
|
+
'',
|
|
148
|
+
'> ', # Input line with prompt indicator
|
|
149
|
+
'',
|
|
150
|
+
'',
|
|
151
|
+
'Press ESC to cancel'
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
# Draw initial dialog
|
|
155
|
+
draw_floating_window(x, y, width, height, title, content_lines, options)
|
|
156
|
+
|
|
157
|
+
# Position cursor at input line
|
|
158
|
+
# y + 1 (top border) + 1 (title) + 1 (separator) + 1 (blank) + 1 (prompt) + 1 (blank) + 1 (input line) = y + 6
|
|
159
|
+
input_y = y + 6
|
|
160
|
+
input_x = x + 4 # Inside border with prompt '> ' (border 1 + space 1 + '> ' 2)
|
|
161
|
+
print "\e[#{input_y};#{input_x}H"
|
|
162
|
+
STDOUT.flush
|
|
163
|
+
|
|
164
|
+
# Read input with escape support
|
|
165
|
+
input = read_input_in_dialog(x, y, width, height, input_x, input_y, options)
|
|
166
|
+
|
|
167
|
+
# Clear dialog
|
|
168
|
+
clear_area(x, y, width, height)
|
|
169
|
+
|
|
170
|
+
input
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
private
|
|
174
|
+
|
|
175
|
+
# ASCII character range constants
|
|
176
|
+
ASCII_PRINTABLE_START = 32
|
|
177
|
+
ASCII_PRINTABLE_END = 127
|
|
178
|
+
MULTIBYTE_THRESHOLD = 1
|
|
179
|
+
|
|
180
|
+
# Read user input within a dialog
|
|
181
|
+
# @param dialog_x [Integer] Dialog X position
|
|
182
|
+
# @param dialog_y [Integer] Dialog Y position
|
|
183
|
+
# @param dialog_width [Integer] Dialog width
|
|
184
|
+
# @param dialog_height [Integer] Dialog height
|
|
185
|
+
# @param input_x [Integer] Input field X position
|
|
186
|
+
# @param input_y [Integer] Input field Y position
|
|
187
|
+
# @param options [Hash] Display options
|
|
188
|
+
# @return [String, nil] User input (nil if cancelled)
|
|
189
|
+
def read_input_in_dialog(dialog_x, dialog_y, dialog_width, dialog_height, input_x, input_y, options)
|
|
190
|
+
content_color = options[:content_color] || "\e[37m"
|
|
191
|
+
reset_color = "\e[0m"
|
|
192
|
+
|
|
193
|
+
input_chars = []
|
|
194
|
+
max_input_width = dialog_width - 8 # Leave space for borders and padding (border 2 + padding 4 + border 2)
|
|
195
|
+
|
|
196
|
+
loop do
|
|
197
|
+
char = STDIN.getch
|
|
198
|
+
|
|
199
|
+
case char
|
|
200
|
+
when "\e" # Escape - cancel
|
|
201
|
+
return nil
|
|
202
|
+
when "\r", "\n" # Enter - submit
|
|
203
|
+
return input_chars.join.strip
|
|
204
|
+
when "\u007F", "\b" # Backspace/Delete
|
|
205
|
+
unless input_chars.empty?
|
|
206
|
+
input_chars.pop
|
|
207
|
+
# Redraw input line - clear the entire input area
|
|
208
|
+
print "\e[#{input_y};#{input_x}H"
|
|
209
|
+
print "#{content_color}#{' ' * max_input_width}#{reset_color}"
|
|
210
|
+
print "\e[#{input_y};#{input_x}H"
|
|
211
|
+
print "#{content_color}#{input_chars.join}#{reset_color}"
|
|
212
|
+
STDOUT.flush
|
|
213
|
+
end
|
|
214
|
+
when "\u0003" # Ctrl+C
|
|
215
|
+
raise Interrupt
|
|
216
|
+
else
|
|
217
|
+
# Accept printable characters
|
|
218
|
+
if (char.ord >= ASCII_PRINTABLE_START && char.ord < ASCII_PRINTABLE_END) ||
|
|
219
|
+
char.bytesize > MULTIBYTE_THRESHOLD # Multibyte characters (Japanese, etc.)
|
|
220
|
+
current_width = TextUtils.display_width(input_chars.join)
|
|
221
|
+
char_width = TextUtils.display_width(char)
|
|
222
|
+
|
|
223
|
+
if current_width + char_width <= max_input_width
|
|
224
|
+
input_chars << char
|
|
225
|
+
print "#{content_color}#{char}#{reset_color}"
|
|
226
|
+
STDOUT.flush
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
126
232
|
end
|
|
127
233
|
end
|
|
@@ -698,15 +698,24 @@ module Rufio
|
|
|
698
698
|
case result[:action]
|
|
699
699
|
when :add
|
|
700
700
|
success = @bookmark_manager.add_interactive(result[:path])
|
|
701
|
-
|
|
701
|
+
@terminal_ui&.refresh_display
|
|
702
702
|
success
|
|
703
703
|
when :list
|
|
704
|
-
@bookmark_manager.list_interactive
|
|
705
|
-
|
|
706
|
-
|
|
704
|
+
selected_bookmark = @bookmark_manager.list_interactive
|
|
705
|
+
@terminal_ui&.refresh_display
|
|
706
|
+
if selected_bookmark
|
|
707
|
+
# Navigate to selected bookmark
|
|
708
|
+
if @bookmark_manager.path_exists?(selected_bookmark)
|
|
709
|
+
navigate_to_directory(selected_bookmark[:path])
|
|
710
|
+
else
|
|
711
|
+
show_error_and_wait('bookmark.path_not_exist', selected_bookmark[:path])
|
|
712
|
+
end
|
|
713
|
+
else
|
|
714
|
+
false
|
|
715
|
+
end
|
|
707
716
|
when :remove
|
|
708
717
|
@bookmark_manager.remove_interactive
|
|
709
|
-
|
|
718
|
+
@terminal_ui&.refresh_display
|
|
710
719
|
true
|
|
711
720
|
when :navigate
|
|
712
721
|
goto_bookmark(result[:number])
|
data/lib/rufio/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rufio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- masisz
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: io-console
|
|
@@ -117,6 +117,7 @@ extensions: []
|
|
|
117
117
|
extra_rdoc_files: []
|
|
118
118
|
files:
|
|
119
119
|
- CHANGELOG.md
|
|
120
|
+
- CHANGELOG_v0.10.0.md
|
|
120
121
|
- CHANGELOG_v0.4.0.md
|
|
121
122
|
- CHANGELOG_v0.5.0.md
|
|
122
123
|
- CHANGELOG_v0.6.0.md
|
|
@@ -183,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
183
184
|
- !ruby/object:Gem::Version
|
|
184
185
|
version: '0'
|
|
185
186
|
requirements: []
|
|
186
|
-
rubygems_version:
|
|
187
|
+
rubygems_version: 4.0.2
|
|
187
188
|
specification_version: 4
|
|
188
189
|
summary: Ruby file manager
|
|
189
190
|
test_files: []
|