sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/

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