about summary refs log tree commit diff stats
path: root/code/fm
diff options
context:
space:
mode:
Diffstat (limited to 'code/fm')
-rw-r--r--code/fm/fm.rb289
-rw-r--r--code/fm/keys.rb589
-rw-r--r--code/fm/types.rb151
3 files changed, 1029 insertions, 0 deletions
diff --git a/code/fm/fm.rb b/code/fm/fm.rb
new file mode 100644
index 00000000..81b868ca
--- /dev/null
+++ b/code/fm/fm.rb
@@ -0,0 +1,289 @@
+OPTIONS = {
+	'hidden' => false,
+	'sort' => :name,
+	'dir_first' => true,
+	'sort_reverse' => false,
+	'color' => true,
+	'filepreview' => true,
+}
+
+class Void
+	oldv, $-v = $-v, nil
+
+	for method in instance_methods
+		remove_method(method) rescue nil
+	end
+
+	def self.method_missing(*a) end
+
+	$-v = oldv
+end
+
+module Fm
+	extend self
+	COPY_PRIORITY = -2
+
+	COLUMNS = 4
+	VI = "vi -c 'map h :quit<CR>' -c 'map q :quit<CR>'" <<
+		" -c 'map H :unmap h<CR>:unmap H<CR>' %s"
+	
+	def self.initialize(pwd=nil)
+		@bars = []
+		@bars_thread = nil
+		
+		@buffer = ''
+		@pwd = nil
+		@search_string = ''
+		@copy = []
+		@ignore_until = nil
+		@trash = File.expand_path('~/.trash')
+		pwd ||= Dir.getwd
+
+		# `' and `` are the original PWD unless overwritten by .fmrc
+		@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)
+			end
+		end
+
+		# `0 is always the original PWD
+		@memory['0'] = pwd
+
+		# Give me some way to redraw screen while waiting for
+		# input from Interface.geti
+
+#		for i in 1..20
+#			eval "Signal.trap(#{i}) do
+#				log #{i}
+#				exit if #{i} == 9 end"
+#		end
+
+		boot_up(pwd)
+	end
+
+	attr_reader(:dirs, :pwd)
+
+	def pwd() @pwd end
+
+	def refresh()
+		begin
+			@pwd.refresh
+			draw
+		rescue
+		end
+	end
+
+	def boot_up(pwd=nil)
+		pwd ||= @pwd.path || Dir.getwd
+		Scheduler.reset
+
+		@dirs = Hash.new() do |hash, key|
+			hash[key] = newdir = Directory.new(key)
+#			newdir.schedule
+			newdir
+		end
+
+		@path = [@dirs['/']]
+		enter_dir(pwd)
+
+		Scheduler.run
+	end
+
+	def lines
+		Interface::lines - @bars.size
+	end
+
+	def dump
+		remember_dir
+		dumped = Marshal.dump(@memory)
+		File.open(@fmrc, 'w') do |f|
+			f.write(dumped)
+		end
+	end
+
+	def on_interrupt
+		@buffer = ''
+		sleep 0.2
+	end
+
+	def main_loop
+		bool = false
+		while true
+			if @pwd.size == 0 or @pwd.pos < 0
+				@pwd.pos = 0
+			elsif @pwd.pos >= @pwd.size - 1
+				@pwd.pos = @pwd.size - 1
+			end
+
+			begin
+				log "drawing"
+				draw()
+			rescue Interrupt
+				on_interrupt
+#			rescue Exception
+#				log($!)
+#				log(caller)
+			end
+
+			begin
+#				unless bool
+#					bool = true
+					key = geti
+#				else
+#					key = geti
+#					key = 'j'
+#				end
+#				@mutex.synchronize {
+					press(key)
+#				}
+			rescue Interrupt
+				on_interrupt
+			end
+		end
+	end
+
+	def current_path() @pwd.path end
+
+	def reset_title() set_title("fm: #{@pwd.path}") end
+
+	def enter_dir_safely(dir)
+		dir = File.expand_path(dir)
+		if File.exists?(dir) and File.directory?(dir)
+			olddir = @pwd.path
+			begin
+				enter_dir(dir)
+				return true
+			rescue
+				log("NIGGER" * 100)
+				log($!)
+				log(caller)
+				enter_dir(olddir)
+				return false
+			end
+		end
+	end
+
+	def enter_dir(dir)
+		@pwd.restore if @pwd
+		@marked = []
+		dir = File.expand_path(dir)
+
+		oldpath = @path.dup
+
+		# NOTE: @dirs[unknown] is not nil but Directory.new(unknown)
+		@path = [@dirs['/']]
+		unless dir == '/'
+			dir.slice(0)
+			accumulated = '/'
+			for part in dir.split('/')
+				unless part.empty?
+					accumulated = File.join(accumulated, part)
+					@path << @dirs[accumulated]
+				end
+			end
+		end
+
+		@pwd = @path.last
+		@pwd.pos = @pwd.pos
+
+		@pwd.files_raw.dup.each do |x|
+			@dirs[x] if File.directory?(x)
+		end
+
+		reset_title()
+
+		if @path.size < oldpath.size
+			@pwd.pos = @pwd.files_raw.index(oldpath.last.path) || 0
+		end
+
+		i = 0
+
+		@path.each_with_index do |p, i|
+			p.schedule
+			unless i == @path.size - 1
+				p.pointed_file = @path[i+1].path
+			end
+		end
+
+		Dir.chdir(@pwd.path)
+	end
+
+	def currentfile() @pwd.files[@pwd.pos] end
+	def selection()
+		if @marked.empty?
+			[currentfile]
+		else
+			@marked.dup
+		end
+	end
+
+	def move_to_trash!(fn)
+		unless File.exists?(@trash)
+			Dir.mkdir(@trash)
+		end
+		new_path = File.join(@trash, fn.basename)
+
+		Action.move(fn, new_path)
+
+		return new_path
+	end
+
+	def move_to_trash(file)
+		unless file
+			return
+		end
+
+		if String === file
+			file = Directory::Entry.new(file)
+		end
+
+		if file.exists?
+			if file.dir?
+				if !file.in?(@trash) and file.size > 0
+					return move_to_trash!(file)
+				else
+					Dir.rmdir(file.path) rescue nil
+				end
+			elsif file.symlink?
+				file.delete!
+			else
+				if !file.in?(@trash) and file.size > 0
+					return move_to_trash!(file)
+				else
+					file.delete!
+				end
+			end
+		end
+		return nil
+	end
+
+	def bar_add(bar)
+		if @bars.empty?
+			# This thread updates the statusbars
+			@bars_thread = Thread.new do
+				while true
+					draw_bars
+					sleep 0.5
+				end
+			end
+		end
+		@bars << bar
+	end
+
+	def bar_del(bar)
+		@bars.delete(bar)
+		if @bars.empty?
+			@bars_thread.kill
+			@bars_thread = nil
+		end
+	end
+end
+
diff --git a/code/fm/keys.rb b/code/fm/keys.rb
new file mode 100644
index 00000000..bca4f4cd
--- /dev/null
+++ b/code/fm/keys.rb
@@ -0,0 +1,589 @@
+module Fm
+	# ALL combinations of multiple keys (but without the last letter)
+	# or regexps which match combinations need to be in here!
+	COMBS = %w(
+		g d df y c Z delet cu
+		ter ta S ? ?g ?f :q
+
+		/[m`']/ /[fF/!].*/
+		/[ri]\d*\w*[^ri]/
+		/(cw|cd|mv).*/
+		/b(l(o(c(k(.*)?)?)?)?)?/
+		/m(k(d(i(r(.*)?)?)?)?)?/
+		/r(e(n(a(m(e(.*)?)?)?)?)?)?/
+	)
+
+	# Create a regular expression which detects these combos
+	ary = []
+	for token in COMBS
+		if token =~ /^\/(.*)\/$/
+			ary << $1
+		elsif token.size > 0
+			ary << token.each_char.map {|t|
+				if t == '?'
+					t = '\?'
+				end
+
+				"(?:#{t}"
+			}.join +
+				(')?' * (token.size - 1)) + ')'
+		end
+	end
+	REGX = Regexp.new('^(?:' + ary.uniq.join('|') + ')$')
+
+	def self.ignore_keys_for(t)
+		@ignore_until = Time.now + t
+	end
+
+	def self.search(str, offset=0, backwards=false)
+		begin
+			rx = Regexp.new(str, Regexp::IGNORECASE)
+		rescue
+			return false
+		end
+
+		ary = @pwd.files_raw.dup
+		ary.wrap(@pwd.pos + offset)
+
+		ary.reverse! if backwards
+
+		for f in ary
+			g = File.basename(f)
+			if g =~ rx
+				@pwd.pointed_file = f
+				break
+			end
+		end
+	end
+
+	def self.find_newest()
+		newest = nil
+		for f in @pwd.files
+			if newest.nil? or newest.ctime < f.ctime
+				newest = f
+			end
+		end
+		@pwd.pointed_file = newest.path
+	end
+
+	def self.hints(str)
+		begin
+			rx = Regexp.new(str, Regexp::IGNORECASE)
+		rescue
+			return false
+		end
+
+		ary = @pwd.files_raw.dup
+		ary.wrap(@pwd.pos)
+
+		n = 0
+		pointed = false
+		for f in ary
+			g = File.basename(f)
+			if g =~ rx
+				unless pointed
+					log "point at #{f}"
+					@pwd.pointed_file = f
+					pointed = true
+				end
+				n += 1
+			end
+		end
+
+		return n
+	end
+
+	def self.remember_dir
+		@memory["`"] = @memory["'"] = @pwd.path
+	end
+
+	def self.press(key)
+		return if @ignore_until and Time.now < @ignore_until
+
+		@ignore_until = nil
+
+		if key == '<bs>'
+			if @buffer.empty?
+				@buffer = key
+			elsif @buffer == 'F'
+				descend
+			elsif @buffer[-1] == ?>
+				@buffer.slice!(/(<.*)?>$/)
+			else
+				@buffer.slice!(-1)
+			end
+		elsif key == '<c-u>'
+			@buffer = ''
+		else
+			@buffer << key
+		end
+
+		case @buffer
+		when '<redraw>'
+			closei
+			starti
+
+		when 'j', '<down>'
+			@pwd.pos += 1
+
+		when 's'
+			closei
+			system('clear')
+			ls = ['ls']
+			ls << '--color=auto' if OPTIONS['color']
+			ls << '--group-directories-first' if OPTIONS['color']
+			system(*ls)
+			system('bash')
+			@pwd.schedule
+			starti
+
+
+		when /^S(.)$/
+			OPTIONS['sort_reverse'] = $1.ord.between?(65, 90)
+
+			case $1
+			when 'n'
+				OPTIONS['sort'] = :name
+			when 'e'
+				OPTIONS['sort'] = :ext
+			when 't'
+				OPTIONS['sort'] = :type
+			when 's'
+				OPTIONS['sort'] = :size
+			when 'm'
+				OPTIONS['sort'] = :mtime
+			when 'c'
+				OPTIONS['sort'] = :ctime
+			end
+			@pwd.schedule
+
+		when 'tar'
+			closei
+			system('tar', 'cvvf', 'pack.tar', *selection.map{|x| x.basename})
+			@pwd.refresh!
+			starti
+
+		when 'R'
+			@pwd.refresh!
+
+		when 'a'
+			Process.kill('INT', Process.pid)
+#			Process.kill('INT', Process.pid)
+
+		when 'x'
+			@bars.first.kill unless @bars.empty?
+
+		when 'X'
+			@bars.last.kill unless @bars.empty?
+
+		when 'J'
+			@pwd.pos += lines/2
+
+		when 'K'
+			@pwd.pos -= lines/2
+
+		when 'cp', 'yy'
+			@copy = selection
+			@cut = false
+
+		when 'cut'
+			@copy = selection
+			@cut = true
+
+		when 'n'
+			if @search_string.empty?
+				find_newest
+			else
+				search(@search_string, 1)
+			end
+
+		when 'N'
+			search(@search_string, 0, true)
+
+#		when 'fh'
+#			@buffer.clear
+#			press('h')
+
+		when /^F(.+)$/
+			str = $1
+			if str =~ /^\s?(.*)(<cr>|<esc>)$/
+				if $2 == '<cr>'
+					ascend
+					@buffer = 'F'
+				else
+					@buffer.clear
+					@search_string = $1
+				end
+			else
+				test = hints(str)
+				if test == 1
+					if ascend
+						@buffer.clear
+					else
+						@buffer = 'F'
+					end
+					ignore_keys_for 0.5
+				elsif test == 0
+					@buffer = 'F'
+					ignore_keys_for 1
+				end
+			end
+
+		when 'A'
+			@buffer = "cw #{currentfile.name}"
+
+		when /^f(.+)$/
+			str = $1
+			if str =~ /^\s?(.*)(L|;|<cr>|<esc>)$/
+				@buffer = ''
+				@search_string = $1
+				press('l') if $2 == ';' or $2 == 'L'
+			else
+				test = hints(str)
+				if test == 1
+					@buffer = ''
+					press('l')
+					ignore_keys_for 0.5
+				elsif test == 0
+					@buffer = ''
+					ignore_keys_for 1
+				end
+			end
+
+		when /^\/(.+)$/
+			str = $1
+			if str =~ /^\s?(.*)(L|;|<cr>|<esc>)$/
+				@buffer = ''
+				@search_string = $1
+				press('l') if $2 == ';' or $2 == 'L'
+			else
+				search(str)
+			end
+
+		when /^mkdir(.*)$/
+			str = $1
+			if str =~ /^\s?(.*)(<cr>|<esc>)$/
+				@buffer = ''
+				if $2 == '<cr>'
+					closei
+					system('mkdir', $1)
+					starti
+					@pwd.schedule
+				end
+			end
+
+		when /^block.*stop$/
+			@buffer = ''
+			
+		when /^!(.+)$/
+			str = $1
+			if str =~ /^(\!?)(.*)(<cr>|<esc>)$/
+				@buffer = ''
+				if $3 == '<cr>'
+					closei
+					system("bash", "-c", $2)
+					gets unless $1.empty?
+					starti
+					@pwd.schedule
+				end
+			end
+
+		when /^cd(.+)$/
+			str = $1
+			if str =~ /^\s?(.*)(<cr>|<esc>)$/
+				@buffer = ''
+				if $2 == '<cr>'
+					remember_dir
+					enter_dir_safely($1)
+				end
+			end
+
+		when /^(mv|cw|rename)(.+)$/
+			str = $2
+			if $1 == 'mv'
+				if str =~ /['`"]([\w\d])/
+					if path = @memory[$1]
+						str = ''
+						@buffer.clear
+						if File.exists?(path) and File.directory?(path)
+							Action.move(selection, path)
+						end
+					end
+				end
+			end
+			log str
+			if str =~ /^\s?(.*)(<cr>|<esc>)$/
+				@buffer = ''
+				if $2 == '<cr>'
+					files = selection
+					if files.size == 1
+						fn = $1
+						log "!!! #{fn}"
+						unless fn.include? '.'
+							if ext = files.first.basename.from_last('.')
+								fn << ".#{ext}"
+							end
+							log "??? #{ext}"
+						end
+						Action.move(files, fn)
+						@pwd.refresh!
+						@pwd.find_file(fn)
+					else
+						Action.move(files, $1)
+						@pwd.refresh!
+					end
+				end
+			end
+
+		when 'tc'
+			OPTIONS['color'] ^= true
+
+		when 'tf'
+			OPTIONS['filepreview'] ^= true
+
+		when 'th'
+			OPTIONS['hidden'] ^= true
+			@pwd.refresh!
+
+		when 'td'
+			OPTIONS['dir_first'] ^= true
+			@pwd.schedule
+
+		when 'delete'
+			files = selection
+			@marked = []
+			for f in files
+				if f and f.exists? and f.dir?
+					system('rm', '-r', f.to_s)
+					@pwd.schedule
+				end
+			end
+
+		when 'p'
+			if @cut
+				Action.move(@copy, @pwd.path)
+				@cut = false
+			else
+				Action.copy(@copy, @pwd.path)
+			end
+			@pwd.refresh!
+			if @copy.size == 1
+				@pwd.find_file(@copy[0].basename)
+			end
+
+		when /^[`'](.)$/
+			if dir = @memory[$1] and not @pwd.path == dir
+				remember_dir
+				enter_dir_safely(dir)
+			end
+
+		when '<s-tab>'
+			if dir = @memory['`'] and not @pwd.path == dir
+				remember_dir
+				enter_dir_safely(dir)
+			end
+			
+		when '<tab>'
+			if dir = @memory['9'] and dir != '/'
+				unless @pwd.path == dir
+					enter_dir_safely(dir)
+				end
+			elsif dir = @memory['`'] and not @pwd.path == dir
+				remember_dir
+				enter_dir_safely(dir)
+			end
+			
+
+		when /^m(.)$/
+			@memory[$1] = @pwd.path
+
+		when ' '
+			if currentfile.marked
+				@marked.delete(currentfile)
+				currentfile.marked = false
+			else
+				@marked << currentfile
+				currentfile.marked = true
+			end
+
+			@pwd.pos += 1
+
+		when 'v'
+			@marked = []
+			for file in @pwd.files
+				if file.marked
+					file.marked = false
+				else
+					file.marked = true
+					@marked << file
+				end
+			end
+
+		when 'V'
+			for file in @marked
+				file.marked = false
+			end
+			@marked = []
+
+
+		when 'gg'
+			@pwd.pos = 0
+
+		when 'dd'
+			new_path = move_to_trash(currentfile)
+			if new_path
+				new_path = Directory::Entry.new(new_path)
+				new_path.get_data
+				@copy = [new_path]
+				@cut = false
+			end
+			@pwd.schedule
+
+		when 'dD', 'dfd'
+			cf = currentfile
+			if cf and cf.exists?
+				cf.delete!
+				@pwd.schedule
+			end
+
+		when 'term'
+			fork do exec 'x-terminal-emulator' end
+
+		when 'g0'
+			remember_dir
+			enter_dir('/')
+
+		when 'gh'
+			remember_dir
+			enter_dir('~')
+
+		when 'gu'
+			remember_dir
+			enter_dir('/usr')
+
+		when 'ge'
+			remember_dir
+			enter_dir('/etc')
+
+		when 'gm'
+			remember_dir
+			enter_dir('/media')
+
+		when 'gt'
+			remember_dir
+			enter_dir('~/.trash')
+
+		when 'G'
+			@pwd.pos = @pwd.size - 1
+
+		when 'k', '<up>'
+			@pwd.pos -= 1
+
+		when '<bs>', 'h', 'H', '<left>'
+			descend
+
+		when 'E'
+			cf = currentfile.path
+			unless cf.nil? or enter_dir_safely(cf)
+				closei
+				system VI % cf
+				starti
+			end
+
+		when '<cr>', 'l', ';', 'L', '<right>'
+			ascend(@buffer=='L', @buffer=='l')
+
+		# a = run all
+		# d or e = detach
+		# t = run in a terminal
+		# 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__)
+		
+#		when 'ra'
+#			unless File.directory?(currentfile.path)
+#				Action.run(:all=>true)
+#			end
+
+		when 'ZZ', '<c-d>', ':q<cr>', 'Q'
+			exit
+			
+		when '<c-r>'
+			Fm.boot_up
+
+		when "-", "="
+			val = "2#{key=='-' ? '-' : '+'}"
+			system("amixer", "-q", "set", "PCM", val, "unmute")
+
+		else
+#			log key.ord
+
+		end
+
+		@buffer = '' unless @buffer == '' or @buffer =~ REGX
+	end
+	
+	def self.ascend(wait = false, all=false)
+		if all and !@marked.empty?
+			closei
+			system(*['mplayer', '-fs', *@marked.map{|x| x.path}])
+			starti
+			return true
+		else
+			cf = currentfile
+			enter = enter_dir_safely(cf.path)
+			unless enter
+				return Action.run(:detach=>false)
+			end
+			return false
+		end
+	end
+
+	def self.descend
+		unless @path.size == 1
+			enter_dir(@buffer=='H' ? '..' : @path[-2].path)
+		end
+	end
+end
+
diff --git a/code/fm/types.rb b/code/fm/types.rb
new file mode 100644
index 00000000..2c21c214
--- /dev/null
+++ b/code/fm/types.rb
@@ -0,0 +1,151 @@
+module Fm
+	MIMETYPES = Marshal.load(File.read(
+		File.join(MYDIR, 'data', 'mime.dat')))
+
+	def self.get_default_flags(file)
+		case file.mimetype
+		when /^(?:image|video)\//; 'd'
+		when 'application/pdf'; 'd'
+		else '' end
+	end
+
+	def self.filehandler(files, hash)
+		str = files.map{|x| x.sh}.join(' ')
+		type = files.first.mimetype
+		name = files.first.basename
+		mode = hash.mode
+
+		use = lambda do |sym|
+			hash.exec = App.send(sym, mode, name, str, files)
+		end
+
+		case type
+		when /^(video|audio)\//
+			use.call :mplayer
+		when "application/pdf"
+			use.call :evince
+		when /^(image)\//
+			use.call :image
+		else
+			case name
+			when /\.(swc|smc)/
+				use.call :zsnes
+			end
+		end
+
+		return hash
+	end
+
+	module App
+		def image(mode, name, str, file)
+			case mode
+			when 4; "feh --bg-scale #{str}"
+			when 5; "feh --bg-tile #{str}"
+			when 6; "feh --bg-center #{str}"
+			when 2; "gimp #{str}"
+			when 1; "feh -F #{str}"
+			else "feh #{str}"
+			end
+		end
+		def evince(mode, name, str, file)
+			"evince #{str}"
+		end
+		def mplayer(mode, name, str, files)
+			rest = name, str, files
+
+			case mode
+			when nil
+				if name =~ /720p/
+					mplayer(1, *rest)
+				else
+					mplayer(0, *rest)
+				end
+			when 0
+				return "mplayer -fs -sid 0 #{str}"
+			when 1
+				return "mplayer -vm sdl -sid 0 #{str}"
+			end
+		end
+		def zsnes(mode, name, str, files)
+			case mode
+			when 1
+				return "zsnes -ad sdl -o #{str}"
+			else
+				return "zsnes -ad sdl -u -o #{str}"
+			end
+		end
+
+		module_function(*%w{
+			mplayer zsnes evince image
+		})
+	end
+
+	def self.getfilehandler_frompath(*files)
+		file = files.first
+		n = files.size
+		case file
+		when /\.(part|avi|mpe?[g\d]|flv|fid|mkv|mov|wm[av]|vob|php|divx?|og[gmv])$/i
+			if file =~ /720p/
+				return "mplayer -vm sdl #{file.sh}", false
+			else
+				return "mplayer -fs #{file.sh}", false
+			end
+
+		when /\.java$/
+			return "javac #{file.sh}", true
+
+		when /\.class$/
+			return log "java #{file.sh.before_last('.')}"
+
+		when /\.part$/
+			test = getfilehandler_frompath($`)
+			if test
+				return test
+			end
+
+		when /\.(swc|smc)$/i
+			return "zsnes -ad sdl -u -o #{file.sh}"
+
+		when /\.(zip|rar|tar|gz|7z|jar|bz2)$/i
+			return "aunpack #{file.sh}", false
+
+		when "Makefile"
+			return "make"
+
+		when /\.(jpe?g|png|gif)$/i
+			return "feh #{file.sh}", false
+
+		when /\.(html?|swf)$/i
+			return "firefox #{file.sh}"
+
+		when /\.pdf$/i
+			return "evince #{file.sh}"
+
+		when /\.txt$/i
+			return VI % file.sh
+
+		when /\.wav$/i
+			return "aplay -q #{file.sh}"
+
+		when /\.m3u$/i
+#			return "mpc play #{File.expand_path(file)[13..-1].sh}", false
+			return "/home/hut/bin/loadplaylist.rb #{file.sh}"
+#			return "cmus-remote -c && cmus-remote -P #{file} && cmus-remote -C 'set play_library=false' && sleep 0.3 && cmus-remote -n", false
+
+		end
+
+	end
+	def self.getfilehandler(file)
+		test = getfilehandler_frompath(file.basename)
+		if test
+			return test
+		end
+
+		if file.executable?
+			return "#{file.sh}", true
+		end
+
+		return VI % file.sh
+	end
+end
+