summary refs log blame commit diff stats
path: root/ranger/gui/widgets/console.py
blob: e9356613df1daa7d5140aaee90ed3b9c1d417ce2 (plain) (tree)
1
2
3
4
5
6
7

                                                                
                    
             
                      
 
                      





                            
                                
                                                        
                                          
                                                
                                                                                
                            


                       



                                     
                                                                        


                           
                                                                                   



                             
                                                 



                                                          
                                                        
                           





                                                      
                            
                                        








                                             
                             
                                                  

                    
                                                                  
                                
                                            




                                                        
                                 
                                    


























                                                                                     








                                                                        

                              

                                                     




                                                                
                          
                          



                              
 


                              
 


                                   
 



                             
                         
                                   





                                                                             
 

                           







                                                                                                      
 
                                





                                                                 
                              
 
                          
                                         
                                                             
                                     
                                                      


                                              
                                     
 













                                                                
 

                                   
 






























































                                                                 
 
 







                                         
"""The Console widget implements a vim-like console for entering
commands, searching and executing files."""
from . import Widget
import curses
from ranger import log

class Console(Widget):
	mode = None
	visible = False
	commandlist = None
	last_cursor_mode = 1
	prompt = ':'

	def __init__(self, win):
		from ranger.container import CommandList
		Widget.__init__(self, win)
		self.commandlist = CommandList()
		self.settings.keys.initialize_console_commands(self.commandlist)
		self.clear()
	
	def init(self):
		pass

	def draw(self):
		if self.mode is None:
			return
		self.win.addstr(self.y, self.x, self.prompt + self.line)

	def finalize(self):
		try:
			self.win.move(self.y, self.x + self.pos + len(self.prompt))
		except:
			pass

	def open(self, mode):
		if mode not in self.mode_classes:
			return False

		self.last_cursor_mode = curses.curs_set(1)
		self.mode = mode
		self.__class__ = self.mode_classes[mode]
		self.init()
		self.focused = True
		self.visible = True
		return True

	def close(self):
		curses.curs_set(self.last_cursor_mode)
		self.clear()
		self.__class__ = Console
		self.focused = False
		self.visible = False
		if hasattr(self, 'on_close'):
			self.on_close()
	
	def clear(self):
		self.pos = 0
		self.line = ''
	
	def press(self, key):
		from curses.ascii import ctrl, ESC

		try:
			cmd = self.commandlist[self.env.keybuffer]
		except KeyError:
			self.env.key_clear()
			return

		if cmd == self.commandlist.dummy_object:
			return

		cmd.execute(self)
		self.env.key_clear()

	def type_key(self, key):
		if isinstance(key, int):
			key = chr(key)

		if self.pos == len(self.line):
			self.line += key
		else:
			self.line = self.line[:self.pos] + key + self.line[self.pos:]

		self.pos += len(key)

	def move(self, relative = 0, absolute = None):
		if absolute is not None:
			if absolute < 0:
				self.pos = len(self.line) + 1 + absolute
			else:
				self.pos = absolute

		self.pos = min(max(0, self.pos + relative), len(self.line))

	def delete_rest(self, direction):
		if direction > 0:
			self.line = self.line[:self.pos]
		else:
			self.line = self.line[self.pos:]
			self.pos = 0

	def delete_word(self):
		try:
			i = self.line.rindex(' ', 0, self.pos - 1) + 1
			self.line = self.line[:i] + self.line[self.pos:]
			self.pos = len(self.line)
		except ValueError:
			self.line = ''
			self.pos = 0
	
	def delete(self, mod):
		if mod == -1 and len(self.line) == 0:
			self.close()
		pos = self.pos + mod

		self.line = self.line[0:pos] + self.line[pos+1:]
		self.move(relative = mod)

	def execute(self):
		log("aww")
		self.line = ''
		self.pos = 0
		self.close()


class CommandConsole(Console):
	prompt = ':'


class QuickCommandConsole(Console):
	prompt = '>'


class SearchConsole(Console):
	prompt = '/'
	def execute(self):
		log("yay")
		import re
		if self.fm.env.pwd:
			regexp = re.compile(self.line, re.L | re.U | re.I)
			self.fm.env.last_search = regexp
			if self.fm.env.pwd.search(regexp):
				self.fm.env.cf = self.fm.env.pwd.pointed_file
		Console.execute(self)


class OpenConsole(Console):
	prompt = '!'
#	def execute(self):
#		line = self.line
#		if line[0] == '!':
#			self.fm.execute_file(tuple(line[1:].split()) + (self.fm.env.cf.path, ))
#		else:
#			self.fm.execute_file(tuple(line.split()) + (self.fm.env.cf.path, ), flags='d')
#		Console.execute(self)


class QuickOpenConsole(Console):
	"""The QuickOpenConsole allows you to open files with
pre-defined programs and modes very quickly. By adding flags
to the command, you can specify precisely how the program is run,
ie. the d-flag will run it detached from the filemanager.
"""

	prompt = 'open with: '

	def execute(self):
		split = self.line.split()
		app, flags, mode = self._get_app_flags_mode()
		self.fm.execute_file(
				files = [self.env.cf],
				app = app,
				flags = flags,
				mode = mode )
		Console.execute(self)

	def _get_app_flags_mode(self):
		"""extracts the application, flags and mode from
a string entered into the "openwith_quick" console.
"""
		# examples:
		# "mplayer d 1" => ("mplayer", "d", 1)
		# "aunpack 4" => ("aunpack", "", 4)
		# "p" => ("", "p", 0)
		# "" => None

		app = ''
		flags = ''
		mode = 0
		split = self.line.split()

		if len(split) == 0:
			pass

		elif len(split) == 1:
			part = split[0]
			if self._is_app(part):
				app = part
			elif self._is_flags(part):
				flags = part
			elif self._is_mode(part):
				mode = part

		elif len(split) == 2:
			part0 = split[0]
			part1 = split[1]

			if self._is_app(part0):
				app = part0
				if self._is_flags(part1):
					flags = part1
				elif self._is_mode(part1):
					mode = part1
			elif self._is_flags(part0):
				flags = part0
				if self._is_mode(part1):
					mode = part1
			elif self._is_mode(part0):
				mode = part0
				if self._is_flags(part1):
					flags = part1

		elif len(split) >= 3:
			part0 = split[0]
			part1 = split[1]
			part2 = split[2]

			if self._is_app(part0):
				app = part0
				if self._is_flags(part1):
					flags = part1
					if self._is_mode(part2):
						mode = part2
				elif self._is_mode(part1):
					mode = part1
					if self._is_flags(part2):
						flags = part2
			elif self._is_flags(part0):
				flags = part0
				if self._is_mode(part1):
					mode = part1
			elif self._is_mode(part0):
				mode = part0
				if self._is_flags(part1):
					flags = part1

		return app, flags, int(mode)

	def _is_app(self, arg):
		return self.fm.apps.has(arg)

	def _is_flags(self, arg):
		from ranger.applications import ALLOWED_FLAGS
		return all(x in ALLOWED_FLAGS for x in arg)

	def _is_mode(self, arg):
		return all(x in '0123456789' for x in arg)


Console.mode_classes = {
		':': CommandConsole,
		'>': QuickCommandConsole,
		'!': OpenConsole,
		'@': QuickOpenConsole,
		'/': SearchConsole,
		'?': SearchConsole,
}