rufio 0.60.0 → 0.62.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.
@@ -47,13 +47,13 @@ module Rufio
47
47
  # @param suggestions [Array<String>] 補完候補(オプション)
48
48
  def show_input_prompt(input, suggestions = [])
49
49
  # タイトル
50
- title = "コマンドモード"
50
+ title = "Command Mode"
51
51
 
52
- # コンテンツ行を構築
52
+ # Build content lines
53
53
  content_lines = [""]
54
- content_lines << "#{input}_" # カーソルを_で表現
54
+ content_lines << "#{input}_" # Show cursor as _
55
55
  content_lines << ""
56
- content_lines << "Tab: 補完 | Enter: 実行 | ESC: キャンセル"
56
+ content_lines << "Tab: Complete | Enter: Execute | ESC: Cancel"
57
57
 
58
58
  # ウィンドウの色設定(青)
59
59
  border_color = "\e[34m" # Blue
@@ -94,7 +94,7 @@ module Rufio
94
94
  else
95
95
  # 文字列形式の結果(従来の動作)
96
96
  result_text = result
97
- is_error = result.include?("⚠️") || result.include?("エラー")
97
+ is_error = result.include?("⚠️") || result.include?("Error")
98
98
  end
99
99
 
100
100
  # 結果を行に分割
@@ -112,7 +112,7 @@ module Rufio
112
112
  end
113
113
 
114
114
  # ウィンドウタイトル
115
- title = "コマンド実行結果"
115
+ title = "Command Result"
116
116
 
117
117
  # コンテンツ行を構築
118
118
  content_lines = [""] + result_lines + ["", "Press any key to close"]
@@ -207,9 +207,9 @@ module Rufio
207
207
  # 何も出力がない場合
208
208
  if lines.empty?
209
209
  if result[:success]
210
- lines << "コマンドが正常に実行されました"
210
+ lines << "Command executed successfully"
211
211
  else
212
- lines << "コマンドが失敗しました"
212
+ lines << "Command failed"
213
213
  end
214
214
  end
215
215
 
data/lib/rufio/config.rb CHANGED
@@ -1,11 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'yaml'
4
+ require 'fileutils'
5
+
3
6
  module Rufio
4
7
  class Config
5
8
  # Default language settings
6
9
  DEFAULT_LANGUAGE = 'en'
7
10
  AVAILABLE_LANGUAGES = %w[en ja].freeze
8
11
 
12
+ # 設定ディレクトリとファイルパス
13
+ CONFIG_DIR = File.expand_path('~/.config/rufio').freeze
14
+ CONFIG_RB_PATH = File.join(CONFIG_DIR, 'config.rb').freeze
15
+ SCRIPT_PATHS_YML = File.join(CONFIG_DIR, 'script_paths.yml').freeze
16
+ BOOKMARKS_YML = File.join(CONFIG_DIR, 'bookmarks.yml').freeze
17
+
18
+ # 後方互換性のためのパス(非推奨)
19
+ YAML_CONFIG_PATH = File.join(CONFIG_DIR, 'config.yml').freeze
20
+ LOCAL_YAML_PATH = './rufio.yml'
21
+
9
22
  # Multi-language message definitions
10
23
  MESSAGES = {
11
24
  'en' => {
@@ -79,71 +92,71 @@ module Rufio
79
92
 
80
93
  'ja' => {
81
94
  # Application messages
82
- 'app.interrupted' => 'rufioを中断しました',
83
- 'app.error_occurred' => 'エラーが発生しました',
84
- 'app.terminated' => 'rufioを終了しました',
95
+ 'app.interrupted' => 'rufio interrupted',
96
+ 'app.error_occurred' => 'Error occurred',
97
+ 'app.terminated' => 'rufio terminated',
85
98
 
86
99
  # File operations
87
- 'file.not_found' => 'ファイルが見つかりません',
88
- 'file.not_readable' => 'ファイルを読み取れません',
89
- 'file.read_error' => 'ファイル読み込みエラー',
90
- 'file.binary_file' => 'バイナリファイル',
91
- 'file.cannot_preview' => 'プレビューできません',
92
- 'file.encoding_error' => '文字エンコーディングエラー - ファイルを読み取れません',
93
- 'file.preview_error' => 'プレビューエラー',
94
- 'file.error_prefix' => 'エラー',
100
+ 'file.not_found' => 'File not found',
101
+ 'file.not_readable' => 'File not readable',
102
+ 'file.read_error' => 'File read error',
103
+ 'file.binary_file' => 'Binary file',
104
+ 'file.cannot_preview' => 'Cannot preview',
105
+ 'file.encoding_error' => 'Encoding error - cannot read file',
106
+ 'file.preview_error' => 'Preview error',
107
+ 'file.error_prefix' => 'Error',
95
108
 
96
109
  # Keybind messages
97
- 'keybind.invalid_key' => '無効なキー',
98
- 'keybind.search_text' => '検索テキスト: ',
99
- 'keybind.no_matches' => 'マッチするものが見つかりません。',
100
- 'keybind.press_any_key' => '何かキーを押して続行...',
101
- 'keybind.input_filename' => 'ファイル名を入力: ',
102
- 'keybind.input_dirname' => 'ディレクトリ名を入力: ',
103
- 'keybind.invalid_filename' => '無効なファイル名(/や\\を含むことはできません)',
104
- 'keybind.invalid_dirname' => '無効なディレクトリ名(/や\\を含むことはできません)',
105
- 'keybind.file_exists' => 'ファイルが既に存在します',
106
- 'keybind.directory_exists' => 'ディレクトリが既に存在します',
107
- 'keybind.file_created' => 'ファイルを作成しました',
108
- 'keybind.directory_created' => 'ディレクトリを作成しました',
109
- 'keybind.creation_error' => '作成エラー',
110
+ 'keybind.invalid_key' => 'Invalid key',
111
+ 'keybind.search_text' => 'Search: ',
112
+ 'keybind.no_matches' => 'No matches found.',
113
+ 'keybind.press_any_key' => 'Press any key to continue...',
114
+ 'keybind.input_filename' => 'Enter filename: ',
115
+ 'keybind.input_dirname' => 'Enter directory name: ',
116
+ 'keybind.invalid_filename' => 'Invalid filename (cannot contain / or \\)',
117
+ 'keybind.invalid_dirname' => 'Invalid directory name (cannot contain / or \\)',
118
+ 'keybind.file_exists' => 'File already exists',
119
+ 'keybind.directory_exists' => 'Directory already exists',
120
+ 'keybind.file_created' => 'File created',
121
+ 'keybind.directory_created' => 'Directory created',
122
+ 'keybind.creation_error' => 'Creation error',
110
123
 
111
124
  # UI messages
112
- 'ui.operation_prompt' => '操作: ',
125
+ 'ui.operation_prompt' => 'Operation: ',
113
126
 
114
127
  # Help text
115
- 'help.full' => 'j/k:移動 h:戻る l:入る o:開く g/G:先頭/末尾 r:更新 f:絞込 s:検索 F:内容 a/A:作成 m/p/x:操作 b:ブックマーク z:zoxide 1-9:移動 q:終了',
116
- 'help.short' => 'j/k:移動 h:戻る l:入る o:開く f:絞込 s:検索 b:ブックマーク z:zoxide 1-9:移動 q:終了',
128
+ 'help.full' => 'j/k:move h:back l:enter o:open g/G:top/end r:refresh f:filter s:search F:content a/A:create m/c/x:ops b:bookmark z:zoxide 1-9:jump q:quit',
129
+ 'help.short' => 'j/k:move h:back l:enter o:open f:filter s:search b:bookmark z:zoxide 1-9:jump q:quit',
117
130
 
118
131
  # Health check messages
119
- 'health.title' => 'rufio ヘルスチェック',
120
- 'health.ruby_version' => 'Ruby バージョン',
121
- 'health.required_gems' => '必須 gem',
122
- 'health.fzf' => 'fzf (ファイル検索)',
123
- 'health.rga' => 'rga (内容検索)',
124
- 'health.zoxide' => 'zoxide (ディレクトリ履歴)',
125
- 'health.file_opener' => 'システムファイルオープナー',
126
- 'health.summary' => 'サマリー:',
132
+ 'health.title' => 'rufio Health Check',
133
+ 'health.ruby_version' => 'Ruby version',
134
+ 'health.required_gems' => 'Required gems',
135
+ 'health.fzf' => 'fzf (file search)',
136
+ 'health.rga' => 'rga (content search)',
137
+ 'health.zoxide' => 'zoxide (directory history)',
138
+ 'health.file_opener' => 'System file opener',
139
+ 'health.summary' => 'Summary:',
127
140
  'health.ok' => 'OK',
128
- 'health.warnings' => '警告',
129
- 'health.errors' => 'エラー',
130
- 'health.all_passed' => '全てのチェックが完了しました!rufioは使用可能です。',
131
- 'health.critical_missing' => '重要なコンポーネントが不足しています。rufioは正常に動作しない可能性があります。',
132
- 'health.optional_missing' => 'オプション機能が利用できません。基本機能は動作します。',
133
- 'health.all_gems_installed' => '全ての必須gemがインストールされています',
134
- 'health.missing_gems' => '不足しているgem',
135
- 'health.gem_install_instruction' => '実行: gem install',
136
- 'health.tool_not_found' => 'が見つかりません',
137
- 'health.unknown_platform' => '不明なプラットフォーム',
138
- 'health.file_open_may_not_work' => 'ファイルオープンが正常に動作しない可能性があります',
139
- 'health.macos_opener' => 'macOS ファイルオープナー',
140
- 'health.linux_opener' => 'Linux ファイルオープナー',
141
- 'health.windows_opener' => 'Windows ファイルオープナー',
142
- 'health.install_brew' => 'インストール: brew install',
143
- 'health.install_apt' => 'インストール: apt install',
144
- 'health.install_guide' => 'お使いのプラットフォーム向けのインストールガイドを確認してください',
145
- 'health.rga_releases' => 'インストール: https://github.com/phiresky/ripgrep-all/releases',
146
- 'health.ruby_upgrade_needed' => 'Rubyをバージョン2.7.0以上にアップグレードしてください'
141
+ 'health.warnings' => 'Warnings',
142
+ 'health.errors' => 'Errors',
143
+ 'health.all_passed' => 'All checks passed! rufio is ready to use.',
144
+ 'health.critical_missing' => 'Critical components missing. rufio may not work properly.',
145
+ 'health.optional_missing' => 'Optional features unavailable. Basic features will work.',
146
+ 'health.all_gems_installed' => 'All required gems are installed',
147
+ 'health.missing_gems' => 'Missing gems',
148
+ 'health.gem_install_instruction' => 'Run: gem install',
149
+ 'health.tool_not_found' => 'not found',
150
+ 'health.unknown_platform' => 'Unknown platform',
151
+ 'health.file_open_may_not_work' => 'File open may not work properly',
152
+ 'health.macos_opener' => 'macOS file opener',
153
+ 'health.linux_opener' => 'Linux file opener',
154
+ 'health.windows_opener' => 'Windows file opener',
155
+ 'health.install_brew' => 'Install: brew install',
156
+ 'health.install_apt' => 'Install: apt install',
157
+ 'health.install_guide' => 'Check installation guide for your platform',
158
+ 'health.rga_releases' => 'Install: https://github.com/phiresky/ripgrep-all/releases',
159
+ 'health.ruby_upgrade_needed' => 'Please upgrade Ruby to version 2.7.0 or higher'
147
160
  }
148
161
  }.freeze
149
162
 
@@ -179,8 +192,209 @@ module Rufio
179
192
  @current_language = nil
180
193
  end
181
194
 
195
+ # YAML設定を取得(キャッシュあり)
196
+ # @return [Hash] YAML設定
197
+ def yaml_config
198
+ @yaml_config ||= load_yaml_config(YAML_CONFIG_PATH)
199
+ end
200
+
201
+ # YAML設定をリロード
202
+ def reload_yaml_config!
203
+ @yaml_config = nil
204
+ end
205
+
206
+ # 全設定をリセット
207
+ def reset_config!
208
+ @yaml_config = nil
209
+ @script_paths = nil
210
+ @bookmarks = nil
211
+ end
212
+
213
+ # ========================================
214
+ # script_paths.yml の操作
215
+ # ========================================
216
+
217
+ # スクリプトパスを読み込む
218
+ # @param path [String] YAMLファイルのパス
219
+ # @return [Array<String>] 展開済みのパス配列
220
+ def load_script_paths(path = SCRIPT_PATHS_YML)
221
+ return [] unless File.exist?(path)
222
+
223
+ yaml = YAML.safe_load(File.read(path))
224
+ return [] unless yaml.is_a?(Array)
225
+
226
+ yaml.map { |p| File.expand_path(p) }
227
+ rescue StandardError => e
228
+ warn "Failed to load script paths: #{e.message}"
229
+ []
230
+ end
231
+
232
+ # スクリプトパスを保存
233
+ # @param path [String] YAMLファイルのパス
234
+ # @param paths [Array<String>] パス配列
235
+ def save_script_paths(path, paths)
236
+ ensure_config_directory(path)
237
+ File.write(path, YAML.dump(paths))
238
+ end
239
+
240
+ # スクリプトパスを追加
241
+ # @param path [String] YAMLファイルのパス
242
+ # @param new_path [String] 追加するパス
243
+ def add_script_path(path, new_path)
244
+ paths = load_script_paths(path)
245
+ expanded = File.expand_path(new_path)
246
+ return if paths.include?(expanded)
247
+
248
+ paths << expanded
249
+ save_script_paths(path, paths)
250
+ end
251
+
252
+ # スクリプトパスを削除
253
+ # @param path [String] YAMLファイルのパス
254
+ # @param remove_path [String] 削除するパス
255
+ def remove_script_path(path, remove_path)
256
+ paths = load_script_paths(path)
257
+ expanded = File.expand_path(remove_path)
258
+ paths.delete(expanded)
259
+ save_script_paths(path, paths)
260
+ end
261
+
262
+ # ========================================
263
+ # bookmarks.yml の操作
264
+ # ========================================
265
+
266
+ # ブックマークを読み込む
267
+ # @param path [String] YAMLファイルのパス
268
+ # @return [Array<Hash>] ブックマーク配列
269
+ def load_bookmarks_from_yml(path = BOOKMARKS_YML)
270
+ return [] unless File.exist?(path)
271
+
272
+ yaml = YAML.safe_load(File.read(path), symbolize_names: true)
273
+ return [] unless yaml.is_a?(Array)
274
+
275
+ yaml.select { |b| b.is_a?(Hash) && b[:path] && b[:name] }
276
+ rescue StandardError => e
277
+ warn "Failed to load bookmarks: #{e.message}"
278
+ []
279
+ end
280
+
281
+ # ブックマークを保存
282
+ # @param path [String] YAMLファイルのパス
283
+ # @param bookmarks [Array<Hash>] ブックマーク配列
284
+ def save_bookmarks_to_yml(path, bookmarks)
285
+ ensure_config_directory(path)
286
+ data = bookmarks.map { |b| { 'path' => b[:path], 'name' => b[:name] } }
287
+ File.write(path, YAML.dump(data))
288
+ end
289
+
290
+ # ブックマークを追加
291
+ # @param path [String] YAMLファイルのパス
292
+ # @param bookmark_path [String] ブックマークするパス
293
+ # @param name [String] ブックマーク名
294
+ def add_bookmark(path, bookmark_path, name)
295
+ bookmarks = load_bookmarks_from_yml(path)
296
+ bookmarks << { path: bookmark_path, name: name }
297
+ save_bookmarks_to_yml(path, bookmarks)
298
+ end
299
+
300
+ # ブックマークを削除
301
+ # @param path [String] YAMLファイルのパス
302
+ # @param name [String] 削除するブックマーク名
303
+ def remove_bookmark(path, name)
304
+ bookmarks = load_bookmarks_from_yml(path)
305
+ bookmarks.reject! { |b| b[:name] == name }
306
+ save_bookmarks_to_yml(path, bookmarks)
307
+ end
308
+
309
+ # ========================================
310
+ # config.rb (DSL) の操作
311
+ # ========================================
312
+
313
+ # config.rb を読み込む
314
+ # @param path [String] config.rb のパス
315
+ def load_config_rb(path = CONFIG_RB_PATH)
316
+ return unless File.exist?(path)
317
+
318
+ load path
319
+ rescue StandardError => e
320
+ warn "Failed to load config.rb: #{e.message}"
321
+ end
322
+
323
+ # ========================================
324
+ # マイグレーション
325
+ # ========================================
326
+
327
+ # 古い config.yml から新形式にマイグレーション
328
+ # @param old_config_yml [String] 古い config.yml のパス
329
+ # @param script_paths_yml [String] 新しい script_paths.yml のパス
330
+ # @param bookmarks_yml [String] 新しい bookmarks.yml のパス
331
+ def migrate_from_config_yml(old_config_yml, script_paths_yml, bookmarks_yml)
332
+ return unless File.exist?(old_config_yml)
333
+
334
+ old_config = load_yaml_config(old_config_yml)
335
+
336
+ # script_paths のマイグレーション
337
+ if old_config[:script_paths].is_a?(Array) && !old_config[:script_paths].empty?
338
+ save_script_paths(script_paths_yml, old_config[:script_paths])
339
+ end
340
+
341
+ # bookmarks のマイグレーション
342
+ if old_config[:bookmarks].is_a?(Array) && !old_config[:bookmarks].empty?
343
+ save_bookmarks_to_yml(bookmarks_yml, old_config[:bookmarks])
344
+ end
345
+ end
346
+
347
+ # YAML設定ファイルを読み込む
348
+ # @param path [String] 設定ファイルのパス
349
+ # @return [Hash] 設定内容(シンボルキー)
350
+ def load_yaml_config(path)
351
+ return {} unless File.exist?(path)
352
+
353
+ yaml = YAML.safe_load(File.read(path), symbolize_names: true)
354
+ yaml || {}
355
+ rescue StandardError => e
356
+ warn "Failed to load YAML config: #{e.message}"
357
+ {}
358
+ end
359
+
360
+ # YAML設定ファイルにセクションを保存
361
+ # @param path [String] 設定ファイルのパス
362
+ # @param key [Symbol, String] 保存するキー
363
+ # @param value [Object] 保存する値
364
+ def save_yaml_config(path, key, value)
365
+ ensure_config_directory(path)
366
+
367
+ existing = if File.exist?(path)
368
+ YAML.safe_load(File.read(path), symbolize_names: true) || {}
369
+ else
370
+ {}
371
+ end
372
+
373
+ existing[key.to_sym] = value
374
+ File.write(path, YAML.dump(stringify_keys(existing)))
375
+ reload_yaml_config! if path == YAML_CONFIG_PATH
376
+ end
377
+
182
378
  private
183
379
 
380
+ def ensure_config_directory(path)
381
+ dir = File.dirname(path)
382
+ FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
383
+ end
384
+
385
+ def stringify_keys(hash)
386
+ hash.transform_keys(&:to_s).transform_values do |value|
387
+ case value
388
+ when Hash
389
+ stringify_keys(value)
390
+ when Array
391
+ value.map { |v| v.is_a?(Hash) ? stringify_keys(v) : v }
392
+ else
393
+ value
394
+ end
395
+ end
396
+ end
397
+
184
398
  def detect_language
185
399
  # Only BENIYA_LANG environment variable takes precedence
186
400
  # This ensures English is default unless explicitly requested
@@ -1,12 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'yaml'
4
+ require 'json'
4
5
  require_relative 'config'
5
6
 
6
7
  module Rufio
7
8
  class ConfigLoader
8
- CONFIG_PATH = File.expand_path('~/.config/rufio/config.rb').freeze
9
- YAML_CONFIG_PATH = File.expand_path('~/.config/rufio/config.yml').freeze
9
+ # 新しいパス定数(Configから取得)
10
+ CONFIG_PATH = Config::CONFIG_RB_PATH
11
+ SCRIPT_PATHS_YML = Config::SCRIPT_PATHS_YML
12
+ BOOKMARKS_YML = Config::BOOKMARKS_YML
13
+
14
+ # 後方互換性のためのパス(非推奨)
15
+ YAML_CONFIG_PATH = Config::YAML_CONFIG_PATH
16
+ LOCAL_YAML_PATH = Config::LOCAL_YAML_PATH
10
17
 
11
18
  class << self
12
19
  def load_config
@@ -19,6 +26,7 @@ module Rufio
19
26
 
20
27
  def reload_config!
21
28
  @config = nil
29
+ @script_paths = nil
22
30
  load_config
23
31
  end
24
32
 
@@ -40,7 +48,6 @@ module Rufio
40
48
 
41
49
  def set_language(lang)
42
50
  Config.current_language = lang
43
- # Update config if it's user-defined
44
51
  if @config
45
52
  @config[:language] = lang
46
53
  end
@@ -62,12 +69,10 @@ module Rufio
62
69
  load_config[:command_history_size] || 1000
63
70
  end
64
71
 
65
- # スクリプトパスの配列を取得
72
+ # スクリプトパスの配列を取得(ローカル > ユーザー設定の優先順位でマージ)
66
73
  # @return [Array<String>] 展開済みのスクリプトパス
67
74
  def script_paths
68
- yaml_config = load_yaml_config
69
- paths = yaml_config[:script_paths] || default_script_paths
70
- expand_script_paths(paths)
75
+ @script_paths ||= load_merged_script_paths
71
76
  end
72
77
 
73
78
  # デフォルトのスクリプトパス
@@ -83,44 +88,159 @@ module Rufio
83
88
  paths.map { |p| File.expand_path(p) }
84
89
  end
85
90
 
86
- # YAML設定ファイルを読み込む
91
+ # スクリプトパスを追加
92
+ # @param path [String] 追加するパス
93
+ # @return [Boolean] 追加成功したか
94
+ def add_script_path(path)
95
+ expanded = File.expand_path(path)
96
+ current = script_paths
97
+ return false if current.include?(expanded)
98
+
99
+ save_script_paths_to_yaml(current + [expanded])
100
+ @script_paths = nil
101
+ true
102
+ end
103
+
104
+ # スクリプトパスを削除
105
+ # @param path [String] 削除するパス
106
+ # @return [Boolean] 削除成功したか
107
+ def remove_script_path(path)
108
+ expanded = File.expand_path(path)
109
+ current = script_paths
110
+ return false unless current.include?(expanded)
111
+
112
+ save_script_paths_to_yaml(current - [expanded])
113
+ @script_paths = nil
114
+ true
115
+ end
116
+
117
+ # YAML設定ファイルを読み込む(Config経由)
87
118
  # @param path [String, nil] 設定ファイルのパス(nilの場合はデフォルト)
88
119
  # @return [Hash] 設定内容
89
120
  def load_yaml_config(path = nil)
90
121
  config_path = path || YAML_CONFIG_PATH
91
- return {} unless File.exist?(config_path)
122
+ Config.load_yaml_config(config_path)
123
+ end
124
+
125
+ # ブックマークを読み込む(新形式: bookmarks.yml)
126
+ # @return [Array<Hash>] ブックマークの配列
127
+ def load_bookmarks
128
+ # 新形式を優先
129
+ bookmarks = Config.load_bookmarks_from_yml(BOOKMARKS_YML)
130
+ return bookmarks unless bookmarks.empty?
131
+
132
+ # 後方互換: 古いconfig.ymlから読み込み
133
+ yaml_config = load_yaml_config
134
+ filter_valid_bookmarks(yaml_config[:bookmarks] || [])
135
+ end
92
136
 
93
- yaml = YAML.safe_load(File.read(config_path), symbolize_names: true)
94
- yaml || {}
137
+ # ブックマークを保存(新形式: bookmarks.yml)
138
+ # @param bookmarks [Array<Hash>] ブックマークの配列
139
+ # @return [Boolean] 保存成功したか
140
+ def save_bookmarks(bookmarks)
141
+ Config.save_bookmarks_to_yml(BOOKMARKS_YML, bookmarks)
142
+ true
95
143
  rescue StandardError => e
96
- warn "Failed to load YAML config: #{e.message}"
97
- {}
144
+ warn "Failed to save bookmarks: #{e.message}"
145
+ false
146
+ end
147
+
148
+ # ブックマークストレージを取得
149
+ # @return [YamlBookmarkStorage] ブックマークストレージ
150
+ def bookmark_storage
151
+ @bookmark_storage ||= YamlBookmarkStorage.new(BOOKMARKS_YML)
152
+ end
153
+
154
+ # 古いconfig.ymlからのマイグレーション
155
+ def migrate_bookmarks_if_needed
156
+ # 新形式が存在する場合はスキップ
157
+ return if File.exist?(BOOKMARKS_YML)
158
+ return unless File.exist?(YAML_CONFIG_PATH)
159
+
160
+ Config.migrate_from_config_yml(YAML_CONFIG_PATH, SCRIPT_PATHS_YML, BOOKMARKS_YML)
98
161
  end
99
162
 
100
163
  private
101
164
 
165
+ # マージされたスクリプトパスを読み込む
166
+ # @return [Array<String>] マージされたスクリプトパス
167
+ def load_merged_script_paths
168
+ paths = []
169
+ seen = Set.new
170
+
171
+ # ローカル設定(優先)
172
+ if File.exist?(LOCAL_YAML_PATH)
173
+ local_config = load_yaml_config(LOCAL_YAML_PATH)
174
+ local_paths = local_config[:script_paths] || []
175
+ add_unique_paths(paths, seen, expand_script_paths(local_paths))
176
+ end
177
+
178
+ # 新形式: script_paths.yml から読み込み
179
+ script_paths_from_yml = Config.load_script_paths(SCRIPT_PATHS_YML)
180
+ add_unique_paths(paths, seen, script_paths_from_yml)
181
+
182
+ # 後方互換: 古いconfig.ymlから読み込み
183
+ if paths.empty?
184
+ user_config = load_yaml_config
185
+ user_paths = user_config[:script_paths] || []
186
+ add_unique_paths(paths, seen, expand_script_paths(user_paths))
187
+ end
188
+
189
+ # デフォルトパス(何も設定されていない場合)
190
+ if paths.empty?
191
+ add_unique_paths(paths, seen, default_script_paths)
192
+ end
193
+
194
+ paths
195
+ end
196
+
197
+ # ユニークなパスを追加
198
+ def add_unique_paths(paths, seen, new_paths)
199
+ new_paths.each do |path|
200
+ expanded = File.expand_path(path)
201
+ next if seen.include?(expanded)
202
+
203
+ seen.add(expanded)
204
+ paths << expanded
205
+ end
206
+ end
207
+
208
+ # スクリプトパスをYAMLに保存(新形式: script_paths.yml)
209
+ def save_script_paths_to_yaml(paths)
210
+ Config.save_script_paths(SCRIPT_PATHS_YML, paths)
211
+ end
212
+
213
+ # YAMLファイルにセクションを保存(Config経由)
214
+ def save_to_yaml(key, value)
215
+ Config.save_yaml_config(YAML_CONFIG_PATH, key, value)
216
+ end
217
+
218
+ def filter_valid_bookmarks(bookmarks)
219
+ return [] unless bookmarks.is_a?(Array)
220
+
221
+ bookmarks.select do |b|
222
+ b.is_a?(Hash) && b[:path] && b[:name]
223
+ end
224
+ end
225
+
102
226
  def load_config_file
103
- # 設定ファイルを実行してグローバル定数を定義
104
227
  load CONFIG_PATH
105
228
  config = {
106
- applications: Object.const_get(:APPLICATIONS),
107
- colors: Object.const_get(:COLORS),
108
- keybinds: Object.const_get(:KEYBINDS)
229
+ applications: safe_const_get(:APPLICATIONS, default_config[:applications]),
230
+ colors: safe_const_get(:COLORS, default_config[:colors]),
231
+ keybinds: safe_const_get(:KEYBINDS, default_config[:keybinds])
109
232
  }
110
233
 
111
- # Load language setting if defined
112
234
  if Object.const_defined?(:LANGUAGE)
113
235
  language = Object.const_get(:LANGUAGE)
114
236
  config[:language] = language
115
237
  Config.current_language = language if Config.available_languages.include?(language.to_s)
116
238
  end
117
239
 
118
- # Load scripts directory if defined
119
240
  if Object.const_defined?(:SCRIPTS_DIR)
120
241
  config[:scripts_dir] = Object.const_get(:SCRIPTS_DIR)
121
242
  end
122
243
 
123
- # Load command history size if defined
124
244
  if Object.const_defined?(:COMMAND_HISTORY_SIZE)
125
245
  config[:command_history_size] = Object.const_get(:COMMAND_HISTORY_SIZE)
126
246
  end
@@ -132,6 +252,10 @@ module Rufio
132
252
  default_config
133
253
  end
134
254
 
255
+ def safe_const_get(name, default)
256
+ Object.const_defined?(name) ? Object.const_get(name) : default
257
+ end
258
+
135
259
  def default_config
136
260
  {
137
261
  applications: {
@@ -143,11 +267,11 @@ module Rufio
143
267
  :default => 'open'
144
268
  },
145
269
  colors: {
146
- directory: { hsl: [220, 80, 60] }, # Blue
147
- file: { hsl: [0, 0, 90] }, # Light gray
148
- executable: { hsl: [120, 70, 50] }, # Green
149
- selected: { hsl: [50, 90, 70] }, # Yellow
150
- preview: { hsl: [180, 60, 65] } # Cyan
270
+ directory: { hsl: [220, 80, 60] },
271
+ file: { hsl: [0, 0, 90] },
272
+ executable: { hsl: [120, 70, 50] },
273
+ selected: { hsl: [50, 90, 70] },
274
+ preview: { hsl: [180, 60, 65] }
151
275
  },
152
276
  keybinds: {
153
277
  quit: %w[q ESC],
@@ -166,4 +290,3 @@ module Rufio
166
290
  end
167
291
  end
168
292
  end
169
-