summary refs log tree commit diff stats
path: root/code/extensions.rb
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2009-04-10 00:00:00 +0200
committerhut <hut@lavabit.com>2009-04-10 00:00:00 +0200
commit34bfb32ecf2cea5e5de95980beedb681139d9c01 (patch)
tree68acd3339f575782b5ebccbb70d8c1efd0dffc62 /code/extensions.rb
parentadfea091f816cc2f4007e99b6b2be35a821857da (diff)
downloadranger-34bfb32ecf2cea5e5de95980beedb681139d9c01.tar.gz
new minor version v0.2.0
Diffstat (limited to 'code/extensions.rb')
-rw-r--r--code/extensions.rb487
1 files changed, 442 insertions, 45 deletions
diff --git a/code/extensions.rb b/code/extensions.rb
index db238614..a15fc952 100644
--- a/code/extensions.rb
+++ b/code/extensions.rb
@@ -1,13 +1,348 @@
+class Bar
+	def initialize( text = '' )
+		@text = text
+		@done = 0
+		@thread = nil
+		@update_proc = nil
+		Fm.bar_add(self)
+	end
+
+	def kill(evil = true)
+		Fm.bar_del(self)
+		Fm.force_update
+
+		@thread.kill
+	end
+
+	def update(&block)
+		if block
+			@update_proc = block
+		elsif @update_proc
+			@update_proc.call(self)
+		end
+	end
+
+	attr_accessor :text, :done, :thread
+end
+
+class CopyBar < Bar
+	def initialize( text = '' )
+		super
+
+		@update_proc = proc do |b|
+			begin
+				b.done = File.size(fname).to_f / finished
+			rescue
+				b.done = 0
+			end
+		end
+	end
+end
+
+module Action
+#	def self.get_all_files(path)
+#		glob = Dir.new(path).to_a
+#	end
+	
+	def self.make_a_bar_for_one(text, command)
+		bar = CopyBar.new(test)
+
+		finished = File.size(from[0]).to_f
+		fname = File.join(to, File.basename(from[0]))
+
+		bar.thread = Thread.new do
+			begin
+				system('ionice', '-c3', command, *(from + [to]))
+			ensure
+				bar.kill(false)
+			end
+		end
+	end
+
+	def self.copy(from, to)
+#		log [from, to]
+
+#		if String === from[0]
+#			from[0] = Directory::Entry.new(from[0])
+#		end
+
+		if from.size == 1 and from[0].file?
+			from = from[0]
+			bar = Bar.new("Copying...")
+			finished = from.size.to_f
+			fname = File.join(to, from.basename)
+
+			bar.update do |b|
+				begin
+					b.done = File.size(fname).to_f / finished
+				rescue
+					b.done = 0
+				end
+			end
+
+			bar.thread = Thread.new do
+				begin
+					system('cp', from.to_s, to)
+				ensure
+					bar.kill(false)
+				end
+			end
+
+		else
+			bar = Bar.new("Copying...")
+			from = from.dup
+			from = [from] unless Array === from
+			finished = Dir.number_of_files(*from.map{|x| x.to_s})
+			count = 0
+
+			bar.update do |b|
+				begin
+					b.done = count / finished
+				rescue
+					b.done = 0
+				end
+			end
+			
+			from.map!{|x| x.to_s}
+			bar.thread = Thread.new do
+				begin
+					system('cp', '-r', *(from + [to.to_s]))
+#					IO.popen("cp -vr #{from.join(' ')} #{to.sh}") do |f|
+#					IO.popen(['cp', '-vr', *(from + [to])]) do |f|
+#						count += 1 while f.gets =~ /' -> `/
+#					end
+				ensure
+					bar.kill(false)
+				end
+			end
+		end
+	end
+
+	def self.move(from, to)
+#		log [from, to]
+		
+#		if String === from[0]
+#			from[0] = Directory::Entry.new(from[0])
+#		end
+
+		if from.size == 1 and from[0].file?
+			from = from[0]
+			bar = Bar.new("Moving...")
+			finished = from.size.to_f
+			fname = File.join(to, from.basename)
+
+			bar.update do |b|
+				begin
+					b.done = File.size(fname).to_f / finished
+				rescue
+					b.done = 0
+				end
+			end
+
+			bar.thread = Thread.new do
+				begin
+					system('mv', from.to_s, to)
+				ensure
+					bar.kill(false)
+				end
+			end
+
+		else
+			bar = Bar.new("Moving...")
+			from = from.dup
+			from = [from] unless Array === from
+			finished = Dir.number_of_files(*from.map{|x| x.to_s})
+			count = 0
+
+			bar.update do |b|
+				begin
+					b.done = count / finished
+				rescue
+					b.done = 0
+				end
+			end
+			
+			from.map!{|x| x.to_s}
+			bar.thread = Thread.new do
+				begin
+					system('mv', *(from + [to.to_s]))
+#					IO.popen("mv -v #{from.join(' ')} #{to.sh}") do |f|
+#						count += 1 while f.gets =~ /' -> `/
+#					end
+				ensure
+					bar.kill(false)
+				end
+			end
+		end
+	end
+end
+
 class Directory
-	def initialize(path)
+	BAD_TIME = Time.at(0)
+	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
+			@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(:basename, :mtime, :rights, :type, :path,
+					  :infostring, :readlink, :basename, :size, :ctime)
+
+		attr_accessor(:marked)
+		
+		def to_s() @path end
+		def exists?() @exists end
+		def marked?() @marked end
+		def symlink?() @symlink 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 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
+			res = @path.dup
+			res.gsub!('\\\\', "\000")
+			res.gsub!(' ', '\\ ')
+			res.gsub!('(', '\\(')
+			res.gsub!('&', '\\&')
+			res.gsub!(')', '\\)')
+			res.gsub!('*', '\\*')
+			res.gsub!('\'', '\\\'')
+			res.gsub!('"', '\\"')
+			res.gsub!("\000", '\\\\')
+			return res
+		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
-		@pointed_file = ''
-		@width = 0
+		@files = [PLACEHOLDER]
+		@file_size = 0
+		@pointed_file = nil
+		@width = 1000
+
 		refresh
 	end
 
-	attr_reader(:path, :files, :pos, :width, :infos)
+	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)
 
 	def pos=(x)
 		@pos = x
@@ -15,10 +350,16 @@ class Directory
 		resize
 	end
 
+	def restore()
+		for f in @files
+			f.marked = false
+		end
+	end
+
 	def pointed_file=(x)
-		if @files.include?(x)
+		if @files_raw.include?(x)
 			@pointed_file = x
-			@pos = @files.index(x)
+			@pos = @files_raw.index(x)
 		else
 			self.pos = 0
 		end
@@ -35,57 +376,90 @@ class Directory
 			@width = 0
 			@files[pos, lines-2].each_with_index do |fn, ix|
 				ix += pos
-#				log File.basename(fn) + @infos[ix]
-				sz = File.basename(fn).size + @infos[ix].size + 2
+				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_infos()
-		@infos = []
-		@files.each do |fn|
-			if File.directory?(fn)
-				begin
-					sz = Dir.entries(fn).size - 2
-				rescue
-					sz = "?"
-				end
-				@infos << "#{sz}"
-			else
-				if File.size?(fn)
-					@infos << " #{File.size(fn).bytes 2}"
-				else
-					@infos << ""
-				end
-			end
+	def get_file_info()
+		@file_size = 0
+		@files.each do |f|
+			f.refresh
+			@file_size += f.size if f.file?
 		end
 	end
 
-	def refresh()
-		glob = Dir.new(@path).to_a.sort!
-		if OPTIONS['hidden']
-		glob -= ['.', '..', 'lost+found']
-		else
-			glob.reject!{|x| x[0] == ?. or x == 'lost+found'}
+#	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 glob.empty?
-			glob = ['.']
+		if info
+			log("getting file info of #{@path}")
+			get_file_info 
 		end
-		glob.map!{|x| File.join(@path, x)}
-		dirs = glob.select{|x| File.directory?(x)}
-		@files = dirs + (glob - dirs)
+		sort
+	end
 
-		get_file_infos
-		resize
+	def schedule()
+		Fm.schedule(self)
+	end
+
+	def refresh!()
+		read_dir
+		get_file_info
+		sort
+	end
 
-		if @pos >= @files.size
-			@pos = @files.size - 1
-		elsif @files.include?(@pointed_file)
-			@pos = @files.index(@pointed_file)
+	def sort_sub(x, y)
+		case OPTIONS['sort']
+		when :name
+			x.basename <=> y.basename
+		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
 
 
@@ -122,12 +496,27 @@ class File
 	end
 end
 
+class Dir
+	def self.number_of_files(*dirs)
+		n = 0
+		dirs.each do |entry|
+			if File.directory?(entry)
+				n += 1 + number_of_files(*(Dir.new(entry).to_a - ['.', '..']).map\
+												 {|x| File.join entry, x } )
+			else
+				n += 1
+			end
+		end
+		return n
+	end
+end
+
 class Numeric
 	def limit(max, min = 0)
 		self < min ? min : (self > max ? max : self)
 	end
 
-	def bytes n_round = 2
+	def bytes space = true, n_round = 2
 		n = 1024
 		a = %w(B K M G T Y)
 
@@ -146,7 +535,7 @@ class Numeric
 		int = flt.to_i
 		flt = int if int == flt
 
-		return flt.to_s + ' ' + a[i]
+		return flt.to_s + (space ? ' ' + a[i] : a[i])
 	end
 end
 
@@ -160,11 +549,18 @@ class String
 	def clear
 		replace String.new
 	end
+	if RUBY_VERSION < '1.9'
+		def ord
+			self[0]
+		end
+	end
+
 	def sh
-		res = dup
+		res = self.dup
 		res.gsub!('\\\\', "\000")
 		res.gsub!(' ', '\\ ')
 		res.gsub!('(', '\\(')
+		res.gsub!('&', '\\&')
 		res.gsub!(')', '\\)')
 		res.gsub!('*', '\\*')
 		res.gsub!('\'', '\\\'')
@@ -172,5 +568,6 @@ class String
 		res.gsub!("\000", '\\\\')
 		return res
 	end
+
 end