rufio 0.30.0 → 0.32.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.
@@ -56,6 +56,10 @@ module Rufio
56
56
  File.expand_path('~/.config/rufio/scripts')
57
57
  end
58
58
 
59
+ def command_history_size
60
+ load_config[:command_history_size] || 1000
61
+ end
62
+
59
63
  private
60
64
 
61
65
  def load_config_file
@@ -79,6 +83,11 @@ module Rufio
79
83
  config[:scripts_dir] = Object.const_get(:SCRIPTS_DIR)
80
84
  end
81
85
 
86
+ # Load command history size if defined
87
+ if Object.const_defined?(:COMMAND_HISTORY_SIZE)
88
+ config[:command_history_size] = Object.const_get(:COMMAND_HISTORY_SIZE)
89
+ end
90
+
82
91
  config
83
92
  rescue StandardError => e
84
93
  warn "Failed to load config file: #{e.message}"
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rufio
4
+ module Plugins
5
+ # Hello コマンドを提供するプラグイン
6
+ # Rubyコードで挨拶を返す簡単な例
7
+ class Hello < Plugin
8
+ def name
9
+ "Hello"
10
+ end
11
+
12
+ def description
13
+ "Rubyで実装された挨拶コマンドの例"
14
+ end
15
+
16
+ def commands
17
+ {
18
+ hello: method(:say_hello)
19
+ }
20
+ end
21
+
22
+ private
23
+
24
+ # 挨拶メッセージを返す
25
+ def say_hello
26
+ "Hello, World! 🌍\n\nこのコマンドはRubyで実装されています。"
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rufio
4
+ # シェルコマンド補完機能を提供するクラス
5
+ class ShellCommandCompletion
6
+ # PATHからコマンドを補完
7
+ # @param input [String] 入力されたコマンドの一部
8
+ # @return [Array<String>] 補完候補のリスト
9
+ def complete_command(input)
10
+ return [] if input.nil? || input.empty?
11
+
12
+ input_lower = input.downcase
13
+ path_commands.select { |cmd| cmd.downcase.start_with?(input_lower) }
14
+ end
15
+
16
+ # ファイルパスを補完
17
+ # @param input [String] 入力されたパスの一部
18
+ # @param options [Hash] オプション
19
+ # @option options [Boolean] :directories_only ディレクトリのみを補完
20
+ # @return [Array<String>] 補完候補のリスト
21
+ def complete_path(input, options = {})
22
+ return [] if input.nil?
23
+
24
+ # ~を展開
25
+ expanded_input = File.expand_path(input) rescue input
26
+
27
+ # 入力が/で終わる場合(ディレクトリ内を補完)
28
+ if input.end_with?("/")
29
+ dir = expanded_input
30
+ pattern = File.join(dir, "*")
31
+ else
32
+ # ディレクトリ部分とファイル名部分を分離
33
+ dir = File.dirname(expanded_input)
34
+ basename = File.basename(expanded_input)
35
+ pattern = File.join(dir, "#{basename}*")
36
+ end
37
+
38
+ # ディレクトリが存在しない場合は空の配列を返す
39
+ return [] unless Dir.exist?(dir)
40
+
41
+ # マッチするファイル/ディレクトリを取得
42
+ candidates = Dir.glob(pattern)
43
+
44
+ # ディレクトリのみのフィルタリング
45
+ if options[:directories_only]
46
+ candidates.select! { |path| File.directory?(path) }
47
+ end
48
+
49
+ # 元の入力が~で始まる場合、結果も~で始まるように変換
50
+ if input.start_with?("~")
51
+ home = ENV['HOME']
52
+ candidates.map! { |path| path.sub(home, "~") }
53
+ end
54
+
55
+ candidates.sort
56
+ rescue StandardError
57
+ []
58
+ end
59
+
60
+ # コマンド履歴から補完
61
+ # @param input [String] 入力されたコマンドの一部
62
+ # @param history [CommandHistory] コマンド履歴オブジェクト
63
+ # @return [Array<String>] 補完候補のリスト
64
+ def complete_from_history(input, history)
65
+ return [] if input.nil? || input.empty?
66
+ return [] unless history
67
+
68
+ # 履歴から全てのコマンドを取得
69
+ # CommandHistoryクラスから履歴を取得する方法が必要
70
+ # 現在の実装では、@historyインスタンス変数にアクセスできないため、
71
+ # 新しいメソッドを追加する必要がある
72
+ # 一旦、空の配列を返す実装にして、後でCommandHistoryを拡張する
73
+ commands = get_history_commands(history)
74
+
75
+ input_lower = input.downcase
76
+ commands.select { |cmd| cmd.downcase.start_with?(input_lower) }.uniq
77
+ end
78
+
79
+ private
80
+
81
+ # PATHから実行可能なコマンドのリストを取得
82
+ # @return [Array<String>] コマンドのリスト
83
+ def path_commands
84
+ @path_commands ||= begin
85
+ paths = ENV['PATH'].split(File::PATH_SEPARATOR)
86
+ commands = []
87
+
88
+ paths.each do |path|
89
+ next unless Dir.exist?(path)
90
+
91
+ Dir.foreach(path) do |file|
92
+ next if file == '.' || file == '..'
93
+
94
+ filepath = File.join(path, file)
95
+ # 実行可能なファイルのみを追加
96
+ commands << file if File.executable?(filepath) && !File.directory?(filepath)
97
+ end
98
+ end
99
+
100
+ commands.uniq.sort
101
+ rescue StandardError
102
+ []
103
+ end
104
+ end
105
+
106
+ # CommandHistoryオブジェクトからコマンドリストを取得
107
+ # @param history [CommandHistory] 履歴オブジェクト
108
+ # @return [Array<String>] コマンドのリスト
109
+ def get_history_commands(history)
110
+ # CommandHistoryの内部データにアクセスするため、
111
+ # instance_variable_getを使用(本来はpublicメソッドを追加すべき)
112
+ history_array = history.instance_variable_get(:@history) || []
113
+
114
+ # ! を除去したコマンドを返す
115
+ history_array.map do |cmd|
116
+ cmd.start_with?('!') ? cmd[1..-1] : cmd
117
+ end
118
+ end
119
+ end
120
+ end
@@ -48,6 +48,12 @@ module Rufio
48
48
  @dialog_renderer = DialogRenderer.new
49
49
  @command_mode_ui = CommandModeUI.new(@command_mode, @dialog_renderer)
50
50
 
51
+ # コマンド履歴と補完
52
+ history_file = File.join(Dir.home, '.rufio', 'command_history.txt')
53
+ FileUtils.mkdir_p(File.dirname(history_file))
54
+ @command_history = CommandHistory.new(history_file, max_size: ConfigLoader.command_history_size)
55
+ @command_completion = CommandCompletion.new(@command_history)
56
+
51
57
  # Project mode
52
58
  @project_mode = nil
53
59
  @project_command = nil
@@ -151,10 +157,8 @@ module Rufio
151
157
 
152
158
  # コマンドモードがアクティブな場合はコマンド入力ウィンドウを表示
153
159
  if @command_mode_active
154
- # 補完候補を取得
155
- suggestions = @command_mode_ui.autocomplete(@command_input)
156
160
  # フローティングウィンドウで表示
157
- @command_mode_ui.show_input_prompt(@command_input, suggestions)
161
+ @command_mode_ui.show_input_prompt(@command_input)
158
162
  else
159
163
  # move cursor to invisible position
160
164
  print "\e[#{@screen_height};#{@screen_width}H"
@@ -546,7 +550,7 @@ module Rufio
546
550
  deactivate_command_mode
547
551
  when "\t"
548
552
  # Tab キーで補完
549
- @command_input = @command_mode_ui.complete_command(@command_input)
553
+ handle_tab_completion
550
554
  when "\u007F", "\b"
551
555
  # Backspace
552
556
  @command_input.chop! unless @command_input.empty?
@@ -560,6 +564,9 @@ module Rufio
560
564
  def execute_command(command_string)
561
565
  return if command_string.nil? || command_string.empty?
562
566
 
567
+ # コマンド履歴に追加
568
+ @command_history.add(command_string)
569
+
563
570
  result = @command_mode.execute(command_string)
564
571
 
565
572
  # コマンド実行結果をフローティングウィンドウで表示
@@ -569,6 +576,84 @@ module Rufio
569
576
  draw_screen
570
577
  end
571
578
 
579
+ # Tab補完を処理
580
+ def handle_tab_completion
581
+ # 補完候補を取得
582
+ candidates = @command_completion.complete(@command_input)
583
+
584
+ # 候補がない場合は何もしない
585
+ return if candidates.empty?
586
+
587
+ # 候補が1つの場合はそれに補完
588
+ if candidates.size == 1
589
+ @command_input = candidates.first
590
+ return
591
+ end
592
+
593
+ # 複数の候補がある場合、共通プレフィックスまで補完
594
+ prefix = @command_completion.common_prefix(@command_input)
595
+
596
+ # 入力が変わる場合は補完して終了
597
+ if prefix != @command_input
598
+ @command_input = prefix
599
+ return
600
+ end
601
+
602
+ # 入力が変わらない場合は候補リストを表示
603
+ show_completion_candidates(candidates)
604
+ end
605
+
606
+ # 補完候補を一時的に表示
607
+ def show_completion_candidates(candidates)
608
+ title = "補完候補 (#{candidates.size}件)"
609
+
610
+ # 候補を表示用にフォーマット(最大20件)
611
+ display_candidates = candidates.first(20)
612
+ content_lines = [""]
613
+ display_candidates.each do |candidate|
614
+ content_lines << " #{candidate}"
615
+ end
616
+
617
+ if candidates.size > 20
618
+ content_lines << ""
619
+ content_lines << " ... 他 #{candidates.size - 20} 件"
620
+ end
621
+
622
+ content_lines << ""
623
+ content_lines << "Press any key to continue..."
624
+
625
+ # ウィンドウの色設定(黄色)
626
+ border_color = "\e[33m"
627
+ title_color = "\e[1;33m"
628
+ content_color = "\e[37m"
629
+
630
+ # ウィンドウサイズを計算
631
+ width, height = @dialog_renderer.calculate_dimensions(content_lines, {
632
+ title: title,
633
+ min_width: 40,
634
+ max_width: 80
635
+ })
636
+
637
+ # 中央位置を計算
638
+ x, y = @dialog_renderer.calculate_center(width, height)
639
+
640
+ # フローティングウィンドウを描画
641
+ @dialog_renderer.draw_floating_window(x, y, width, height, title, content_lines, {
642
+ border_color: border_color,
643
+ title_color: title_color,
644
+ content_color: content_color
645
+ })
646
+
647
+ # キー入力を待つ
648
+ STDIN.getch
649
+
650
+ # ウィンドウをクリア
651
+ @dialog_renderer.clear_area(x, y, width, height)
652
+
653
+ # 画面を再描画
654
+ draw_screen
655
+ end
656
+
572
657
  # Show info notices from the info directory if any are unread
573
658
  def show_info_notices
574
659
  require_relative 'info_notice'
data/lib/rufio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rufio
4
- VERSION = '0.30.0'
4
+ VERSION = '0.32.0'
5
5
  end
data/lib/rufio.rb CHANGED
@@ -27,12 +27,18 @@ require_relative "rufio/plugin"
27
27
  require_relative "rufio/plugin_manager"
28
28
  require_relative "rufio/command_mode"
29
29
  require_relative "rufio/command_mode_ui"
30
+ require_relative "rufio/command_history"
31
+ require_relative "rufio/command_completion"
32
+ require_relative "rufio/shell_command_completion"
30
33
 
31
34
  # プロジェクトモード
32
35
  require_relative "rufio/project_mode"
33
36
  require_relative "rufio/project_command"
34
37
  require_relative "rufio/project_log"
35
38
 
39
+ # プラグインをロード
40
+ Rufio::PluginManager.load_all
41
+
36
42
  module Rufio
37
43
  class Error < StandardError; end
38
44
  end
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
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.0
4
+ version: 0.32.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - masisz
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-01-02 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: io-console
@@ -117,23 +118,23 @@ extensions: []
117
118
  extra_rdoc_files: []
118
119
  files:
119
120
  - CHANGELOG.md
120
- - CHANGELOG_v0.10.0.md
121
- - CHANGELOG_v0.20.0.md
122
- - CHANGELOG_v0.21.0.md
123
- - CHANGELOG_v0.30.0.md
124
- - CHANGELOG_v0.4.0.md
125
- - CHANGELOG_v0.5.0.md
126
- - CHANGELOG_v0.6.0.md
127
- - CHANGELOG_v0.7.0.md
128
- - CHANGELOG_v0.8.0.md
129
- - CHANGELOG_v0.9.0.md
130
121
  - README.md
131
122
  - README_EN.md
132
123
  - Rakefile
133
124
  - bin/rufio
134
125
  - config_example.rb
135
- - docs/PLUGIN_GUIDE.md
136
- - docs/plugin_example.rb
126
+ - docs/CHANGELOG_v0.10.0.md
127
+ - docs/CHANGELOG_v0.20.0.md
128
+ - docs/CHANGELOG_v0.21.0.md
129
+ - docs/CHANGELOG_v0.30.0.md
130
+ - docs/CHANGELOG_v0.31.0.md
131
+ - docs/CHANGELOG_v0.32.0.md
132
+ - docs/CHANGELOG_v0.4.0.md
133
+ - docs/CHANGELOG_v0.5.0.md
134
+ - docs/CHANGELOG_v0.6.0.md
135
+ - docs/CHANGELOG_v0.7.0.md
136
+ - docs/CHANGELOG_v0.8.0.md
137
+ - docs/CHANGELOG_v0.9.0.md
137
138
  - info/help.md
138
139
  - info/keybindings.md
139
140
  - info/welcome.md
@@ -142,6 +143,8 @@ files:
142
143
  - lib/rufio/bookmark.rb
143
144
  - lib/rufio/bookmark_manager.rb
144
145
  - lib/rufio/color_helper.rb
146
+ - lib/rufio/command_completion.rb
147
+ - lib/rufio/command_history.rb
145
148
  - lib/rufio/command_mode.rb
146
149
  - lib/rufio/command_mode_ui.rb
147
150
  - lib/rufio/config.rb
@@ -160,16 +163,18 @@ files:
160
163
  - lib/rufio/plugin_config.rb
161
164
  - lib/rufio/plugin_manager.rb
162
165
  - lib/rufio/plugins/file_operations.rb
166
+ - lib/rufio/plugins/hello.rb
163
167
  - lib/rufio/project_command.rb
164
168
  - lib/rufio/project_log.rb
165
169
  - lib/rufio/project_mode.rb
166
170
  - lib/rufio/selection_manager.rb
171
+ - lib/rufio/shell_command_completion.rb
167
172
  - lib/rufio/terminal_ui.rb
168
173
  - lib/rufio/text_utils.rb
169
174
  - lib/rufio/version.rb
170
175
  - lib/rufio/zoxide_integration.rb
171
176
  - publish_gem.zsh
172
- - rufio.gemspec
177
+ - retag.sh
173
178
  - test_delete/test1.txt
174
179
  - test_delete/test2.txt
175
180
  homepage: https://github.com/masisz/rufio
@@ -180,6 +185,7 @@ metadata:
180
185
  homepage_uri: https://github.com/masisz/rufio
181
186
  source_code_uri: https://github.com/masisz/rufio
182
187
  changelog_uri: https://github.com/masisz/rufio/blob/main/CHANGELOG.md
188
+ post_install_message:
183
189
  rdoc_options: []
184
190
  require_paths:
185
191
  - lib
@@ -194,7 +200,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
194
200
  - !ruby/object:Gem::Version
195
201
  version: '0'
196
202
  requirements: []
197
- rubygems_version: 4.0.2
203
+ rubygems_version: 3.4.19
204
+ signing_key:
198
205
  specification_version: 4
199
206
  summary: Ruby file manager
200
207
  test_files: []