beniya 0.4.0 → 0.5.1
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 +30 -5
- data/CHANGELOG_v0.5.0.md +26 -0
- data/README.md +36 -8
- data/Rakefile +156 -0
- data/lib/beniya/bookmark.rb +115 -0
- data/lib/beniya/config.rb +4 -4
- data/lib/beniya/directory_listing.rb +14 -0
- data/lib/beniya/keybind_handler.rb +175 -2
- data/lib/beniya/terminal_ui.rb +1 -0
- data/lib/beniya/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6110d8a673eee02088b1d95fac741e95b4d470cbb5b5bb5826b3e6ac65893890
|
4
|
+
data.tar.gz: 9030f59ba585966f29faa34eb2d450cff37f836431368ac5e4b2a0bb011e0cb2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 06a6a371c75c3c36125f26ae556893c32e4e9d0eba25ebd6f14e20e9957408fed671ace6d587f0d98477ad8e5f856373fcb4b0eae9ec3b23e60840f8c8298dbf
|
7
|
+
data.tar.gz: cb5d756ba159db9ecc9018b6fb44c9b0f05d8a213668e686653c09963406cde6ccf136993e259fa88d2d0b9528001e456d9e3b9b1a0cf139e4ddc1f6e8baa72f
|
data/CHANGELOG.md
CHANGED
@@ -7,7 +7,32 @@ 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.5.0] - 2025-09-20
|
11
|
+
|
12
|
+
### Added
|
13
|
+
- **🔖 Bookmark System**: Complete bookmark functionality with persistent storage
|
14
|
+
- **Interactive Bookmark Menu**: Floating dialog with Add/List/Remove operations (`b` key)
|
15
|
+
- **Quick Navigation**: Number keys (1-9) for instant bookmark jumping
|
16
|
+
- **Persistent Storage**: Automatic save/load to `~/.config/beniya/bookmarks.json`
|
17
|
+
- **Comprehensive Test Suite**: Full TDD implementation with 15+ test cases
|
18
|
+
- **Multi-language Support**: English and Japanese bookmark interface
|
19
|
+
- **Safety Features**: Duplicate checking, path validation, error handling
|
20
|
+
|
21
|
+
### Changed
|
22
|
+
- **Updated Help Messages**: Latest keybindings including bookmark operations
|
23
|
+
- **Enhanced KeybindHandler**: Integrated bookmark menu and navigation
|
24
|
+
- **Improved DirectoryListing**: Added `navigate_to_path` method for bookmark jumps
|
25
|
+
- **UI Layout Optimization**: Removed 3rd header row for cleaner interface
|
26
|
+
- **Documentation Updates**: Comprehensive README updates with bookmark usage
|
27
|
+
|
28
|
+
### Technical Details
|
29
|
+
- New `Bookmark` class with full CRUD operations
|
30
|
+
- Maximum 9 bookmarks with automatic sorting
|
31
|
+
- Floating window system for bookmark management
|
32
|
+
- Integration with existing terminal UI components
|
33
|
+
- **Detailed changelog**: [CHANGELOG_v0.5.0.md](./CHANGELOG_v0.5.0.md)
|
34
|
+
|
35
|
+
## [0.4.0] - 2025-09-13
|
11
36
|
|
12
37
|
### Added
|
13
38
|
- **Floating Dialog System**: Modern floating confirmation dialogs for delete operations
|
@@ -40,7 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
40
65
|
|
41
66
|
For detailed information, see [CHANGELOG_v0.4.0.md](./CHANGELOG_v0.4.0.md)
|
42
67
|
|
43
|
-
## [0.3.0] -
|
68
|
+
## [0.3.0] - 2025-09-06
|
44
69
|
|
45
70
|
### Added
|
46
71
|
- Enhanced file operations and management features
|
@@ -51,7 +76,7 @@ For detailed information, see [CHANGELOG_v0.4.0.md](./CHANGELOG_v0.4.0.md)
|
|
51
76
|
- Performance improvements
|
52
77
|
- Bug fixes and stability enhancements
|
53
78
|
|
54
|
-
## [0.2.0] -
|
79
|
+
## [0.2.0] - 2025-08-26
|
55
80
|
|
56
81
|
### Added
|
57
82
|
- New features and functionality improvements
|
@@ -61,7 +86,7 @@ For detailed information, see [CHANGELOG_v0.4.0.md](./CHANGELOG_v0.4.0.md)
|
|
61
86
|
- User interface improvements
|
62
87
|
- Performance optimizations
|
63
88
|
|
64
|
-
## [0.1.0] -
|
89
|
+
## [0.1.0] - 2025-08-17
|
65
90
|
|
66
91
|
### Added
|
67
92
|
- Initial release of beniya
|
@@ -96,4 +121,4 @@ When contributing to beniya:
|
|
96
121
|
3. Link to detailed release notes for major versions
|
97
122
|
4. Include migration notes for breaking changes
|
98
123
|
|
99
|
-
For more information, see [Contributing Guidelines](./README.md#contributing).
|
124
|
+
For more information, see [Contributing Guidelines](./README.md#contributing).
|
data/CHANGELOG_v0.5.0.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# beniya v0.5.0 - Release Notes
|
2
|
+
|
3
|
+
## Added
|
4
|
+
- **Bookmark System**: Complete bookmark functionality for quick directory navigation
|
5
|
+
- **Interactive Bookmark Menu**: Floating dialog accessed via `b` key with Add/List/Remove operations
|
6
|
+
- **Quick Navigation**: Number keys (1-9) for instant bookmark jumping
|
7
|
+
- **Persistent Storage**: Automatic save/load bookmarks to `~/.config/beniya/bookmarks.json`
|
8
|
+
- **Bookmark Management**: Add current directory with custom names, list all bookmarks, remove by selection
|
9
|
+
- **Safety Features**: Duplicate name/path checking, directory existence validation, maximum 9 bookmarks limit
|
10
|
+
- **Multi-language Support**: English and Japanese bookmark interface messages
|
11
|
+
- **Comprehensive Test Suite**: Full TDD implementation with 15+ test cases covering all bookmark operations
|
12
|
+
- **Error Handling**: Graceful handling of non-existent paths, permission errors, and invalid inputs
|
13
|
+
|
14
|
+
## Changed
|
15
|
+
- **Help Messages Updated**: Latest keybinding information including bookmark operations in footer
|
16
|
+
- **KeybindHandler Enhanced**: Integrated bookmark menu and direct navigation functionality
|
17
|
+
- **DirectoryListing Improved**: Added `navigate_to_path` method for bookmark-based navigation
|
18
|
+
- **UI Layout Optimized**: Removed 3rd header row displaying bookmark shortcuts for cleaner interface
|
19
|
+
- **Documentation Updated**: Comprehensive README updates with bookmark usage examples and workflows
|
20
|
+
|
21
|
+
## Technical Implementation
|
22
|
+
- New `Bookmark` class with full CRUD operations and JSON persistence
|
23
|
+
- Floating window system for bookmark management dialogs
|
24
|
+
- Integration with existing terminal UI components and color system
|
25
|
+
- Automatic bookmark sorting by name for consistent display
|
26
|
+
- File system verification and path expansion for reliability
|
data/README.md
CHANGED
@@ -91,7 +91,7 @@ beniya --help # ヘルプメッセージを表示
|
|
91
91
|
|
92
92
|
| キー | 機能 |
|
93
93
|
| ----------- | ------------------------------------------ |
|
94
|
-
| `
|
94
|
+
| `f` | フィルターモード開始・再編集 |
|
95
95
|
| 文字入力 | ファイル名で絞り込み(フィルターモード中) |
|
96
96
|
| `Enter` | フィルター維持で通常モードに戻る |
|
97
97
|
| `ESC` | フィルターをクリアして通常モードに戻る |
|
@@ -101,9 +101,16 @@ beniya --help # ヘルプメッセージを表示
|
|
101
101
|
|
102
102
|
| キー | 機能 |
|
103
103
|
| ---- | ----------------------------------------- |
|
104
|
-
| `
|
104
|
+
| `s` | fzfによるファイル名検索(プレビュー付き) |
|
105
105
|
| `F` | rgaによるファイル内容検索 |
|
106
106
|
|
107
|
+
#### ブックマーク機能
|
108
|
+
|
109
|
+
| キー | 機能 |
|
110
|
+
| --------- | ---------------------------- |
|
111
|
+
| `b` | ブックマークメニューを表示 |
|
112
|
+
| `1`-`9` | 対応する番号のブックマークに移動 |
|
113
|
+
|
107
114
|
#### システム操作
|
108
115
|
|
109
116
|
| キー | 機能 |
|
@@ -162,30 +169,30 @@ beniya起動時のディレクトリが**ベースディレクトリ**として
|
|
162
169
|
|
163
170
|
### フィルター機能の詳細
|
164
171
|
|
165
|
-
#### リアルタイムフィルター (`
|
172
|
+
#### リアルタイムフィルター (`f`)
|
166
173
|
|
167
|
-
- **フィルター開始**: `
|
174
|
+
- **フィルター開始**: `f`キーを押してフィルターモードに入る
|
168
175
|
- **文字入力による絞り込み**: 日本語・英数字・記号に対応
|
169
176
|
- **リアルタイム更新**: 文字を入力するたびに表示が更新される
|
170
177
|
- **フィルター維持**: `Enter`キーでフィルターを保持したまま通常操作に戻る
|
171
178
|
- **フィルタークリア**: `ESC`キーでフィルターをクリアして通常表示に戻る
|
172
|
-
- **再編集**: フィルター適用中に`
|
179
|
+
- **再編集**: フィルター適用中に`f`キーで再編集モード
|
173
180
|
- **文字削除**: `Backspace`で文字削除、全削除時は自動でフィルタークリア
|
174
181
|
|
175
182
|
#### 使用例
|
176
183
|
|
177
184
|
```
|
178
|
-
1.
|
185
|
+
1. f → フィルターモード開始
|
179
186
|
2. ".rb" → Rubyファイルのみ表示
|
180
187
|
3. Enter → フィルター維持で通常操作
|
181
188
|
4. j/k → フィルター結果内をナビゲーション
|
182
|
-
5.
|
189
|
+
5. f → フィルター再編集
|
183
190
|
6. ESC → フィルタークリア
|
184
191
|
```
|
185
192
|
|
186
193
|
### 検索機能の詳細
|
187
194
|
|
188
|
-
#### ファイル名検索 (`
|
195
|
+
#### ファイル名検索 (`s`)
|
189
196
|
|
190
197
|
- `fzf`を使用したインタラクティブなファイル名検索
|
191
198
|
- リアルタイムプレビュー表示
|
@@ -197,6 +204,27 @@ beniya起動時のディレクトリが**ベースディレクトリ**として
|
|
197
204
|
- PDF、Word文書、画像内テキストなども検索対象
|
198
205
|
- 検索結果をfzfで絞り込み、該当行にジャンプしてファイルを開く
|
199
206
|
|
207
|
+
### ブックマーク機能の詳細
|
208
|
+
|
209
|
+
#### ブックマーク操作 (`b`)
|
210
|
+
|
211
|
+
- **ブックマーク追加**: `[A]` - 現在のディレクトリをブックマークに追加
|
212
|
+
- **ブックマーク一覧**: `[L]` - 登録済みブックマークの一覧表示
|
213
|
+
- **ブックマーク削除**: `[R]` - ブックマークを削除
|
214
|
+
- **番号ジャンプ**: `1-9` - 対応する番号のブックマークに直接移動
|
215
|
+
|
216
|
+
#### 高速ナビゲーション (`1`-`9`)
|
217
|
+
|
218
|
+
- ブックマークメニューを経由せず、数字キーでブックマークに直接ジャンプ
|
219
|
+
- 最大9個のブックマークをサポート
|
220
|
+
- ブックマーク情報は画面上部に表示
|
221
|
+
|
222
|
+
#### ブックマークの永続化
|
223
|
+
|
224
|
+
- ブックマーク情報は `~/.config/beniya/bookmarks.json` に自動保存
|
225
|
+
- beniya再起動後もブックマーク情報が保持される
|
226
|
+
- JSONファイルを直接編集することも可能
|
227
|
+
|
200
228
|
### 必要な外部ツール
|
201
229
|
|
202
230
|
検索機能を使用するには、以下のツールが必要です:
|
data/Rakefile
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require_relative 'lib/beniya/version'
|
6
|
+
|
7
|
+
# Test task
|
8
|
+
Rake::TestTask.new(:test) do |t|
|
9
|
+
t.libs << 'test'
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.test_files = FileList['test/test_*.rb']
|
12
|
+
end
|
13
|
+
|
14
|
+
# Default task
|
15
|
+
task default: :test
|
16
|
+
|
17
|
+
# Gem build and push tasks
|
18
|
+
namespace :gem do
|
19
|
+
desc 'Build the gem file'
|
20
|
+
task :build do
|
21
|
+
puts "Building beniya v#{Beniya::VERSION}..."
|
22
|
+
|
23
|
+
# Clean old gem files
|
24
|
+
FileUtils.rm_f(Dir.glob('*.gem'))
|
25
|
+
|
26
|
+
# Build the gem
|
27
|
+
result = system('gem build beniya.gemspec')
|
28
|
+
|
29
|
+
if result
|
30
|
+
gem_file = "beniya-#{Beniya::VERSION}.gem"
|
31
|
+
puts "✅ Successfully built #{gem_file}"
|
32
|
+
else
|
33
|
+
puts "❌ Failed to build gem"
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'Push the gem to RubyGems.org'
|
39
|
+
task :push => :build do
|
40
|
+
gem_file = "beniya-#{Beniya::VERSION}.gem"
|
41
|
+
|
42
|
+
unless File.exist?(gem_file)
|
43
|
+
puts "❌ Gem file not found: #{gem_file}"
|
44
|
+
exit 1
|
45
|
+
end
|
46
|
+
|
47
|
+
puts "Pushing #{gem_file} to RubyGems.org..."
|
48
|
+
|
49
|
+
result = system("gem push #{gem_file}")
|
50
|
+
|
51
|
+
if result
|
52
|
+
puts "✅ Successfully pushed #{gem_file} to RubyGems.org"
|
53
|
+
puts "🎉 beniya v#{Beniya::VERSION} is now available!"
|
54
|
+
puts "📦 Install with: gem install beniya"
|
55
|
+
else
|
56
|
+
puts "❌ Failed to push gem to RubyGems.org"
|
57
|
+
exit 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
desc 'Check if current version already exists on RubyGems.org'
|
62
|
+
task :check_version do
|
63
|
+
puts "Checking if version #{Beniya::VERSION} exists on RubyGems.org..."
|
64
|
+
|
65
|
+
result = system("gem list beniya --remote --exact --all | grep '#{Beniya::VERSION}'", out: File::NULL, err: File::NULL)
|
66
|
+
|
67
|
+
if result
|
68
|
+
puts "⚠️ Version #{Beniya::VERSION} already exists on RubyGems.org"
|
69
|
+
puts "💡 Please update the version in lib/beniya/version.rb before publishing"
|
70
|
+
exit 1
|
71
|
+
else
|
72
|
+
puts "✅ Version #{Beniya::VERSION} is available for publishing"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
desc 'Clean built gem files'
|
77
|
+
task :clean do
|
78
|
+
puts "Cleaning gem files..."
|
79
|
+
removed_files = Dir.glob('*.gem')
|
80
|
+
FileUtils.rm_f(removed_files)
|
81
|
+
|
82
|
+
if removed_files.any?
|
83
|
+
puts "🗑️ Removed: #{removed_files.join(', ')}"
|
84
|
+
else
|
85
|
+
puts "✨ No gem files to clean"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
desc 'Build and publish gem (with version check)'
|
90
|
+
task :publish => [:check_version, :test, :push] do
|
91
|
+
puts "🚀 Gem publishing completed successfully!"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Release tasks
|
96
|
+
namespace :release do
|
97
|
+
desc 'Tag the current version in git'
|
98
|
+
task :tag do
|
99
|
+
version = "v#{Beniya::VERSION}"
|
100
|
+
|
101
|
+
puts "Creating git tag #{version}..."
|
102
|
+
|
103
|
+
# Check if tag already exists
|
104
|
+
if system("git tag -l | grep -q '^#{version}$'", out: File::NULL, err: File::NULL)
|
105
|
+
puts "⚠️ Tag #{version} already exists"
|
106
|
+
exit 1
|
107
|
+
end
|
108
|
+
|
109
|
+
# Create and push tag
|
110
|
+
system("git tag #{version}")
|
111
|
+
system("git push origin #{version}")
|
112
|
+
|
113
|
+
puts "✅ Created and pushed tag #{version}"
|
114
|
+
end
|
115
|
+
|
116
|
+
desc 'Prepare release (tag + gem publish)'
|
117
|
+
task :prepare => ['gem:publish', :tag] do
|
118
|
+
puts "🎉 Release v#{Beniya::VERSION} completed!"
|
119
|
+
puts "📋 Don't forget to:"
|
120
|
+
puts " - Update CHANGELOG.md"
|
121
|
+
puts " - Create GitHub release from tag"
|
122
|
+
puts " - Announce the release"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Utility tasks
|
127
|
+
desc 'Display current version'
|
128
|
+
task :version do
|
129
|
+
puts "beniya v#{Beniya::VERSION}"
|
130
|
+
end
|
131
|
+
|
132
|
+
desc 'Run simple test for basic functionality'
|
133
|
+
task :simple_test do
|
134
|
+
puts "Running simple functionality test..."
|
135
|
+
result = system('ruby test/simple_test.rb')
|
136
|
+
|
137
|
+
if result
|
138
|
+
puts "✅ Simple test passed"
|
139
|
+
else
|
140
|
+
puts "❌ Simple test failed"
|
141
|
+
exit 1
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
desc 'Run bookmark tests'
|
146
|
+
task :test_bookmark do
|
147
|
+
puts "Running bookmark functionality test..."
|
148
|
+
result = system('ruby test/test_bookmark_simple.rb')
|
149
|
+
|
150
|
+
if result
|
151
|
+
puts "✅ Bookmark tests passed"
|
152
|
+
else
|
153
|
+
puts "❌ Bookmark tests failed"
|
154
|
+
exit 1
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
module Beniya
|
7
|
+
class Bookmark
|
8
|
+
MAX_BOOKMARKS = 9
|
9
|
+
|
10
|
+
def initialize(config_file = nil)
|
11
|
+
@config_file = config_file || default_config_file
|
12
|
+
@bookmarks = []
|
13
|
+
ensure_config_directory
|
14
|
+
load
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(path, name)
|
18
|
+
return false if @bookmarks.length >= MAX_BOOKMARKS
|
19
|
+
return false if exists_by_name?(name)
|
20
|
+
return false if exists_by_path?(path)
|
21
|
+
return false unless Dir.exist?(path)
|
22
|
+
|
23
|
+
@bookmarks << { path: File.expand_path(path), name: name }
|
24
|
+
save
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def remove(name)
|
29
|
+
initial_length = @bookmarks.length
|
30
|
+
@bookmarks.reject! { |bookmark| bookmark[:name] == name }
|
31
|
+
|
32
|
+
if @bookmarks.length < initial_length
|
33
|
+
save
|
34
|
+
true
|
35
|
+
else
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_path(name)
|
41
|
+
bookmark = @bookmarks.find { |b| b[:name] == name }
|
42
|
+
bookmark&.[](:path)
|
43
|
+
end
|
44
|
+
|
45
|
+
def find_by_number(number)
|
46
|
+
return nil unless number.is_a?(Integer)
|
47
|
+
return nil if number < 1 || number > @bookmarks.length
|
48
|
+
|
49
|
+
sorted_bookmarks[number - 1]
|
50
|
+
end
|
51
|
+
|
52
|
+
def list
|
53
|
+
sorted_bookmarks
|
54
|
+
end
|
55
|
+
|
56
|
+
def save
|
57
|
+
begin
|
58
|
+
File.write(@config_file, JSON.pretty_generate(@bookmarks))
|
59
|
+
true
|
60
|
+
rescue StandardError => e
|
61
|
+
warn "Failed to save bookmarks: #{e.message}"
|
62
|
+
false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def load
|
67
|
+
return true unless File.exist?(@config_file)
|
68
|
+
|
69
|
+
begin
|
70
|
+
content = File.read(@config_file)
|
71
|
+
@bookmarks = JSON.parse(content, symbolize_names: true)
|
72
|
+
@bookmarks = [] unless @bookmarks.is_a?(Array)
|
73
|
+
|
74
|
+
# 無効なブックマークを除去
|
75
|
+
@bookmarks = @bookmarks.select do |bookmark|
|
76
|
+
bookmark.is_a?(Hash) &&
|
77
|
+
bookmark.key?(:path) &&
|
78
|
+
bookmark.key?(:name) &&
|
79
|
+
bookmark[:path].is_a?(String) &&
|
80
|
+
bookmark[:name].is_a?(String)
|
81
|
+
end
|
82
|
+
|
83
|
+
true
|
84
|
+
rescue JSON::ParserError, StandardError => e
|
85
|
+
warn "Failed to load bookmarks: #{e.message}"
|
86
|
+
@bookmarks = []
|
87
|
+
true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def default_config_file
|
94
|
+
File.expand_path('~/.config/beniya/bookmarks.json')
|
95
|
+
end
|
96
|
+
|
97
|
+
def ensure_config_directory
|
98
|
+
config_dir = File.dirname(@config_file)
|
99
|
+
FileUtils.mkdir_p(config_dir) unless Dir.exist?(config_dir)
|
100
|
+
end
|
101
|
+
|
102
|
+
def exists_by_name?(name)
|
103
|
+
@bookmarks.any? { |bookmark| bookmark[:name] == name }
|
104
|
+
end
|
105
|
+
|
106
|
+
def exists_by_path?(path)
|
107
|
+
expanded_path = File.expand_path(path)
|
108
|
+
@bookmarks.any? { |bookmark| bookmark[:path] == expanded_path }
|
109
|
+
end
|
110
|
+
|
111
|
+
def sorted_bookmarks
|
112
|
+
@bookmarks.sort_by { |bookmark| bookmark[:name] }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/lib/beniya/config.rb
CHANGED
@@ -43,8 +43,8 @@ module Beniya
|
|
43
43
|
'ui.operation_prompt' => 'Operation: ',
|
44
44
|
|
45
45
|
# Help text
|
46
|
-
'help.full' => 'j/k:move h:back l:enter o
|
47
|
-
'help.short' => 'j/k:move h:back l:enter o:open q:quit',
|
46
|
+
'help.full' => 'j/k:move h:back l:enter o:open g/G:top/bottom r:refresh f:filter s:search F:content a/A:create m/p/x:ops b:bookmark 1-9:goto q:quit',
|
47
|
+
'help.short' => 'j/k:move h:back l:enter o:open f:filter s:search b:bookmark 1-9:goto q:quit',
|
48
48
|
|
49
49
|
# Health check messages
|
50
50
|
'health.title' => 'beniya Health Check',
|
@@ -111,8 +111,8 @@ module Beniya
|
|
111
111
|
'ui.operation_prompt' => '操作: ',
|
112
112
|
|
113
113
|
# Help text
|
114
|
-
'help.full' => 'j/k:移動 h:戻る l:入る o
|
115
|
-
'help.short' => 'j/k:移動 h:戻る l:入る o:開く q:終了',
|
114
|
+
'help.full' => 'j/k:移動 h:戻る l:入る o:開く g/G:先頭/末尾 r:更新 f:絞込 s:検索 F:内容 a/A:作成 m/p/x:操作 b:ブックマーク 1-9:移動 q:終了',
|
115
|
+
'help.short' => 'j/k:移動 h:戻る l:入る o:開く f:絞込 s:検索 b:ブックマーク 1-9:移動 q:終了',
|
116
116
|
|
117
117
|
# Health check messages
|
118
118
|
'health.title' => 'beniya ヘルスチェック',
|
@@ -67,6 +67,20 @@ module Beniya
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
def navigate_to_path(path)
|
71
|
+
return false if path.nil? || path.empty?
|
72
|
+
|
73
|
+
expanded_path = File.expand_path(path)
|
74
|
+
|
75
|
+
if File.directory?(expanded_path) && File.readable?(expanded_path)
|
76
|
+
@current_path = expanded_path
|
77
|
+
refresh
|
78
|
+
true
|
79
|
+
else
|
80
|
+
false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
70
84
|
private
|
71
85
|
|
72
86
|
def determine_file_type(path)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'bookmark'
|
4
|
+
|
3
5
|
module Beniya
|
4
6
|
class KeybindHandler
|
5
7
|
attr_reader :current_index, :filter_query
|
@@ -15,6 +17,7 @@ module Beniya
|
|
15
17
|
@original_entries = []
|
16
18
|
@selected_items = []
|
17
19
|
@base_directory = nil
|
20
|
+
@bookmark = Bookmark.new
|
18
21
|
end
|
19
22
|
|
20
23
|
def set_directory_listing(directory_listing)
|
@@ -63,7 +66,7 @@ module Beniya
|
|
63
66
|
open_current_file
|
64
67
|
when 'e' # e - open directory in file explorer
|
65
68
|
open_directory_in_explorer
|
66
|
-
when '
|
69
|
+
when 'f' # f - filter files
|
67
70
|
if !@filter_query.empty?
|
68
71
|
# フィルタが設定されている場合は再編集モードに入る
|
69
72
|
@filter_mode = true
|
@@ -86,7 +89,7 @@ module Beniya
|
|
86
89
|
exit_request
|
87
90
|
when '/' # /
|
88
91
|
fzf_search
|
89
|
-
when '
|
92
|
+
when 's' # s - file name search with fzf
|
90
93
|
fzf_search
|
91
94
|
when 'F' # F - file content search with rga
|
92
95
|
rga_search
|
@@ -100,6 +103,10 @@ module Beniya
|
|
100
103
|
copy_selected_to_base
|
101
104
|
when 'x' # x - delete selected files
|
102
105
|
delete_selected_files
|
106
|
+
when 'b' # b - bookmark operations
|
107
|
+
show_bookmark_menu
|
108
|
+
when '1', '2', '3', '4', '5', '6', '7', '8', '9' # number keys - go to bookmark
|
109
|
+
goto_bookmark(key.to_i)
|
103
110
|
else
|
104
111
|
false # #{ConfigLoader.message('keybind.invalid_key')}
|
105
112
|
end
|
@@ -872,5 +879,171 @@ module Beniya
|
|
872
879
|
print "\e[#{y + row};#{x}H#{' ' * width}"
|
873
880
|
end
|
874
881
|
end
|
882
|
+
|
883
|
+
# ブックマーク機能
|
884
|
+
def show_bookmark_menu
|
885
|
+
current_path = @directory_listing&.current_path || Dir.pwd
|
886
|
+
|
887
|
+
# メニューの準備
|
888
|
+
title = 'Bookmark Menu'
|
889
|
+
content_lines = [
|
890
|
+
'',
|
891
|
+
'[A]dd current directory to bookmarks',
|
892
|
+
'[L]ist bookmarks',
|
893
|
+
'[R]emove bookmark',
|
894
|
+
'',
|
895
|
+
'Press 1-9 to go to bookmark directly',
|
896
|
+
'',
|
897
|
+
'Press any other key to cancel'
|
898
|
+
]
|
899
|
+
|
900
|
+
dialog_width = 45
|
901
|
+
dialog_height = 4 + content_lines.length
|
902
|
+
x, y = get_screen_center(dialog_width, dialog_height)
|
903
|
+
|
904
|
+
# ダイアログの描画
|
905
|
+
draw_floating_window(x, y, dialog_width, dialog_height, title, content_lines, {
|
906
|
+
border_color: "\e[34m", # 青色
|
907
|
+
title_color: "\e[1;34m", # 太字青色
|
908
|
+
content_color: "\e[37m" # 白色
|
909
|
+
})
|
910
|
+
|
911
|
+
# キー入力待機
|
912
|
+
loop do
|
913
|
+
input = STDIN.getch.downcase
|
914
|
+
|
915
|
+
case input
|
916
|
+
when 'a'
|
917
|
+
clear_floating_window_area(x, y, dialog_width, dialog_height)
|
918
|
+
@terminal_ui&.refresh_display
|
919
|
+
add_bookmark_interactive(current_path)
|
920
|
+
return true
|
921
|
+
when 'l'
|
922
|
+
clear_floating_window_area(x, y, dialog_width, dialog_height)
|
923
|
+
@terminal_ui&.refresh_display
|
924
|
+
list_bookmarks_interactive
|
925
|
+
return true
|
926
|
+
when 'r'
|
927
|
+
clear_floating_window_area(x, y, dialog_width, dialog_height)
|
928
|
+
@terminal_ui&.refresh_display
|
929
|
+
remove_bookmark_interactive
|
930
|
+
return true
|
931
|
+
when '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
932
|
+
clear_floating_window_area(x, y, dialog_width, dialog_height)
|
933
|
+
@terminal_ui&.refresh_display
|
934
|
+
goto_bookmark(input.to_i)
|
935
|
+
return true
|
936
|
+
else
|
937
|
+
# キャンセル
|
938
|
+
clear_floating_window_area(x, y, dialog_width, dialog_height)
|
939
|
+
@terminal_ui&.refresh_display
|
940
|
+
return false
|
941
|
+
end
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
945
|
+
def add_bookmark_interactive(path)
|
946
|
+
print ConfigLoader.message('bookmark.input_name') || "Enter bookmark name: "
|
947
|
+
name = STDIN.gets.chomp
|
948
|
+
return false if name.empty?
|
949
|
+
|
950
|
+
if @bookmark.add(path, name)
|
951
|
+
puts "\n#{ConfigLoader.message('bookmark.added') || 'Bookmark added'}: #{name}"
|
952
|
+
else
|
953
|
+
puts "\n#{ConfigLoader.message('bookmark.add_failed') || 'Failed to add bookmark'}"
|
954
|
+
end
|
955
|
+
|
956
|
+
print ConfigLoader.message('keybind.press_any_key') || 'Press any key to continue...'
|
957
|
+
STDIN.getch
|
958
|
+
true
|
959
|
+
end
|
960
|
+
|
961
|
+
def remove_bookmark_interactive
|
962
|
+
bookmarks = @bookmark.list
|
963
|
+
|
964
|
+
if bookmarks.empty?
|
965
|
+
puts "\n#{ConfigLoader.message('bookmark.no_bookmarks') || 'No bookmarks found'}"
|
966
|
+
print ConfigLoader.message('keybind.press_any_key') || 'Press any key to continue...'
|
967
|
+
STDIN.getch
|
968
|
+
return false
|
969
|
+
end
|
970
|
+
|
971
|
+
puts "\nBookmarks:"
|
972
|
+
bookmarks.each_with_index do |bookmark, index|
|
973
|
+
puts " #{index + 1}. #{bookmark[:name]} (#{bookmark[:path]})"
|
974
|
+
end
|
975
|
+
|
976
|
+
print ConfigLoader.message('bookmark.input_number') || "Enter number to remove: "
|
977
|
+
input = STDIN.gets.chomp
|
978
|
+
number = input.to_i
|
979
|
+
|
980
|
+
if number > 0 && number <= bookmarks.length
|
981
|
+
bookmark_to_remove = bookmarks[number - 1]
|
982
|
+
if @bookmark.remove(bookmark_to_remove[:name])
|
983
|
+
puts "\n#{ConfigLoader.message('bookmark.removed') || 'Bookmark removed'}: #{bookmark_to_remove[:name]}"
|
984
|
+
else
|
985
|
+
puts "\n#{ConfigLoader.message('bookmark.remove_failed') || 'Failed to remove bookmark'}"
|
986
|
+
end
|
987
|
+
else
|
988
|
+
puts "\n#{ConfigLoader.message('bookmark.invalid_number') || 'Invalid number'}"
|
989
|
+
end
|
990
|
+
|
991
|
+
print ConfigLoader.message('keybind.press_any_key') || 'Press any key to continue...'
|
992
|
+
STDIN.getch
|
993
|
+
true
|
994
|
+
end
|
995
|
+
|
996
|
+
def list_bookmarks_interactive
|
997
|
+
bookmarks = @bookmark.list
|
998
|
+
|
999
|
+
if bookmarks.empty?
|
1000
|
+
puts "\n#{ConfigLoader.message('bookmark.no_bookmarks') || 'No bookmarks found'}"
|
1001
|
+
print ConfigLoader.message('keybind.press_any_key') || 'Press any key to continue...'
|
1002
|
+
STDIN.getch
|
1003
|
+
return false
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
puts "\nBookmarks:"
|
1007
|
+
bookmarks.each_with_index do |bookmark, index|
|
1008
|
+
puts " #{index + 1}. #{bookmark[:name]} (#{bookmark[:path]})"
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
print ConfigLoader.message('keybind.press_any_key') || 'Press any key to continue...'
|
1012
|
+
STDIN.getch
|
1013
|
+
true
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
def goto_bookmark(number)
|
1017
|
+
bookmark = @bookmark.find_by_number(number)
|
1018
|
+
|
1019
|
+
unless bookmark
|
1020
|
+
puts "\n#{ConfigLoader.message('bookmark.not_found') || 'Bookmark not found'}: #{number}"
|
1021
|
+
print ConfigLoader.message('keybind.press_any_key') || 'Press any key to continue...'
|
1022
|
+
STDIN.getch
|
1023
|
+
return false
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
unless Dir.exist?(bookmark[:path])
|
1027
|
+
puts "\n#{ConfigLoader.message('bookmark.path_not_exist') || 'Bookmark path does not exist'}: #{bookmark[:path]}"
|
1028
|
+
print ConfigLoader.message('keybind.press_any_key') || 'Press any key to continue...'
|
1029
|
+
STDIN.getch
|
1030
|
+
return false
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
# ディレクトリに移動
|
1034
|
+
result = @directory_listing.navigate_to_path(bookmark[:path])
|
1035
|
+
if result
|
1036
|
+
@current_index = 0
|
1037
|
+
clear_filter_mode
|
1038
|
+
puts "\n#{ConfigLoader.message('bookmark.navigated') || 'Navigated to bookmark'}: #{bookmark[:name]}"
|
1039
|
+
sleep(0.5) # 短時間表示
|
1040
|
+
return true
|
1041
|
+
else
|
1042
|
+
puts "\n#{ConfigLoader.message('bookmark.navigate_failed') || 'Failed to navigate to bookmark'}: #{bookmark[:name]}"
|
1043
|
+
print ConfigLoader.message('keybind.press_any_key') || 'Press any key to continue...'
|
1044
|
+
STDIN.getch
|
1045
|
+
return false
|
1046
|
+
end
|
1047
|
+
end
|
875
1048
|
end
|
876
1049
|
end
|
data/lib/beniya/terminal_ui.rb
CHANGED
@@ -163,6 +163,7 @@ module Beniya
|
|
163
163
|
print "\e[2;1H\e[44m\e[37m#{base_info.ljust(@screen_width)}\e[0m"
|
164
164
|
end
|
165
165
|
|
166
|
+
|
166
167
|
def draw_directory_list(entries, width, height)
|
167
168
|
start_index = [@keybind_handler.current_index - height / 2, 0].max
|
168
169
|
[start_index + height - 1, entries.length - 1].min
|
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.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- masisz
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-09-
|
10
|
+
date: 2025-09-23 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: io-console
|
@@ -118,13 +118,16 @@ extra_rdoc_files: []
|
|
118
118
|
files:
|
119
119
|
- CHANGELOG.md
|
120
120
|
- CHANGELOG_v0.4.0.md
|
121
|
+
- CHANGELOG_v0.5.0.md
|
121
122
|
- README.md
|
122
123
|
- README_EN.md
|
124
|
+
- Rakefile
|
123
125
|
- beniya.gemspec
|
124
126
|
- bin/beniya
|
125
127
|
- config_example.rb
|
126
128
|
- lib/beniya.rb
|
127
129
|
- lib/beniya/application.rb
|
130
|
+
- lib/beniya/bookmark.rb
|
128
131
|
- lib/beniya/color_helper.rb
|
129
132
|
- lib/beniya/config.rb
|
130
133
|
- lib/beniya/config_loader.rb
|