lib/sup/modes/file_browser_mode.rb (2359B) - raw
1 require 'pathname'
2
3 module Redwood
4
5 ## meant to be spawned via spawn_modal!
6 class FileBrowserMode < LineCursorMode
7 RESERVED_ROWS = 1
8
9 register_keymap do |k|
10 k.add :back, "Go back to previous directory", "B"
11 k.add :view, "View file", "v"
12 k.add :select_file_or_follow_directory, "Select the highlighted file, or follow the directory", :enter
13 k.add :reload, "Reload file list", "R"
14 end
15
16 bool_reader :done
17 attr_reader :value
18
19 def initialize dir="."
20 @dirs = [Pathname.new(dir).realpath]
21 @done = false
22 @value = nil
23 regen_text
24 super :skip_top_rows => RESERVED_ROWS
25 end
26
27 def cwd; @dirs.last end
28 def lines; @text.length; end
29 def [] i; @text[i]; end
30
31 protected
32
33 def back
34 return if @dirs.size == 1
35 @dirs.pop
36 reload
37 end
38
39 def reload
40 regen_text
41 jump_to_start
42 buffer.mark_dirty
43 end
44
45 def view
46 _name, f = @files[curpos - RESERVED_ROWS]
47 return unless f && f.file?
48
49 begin
50 BufferManager.spawn f.to_s, TextMode.new(f.read.ascii)
51 rescue SystemCallError => e
52 BufferManager.flash e.message
53 end
54 end
55
56 def select_file_or_follow_directory
57 _name, f = @files[curpos - RESERVED_ROWS]
58 return unless f
59
60 if f.directory? && f.to_s != "."
61 if f.readable?
62 @dirs.push f
63 reload
64 else
65 BufferManager.flash "Permission denied - #{f.realpath}"
66 end
67 else
68 begin
69 @value = f.realpath.to_s
70 @done = true
71 rescue SystemCallError => e
72 BufferManager.flash e.message
73 end
74 end
75 end
76
77 def regen_text
78 @files =
79 begin
80 cwd.entries.sort_by do |f|
81 [f.directory? ? 0 : 1, f.basename.to_s]
82 end
83 rescue SystemCallError => e
84 BufferManager.flash "Error: #{e.message}"
85 [Pathname.new("."), Pathname.new("..")]
86 end.map do |f|
87 real_f = cwd + f
88 name = f.basename.to_s +
89 case
90 when real_f.symlink?
91 "@"
92 when real_f.directory?
93 "/"
94 else
95 ""
96 end
97 [name, real_f]
98 end
99
100 size_width = @files.max_of { |name, f| f.human_size.length }
101 time_width = @files.max_of { |name, f| f.human_time.length }
102
103 @text = ["#{cwd}:"] + @files.map do |name, f|
104 sprintf "%#{time_width}s %#{size_width}s %s", f.human_time, f.human_size, name
105 end
106 end
107 end
108
109 end