about summary refs log blame commit diff stats
path: root/code/keys.rb
blob: 96f1bafbd33e651d5a65786dd25a029e54c6ad36 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
         
                                                                         

                                                                 
                                             
                                                
                          
 

                  
                        

                             
                              
                                        
                                        
                                        


                                            




                                                                    





                                               
                                                          
                            
                                                  
                           

                                    


                                      
 
                            



                               


                                       
                                   

                                                                          
                                   
                                      
                                     

                              
                             
                                                                     


                                
                                                   
                                
                                                  
                                
                                                   
                                
                                                   
                                
                                                    
                                
                                                    


                                     






                                                                                         





                                                            
                                                           
 
                               
                                         


                                    
                                         
                                   

                        




                                                         
 


                                                       



                                                         

                                                             
                                   







































                                                             
 


                                                          

                                
                                                             
















                                                                    
                                                             








                                                                    
                                                         




                                                           
                                                     

                                   
 











                                                           

                                    
 




                                                                                  














                                                                         
 
                                  


                                                             






                                                                         
 

                                         


                                             

                           


























                                                                   
 






































                                                                                                    

                               
                         


                                    



















                                           



                                         



                                             


                                         

                      


                                                
                                
                                     
 


                                     

                                               
 




                                           
 




                                                                  
                                                                               

                           








                                                            


















                                                                      



























                                                                              
                                                

                                                                      





                                                                           













                                                           
                
                                                 
                            
 



                                         


                                  










































                                                           

                   
                                                                          
           
        
                                                
                                      








                                                                             
                                                                           
                           
                                    
                   


                        
                                      



                                                                       
























































































                                                                             
   
 
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 seriouslyd y c Z delet cu
		ter ta S ?? ?g ?f ?m ?l ?c ?o ?z
		o m ` ' go

		um

		/:[^<]*/
		/[fF/!].*/
		/r\d*\w*[^r]/
		/(cw|cd|mv).*/
		/b(l(o(c(k(.*)?)?)?)?)?/
		/m(k(d(i(r(.*)?)?)?)?)?/
		/t(o(u(c(h(.*)?)?)?)?)?/
		/r(e(n(a(m(e(.*)?)?)?)?)?)?/
	)

	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 's'
			closei
			system('clear')
			ls = ['ls']
			ls << '--color=auto' #if Option.color
			ls << '--group-directories-first' #if Option.color
			system(*ls)
			system('bash')
			@pwd.schedule
			starti

		when /^S(.)$/
			Option.sort_reverse = $1.ord.between?(65, 90)

			case $1
			when 'n'
				Option.sort = :name
			when 'e'
				Option.sort = :ext
			when 't'
				Option.sort = :type
			when 's'
				Option.sort = :size
			when 'm'
				Option.sort = :mtime
			when 'c'
				Option.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 'x'
			@bars.first.kill unless @bars.empty?

		when 'X'
			@bars.last.kill unless @bars.empty?

		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 /^F(.+)$/
			str = $1
			if str =~ /^\s?(.*)(<cr>|<esc>)$/
				if $2 == '<cr>'
					Directory.filter = $1
					@pwd.refresh!
				end
				@buffer.clear
#			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 /^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 /^touch(.*)$/
			str = $1
			if str =~ /^\s?(.*)(<cr>|<esc>)$/
				@buffer = ''
				if $2 == '<cr>'
#					closei
					system('touch', $1)
#					starti
					@pwd.schedule
				end
			end

		when /^block.*stop$/
			@buffer = ''

		when 'P'
			for f in @copy
				File.symlink(f.path, File.expand_path(f.basename))
			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

		## Destructive {{{

		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 'seriouslydd'
			cf = currrentfile
			if cf and cf.exists?
				cf.delete!
				@pwd.schedule
			end

		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 /^o(.)$/
			if @memory[$1]
				Action.move(selection, @memory[$1])
			end
			@pwd.refresh!

		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

		## }}}

		## Movement {{{

		## gX {{{
		when 'gg'
			@pwd.pos = 0

		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 'gn'
			remember_dir
			enter_dir('/mnt')

		when 'gt'
			remember_dir
			enter_dir('~/.trash')

		when 'gs'
			remember_dir
			enter_dir('/srv')
		## }}}

		when 'G'
			@pwd.pos = @pwd.size - 1

		when 'k', '<up>'
			@pwd.pos -= 1

		when 'j', '<down>'
			@pwd.pos += 1

		when '<bs>', 'h', 'H', '<left>'
			descend

		when 'J'
			@pwd.pos += lines/2

		when 'K'
			@pwd.pos -= lines/2

		when '<cr>', 'l', 'L', '<right>'
			if currentfile.dir?
				enter_dir_safely(currentfile.path)
			else
				mode = @buffer == 'L' ? 1 : 0
				Action.run(RunContext.new(getfiles, mode, 'a'))
			end

		when /^cd(.+)$/
			str = $1
			if str =~ /^\s?(.*)(<cr>|<esc>)$/
				@buffer = ''
				if $2 == '<cr>'
					remember_dir
					enter_dir_safely($1)
				end
			end

		when /^(?:`|'|go)(.)$/
			if dir = @memory[$1] and not @pwd.path == dir
				remember_dir
				enter_dir_safely(dir)
			end

		when '<tab>'
			if dir = @memory['`'] and not @pwd.path == dir
				remember_dir
				enter_dir_safely(dir)
			end

		when /^m(.)$/
			@memory[$1] = @pwd.path

		when /^um(.)$/
			@memory.delete($1)

		## }}}

		## Launching applications {{{
			
		when /^!(.+)$/
			str = $1
			if str =~ /^(\!?)(.*)(<cr>|<esc>)$/
				@buffer = ''
				if $3 == '<cr>'
					closei
					system("bash", "-c", $2)
					Action.wait_for_enter unless $1.empty?
					starti
					@pwd.schedule
				end
			end

		when 'term'
			fork do exec 'x-terminal-emulator' end

		when 'E'
			cf = currentfile.path
			unless cf.nil? or enter_dir_safely(cf)
				closei
				system VI % cf
				starti
			end

		when /^[ri](\d*)([adetw]*)[ri]$/
			run_context = RunContext.new(getfiles, $1, $2)
			Action.run(run_context)

		when "-", "="
			val = "2#{key=='-' ? '-' : '+'}"
			system("amixer", "-q", "set", "PCM", val, "unmute")

		## }}}

		## Control {{{

		when ' '
			if currentfile.marked
				@marked.delete(currentfile)
				currentfile.marked = false
			else
				@marked << currentfile
				currentfile.marked = true
			end

			@pwd.pos += 1

		
		when 'ZZ', '<c-d>', ':q<cr>', 'Q'
			exit

		when 'ZX'
			Option.cd ^= true
			exit

		when '<c-r>'
			Fm.boot_up

		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 = []

		## }}}

		## Options {{{

		when 'tw'
			Option.wide_bar ^= true

		when 'tp'
			Option.preview ^= true

		when 'tf'
			Option.file_preview ^= true

		when 'th'
			Option.show_hidden ^= true
			@pwd.refresh!

		when 'tc'
			Option.cd ^= true

		when 'td'
			Option.dir_first ^= true
			@pwd.schedule

		## }}}

		end

		@buffer = '' unless @buffer == '' or @buffer =~ key_regexp
	end
	
	def self.ascend(wait = false, all=false)
		Directory.filter = nil
		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(RunContext.new(getfiles))
			end
			return false
		end
	end

	def self.descend
		Directory.filter = nil
		unless @path.size == 1
			enter_dir(@buffer=='H' ? '..' : @path[-2].path)
		end
	end

	def ignore_keys_for(t)
		@ignore_until = Time.now + t
	end

	def 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 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 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 key_regexp
		return @@key_regexp if @@key_regexp

		# Create a regular expression which detects 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
		@@key_regexp = Regexp.new('^(?:' + ary.uniq.join('|') + ')$')
	end
end