beniya 0.1.0 → 0.2.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/README.md +12 -10
- data/README_EN.md +12 -10
- data/beniya.gemspec +1 -1
- data/lib/beniya/config.rb +18 -0
- data/lib/beniya/file_opener.rb +26 -0
- data/lib/beniya/keybind_handler.rb +126 -19
- data/lib/beniya/terminal_ui.rb +11 -0
- data/lib/beniya/version.rb +2 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b6ab1b0284a8b86ca20e3ba091dec0f285561c297418b922a436e66721a07e5b
|
4
|
+
data.tar.gz: db0b99cb3adf8534dfa89d2110a02079bad81e04b77ef129884e0cd4aa242c5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a508d6b782f008de95b1c1bc46f0ab1b3ff371c806d277f4bdb7a493134ea0be3ffd678d5a63ea9916afed0256e05f17e08e62178ee1d84b0636e81554bb3c56
|
7
|
+
data.tar.gz: 4474966812a065d193946935e65392eaa18265be92a3d4935655079ce54dc83c07325aa85b05753da0c0d202479e9db62595048028f6e4e9de978aebcef981be
|
data/README.md
CHANGED
@@ -74,12 +74,14 @@ beniya --help # ヘルプメッセージを表示
|
|
74
74
|
| `o` | 選択中のファイルを外部エディタで開く |
|
75
75
|
| `e` | 現在のディレクトリをファイルエクスプローラーで開く |
|
76
76
|
| `r` | ディレクトリ内容を更新 |
|
77
|
+
| `a` | 新しいファイルを作成 |
|
78
|
+
| `A` | 新しいディレクトリを作成 |
|
77
79
|
|
78
80
|
#### リアルタイムフィルター機能
|
79
81
|
|
80
82
|
| キー | 機能 |
|
81
83
|
| ----------- | ------------------------------------------ |
|
82
|
-
| `
|
84
|
+
| `s` | フィルターモード開始・再編集 |
|
83
85
|
| 文字入力 | ファイル名で絞り込み(フィルターモード中) |
|
84
86
|
| `Enter` | フィルター維持で通常モードに戻る |
|
85
87
|
| `ESC` | フィルターをクリアして通常モードに戻る |
|
@@ -89,8 +91,8 @@ beniya --help # ヘルプメッセージを表示
|
|
89
91
|
|
90
92
|
| キー | 機能 |
|
91
93
|
| ---- | ----------------------------------------- |
|
92
|
-
|
|
93
|
-
| `
|
94
|
+
| `f` | fzfによるファイル名検索(プレビュー付き) |
|
95
|
+
| `F` | rgaによるファイル内容検索 |
|
94
96
|
|
95
97
|
#### システム操作
|
96
98
|
|
@@ -100,36 +102,36 @@ beniya --help # ヘルプメッセージを表示
|
|
100
102
|
|
101
103
|
### フィルター機能の詳細
|
102
104
|
|
103
|
-
#### リアルタイムフィルター (`
|
105
|
+
#### リアルタイムフィルター (`s`)
|
104
106
|
|
105
|
-
- **フィルター開始**: `
|
107
|
+
- **フィルター開始**: `s`キーを押してフィルターモードに入る
|
106
108
|
- **文字入力による絞り込み**: 日本語・英数字・記号に対応
|
107
109
|
- **リアルタイム更新**: 文字を入力するたびに表示が更新される
|
108
110
|
- **フィルター維持**: `Enter`キーでフィルターを保持したまま通常操作に戻る
|
109
111
|
- **フィルタークリア**: `ESC`キーでフィルターをクリアして通常表示に戻る
|
110
|
-
- **再編集**: フィルター適用中に`
|
112
|
+
- **再編集**: フィルター適用中に`s`キーで再編集モード
|
111
113
|
- **文字削除**: `Backspace`で文字削除、全削除時は自動でフィルタークリア
|
112
114
|
|
113
115
|
#### 使用例
|
114
116
|
|
115
117
|
```
|
116
|
-
1.
|
118
|
+
1. s → フィルターモード開始
|
117
119
|
2. ".rb" → Rubyファイルのみ表示
|
118
120
|
3. Enter → フィルター維持で通常操作
|
119
121
|
4. j/k → フィルター結果内をナビゲーション
|
120
|
-
5.
|
122
|
+
5. s → フィルター再編集
|
121
123
|
6. ESC → フィルタークリア
|
122
124
|
```
|
123
125
|
|
124
126
|
### 検索機能の詳細
|
125
127
|
|
126
|
-
#### ファイル名検索 (
|
128
|
+
#### ファイル名検索 (`f`)
|
127
129
|
|
128
130
|
- `fzf`を使用したインタラクティブなファイル名検索
|
129
131
|
- リアルタイムプレビュー表示
|
130
132
|
- 選択したファイルは自動で外部エディタで開かれる
|
131
133
|
|
132
|
-
#### ファイル内容検索 (`
|
134
|
+
#### ファイル内容検索 (`F`)
|
133
135
|
|
134
136
|
- `rga`(ripgrep-all)を使用した高度なファイル内容検索
|
135
137
|
- PDF、Word文書、画像内テキストなども検索対象
|
data/README_EN.md
CHANGED
@@ -74,12 +74,14 @@ beniya --help # Show help message
|
|
74
74
|
| `o` | Open selected file with external editor |
|
75
75
|
| `e` | Open current directory in file explorer |
|
76
76
|
| `r` | Refresh directory contents |
|
77
|
+
| `a` | Create new file |
|
78
|
+
| `A` | Create new directory |
|
77
79
|
|
78
80
|
#### Real-time Filter
|
79
81
|
|
80
82
|
| Key | Function |
|
81
83
|
| ----------- | -------------------------------------- |
|
82
|
-
| `
|
84
|
+
| `s` | Start filter mode / Re-edit filter |
|
83
85
|
| Text input | Filter files by name (in filter mode) |
|
84
86
|
| `Enter` | Keep filter and return to normal mode |
|
85
87
|
| `ESC` | Clear filter and return to normal mode |
|
@@ -89,8 +91,8 @@ beniya --help # Show help message
|
|
89
91
|
|
90
92
|
| Key | Function |
|
91
93
|
| --- | ---------------------------------------- |
|
92
|
-
|
|
93
|
-
| `
|
94
|
+
| `f` | File name search with fzf (with preview) |
|
95
|
+
| `F` | File content search with rga |
|
94
96
|
|
95
97
|
#### System Operations
|
96
98
|
|
@@ -100,36 +102,36 @@ beniya --help # Show help message
|
|
100
102
|
|
101
103
|
### Filter Feature
|
102
104
|
|
103
|
-
#### Real-time Filter (`
|
105
|
+
#### Real-time Filter (`s`)
|
104
106
|
|
105
|
-
- **Start Filter**: Press `
|
107
|
+
- **Start Filter**: Press `s` to enter filter mode
|
106
108
|
- **Text Input Filtering**: Supports Japanese, English, numbers, and symbols
|
107
109
|
- **Real-time Updates**: Display updates with each character typed
|
108
110
|
- **Keep Filter**: Press `Enter` to maintain filter while returning to normal operations
|
109
111
|
- **Clear Filter**: Press `ESC` to clear filter and return to normal display
|
110
|
-
- **Re-edit**: Press `
|
112
|
+
- **Re-edit**: Press `s` again while filter is active to re-edit
|
111
113
|
- **Character Deletion**: Use `Backspace` to delete characters, auto-clear when empty
|
112
114
|
|
113
115
|
#### Usage Example
|
114
116
|
|
115
117
|
```
|
116
|
-
1.
|
118
|
+
1. s → Start filter mode
|
117
119
|
2. ".rb" → Show only Ruby files
|
118
120
|
3. Enter → Keep filter, return to normal operations
|
119
121
|
4. j/k → Navigate within filtered results
|
120
|
-
5.
|
122
|
+
5. s → Re-edit filter
|
121
123
|
6. ESC → Clear filter
|
122
124
|
```
|
123
125
|
|
124
126
|
### Search Features
|
125
127
|
|
126
|
-
#### File Name Search (
|
128
|
+
#### File Name Search (`f`)
|
127
129
|
|
128
130
|
- Interactive file name search using `fzf`
|
129
131
|
- Real-time preview display
|
130
132
|
- Selected files automatically open in external editor
|
131
133
|
|
132
|
-
#### File Content Search (`
|
134
|
+
#### File Content Search (`F`)
|
133
135
|
|
134
136
|
- Advanced file content search using `rga` (ripgrep-all)
|
135
137
|
- Searches PDFs, Word documents, text in images, and more
|
data/beniya.gemspec
CHANGED
@@ -5,7 +5,7 @@ require_relative 'lib/beniya/version'
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'beniya'
|
7
7
|
spec.version = Beniya::VERSION
|
8
|
-
spec.authors = ['
|
8
|
+
spec.authors = ['masisz']
|
9
9
|
spec.email = ['masisz.1567@gmail.com']
|
10
10
|
|
11
11
|
spec.summary = 'Ruby file manager'
|
data/lib/beniya/config.rb
CHANGED
@@ -29,6 +29,15 @@ module Beniya
|
|
29
29
|
'keybind.search_text' => 'Search text: ',
|
30
30
|
'keybind.no_matches' => 'No matches found.',
|
31
31
|
'keybind.press_any_key' => 'Press any key to continue...',
|
32
|
+
'keybind.input_filename' => 'Enter filename: ',
|
33
|
+
'keybind.input_dirname' => 'Enter directory name: ',
|
34
|
+
'keybind.invalid_filename' => 'Invalid filename (cannot contain / or \\)',
|
35
|
+
'keybind.invalid_dirname' => 'Invalid directory name (cannot contain / or \\)',
|
36
|
+
'keybind.file_exists' => 'File already exists',
|
37
|
+
'keybind.directory_exists' => 'Directory already exists',
|
38
|
+
'keybind.file_created' => 'File created',
|
39
|
+
'keybind.directory_created' => 'Directory created',
|
40
|
+
'keybind.creation_error' => 'Creation error',
|
32
41
|
|
33
42
|
# UI messages
|
34
43
|
'ui.operation_prompt' => 'Operation: ',
|
@@ -88,6 +97,15 @@ module Beniya
|
|
88
97
|
'keybind.search_text' => '検索テキスト: ',
|
89
98
|
'keybind.no_matches' => 'マッチするものが見つかりません。',
|
90
99
|
'keybind.press_any_key' => '何かキーを押して続行...',
|
100
|
+
'keybind.input_filename' => 'ファイル名を入力: ',
|
101
|
+
'keybind.input_dirname' => 'ディレクトリ名を入力: ',
|
102
|
+
'keybind.invalid_filename' => '無効なファイル名(/や\\を含むことはできません)',
|
103
|
+
'keybind.invalid_dirname' => '無効なディレクトリ名(/や\\を含むことはできません)',
|
104
|
+
'keybind.file_exists' => 'ファイルが既に存在します',
|
105
|
+
'keybind.directory_exists' => 'ディレクトリが既に存在します',
|
106
|
+
'keybind.file_created' => 'ファイルを作成しました',
|
107
|
+
'keybind.directory_created' => 'ディレクトリを作成しました',
|
108
|
+
'keybind.creation_error' => '作成エラー',
|
91
109
|
|
92
110
|
# UI messages
|
93
111
|
'ui.operation_prompt' => '操作: ',
|
data/lib/beniya/file_opener.rb
CHANGED
@@ -22,6 +22,13 @@ module Beniya
|
|
22
22
|
execute_command_with_line(application, file_path, line_number)
|
23
23
|
end
|
24
24
|
|
25
|
+
def open_directory_in_explorer(directory_path)
|
26
|
+
return false unless File.exist?(directory_path)
|
27
|
+
return false unless File.directory?(directory_path)
|
28
|
+
|
29
|
+
execute_explorer_command(directory_path)
|
30
|
+
end
|
31
|
+
|
25
32
|
private
|
26
33
|
|
27
34
|
def find_application_for_file(file_path)
|
@@ -109,6 +116,25 @@ module Beniya
|
|
109
116
|
argument
|
110
117
|
end
|
111
118
|
end
|
119
|
+
|
120
|
+
def execute_explorer_command(directory_path)
|
121
|
+
quoted_path = quote_shell_argument(directory_path)
|
122
|
+
|
123
|
+
case RbConfig::CONFIG['host_os']
|
124
|
+
when /mswin|mingw|cygwin/
|
125
|
+
# Windows
|
126
|
+
system("explorer #{quoted_path}")
|
127
|
+
when /darwin/
|
128
|
+
# macOS
|
129
|
+
system("open #{quoted_path}")
|
130
|
+
else
|
131
|
+
# Linux/Unix
|
132
|
+
system("xdg-open #{quoted_path}")
|
133
|
+
end
|
134
|
+
rescue StandardError => e
|
135
|
+
warn "ディレクトリを開けませんでした: #{e.message}"
|
136
|
+
false
|
137
|
+
end
|
112
138
|
end
|
113
139
|
end
|
114
140
|
|
@@ -7,6 +7,7 @@ module Beniya
|
|
7
7
|
def initialize
|
8
8
|
@current_index = 0
|
9
9
|
@directory_listing = nil
|
10
|
+
@terminal_ui = nil
|
10
11
|
@file_opener = FileOpener.new
|
11
12
|
@filter_mode = false
|
12
13
|
@filter_query = ""
|
@@ -19,6 +20,10 @@ module Beniya
|
|
19
20
|
@current_index = 0
|
20
21
|
end
|
21
22
|
|
23
|
+
def set_terminal_ui(terminal_ui)
|
24
|
+
@terminal_ui = terminal_ui
|
25
|
+
end
|
26
|
+
|
22
27
|
def handle_key(key)
|
23
28
|
return false unless @directory_listing
|
24
29
|
|
@@ -44,7 +49,9 @@ module Beniya
|
|
44
49
|
refresh
|
45
50
|
when 'o' # o
|
46
51
|
open_current_file
|
47
|
-
when '
|
52
|
+
when 'e' # e - open directory in file explorer
|
53
|
+
open_directory_in_explorer
|
54
|
+
when 's' # s - filter files
|
48
55
|
if !@filter_query.empty?
|
49
56
|
# フィルタが設定されている場合は再編集モードに入る
|
50
57
|
@filter_mode = true
|
@@ -53,6 +60,8 @@ module Beniya
|
|
53
60
|
# 新規フィルターモード開始
|
54
61
|
start_filter_mode
|
55
62
|
end
|
63
|
+
when ' ' # Space - disabled for future functionality
|
64
|
+
false
|
56
65
|
when "\e" # ESC
|
57
66
|
if !@filter_query.empty?
|
58
67
|
# フィルタが設定されている場合はクリア
|
@@ -63,12 +72,16 @@ module Beniya
|
|
63
72
|
end
|
64
73
|
when 'q' # q
|
65
74
|
exit_request
|
66
|
-
when 'e' # e
|
67
|
-
open_explorer
|
68
75
|
when '/' # /
|
69
76
|
fzf_search
|
70
|
-
when 'f' # f
|
77
|
+
when 'f' # f - file name search with fzf
|
78
|
+
fzf_search
|
79
|
+
when 'F' # F - file content search with rga
|
71
80
|
rga_search
|
81
|
+
when 'a' # a
|
82
|
+
create_file
|
83
|
+
when 'A' # A
|
84
|
+
create_directory
|
72
85
|
else
|
73
86
|
false # #{ConfigLoader.message('keybind.invalid_key')}
|
74
87
|
end
|
@@ -151,6 +164,9 @@ module Beniya
|
|
151
164
|
end
|
152
165
|
|
153
166
|
def refresh
|
167
|
+
# ウィンドウサイズを更新して画面を再描画
|
168
|
+
@terminal_ui&.refresh_display
|
169
|
+
|
154
170
|
@directory_listing.refresh
|
155
171
|
if @filter_mode || !@filter_query.empty?
|
156
172
|
# Re-apply filter with new directory contents
|
@@ -176,25 +192,16 @@ module Beniya
|
|
176
192
|
end
|
177
193
|
end
|
178
194
|
|
179
|
-
def
|
180
|
-
true # request exit
|
181
|
-
end
|
182
|
-
|
183
|
-
def open_explorer
|
195
|
+
def open_directory_in_explorer
|
184
196
|
current_path = @directory_listing&.current_path || Dir.pwd
|
185
|
-
|
186
|
-
case RUBY_PLATFORM
|
187
|
-
when /darwin/ # macOS
|
188
|
-
system("open", current_path)
|
189
|
-
when /linux/ # Linux
|
190
|
-
system("xdg-open", current_path)
|
191
|
-
when /mswin|mingw|cygwin/ # Windows
|
192
|
-
system("explorer", current_path)
|
193
|
-
end
|
194
|
-
|
197
|
+
@file_opener.open_directory_in_explorer(current_path)
|
195
198
|
true
|
196
199
|
end
|
197
200
|
|
201
|
+
def exit_request
|
202
|
+
true # request exit
|
203
|
+
end
|
204
|
+
|
198
205
|
def fzf_search
|
199
206
|
return false unless fzf_available?
|
200
207
|
|
@@ -328,5 +335,105 @@ module Beniya
|
|
328
335
|
# 既存メソッド(後方互換用)
|
329
336
|
clear_filter_mode
|
330
337
|
end
|
338
|
+
|
339
|
+
def create_file
|
340
|
+
current_path = @directory_listing&.current_path || Dir.pwd
|
341
|
+
|
342
|
+
# ファイル名の入力を求める
|
343
|
+
print ConfigLoader.message('keybind.input_filename')
|
344
|
+
filename = STDIN.gets.chomp
|
345
|
+
return false if filename.empty?
|
346
|
+
|
347
|
+
# 不正なファイル名のチェック
|
348
|
+
if filename.include?('/') || filename.include?('\\')
|
349
|
+
puts "\n#{ConfigLoader.message('keybind.invalid_filename')}"
|
350
|
+
print ConfigLoader.message('keybind.press_any_key')
|
351
|
+
STDIN.getch
|
352
|
+
return false
|
353
|
+
end
|
354
|
+
|
355
|
+
file_path = File.join(current_path, filename)
|
356
|
+
|
357
|
+
# ファイルが既に存在する場合の確認
|
358
|
+
if File.exist?(file_path)
|
359
|
+
puts "\n#{ConfigLoader.message('keybind.file_exists')}"
|
360
|
+
print ConfigLoader.message('keybind.press_any_key')
|
361
|
+
STDIN.getch
|
362
|
+
return false
|
363
|
+
end
|
364
|
+
|
365
|
+
begin
|
366
|
+
# ファイルを作成
|
367
|
+
File.write(file_path, '')
|
368
|
+
|
369
|
+
# ディレクトリ表示を更新
|
370
|
+
@directory_listing.refresh
|
371
|
+
|
372
|
+
# 作成したファイルを選択状態にする
|
373
|
+
entries = @directory_listing.list_entries
|
374
|
+
new_file_index = entries.find_index { |entry| entry[:name] == filename }
|
375
|
+
@current_index = new_file_index if new_file_index
|
376
|
+
|
377
|
+
puts "\n#{ConfigLoader.message('keybind.file_created')}: #{filename}"
|
378
|
+
print ConfigLoader.message('keybind.press_any_key')
|
379
|
+
STDIN.getch
|
380
|
+
true
|
381
|
+
rescue => e
|
382
|
+
puts "\n#{ConfigLoader.message('keybind.creation_error')}: #{e.message}"
|
383
|
+
print ConfigLoader.message('keybind.press_any_key')
|
384
|
+
STDIN.getch
|
385
|
+
false
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
def create_directory
|
390
|
+
current_path = @directory_listing&.current_path || Dir.pwd
|
391
|
+
|
392
|
+
# ディレクトリ名の入力を求める
|
393
|
+
print ConfigLoader.message('keybind.input_dirname')
|
394
|
+
dirname = STDIN.gets.chomp
|
395
|
+
return false if dirname.empty?
|
396
|
+
|
397
|
+
# 不正なディレクトリ名のチェック
|
398
|
+
if dirname.include?('/') || dirname.include?('\\')
|
399
|
+
puts "\n#{ConfigLoader.message('keybind.invalid_dirname')}"
|
400
|
+
print ConfigLoader.message('keybind.press_any_key')
|
401
|
+
STDIN.getch
|
402
|
+
return false
|
403
|
+
end
|
404
|
+
|
405
|
+
dir_path = File.join(current_path, dirname)
|
406
|
+
|
407
|
+
# ディレクトリが既に存在する場合の確認
|
408
|
+
if File.exist?(dir_path)
|
409
|
+
puts "\n#{ConfigLoader.message('keybind.directory_exists')}"
|
410
|
+
print ConfigLoader.message('keybind.press_any_key')
|
411
|
+
STDIN.getch
|
412
|
+
return false
|
413
|
+
end
|
414
|
+
|
415
|
+
begin
|
416
|
+
# ディレクトリを作成
|
417
|
+
Dir.mkdir(dir_path)
|
418
|
+
|
419
|
+
# ディレクトリ表示を更新
|
420
|
+
@directory_listing.refresh
|
421
|
+
|
422
|
+
# 作成したディレクトリを選択状態にする
|
423
|
+
entries = @directory_listing.list_entries
|
424
|
+
new_dir_index = entries.find_index { |entry| entry[:name] == dirname }
|
425
|
+
@current_index = new_dir_index if new_dir_index
|
426
|
+
|
427
|
+
puts "\n#{ConfigLoader.message('keybind.directory_created')}: #{dirname}"
|
428
|
+
print ConfigLoader.message('keybind.press_any_key')
|
429
|
+
STDIN.getch
|
430
|
+
true
|
431
|
+
rescue => e
|
432
|
+
puts "\n#{ConfigLoader.message('keybind.creation_error')}: #{e.message}"
|
433
|
+
print ConfigLoader.message('keybind.press_any_key')
|
434
|
+
STDIN.getch
|
435
|
+
false
|
436
|
+
end
|
437
|
+
end
|
331
438
|
end
|
332
439
|
end
|
data/lib/beniya/terminal_ui.rb
CHANGED
@@ -21,6 +21,7 @@ module Beniya
|
|
21
21
|
@keybind_handler = keybind_handler
|
22
22
|
@file_preview = file_preview
|
23
23
|
@keybind_handler.set_directory_listing(@directory_listing)
|
24
|
+
@keybind_handler.set_terminal_ui(self)
|
24
25
|
|
25
26
|
@running = true
|
26
27
|
setup_terminal
|
@@ -32,6 +33,12 @@ module Beniya
|
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
36
|
+
def refresh_display
|
37
|
+
# ウィンドウサイズを更新してから画面をクリアして再描画
|
38
|
+
update_screen_size
|
39
|
+
print "\e[2J\e[H" # clear screen, cursor to home
|
40
|
+
end
|
41
|
+
|
35
42
|
private
|
36
43
|
|
37
44
|
def setup_terminal
|
@@ -41,6 +48,10 @@ module Beniya
|
|
41
48
|
print "\e[2J\e[H" # clear screen, cursor to home (first time only)
|
42
49
|
|
43
50
|
# re-acquire terminal size (just in case)
|
51
|
+
update_screen_size
|
52
|
+
end
|
53
|
+
|
54
|
+
def update_screen_size
|
44
55
|
console = IO.console
|
45
56
|
return unless console
|
46
57
|
|
data/lib/beniya/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beniya
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- masisz
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-08-
|
10
|
+
date: 2025-08-26 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: io-console
|