summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--code/action.rb55
-rw-r--r--code/application.rb9
-rw-r--r--code/entry.rb26
-rw-r--r--code/extensions/basic.rb13
-rw-r--r--code/fm/fm.rb49
-rw-r--r--code/fm/keys.rb47
-rw-r--r--code/runcontext.rb130
-rw-r--r--data/apps.rb58
-rw-r--r--data/types.rb35
-rwxr-xr-xranger.rb6
10 files changed, 336 insertions, 92 deletions
diff --git a/code/action.rb b/code/action.rb
index e463e852..34a07242 100644
--- a/code/action.rb
+++ b/code/action.rb
@@ -1,44 +1,54 @@
 module Action
-	def self.copy(files, path)
+	extend self
+
+	def close_interface
+		closei
+	end
+
+	def start_interface
+		starti
+	end
+
+	def copy(files, path)
 		files = [files] unless files.is_a? Array
 		unless files.empty?
 			CopyBar2.new(files, path)
 		end
 	end
 
-	def self.move(files, path)
+	def move(files, path)
 		files = [files] unless files.is_a? Array
 		unless files.empty?
 			MoveBar2.new(files, path)
 		end
 	end
 
-	def self.run(hash = {})
-		unless OpenStruct === hash
-			hash = OpenStruct.new(hash)
-		end
+	def run(rc = nil)
+		rc ||= RunContext.new(Fm.getfiles)
+		assert rc, RunContext
 
 		cf       = Fm.currentfile
 		
-		all      = hash.all.or true
-		files    = hash.files.or(all ? Fm.selection : [cf])
-		mode     = hash.mode.or 0
-		newway   = hash.newway.or false
+		all      = rc.all.or true
+		files    = rc.files.or(all ? Fm.selection : [cf])
+		mode     = rc.mode.or 0
+		newway   = rc.newway.or false
 
 		return false if files.nil?
 
 		if newway
-			hash = Fm.filehandler(files, hash)
-			handler = hash.exec
+#			logpp files.first.handler
+#			rc = Fm.filehandler(files, struct)
+			handler = rc.exec
 		else
 			handler, wait = Fm.getfilehandler(*files)
 		end
 
 		return false unless handler
 
-		wait     = hash.wait.or wait
-		new_term = hash.new_term.or false
-		detach   = hash.detach.or false
+		wait     = rc.wait.or wait
+		new_term = rc.new_term.or false
+		detach   = rc.detach.or false
 
 		log handler
 		if detach
@@ -49,7 +59,7 @@ module Action
 		return true
 	end
 
-	def self.run_detached(what, new_term)
+	def run_detached(what, new_term)
 		if new_term
 			p = fork { exec('x-terminal-emulator', '-e', 'bash', '-c', what) }
 #			Process.detach(p)
@@ -59,11 +69,16 @@ module Action
 		end
 	end
 
-	def self.run_inside(what, wait)
-		closei
+	def run_inside(what, wait)
+		close_interface
 		system(*what)
-		gets if wait
-		starti
+		wait_for_enter if wait
+		start_interface
+	end
+
+	def wait_for_enter
+		print "Press [ENTER] to continue..."
+		gets
 	end
 end
 
diff --git a/code/application.rb b/code/application.rb
new file mode 100644
index 00000000..f2397d30
--- /dev/null
+++ b/code/application.rb
@@ -0,0 +1,9 @@
+module Application
+	## to be extended by data/apps.rb
+	extend self
+	def self.method_missing(*_) end
+	def check(rc)
+		assert rc, RunContext
+	end
+end
+
diff --git a/code/entry.rb b/code/entry.rb
index f2871847..bc0d2d7b 100644
--- a/code/entry.rb
+++ b/code/entry.rb
@@ -5,8 +5,17 @@ class Directory::Entry
 	# to call File methods all the time
 
 	BAD_TIME = Time.at(0)
-	MOVIE_EXTENSIONS = %w(avi mpg mpeg mp4 mp5 ogv ogm wmv mkv flv fid vob div divx)
+	MIMETYPES = Marshal.load(File.read(
+		File.join(MYDIR, 'data', 'mime.dat')))
+
 	
+	## wrapper
+	def use() Use end
+	module Use
+		def self.method_missing(app,*_) throw(:use, app) end
+		def self.no_handler()           throw(:use, nil) end
+	end
+
 	def initialize(dirname, basename=nil)
 		if basename
 			@path = File.join(dirname, basename)
@@ -27,6 +36,7 @@ class Directory::Entry
 		@symlink = false
 		@writable = false
 		@infostring = ''
+		@mimetype = nil
 		@executable = false
 		@type = :nonexistent
 		@mtime = BAD_TIME
@@ -35,7 +45,7 @@ class Directory::Entry
 	end
 
 	attr_reader(*%w{
-		basename mtime rights type path ext
+		basename mtime rights type path ext mimetype
 		infostring readlink basename size ctime name
 	})
 
@@ -45,17 +55,18 @@ class Directory::Entry
 	def exists?() @exists end
 	def marked?() @marked end
 	def symlink?() @symlink end
+	def socket?() @type == :socket 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]
+
+	def handler()
+		## get_handler has to be defined in another file
+		@handler = catch(:use) do
+			get_handler
 		end
 	end
 
@@ -109,6 +120,7 @@ class Directory::Entry
 				@type = :socket
 			else
 				@type = :file
+				@mimetype = MIMETYPES[@ext]
 				@size = File.size(@path)
 				if File.size?(@path)
 					@infostring << " #{File.size(@path).bytes 2}"
diff --git a/code/extensions/basic.rb b/code/extensions/basic.rb
index 1bc67519..1e890a04 100644
--- a/code/extensions/basic.rb
+++ b/code/extensions/basic.rb
@@ -8,6 +8,7 @@ class MutableNumber
 	end
 	def add(n=1) @value += n end
 	def sub(n=1) @value -= n end
+	def set(n)   @value  = n end
 end
 
 class Array
@@ -15,6 +16,10 @@ class Array
 		# TODO: this can be done better...
 		n.times { push shift }
 	end
+	def cdr(n = 1)
+		self[n .. -1]
+	end
+	alias car first
 end
 
 class String
@@ -65,6 +70,14 @@ class String
 		res.gsub!("\000", '\\\\')
 		return res
 	end
+
+	## encodes a string for the shell.
+	##   peter's song.mp3 -> 'peter'\''s song.mp3'
+	##
+	##   system("mplayer #{ ~some_video_file }")
+	def ~
+		"'#{ gsub("'", "'\\\\''") }'"
+	end
 end
 
 class Numeric
diff --git a/code/fm/fm.rb b/code/fm/fm.rb
index 5033c161..91b17f2d 100644
--- a/code/fm/fm.rb
+++ b/code/fm/fm.rb
@@ -1,3 +1,5 @@
+require 'thread'
+
 OPTIONS = {
 	'hidden' => false,
 	'sort' => :name,
@@ -18,6 +20,8 @@ module Fm
 	def self.initialize(pwd=nil)
 		@bars = []
 		@bars_thread = nil
+
+		@entering_directory = true
 		
 		@buffer = ''
 		@pwd = nil
@@ -27,33 +31,28 @@ module Fm
 		@trash = File.expand_path('~/.trash')
 		pwd ||= Dir.getwd
 
-		# `' and `` are the original PWD unless overwritten by .fmrc
+		# `' and `` are the original PWD unless overwritten by .rangerrc
 		@memory = {
 			'`' => pwd,
 			'\'' => pwd
 		}
 
-		# Read the .fmrc
-		@fmrc = File.expand_path('~/.fmrc')
-		if (File.exists?(@fmrc))
-			loaded = Marshal.load(File.read(@fmrc)) rescue nil
-			if Hash === loaded
-				@memory.update(loaded)
+		# Read the .rangerrc
+		@rangerrc = File.expand_path('~/.rangerrc')
+		if (File.exists?(@rangerrc))
+			content = File.read(@rangerrc)
+			unless content.empty?
+				loaded = Marshal.load() rescue nil
+				if Hash === loaded
+					@memory.update(loaded)
+				end
 			end
 		end
+		@dump_config_on_exit = true
 
 		# `0 is always the original PWD
 		@memory['0'] = pwd
 
-		# Give me some way to redraw screen while waiting for
-		# input from CLI.geti
-
-#		for i in 1..20
-#			eval "Signal.trap(#{i}) do
-#				log #{i}
-#				exit if #{i} == 9 end"
-#		end
-
 		boot_up(pwd)
 	end
 
@@ -90,10 +89,15 @@ module Fm
 	end
 
 	def dump
-		remember_dir
-		dumped = Marshal.dump(@memory)
-		File.open(@fmrc, 'w') do |f|
-			f.write(dumped)
+		if defined? @dump_config_on_exit
+			begin
+				remember_dir
+				dumped = Marshal.dump(@memory)
+				File.open(@rangerrc, 'w') do |f|
+					f.write(dumped)
+				end
+			rescue Exception
+			end
 		end
 	end
 
@@ -198,6 +202,7 @@ module Fm
 			end
 		end
 
+		@entering_directory = true
 		Dir.chdir(@pwd.path)
 	end
 
@@ -270,5 +275,9 @@ module Fm
 			@bars_thread = nil
 		end
 	end
+
+	def getfiles()
+		@marked.empty? ? [currentfile] : @marked
+	end
 end
 
diff --git a/code/fm/keys.rb b/code/fm/keys.rb
index c7abea17..4e3af766 100644
--- a/code/fm/keys.rb
+++ b/code/fm/keys.rb
@@ -305,7 +305,7 @@ module Fm
 				if $3 == '<cr>'
 					closei
 					system("bash", "-c", $2)
-					gets unless $1.empty?
+					Action.wait_for_enter unless $1.empty?
 					starti
 					@pwd.schedule
 				end
@@ -522,47 +522,8 @@ module Fm
 		# w = wait for <enter> after execution
 		# capital letter inverts
 		when /^[ri](\d*)([adetw]*)[ri]$/
-			if $2.empty?
-				f = @marked.empty?? currentfile : @marked.first
-				flags = get_default_flags(f)
-			else
-				flags = $2
-			end
-			opt = OpenStruct.new
-			opt.newway = true
-
-			opt.mode = $1.to_i unless $1.empty?
-
-			# Set options based on flags
-			
-			if flags =~ /a/
-				opt.all = true
-			end
-			if flags =~ /[de]/
-				opt.detach = true
-			end
-			if flags =~ /t/
-				opt.new_term = true
-				opt.detach = true
-			end
-			if flags =~ /w/
-				opt.wait = true
-			end
-
-			if flags =~ /A/
-				opt.all = false
-			end
-			if flags =~ /[DE]/
-				opt.detach = false
-			end
-			if flags =~ /T/
-				opt.new_term = false
-			end
-			if flags =~ /W/
-				opt.wait = false
-			end
-
-			Action.run(opt.__table__)
+			run_context = RunContext.new(getfiles, $1, $2)
+			Action.run(run_context)
 		
 #		when 'ra'
 #			unless File.directory?(currentfile.path)
@@ -598,7 +559,7 @@ module Fm
 			cf = currentfile
 			enter = enter_dir_safely(cf.path)
 			unless enter
-				return Action.run(:detach=>false)
+				return Action.run(RunContext.new(getfiles))
 			end
 			return false
 		end
diff --git a/code/runcontext.rb b/code/runcontext.rb
new file mode 100644
index 00000000..3d9ff457
--- /dev/null
+++ b/code/runcontext.rb
@@ -0,0 +1,130 @@
+class RunContext
+	## accessors {{{
+	attr_accessor( *%w[
+		all detach wait new_term
+		files handlers paths
+		mode
+		exec
+		multi
+	])
+	attr_reader( :flags )
+	def flags=(x)
+		assert x, Array, String
+
+		if x.is_a? Array
+			@flagstring = x.join('')
+			@flags = x
+		elsif x.is_a? String
+			@flagstring = x
+			@flags = x.split(//)
+		end
+
+		parse_flags
+		return x
+	end
+	## }}}
+
+	def initialize(files, mode=0, flags='')
+		@mode = mode.to_i
+		@files = files.dup
+		self.flags = flags
+		
+		@files.reject! {|file|
+			file.handler == nil or !file.exists?
+		}
+		@handlers = @files.map {|file| file.handler}
+		@paths = @files.map {|file| file.path}
+		@handler = @handlers.first
+
+		@multi = (@files.size > 1 and @handlers.uniq.size == 1)
+
+		@exec = Application.send(@handler, self)
+	end
+
+	def has_flag? x
+		if x.is_a? Regexp
+			@flagstring =~ x
+		elsif x.is_a? String
+			@flags.include? x
+		else
+			false
+		end
+	end
+
+	def parse_flags
+		@all = @detach = @new_term = @wait = false
+
+		## Positive flags
+		if has_flag? 'a'
+			@all = true
+		end
+		if has_flag? /[de]/
+			@detach = true
+		end
+		if has_flag? 't'
+			@new_term = true
+			@detach = true
+		end
+		if has_flag? 'w'
+			@wait = true
+		end
+
+		## Negative flags
+		if has_flag? 'A'
+			@all = false
+		end
+		if has_flag? /[DE]/
+			@detach = false
+		end
+		if has_flag? 'T'
+			@new_term = false
+		end
+		if has_flag? 'W'
+			@wait = false
+		end
+	end
+
+	def newway() true end
+
+	def no_mode?()
+		@mode == 0
+	end
+
+	def no_flags?()
+		@flagstring.empty?
+	end
+
+	def default_flags=(x)
+		if @flagstring.empty?
+			self.flags = x
+		end
+		x
+	end
+
+	## set the mode and return self.
+	def with_mode(n)
+		@mode = n
+		self
+	end
+
+	## wrapper {{{
+
+	## escape all files for direct use in the shell.
+	## if the _multi_ attribute is true, this is a shortcut for
+	##   rc.paths.map {|x| ~x}.join(' ')
+	## otherwise:
+	##   ~(rc.paths.first)
+	def ~() @paths.map {|x| ~x}.join(' ') end
+
+	## shortcut for _files.size_
+	def size() @files.size end
+
+	## shortcut for _files.first.path_
+	def first() @files.first.path end
+
+	## shortcut for _files.first.name_
+	def name() @files.first.name end
+
+	## }}}
+end
+
diff --git a/data/apps.rb b/data/apps.rb
new file mode 100644
index 00000000..6ba7f44b
--- /dev/null
+++ b/data/apps.rb
@@ -0,0 +1,58 @@
+module Application
+	def mplayer(rc)
+		check rc
+
+		rc.default_flags = 'd'
+
+		if rc.no_mode?
+			rc.mode = (rc.name =~ /720p/) ? 2 : 1
+		end
+
+		case rc.mode
+		when 1; "mplayer -fs -sid 0 #{~rc}"
+		when 2; "mplayer -sid 0 #{~rc}"
+		when 3; "mplayer -vm sdl -sid 0 #{~rc}"
+		else nil end
+	end
+
+	def evince(rc)
+		check rc
+		"evince #{~rc}"
+	end
+
+	def feh(rc)
+		check rc
+		case rc.mode
+		when 4; "feh --bg-scale #{~rc.first}"
+		when 5; "feh --bg-tile #{~rc.first}"
+		when 6; "feh --bg-center #{~rc.first}"
+		when 2; "gimp #{~rc}"
+		when 1; "feh -F #{~rc}"
+		else "feh #{~rc}"
+		end
+	end
+
+	def interpreted_language(rc)
+		check rc
+		case rc.mode
+		when 1; "./#{~rc.first}"
+		when 0; vi(rc)
+		else nil end
+	end
+
+	def zsnes(rc)
+		check rc
+		"zsnes #{~rc.first}"
+	end
+
+	def vi(rc)
+		commands = [
+			'map h :quit<cr>',
+			'map q h',
+			'map H :unmap h<CR>:unmap H<CR>:unmap q<CR>',
+		].map {|x| "+'#{x}'"}.join(' ')
+
+		"vi #{commands} #{~rc}"
+	end
+end
+
diff --git a/data/types.rb b/data/types.rb
new file mode 100644
index 00000000..773df758
--- /dev/null
+++ b/data/types.rb
@@ -0,0 +1,35 @@
+class Directory::Entry
+	INTERPRETED_LANGUAGES = %w[haskell perl python ruby sh]
+	MOVIE_EXTENSIONS = %w[avi mpg mpeg mp4 mp5 ogv ogm wmv mkv flv fid vob div divx]
+
+	def get_handler
+		## directories or sockets don't have any handler
+		use.no_handler if dir? or socket?
+
+		## at first, look at the mime type
+		case @mimetype
+		when /^video|audio/
+			use.mplayer
+
+		when "application/pdf"
+			use.evince
+
+		when /^image/
+			use.feh
+
+		when /^(text|application).x-(#{INTERPRETED_LANGUAGES.join('|')})$/
+			use.interpreted_language
+
+		end
+
+		## second, look at the extension
+		case @ext
+		when 'swc', 'smc'
+			use.zsnes
+
+		end
+
+		use.vi
+	end
+end
+
diff --git a/ranger.rb b/ranger.rb
index 472f02ae..6f3f3aa2 100755
--- a/ranger.rb
+++ b/ranger.rb
@@ -34,8 +34,10 @@ for file in Dir.glob "#{MYDIR}/code/**/*.rb"
 	require file [MYDIR.size + 1 ... -3]
 end
 
+load 'data/types.rb'
+load 'data/apps.rb'
 load 'data/colorscheme/default.rb'
-require 'data/screensaver/clock.rb'
+load 'data/screensaver/clock.rb'
 
 unless ARGV.empty? or File.directory?(pwd)
 	exec(Fm.getfilehandler_frompath(pwd))
@@ -61,7 +63,7 @@ ensure
 	log "exiting!"
 	log ""
 	closei if CLI.running?
-#	Fm.dump
+	Fm.dump
 	ERROR_STREAM.close
 
 	# Kill all other threads