rufio 0.21.0 → 0.31.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_v0.30.0.md +148 -0
- data/CHANGELOG_v0.31.0.md +125 -0
- data/README.md +65 -0
- data/bin/rufio +80 -9
- data/info/help.md +111 -0
- data/info/keybindings.md +102 -0
- data/info/welcome.md +40 -0
- data/lib/rufio/directory_listing.rb +2 -1
- data/lib/rufio/keybind_handler.rb +224 -11
- data/lib/rufio/terminal_ui.rb +138 -17
- data/lib/rufio/version.rb +1 -1
- data/retag.sh +55 -0
- metadata +12 -7
- data/docs/PLUGIN_GUIDE.md +0 -431
- data/docs/plugin_example.rb +0 -119
- data/info/welcome.txt +0 -21
- data/rufio.gemspec +0 -40
data/info/welcome.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Welcome to rufio! 🚀
|
|
2
|
+
|
|
3
|
+
Thank you for using **rufio** - a terminal-based file manager inspired by [Yazi](https://github.com/sxyazi/yazi).
|
|
4
|
+
|
|
5
|
+
## Key Features
|
|
6
|
+
|
|
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
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
| Key | Action |
|
|
17
|
+
|-----|--------|
|
|
18
|
+
| `j/k` | Move down/up |
|
|
19
|
+
| `h/l` | Go to parent / Enter directory |
|
|
20
|
+
| `f` | Filter files |
|
|
21
|
+
| `b` | Add bookmark |
|
|
22
|
+
| `p` | Project mode |
|
|
23
|
+
| `?` | Help mode |
|
|
24
|
+
| `:` | Command mode |
|
|
25
|
+
| `q` | Quit |
|
|
26
|
+
|
|
27
|
+
## Getting Help
|
|
28
|
+
|
|
29
|
+
Press `?` to enter **Help Mode** where you can browse all documentation files.
|
|
30
|
+
Press `ESC` to exit Help Mode.
|
|
31
|
+
|
|
32
|
+
## More Information
|
|
33
|
+
|
|
34
|
+
Visit the GitHub repository for detailed documentation:
|
|
35
|
+
- **Repository**: https://github.com/masisz/rufio
|
|
36
|
+
- **Issues**: https://github.com/masisz/rufio/issues
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
*Happy file managing! 📁*
|
|
@@ -4,10 +4,11 @@ require 'fileutils'
|
|
|
4
4
|
|
|
5
5
|
module Rufio
|
|
6
6
|
class DirectoryListing
|
|
7
|
-
attr_reader :current_path
|
|
7
|
+
attr_reader :current_path, :start_directory
|
|
8
8
|
|
|
9
9
|
def initialize(path = Dir.pwd)
|
|
10
10
|
@current_path = File.expand_path(path)
|
|
11
|
+
@start_directory = @current_path # 起動時のディレクトリを保存
|
|
11
12
|
@entries = []
|
|
12
13
|
refresh
|
|
13
14
|
end
|
|
@@ -51,6 +51,14 @@ module Rufio
|
|
|
51
51
|
@project_log = ProjectLog.new(log_dir)
|
|
52
52
|
@in_project_mode = false
|
|
53
53
|
@in_log_mode = false
|
|
54
|
+
|
|
55
|
+
# Help mode
|
|
56
|
+
@in_help_mode = false
|
|
57
|
+
@pre_help_directory = nil
|
|
58
|
+
|
|
59
|
+
# Preview pane focus and scroll
|
|
60
|
+
@preview_focused = false
|
|
61
|
+
@preview_scroll_offset = 0
|
|
54
62
|
end
|
|
55
63
|
|
|
56
64
|
def set_directory_listing(directory_listing)
|
|
@@ -85,6 +93,16 @@ module Rufio
|
|
|
85
93
|
return handle_project_mode_key(key)
|
|
86
94
|
end
|
|
87
95
|
|
|
96
|
+
# プレビューペインフォーカス中の特別処理
|
|
97
|
+
if @preview_focused
|
|
98
|
+
return handle_preview_focus_key(key)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# ヘルプモード中のESCキー特別処理
|
|
102
|
+
if @in_help_mode && key == "\e"
|
|
103
|
+
return exit_help_mode
|
|
104
|
+
end
|
|
105
|
+
|
|
88
106
|
# フィルターモード中は他のキーバインドを無効化
|
|
89
107
|
return handle_filter_input(key) if @filter_manager.filter_mode
|
|
90
108
|
|
|
@@ -94,9 +112,11 @@ module Rufio
|
|
|
94
112
|
when 'k'
|
|
95
113
|
move_up
|
|
96
114
|
when 'h'
|
|
97
|
-
|
|
98
|
-
when 'l'
|
|
115
|
+
navigate_parent_with_restriction
|
|
116
|
+
when 'l' # l - navigate into directory
|
|
99
117
|
navigate_enter
|
|
118
|
+
when "\r", "\n" # Enter - focus preview pane or navigate
|
|
119
|
+
handle_enter_key
|
|
100
120
|
when 'g'
|
|
101
121
|
move_to_top
|
|
102
122
|
when 'G'
|
|
@@ -153,8 +173,12 @@ module Rufio
|
|
|
153
173
|
add_bookmark
|
|
154
174
|
when 'z' # z - zoxide history navigation
|
|
155
175
|
show_zoxide_menu
|
|
176
|
+
when '0' # 0 - go to start directory
|
|
177
|
+
goto_start_directory
|
|
156
178
|
when '1', '2', '3', '4', '5', '6', '7', '8', '9' # number keys - go to bookmark
|
|
157
179
|
goto_bookmark(key.to_i)
|
|
180
|
+
when '?' # ? - enter help mode
|
|
181
|
+
enter_help_mode
|
|
158
182
|
when ':' # : - command mode
|
|
159
183
|
activate_command_mode
|
|
160
184
|
else
|
|
@@ -184,16 +208,197 @@ module Rufio
|
|
|
184
208
|
end
|
|
185
209
|
end
|
|
186
210
|
|
|
211
|
+
# ヘルプモード関連メソッド
|
|
212
|
+
|
|
213
|
+
# ヘルプモード中かどうか
|
|
214
|
+
def help_mode?
|
|
215
|
+
@in_help_mode
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# ヘルプモードに入る
|
|
219
|
+
def enter_help_mode
|
|
220
|
+
return false unless @directory_listing
|
|
221
|
+
|
|
222
|
+
# 現在のディレクトリを保存
|
|
223
|
+
@pre_help_directory = @directory_listing.current_path
|
|
224
|
+
|
|
225
|
+
# info ディレクトリに移動
|
|
226
|
+
rufio_root = File.expand_path('../..', __dir__)
|
|
227
|
+
info_dir = File.join(rufio_root, 'info')
|
|
228
|
+
|
|
229
|
+
# info ディレクトリが存在することを確認
|
|
230
|
+
return false unless Dir.exist?(info_dir)
|
|
231
|
+
|
|
232
|
+
# ヘルプモードを有効化
|
|
233
|
+
@in_help_mode = true
|
|
234
|
+
|
|
235
|
+
# info ディレクトリに移動
|
|
236
|
+
navigate_to_directory(info_dir)
|
|
237
|
+
|
|
238
|
+
true
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# ヘルプモードを終了
|
|
242
|
+
def exit_help_mode
|
|
243
|
+
return false unless @in_help_mode
|
|
244
|
+
return false unless @pre_help_directory
|
|
245
|
+
|
|
246
|
+
# ヘルプモードを無効化
|
|
247
|
+
@in_help_mode = false
|
|
248
|
+
|
|
249
|
+
# 元のディレクトリに戻る
|
|
250
|
+
navigate_to_directory(@pre_help_directory)
|
|
251
|
+
|
|
252
|
+
# 保存したディレクトリをクリア
|
|
253
|
+
@pre_help_directory = nil
|
|
254
|
+
|
|
255
|
+
true
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# ヘルプモード時の制限付き親ディレクトリナビゲーション
|
|
259
|
+
def navigate_parent_with_restriction
|
|
260
|
+
if @in_help_mode
|
|
261
|
+
# info ディレクトリより上には移動できない
|
|
262
|
+
rufio_root = File.expand_path('../..', __dir__)
|
|
263
|
+
info_dir = File.join(rufio_root, 'info')
|
|
264
|
+
|
|
265
|
+
current_path = @directory_listing.current_path
|
|
266
|
+
|
|
267
|
+
# 現在のパスが info ディレクトリ以下でない場合は移動を許可しない
|
|
268
|
+
unless current_path.start_with?(info_dir)
|
|
269
|
+
return false
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# 現在のパスが info ディレクトリそのものの場合は移動を許可しない
|
|
273
|
+
if current_path == info_dir
|
|
274
|
+
return false
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# info ディレクトリ配下であれば、通常のナビゲーションを実行
|
|
278
|
+
navigate_parent
|
|
279
|
+
else
|
|
280
|
+
# ヘルプモード外では通常のナビゲーション
|
|
281
|
+
navigate_parent
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# プレビューペイン関連メソッド
|
|
286
|
+
|
|
287
|
+
# プレビューペインがフォーカスされているか
|
|
288
|
+
def preview_focused?
|
|
289
|
+
@preview_focused
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# プレビューペインにフォーカスを移す
|
|
293
|
+
def focus_preview_pane
|
|
294
|
+
# ファイルが選択されている場合のみフォーカス可能
|
|
295
|
+
entry = current_entry
|
|
296
|
+
return false unless entry
|
|
297
|
+
return false unless entry[:type] == 'file'
|
|
298
|
+
|
|
299
|
+
@preview_focused = true
|
|
300
|
+
@preview_scroll_offset = 0 # フォーカス時にスクロール位置をリセット
|
|
301
|
+
true
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# プレビューペインのフォーカスを解除
|
|
305
|
+
def unfocus_preview_pane
|
|
306
|
+
return false unless @preview_focused
|
|
307
|
+
|
|
308
|
+
@preview_focused = false
|
|
309
|
+
true
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# 現在のプレビュースクロールオフセット
|
|
313
|
+
def preview_scroll_offset
|
|
314
|
+
@preview_scroll_offset
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# プレビューを1行下にスクロール
|
|
318
|
+
def scroll_preview_down
|
|
319
|
+
return false unless @preview_focused
|
|
320
|
+
|
|
321
|
+
@preview_scroll_offset += 1
|
|
322
|
+
true
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# プレビューを1行上にスクロール
|
|
326
|
+
def scroll_preview_up
|
|
327
|
+
return false unless @preview_focused
|
|
328
|
+
|
|
329
|
+
@preview_scroll_offset = [@preview_scroll_offset - 1, 0].max
|
|
330
|
+
true
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# プレビューを半画面下にスクロール(Ctrl+D)
|
|
334
|
+
def scroll_preview_page_down
|
|
335
|
+
return false unless @preview_focused
|
|
336
|
+
|
|
337
|
+
# 半画面分スクロール(仮に20行とする)
|
|
338
|
+
page_size = 20
|
|
339
|
+
@preview_scroll_offset += page_size
|
|
340
|
+
true
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# プレビューを半画面上にスクロール(Ctrl+U)
|
|
344
|
+
def scroll_preview_page_up
|
|
345
|
+
return false unless @preview_focused
|
|
346
|
+
|
|
347
|
+
# 半画面分スクロール(仮に20行とする)
|
|
348
|
+
page_size = 20
|
|
349
|
+
@preview_scroll_offset = [@preview_scroll_offset - page_size, 0].max
|
|
350
|
+
true
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# プレビュースクロール位置をリセット(ファイル変更時など)
|
|
354
|
+
def reset_preview_scroll
|
|
355
|
+
@preview_scroll_offset = 0
|
|
356
|
+
end
|
|
357
|
+
|
|
187
358
|
private
|
|
188
359
|
|
|
360
|
+
# Enterキーの処理:ファイルならプレビューフォーカス、ディレクトリならナビゲート
|
|
361
|
+
def handle_enter_key
|
|
362
|
+
entry = current_entry
|
|
363
|
+
return false unless entry
|
|
364
|
+
|
|
365
|
+
if entry[:type] == 'file'
|
|
366
|
+
# ファイルの場合はプレビューペインにフォーカス
|
|
367
|
+
focus_preview_pane
|
|
368
|
+
else
|
|
369
|
+
# ディレクトリの場合は通常のナビゲーション
|
|
370
|
+
navigate_enter
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# プレビューペインフォーカス中のキー処理
|
|
375
|
+
def handle_preview_focus_key(key)
|
|
376
|
+
case key
|
|
377
|
+
when 'j', "\e[B" # j or Down arrow
|
|
378
|
+
scroll_preview_down
|
|
379
|
+
when 'k', "\e[A" # k or Up arrow
|
|
380
|
+
scroll_preview_up
|
|
381
|
+
when "\x04" # Ctrl+D
|
|
382
|
+
scroll_preview_page_down
|
|
383
|
+
when "\x15" # Ctrl+U
|
|
384
|
+
scroll_preview_page_up
|
|
385
|
+
when "\e" # ESC
|
|
386
|
+
unfocus_preview_pane
|
|
387
|
+
else
|
|
388
|
+
false # Unknown key in preview mode
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
189
392
|
def move_down
|
|
190
393
|
entries = get_active_entries
|
|
191
394
|
@current_index = [@current_index + 1, entries.length - 1].min
|
|
395
|
+
reset_preview_scroll # ファイル変更時にスクロール位置をリセット
|
|
192
396
|
true
|
|
193
397
|
end
|
|
194
398
|
|
|
195
399
|
def move_up
|
|
196
400
|
@current_index = [@current_index - 1, 0].max
|
|
401
|
+
reset_preview_scroll # ファイル変更時にスクロール位置をリセット
|
|
197
402
|
true
|
|
198
403
|
end
|
|
199
404
|
|
|
@@ -1012,20 +1217,22 @@ module Rufio
|
|
|
1012
1217
|
end
|
|
1013
1218
|
end
|
|
1014
1219
|
|
|
1220
|
+
def goto_start_directory
|
|
1221
|
+
start_dir = @directory_listing&.start_directory
|
|
1222
|
+
return false unless start_dir
|
|
1223
|
+
|
|
1224
|
+
# 起動ディレクトリに移動
|
|
1225
|
+
navigate_to_directory(start_dir)
|
|
1226
|
+
end
|
|
1227
|
+
|
|
1015
1228
|
def goto_bookmark(number)
|
|
1016
1229
|
bookmark = @bookmark_manager.find_by_number(number)
|
|
1017
1230
|
|
|
1018
|
-
return
|
|
1019
|
-
return
|
|
1231
|
+
return false unless bookmark
|
|
1232
|
+
return false unless @bookmark_manager.path_exists?(bookmark)
|
|
1020
1233
|
|
|
1021
1234
|
# ディレクトリに移動
|
|
1022
|
-
|
|
1023
|
-
puts "\n#{ConfigLoader.message('bookmark.navigated') || 'Navigated to bookmark'}: #{bookmark[:name]}"
|
|
1024
|
-
sleep(0.5) # 短時間表示
|
|
1025
|
-
true
|
|
1026
|
-
else
|
|
1027
|
-
show_error_and_wait('bookmark.navigate_failed', bookmark[:name])
|
|
1028
|
-
end
|
|
1235
|
+
navigate_to_directory(bookmark[:path])
|
|
1029
1236
|
end
|
|
1030
1237
|
|
|
1031
1238
|
def add_bookmark
|
|
@@ -1405,5 +1612,11 @@ module Rufio
|
|
|
1405
1612
|
def in_log_mode?
|
|
1406
1613
|
@in_log_mode
|
|
1407
1614
|
end
|
|
1615
|
+
|
|
1616
|
+
# ヘルプダイアログを表示
|
|
1617
|
+
def show_help_dialog
|
|
1618
|
+
@terminal_ui&.show_help_dialog if @terminal_ui
|
|
1619
|
+
true
|
|
1620
|
+
end
|
|
1408
1621
|
end
|
|
1409
1622
|
end
|
data/lib/rufio/terminal_ui.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Rufio
|
|
|
7
7
|
class TerminalUI
|
|
8
8
|
# Layout constants
|
|
9
9
|
HEADER_HEIGHT = 1 # Header占有行数
|
|
10
|
-
FOOTER_HEIGHT = 1 # Footer
|
|
10
|
+
FOOTER_HEIGHT = 1 # Footer占有行数(ブックマーク一覧 + ステータス情報)
|
|
11
11
|
HEADER_FOOTER_MARGIN = 3 # Header + Footer分のマージン
|
|
12
12
|
|
|
13
13
|
# Panel layout ratios
|
|
@@ -115,6 +115,9 @@ module Rufio
|
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def draw_screen
|
|
118
|
+
# 処理時間測定開始
|
|
119
|
+
start_time = Time.now
|
|
120
|
+
|
|
118
121
|
# move cursor to top of screen (don't clear)
|
|
119
122
|
print "\e[H"
|
|
120
123
|
|
|
@@ -142,8 +145,9 @@ module Rufio
|
|
|
142
145
|
draw_directory_list(entries, left_width, content_height)
|
|
143
146
|
draw_file_preview(selected_entry, right_width, content_height, left_width)
|
|
144
147
|
|
|
145
|
-
# footer
|
|
146
|
-
|
|
148
|
+
# footer (統合されたステータス情報を含む)
|
|
149
|
+
render_time = Time.now - start_time
|
|
150
|
+
draw_footer(render_time)
|
|
147
151
|
|
|
148
152
|
# コマンドモードがアクティブな場合はコマンド入力ウィンドウを表示
|
|
149
153
|
if @command_mode_active
|
|
@@ -161,6 +165,11 @@ module Rufio
|
|
|
161
165
|
current_path = @directory_listing.current_path
|
|
162
166
|
header = "📁 rufio - #{current_path}"
|
|
163
167
|
|
|
168
|
+
# Add help mode indicator if in help mode
|
|
169
|
+
if @keybind_handler.help_mode?
|
|
170
|
+
header += " [Help Mode - Press ESC to exit]"
|
|
171
|
+
end
|
|
172
|
+
|
|
164
173
|
# Add filter indicator if in filter mode
|
|
165
174
|
if @keybind_handler.filter_active?
|
|
166
175
|
filter_text = " [Filter: #{@keybind_handler.filter_query}]"
|
|
@@ -169,7 +178,12 @@ module Rufio
|
|
|
169
178
|
|
|
170
179
|
# abbreviate if path is too long
|
|
171
180
|
if header.length > @screen_width - HEADER_PADDING
|
|
172
|
-
if @keybind_handler.
|
|
181
|
+
if @keybind_handler.help_mode?
|
|
182
|
+
# prioritize showing help mode indicator
|
|
183
|
+
help_text = " [Help Mode - Press ESC to exit]"
|
|
184
|
+
base_length = @screen_width - help_text.length - FILTER_TEXT_RESERVED
|
|
185
|
+
header = "📁 rufio - ...#{current_path[-base_length..-1]}#{help_text}"
|
|
186
|
+
elsif @keybind_handler.filter_active?
|
|
173
187
|
# prioritize showing filter when active
|
|
174
188
|
filter_text = " [Filter: #{@keybind_handler.filter_query}]"
|
|
175
189
|
base_length = @screen_width - filter_text.length - FILTER_TEXT_RESERVED
|
|
@@ -310,12 +324,19 @@ module Rufio
|
|
|
310
324
|
if selected_entry && i == 0
|
|
311
325
|
# プレビューヘッダー
|
|
312
326
|
header = " #{selected_entry[:name]} "
|
|
327
|
+
# プレビューフォーカス中は表示を追加
|
|
328
|
+
if @keybind_handler&.preview_focused?
|
|
329
|
+
header += "[PREVIEW MODE]"
|
|
330
|
+
end
|
|
313
331
|
content_to_print = header
|
|
314
332
|
elsif selected_entry && selected_entry[:type] == 'file' && i >= 2
|
|
315
333
|
# ファイルプレビュー(折り返し対応)
|
|
316
334
|
preview_content = get_preview_content(selected_entry)
|
|
317
335
|
wrapped_lines = TextUtils.wrap_preview_lines(preview_content, safe_width - 1) # スペース分を除く
|
|
318
|
-
|
|
336
|
+
|
|
337
|
+
# スクロールオフセットを適用
|
|
338
|
+
scroll_offset = @keybind_handler&.preview_scroll_offset || 0
|
|
339
|
+
display_line_index = i - 2 + scroll_offset
|
|
319
340
|
|
|
320
341
|
if display_line_index < wrapped_lines.length
|
|
321
342
|
line = wrapped_lines[display_line_index] || ''
|
|
@@ -376,9 +397,9 @@ module Rufio
|
|
|
376
397
|
end
|
|
377
398
|
end
|
|
378
399
|
|
|
379
|
-
def draw_footer
|
|
380
|
-
#
|
|
381
|
-
footer_line = @screen_height - FOOTER_HEIGHT
|
|
400
|
+
def draw_footer(render_time = nil)
|
|
401
|
+
# フッタは最下行に表示
|
|
402
|
+
footer_line = @screen_height - FOOTER_HEIGHT + 1
|
|
382
403
|
print "\e[#{footer_line};1H"
|
|
383
404
|
|
|
384
405
|
if @keybind_handler.filter_active?
|
|
@@ -387,14 +408,50 @@ module Rufio
|
|
|
387
408
|
else
|
|
388
409
|
help_text = "Filtered view active - Space to edit filter, ESC to clear filter"
|
|
389
410
|
end
|
|
411
|
+
# フィルタモードでは通常のフッタを表示
|
|
412
|
+
footer_content = help_text.ljust(@screen_width)[0...@screen_width]
|
|
413
|
+
print "\e[7m#{footer_content}\e[0m"
|
|
390
414
|
else
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
415
|
+
# 通常モードではブックマーク一覧、ステータス情報、?:helpを1行に表示
|
|
416
|
+
require_relative 'bookmark'
|
|
417
|
+
bookmark = Bookmark.new
|
|
418
|
+
bookmarks = bookmark.list
|
|
419
|
+
|
|
420
|
+
# 起動ディレクトリを取得
|
|
421
|
+
start_dir = @directory_listing&.start_directory
|
|
422
|
+
start_dir_name = if start_dir
|
|
423
|
+
File.basename(start_dir)
|
|
424
|
+
else
|
|
425
|
+
"start"
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# ブックマーク一覧を作成(0.起動dir を先頭に追加)
|
|
429
|
+
bookmark_parts = ["0.#{start_dir_name}"]
|
|
430
|
+
unless bookmarks.empty?
|
|
431
|
+
bookmark_parts.concat(bookmarks.take(9).map.with_index(1) { |bm, idx| "#{idx}.#{bm[:name]}" })
|
|
432
|
+
end
|
|
433
|
+
bookmark_text = bookmark_parts.join(" ")
|
|
394
434
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
435
|
+
# ステータス情報を作成
|
|
436
|
+
time_info = render_time ? "#{(render_time * 1000).round(1)}ms" : "-ms"
|
|
437
|
+
|
|
438
|
+
# 右側の情報: 処理時間 | ?:help
|
|
439
|
+
right_info = "#{time_info} | ?:help"
|
|
440
|
+
|
|
441
|
+
# ブックマーク一覧を利用可能な幅に収める
|
|
442
|
+
available_width = @screen_width - right_info.length - 3
|
|
443
|
+
if bookmark_text.length > available_width && available_width > 3
|
|
444
|
+
bookmark_text = bookmark_text[0...available_width - 3] + "..."
|
|
445
|
+
elsif available_width <= 3
|
|
446
|
+
bookmark_text = ""
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
# フッタ全体を構築
|
|
450
|
+
padding = @screen_width - bookmark_text.length - right_info.length
|
|
451
|
+
footer_content = "#{bookmark_text}#{' ' * padding}#{right_info}"
|
|
452
|
+
footer_content = footer_content.ljust(@screen_width)[0...@screen_width]
|
|
453
|
+
print "\e[7m#{footer_content}\e[0m"
|
|
454
|
+
end
|
|
398
455
|
end
|
|
399
456
|
|
|
400
457
|
def handle_input
|
|
@@ -656,11 +713,12 @@ module Rufio
|
|
|
656
713
|
is_project_selected = (bookmark[:name] == selected_name)
|
|
657
714
|
selection_mark = is_project_selected ? "✓ " : " "
|
|
658
715
|
|
|
659
|
-
#
|
|
716
|
+
# ブックマーク名を表示(番号付き)
|
|
717
|
+
number = index + 1 # 1-based index
|
|
660
718
|
name = bookmark[:name]
|
|
661
|
-
max_name_length = width -
|
|
719
|
+
max_name_length = width - 8 # selection_mark(2) + number(1-2) + ". "(2) + padding
|
|
662
720
|
display_name = name.length > max_name_length ? name[0...max_name_length - 3] + '...' : name
|
|
663
|
-
line_content = "#{selection_mark}#{display_name}".ljust(width)
|
|
721
|
+
line_content = "#{selection_mark}#{number}. #{display_name}".ljust(width)
|
|
664
722
|
|
|
665
723
|
if index == current_index
|
|
666
724
|
# カーソル位置は選択色でハイライト
|
|
@@ -864,6 +922,69 @@ module Rufio
|
|
|
864
922
|
draw_screen
|
|
865
923
|
end
|
|
866
924
|
|
|
925
|
+
# ヘルプダイアログを表示
|
|
926
|
+
def show_help_dialog
|
|
927
|
+
content_lines = [
|
|
928
|
+
'',
|
|
929
|
+
"rufio v#{VERSION}",
|
|
930
|
+
'',
|
|
931
|
+
'Key Bindings:',
|
|
932
|
+
'',
|
|
933
|
+
'j/k - Move up/down',
|
|
934
|
+
'h/l - Navigate back/enter',
|
|
935
|
+
'g/G - Go to top/bottom',
|
|
936
|
+
'o - Open file',
|
|
937
|
+
'f - Filter files',
|
|
938
|
+
's - Search with fzf',
|
|
939
|
+
'F - Content search (rga)',
|
|
940
|
+
'a/A - Create file/directory',
|
|
941
|
+
'm/c/x - Move/Copy/Delete',
|
|
942
|
+
'b - Add bookmark',
|
|
943
|
+
'z - Zoxide navigation',
|
|
944
|
+
'0 - Go to start directory',
|
|
945
|
+
'1-9 - Go to bookmark',
|
|
946
|
+
'p - Project mode',
|
|
947
|
+
': - Command mode',
|
|
948
|
+
'q - Quit',
|
|
949
|
+
''
|
|
950
|
+
]
|
|
951
|
+
|
|
952
|
+
# お知らせ情報を追加
|
|
953
|
+
require_relative 'info_notice'
|
|
954
|
+
info_notice = InfoNotice.new
|
|
955
|
+
all_notices = Dir.glob(File.join(info_notice.info_dir, '*.txt'))
|
|
956
|
+
|
|
957
|
+
if !all_notices.empty?
|
|
958
|
+
content_lines << 'Recent Updates:'
|
|
959
|
+
content_lines << ''
|
|
960
|
+
all_notices.take(3).each do |file|
|
|
961
|
+
title = info_notice.extract_title(file)
|
|
962
|
+
content_lines << " • #{title}"
|
|
963
|
+
end
|
|
964
|
+
content_lines << ''
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
content_lines << 'Press any key to continue...'
|
|
968
|
+
|
|
969
|
+
width = 60
|
|
970
|
+
height = [content_lines.length + 4, @screen_height - 4].min
|
|
971
|
+
x, y = @dialog_renderer.calculate_center(width, height)
|
|
972
|
+
|
|
973
|
+
@dialog_renderer.draw_floating_window(x, y, width, height, 'rufio - Help', content_lines, {
|
|
974
|
+
border_color: "\e[36m", # Cyan
|
|
975
|
+
title_color: "\e[1;36m", # Bold cyan
|
|
976
|
+
content_color: "\e[37m" # White
|
|
977
|
+
})
|
|
978
|
+
|
|
979
|
+
require 'io/console'
|
|
980
|
+
IO.console.getch
|
|
981
|
+
@dialog_renderer.clear_area(x, y, width, height)
|
|
982
|
+
|
|
983
|
+
# 画面を再描画
|
|
984
|
+
refresh_display
|
|
985
|
+
draw_screen
|
|
986
|
+
end
|
|
987
|
+
|
|
867
988
|
# プロジェクトモードでコマンドを実行
|
|
868
989
|
def activate_project_command_mode(project_mode, project_command, project_log)
|
|
869
990
|
return unless project_mode.selected_path
|
data/lib/rufio/version.rb
CHANGED
data/retag.sh
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/bin/zsh
|
|
2
|
+
|
|
3
|
+
# 使い方: ./retag.sh v0.31.0
|
|
4
|
+
|
|
5
|
+
# 引数チェック
|
|
6
|
+
if [ $# -eq 0 ]; then
|
|
7
|
+
echo "使い方: $0 <タグ名>"
|
|
8
|
+
echo "例: $0 v0.31.0"
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
TAG_NAME=$1
|
|
13
|
+
|
|
14
|
+
echo "=== タグ再作成スクリプト ==="
|
|
15
|
+
echo "タグ: $TAG_NAME"
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
# 1. ローカルのタグを削除
|
|
19
|
+
echo "1. ローカルタグを削除中..."
|
|
20
|
+
if git tag -d $TAG_NAME; then
|
|
21
|
+
echo "✓ ローカルタグを削除しました"
|
|
22
|
+
else
|
|
23
|
+
echo "⚠ ローカルタグが存在しないか、削除に失敗しました"
|
|
24
|
+
fi
|
|
25
|
+
echo ""
|
|
26
|
+
|
|
27
|
+
# 2. リモートのタグを削除
|
|
28
|
+
echo "2. リモートタグを削除中..."
|
|
29
|
+
if git push origin :refs/tags/$TAG_NAME; then
|
|
30
|
+
echo "✓ リモートタグを削除しました"
|
|
31
|
+
else
|
|
32
|
+
echo "⚠ リモートタグの削除に失敗しました(存在しない可能性があります)"
|
|
33
|
+
fi
|
|
34
|
+
echo ""
|
|
35
|
+
|
|
36
|
+
# 3. タグを再作成
|
|
37
|
+
echo "3. タグを再作成中..."
|
|
38
|
+
if git tag $TAG_NAME; then
|
|
39
|
+
echo "✓ タグを再作成しました"
|
|
40
|
+
else
|
|
41
|
+
echo "✗ タグの再作成に失敗しました"
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
echo ""
|
|
45
|
+
|
|
46
|
+
# 4. タグをプッシュ
|
|
47
|
+
echo "4. タグをプッシュ中..."
|
|
48
|
+
if git push origin $TAG_NAME; then
|
|
49
|
+
echo "✓ タグをプッシュしました"
|
|
50
|
+
echo ""
|
|
51
|
+
echo "🎉 完了!GitHub Actionsが実行されます。"
|
|
52
|
+
else
|
|
53
|
+
echo "✗ タグのプッシュに失敗しました"
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|