about summary refs log blame commit diff stats
path: root/code/directory.rb
blob: a5bee819c97b8fa973a5e2d76c1f92a98e733a24 (plain) (tree)
1
2
3
4
                                  
               
                             
                                                                                        














                                                                    


                                                                 













                                              



                                                                    






                                           
                                       




                                                               






                                                   



















                                                              
                                






























































                                                                                             

                            



                                      


                                  
 


                       







                                                                           
 







                                                                  





                                                            

                   




                                            
                        
                                              



                                         


































                                                         





                                        
                            
                                         
                                         
                                                  















                                                                        
                                                                              





                                                                                       




                                                       
                   
                            

           




















                                                                           
                   


                                                            
                   

                    
 
                      
                                 



                                 
                                       


                             



                                                   
           
 



                                                 



                                                         







                                                 

                   















                                                                                 

   
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()
		@scheduled = true
		Fm.schedule(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