require 'code/extensions/basic.rb' class Directory BAD_TIME = Time.at(0) MOVIE_EXTENSIONS = %w(avi mpg mpeg mp4 mp5 ogv ogm wmv mkv flv fid vob div divx) class Entry #{{{ # Let's just cache every shit, because i don't want # to call File methods all the time def initialize(dirname, basename=nil) if basename @path = File.join(dirname, basename) @dirname = dirname @basename = basename else @path = dirname @dirname = File.dirname(dirname) @basename = File.basename(dirname) end @name, @ext = @basename.split_at_last_dot # @ext = @basename.from_last('.') || '' @movie = MOVIE_EXTENSIONS.include?(@ext) @size = 0 @exists = false @rights = '----------' @readlink = '' @symlink = false @writable = false @infostring = '' @executable = false @type = :nonexistent @mtime = BAD_TIME @ctime = BAD_TIME @marked = false end attr_reader(*%w{ basename mtime rights type path ext infostring readlink basename size ctime name }) attr_accessor(:marked) def to_s() @path end def exists?() @exists end def marked?() @marked end def symlink?() @symlink end def movie?() @movie end def broken_symlink?() @symlink and !@exists end def dir?() @type == :dir end def file?() @type == :file end def writable?() @writable end def executable?() @executable end def mimetype() if @type == :dir nil else Fm::MIMETYPES[@ext] end end def delete! if @type == :dir Dir.delete(@path) rescue nil else File.delete(@path) rescue nil end end def refresh if File.exists?(@path) if File.ctime(@path) != @ctime get_data end else get_data end end def sh @path.sh end def in? path to_s[0, path.size] == path end def get_data @size = 0 @infostring = '' @exists = File.exists?(@path) if @exists @writable = File.writable?(@path) @symlink = File.symlink?(@path) if @symlink @readlink = File.readlink(@path) end if File.directory?(@path) @type = :dir begin sz = Dir.entries(@path).size - 2 @size = sz rescue sz = "?" end @infostring << "#{sz}" elsif File.socket?(@path) @type = :socket else @type = :file @size = File.size(@path) if File.size?(@path) @infostring << " #{File.size(@path).bytes 2}" else @infostring << "" end end @rights = File.modestr(@path) @executable = File.executable?(@path) @mtime = File.mtime(@path) @ctime = File.ctime(@path) else if File.symlink?(@path) @readlink = File.readlink(@path) @infostring = '->' @symlink = true else @symlink = false end @executable = false @writable = false @type = :nonexistent @rights = '----------' @mtime = BAD_TIME @ctime = BAD_TIME end end end #}}} PLACEHOLDER = Entry.new('/', 'placeholder') def initialize(path, allow_delay=false) @path = path @pos = 0 @files = [PLACEHOLDER] @file_size = 0 @pointed_file = nil @width = 1000 @read = false @empty = true @scheduled = false refresh end def read_dir @mtime = File.mtime(@path) @files = Dir.new(@path).to_a if OPTIONS['hidden'] @files -= ['.', '..', 'lost+found'] else @files.reject!{|x| x[0] == ?. or x == 'lost+found'} end if @files.empty? @files = ['.'] end @files_raw = @files.map{|bn| File.join(@path, bn)} @files.map!{|basename| Entry.new(@path, basename)} end attr_reader(:path, :files, :pos, :width, :files_raw, :file_size, :read) attr_accessor(:scheduled) def scheduled?() @scheduled end def read?() @read end def pos=(x) # if @files.size <= 1 or x < 0 # x = 0 # elsif x > @files.size # x = @files.size - 1 # end @pos = x make_sure_cursor_is_in_range() @pointed_file = @files[x] resize end def recheck_stuff() # log "pointed file: #@pointed_file" # log @files_raw # log "" if test = @files_raw.index(@pointed_file) # log("if") @pos = test else # log("else") make_sure_cursor_is_in_range() end end def make_sure_cursor_is_in_range() if @files.size <= 1 or @pos < 0 @pos = 0 elsif @pos > @files.size @pos = @files.size - 1 end end def find_file(x) x = File.basename(x) files.each_with_index do |file, i| if file.basename == x self.pos = i end end end def empty?() Dir.entries(@path).size <= 2 end def restore() for f in @files f.marked = false end end def pointed_file=(x) if @files_raw.include?(x) @pointed_file = x @pos = @files_raw.index(x) else self.pos = 0 end resize end def size() @files.size end def resize() pos = Fm.get_offset(self, lines) if @files.empty? @width = 0 else @width = 0 @files[pos, lines-2].each_with_index do |fn, ix| ix += pos sz = fn.basename.size + fn.infostring.size + 2 @width = sz if @width < sz end # @width = @files[pos,lines-2].map{|x| File.basename(x).size}.max end end def get_file_info() @file_size = 0 @files.each do |f| f.refresh @file_size += f.size if f.file? end @read = true end # def refresh() # @files = Dir.new(@path).to_a # if OPTIONS['hidden'] # @files -= ['.', '..', 'lost+found'] # else # @files.reject!{|x| x[0] == ?. or x == 'lost+found'} # end # if @files.empty? # @files = ['.'] # end # @files.map!{|basename| Entry.new(@path, basename)} # # if @pos >= @files.size # @pos = @files.size - 1 # elsif @files.include?(@pointed_file) # @pos = @files.index(@pointed_file) # end # end def refresh(info=false) if File.mtime(@path) != @mtime read_dir end if info log("getting file info of #{@path}") get_file_info end sort end def schedule() Scheduler << self end def refresh!() oldfile = @pointed_file read_dir get_file_info sort if @files.include? oldfile self.pointed_file = oldfile end end def sort_sub(x, y) case OPTIONS['sort'] when :name x.basename <=> y.basename when :ext x.ext <=> y.ext when :type x.ext.filetype <=> y.ext.filetype when :size x.size <=> y.size when :ctime x.ctime <=> y.ctime when :mtime x.mtime <=> y.mtime else x.basename <=> y.basename end end def sort() @files = @files.sort {|x,y| if OPTIONS['dir_first'] if x.dir? if y.dir? then sort_sub(x, y) else -1 end else if y.dir? then 1 else sort_sub(x, y) end end else sort_sub(x, y) end } @files.reverse! if OPTIONS['sort_reverse'] @files_raw = @files.map{|x| x.to_s} end end