rufio 1.3.0 → 1.4.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.
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+
5
+ module Rufio
6
+ # :cd に貼り付けられたパスを移動先に解決する。
7
+ # 引用符・末尾の改行・バックスラッシュエスケープされた空白・file:// URL を受け付け、
8
+ # ファイルを指す場合はその親ディレクトリとファイル自体を返す。
9
+ module PathJump
10
+ QUOTE_PAIRS = [%w[' '], %w[" "]].freeze
11
+
12
+ class << self
13
+ # @param input [String] 貼り付けられたパス(空なら ホーム)
14
+ # @param base_dir [String] 相対パスの基準ディレクトリ
15
+ # @return [Hash] { directory:, file: } または { directory: nil, error: }
16
+ def resolve(input, base_dir)
17
+ path = normalize(input.to_s)
18
+ path = '~' if path.empty?
19
+ expanded = File.expand_path(path, base_dir)
20
+
21
+ if File.directory?(expanded)
22
+ { directory: expanded, file: nil }
23
+ elsif File.file?(expanded)
24
+ { directory: File.dirname(expanded), file: expanded }
25
+ else
26
+ { directory: nil, error: "Path not found: #{path}" }
27
+ end
28
+ rescue ArgumentError => e
29
+ { directory: nil, error: "Invalid path: #{e.message}" }
30
+ end
31
+
32
+ private
33
+
34
+ def normalize(text)
35
+ path = text.strip
36
+ QUOTE_PAIRS.each do |open, close|
37
+ if path.length >= 2 && path.start_with?(open) && path.end_with?(close)
38
+ path = path[1..-2]
39
+ break
40
+ end
41
+ end
42
+ path = from_file_url(path) if path.start_with?('file://')
43
+ path = path.gsub(/\\(.)/, '\1') unless Gem.win_platform?
44
+ path
45
+ end
46
+
47
+ def from_file_url(url)
48
+ uri = URI.parse(url)
49
+ URI.decode_www_form_component(uri.path.to_s.gsub('+', '%2B'))
50
+ rescue URI::InvalidURIError
51
+ url.delete_prefix('file://')
52
+ end
53
+ end
54
+ end
55
+ end
@@ -617,6 +617,8 @@ module Rufio
617
617
 
618
618
  # マウス左クリックを処理する
619
619
  def handle_mouse_left_click(col, row)
620
+ return if @keybind_handler.preview_focused?
621
+
620
622
  left_width = left_panel_col_width
621
623
 
622
624
  if col <= left_width
@@ -662,10 +664,8 @@ module Rufio
662
664
  end
663
665
 
664
666
  # マウスホイールスクロールを処理する
665
- def handle_mouse_scroll(direction, col, _row)
666
- left_width = left_panel_col_width
667
-
668
- if col > left_width && @keybind_handler.preview_focused?
667
+ def handle_mouse_scroll(direction, _col, _row)
668
+ if @keybind_handler.preview_focused?
669
669
  # プレビューペインのスクロール
670
670
  case direction
671
671
  when :up then @keybind_handler.scroll_preview_up
@@ -790,6 +790,9 @@ module Rufio
790
790
 
791
791
  result = @command_mode.execute(command_string, working_dir: working_dir)
792
792
 
793
+ # :cd はディレクトリを移動してコマンドモードを閉じる
794
+ return change_directory(result[:cd]) if result.is_a?(Hash) && result.key?(:cd)
795
+
793
796
  # バックグラウンドコマンドの場合は結果表示をスキップ
794
797
  # (完了通知は別途メインループで表示される)
795
798
  if result && !result.to_s.include?("🔄 Running in background")
@@ -802,6 +805,28 @@ module Rufio
802
805
  # 使用するとコマンドプロンプトの枠線が残る不具合が発生する
803
806
  end
804
807
 
808
+ # :cd の移動先へ移動する。ファイルが指定されていればそのファイルを選択する
809
+ # @param target [Hash, Symbol] { directory:, file: } または :previous(cd -)
810
+ def change_directory(target)
811
+ if target == :previous
812
+ return @command_mode_ui.show_result('⚠️ No previous directory') unless @previous_directory
813
+
814
+ target = { directory: @previous_directory, file: nil }
815
+ end
816
+
817
+ origin = @directory_listing&.current_path
818
+ unless @keybind_handler.navigate_to_directory(target[:directory])
819
+ return @command_mode_ui.show_result("⚠️ Cannot open directory: #{target[:directory]}")
820
+ end
821
+
822
+ @previous_directory = origin
823
+ index = target[:file] && @keybind_handler.get_active_entries.index { |entry| entry[:path] == target[:file] }
824
+ @keybind_handler.select_index(index || 0)
825
+ @keybind_handler.unfocus_preview_pane
826
+ @tab_mode_manager&.switch_to(@keybind_handler.config_mode? ? :config : :files)
827
+ deactivate_command_mode
828
+ end
829
+
805
830
  # Tab補完を処理
806
831
  def handle_tab_completion
807
832
  # 補完候補を取得
@@ -147,8 +147,12 @@ module Rufio
147
147
  left_width = (@screen_width * @left_panel_ratio).to_i
148
148
  right_width = @screen_width - left_width
149
149
 
150
- draw_directory_list_to_buffer(screen, entries, left_width, content_height)
151
- draw_file_preview_to_buffer(screen, selected_entry, right_width, content_height, left_width)
150
+ if @keybind_handler.preview_focused?
151
+ draw_file_preview_to_buffer(screen, selected_entry, @screen_width, content_height, 0)
152
+ else
153
+ draw_directory_list_to_buffer(screen, entries, left_width, content_height)
154
+ draw_file_preview_to_buffer(screen, selected_entry, right_width, content_height, left_width)
155
+ end
152
156
 
153
157
  draw_mode_tabs_to_buffer(screen, @screen_height - 1, show_path: false)
154
158
  end
@@ -314,9 +318,10 @@ module Rufio
314
318
 
315
319
  def draw_file_preview_to_buffer(screen, selected_entry, width, height, left_offset)
316
320
  # 事前計算
321
+ fullscreen = @keybind_handler&.preview_focused?
317
322
  cursor_position = left_offset + CURSOR_OFFSET
318
323
  max_chars_from_cursor = @screen_width - cursor_position
319
- safe_width = [max_chars_from_cursor - 2, width - 2, 0].max
324
+ safe_width = fullscreen ? @screen_width : [max_chars_from_cursor - 2, width - 2, 0].max
320
325
 
321
326
  # プレビューコンテンツをキャッシュから取得
322
327
  preview_content = nil
@@ -387,13 +392,13 @@ module Rufio
387
392
  end
388
393
  end
389
394
 
390
- content_x = cursor_position + 1
395
+ content_x = fullscreen ? 0 : cursor_position + 1
391
396
 
392
397
  (0...height).each do |i|
393
398
  line_num = i + CONTENT_START_LINE
394
399
 
395
400
  # 区切り線
396
- screen.put(cursor_position, line_num, '│')
401
+ screen.put(cursor_position, line_num, '│') unless fullscreen
397
402
 
398
403
  next if safe_width <= 0
399
404
 
data/lib/rufio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rufio
4
- VERSION = '1.3.0'
4
+ VERSION = '1.4.1'
5
5
  end
data/lib/rufio.rb CHANGED
@@ -40,6 +40,7 @@ require_relative 'rufio/script_executor'
40
40
  require_relative 'rufio/dsl_command_loader'
41
41
  require_relative 'rufio/builtin_commands'
42
42
 
43
+ require_relative 'rufio/path_jump'
43
44
  require_relative 'rufio/command_mode'
44
45
  require_relative 'rufio/command_mode_ui'
45
46
  require_relative 'rufio/command_history'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rufio
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - masisz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-11-01 00:00:00.000000000 Z
11
+ date: 2026-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: io-console
@@ -238,6 +238,8 @@ files:
238
238
  - docs/CHANGELOG_v0.9.0.md
239
239
  - docs/architecture_concurrency_ja_v0.82.1.md
240
240
  - docs/fast_zip_design_ja.md
241
+ - docs/guide.md
242
+ - docs/guide_ja.md
241
243
  - examples/bookmarks.yml
242
244
  - examples/config.rb
243
245
  - examples/script_paths.yml
@@ -303,6 +305,7 @@ files:
303
305
  - lib/rufio/navigation_controller.rb
304
306
  - lib/rufio/notification_manager.rb
305
307
  - lib/rufio/parallel_scanner.rb
308
+ - lib/rufio/path_jump.rb
306
309
  - lib/rufio/rakefile_parser.rb
307
310
  - lib/rufio/renderer.rb
308
311
  - lib/rufio/screen.rb