summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/command.py6
-rw-r--r--ranger/conf/keys.py75
-rw-r--r--ranger/conf/options.py12
-rw-r--r--ranger/fm.py22
-rw-r--r--ranger/gui/defaultui.py28
-rw-r--r--ranger/gui/ui.py55
-rw-r--r--ranger/gui/wconsole.py105
-rw-r--r--ranger/gui/widget.py10
8 files changed, 246 insertions, 67 deletions
diff --git a/ranger/command.py b/ranger/command.py
index 203a0329..389f0df5 100644
--- a/ranger/command.py
+++ b/ranger/command.py
@@ -72,10 +72,10 @@ class CommandList():
 	
 class Command():
 	def __init__(self, fnc, keys):
-		self.fnc = fnc
+		self.execute = fnc
 		self.keys = keys
 		self.commandlist = None
 
-	def execute(self, fm):
-		self.fnc(fm)
+#	def execute(self, fm):
+#		self.fnc(fm)
 
diff --git a/ranger/conf/keys.py b/ranger/conf/keys.py
index f1349717..fef36b6e 100644
--- a/ranger/conf/keys.py
+++ b/ranger/conf/keys.py
@@ -10,39 +10,39 @@ def initialize_commands(cl):
 	# * an integer which represents an ascii code
 	# * a tuple of integers
 
+	def curry(fnc, *args, **keywords):
+		return lambda fm: fnc(fm, *args, **keywords)
+
 	def move(**keywords):
 		return lambda fm: fm.move_pointer(**keywords)
 
 	def move_pages(n):
 		return lambda fm: fm.move_pointer_by_pages(n)
 
+	cl.bind(FM.move_left,               'h', curses.KEY_BACKSPACE, 127)
+	cl.bind(FM.move_right,              'l', curses.KEY_ENTER, ctrl('j'))
+	cl.bind(curry(FM.history_go, -1),   'H')
+	cl.bind(curry(FM.history_go,  1),   'L')
+	cl.bind(move( relative = 1 ),       'j')
+	cl.bind(move_pages( 0.5 ),          'J')
+	cl.bind(move( relative = -1 ),      'k')
+	cl.bind(move_pages( -0.5 ),         'K')
+	cl.bind(move( absolute = 0 ),       'gg')
+	cl.bind(move( absolute = -1 ),      'G')
+	cl.bind(FM.edit_file,               'E')
+
+	# toggle options
 	def toggle_option(string):
 		return lambda fm: fm.toggle_boolean_option(string)
 
-	def cd(path):
-		return lambda fm: fm.enter_dir(path)
-
-	def history(n):
-		return lambda fm: fm.history_go(n)
-
-	cl.bind(FM.move_left,           'h', curses.KEY_BACKSPACE, 127)
-	cl.bind(FM.move_right,          'l', curses.KEY_ENTER, ctrl('j'))
-	cl.bind(history(-1),            'H')
-	cl.bind(history(1),             'L')
-	cl.bind(move( relative = 1 ),   'j')
-	cl.bind(move_pages( 0.5 ),      'J')
-	cl.bind(move( relative = -1 ),  'k')
-	cl.bind(move_pages( -0.5 ),     'K')
-	cl.bind(move( absolute = 0 ),   'gg')
-	cl.bind(move( absolute = -1 ),  'G')
-	cl.bind(FM.edit_file,           'E')
-
-	# toggle options
 	cl.bind(toggle_option('show_hidden'),       'th')
 	cl.bind(toggle_option('preview_files'),     'tp')
 	cl.bind(toggle_option('directories_first'), 'td')
 
 	# key combinations which change the current directory
+	def cd(path):
+		return lambda fm: fm.enter_dir(path)
+
 	cl.bind(cd("~"),          'gh')
 	cl.bind(cd("/etc"),       'ge')
 	cl.bind(cd("/usr"),       'gu')
@@ -56,8 +56,45 @@ def initialize_commands(cl):
 	cl.bind(FM.exit,         ctrl('D'), 'q', 'ZZ')
 	cl.bind(FM.reset,        ctrl('R'))
 	cl.bind(FM.redraw,       ctrl('L'))
+	cl.bind(FM.interrupt,    ctrl('C'))
 	cl.bind(FM.resize,       curses.KEY_RESIZE)
 	cl.bind(FM.handle_mouse, curses.KEY_MOUSE)
+	cl.bind(curry(FM.open_console, ':'), ':')
 
 	cl.rebuild_paths()
 
+
+def initialize_console_commands(cl):
+	from ranger.fm import FM
+	from ranger.gui.wconsole import WConsole
+	from curses.ascii import ctrl, ESC
+	import curses
+
+	def type_key(key):
+		return lambda con, fm: con.type_key(key)
+
+	def curry(fnc, *args, **keywords):
+		return lambda con, fm: fnc(con, *args, **keywords)
+
+	def curry_fm(fnc, *args, **keywords):
+		return lambda con, fm: fnc(fm, *args, **keywords)
+
+	# movement
+	cl.bind(curry(WConsole.move, relative = -1), curses.KEY_LEFT, ctrl('b'))
+	cl.bind(curry(WConsole.move, relative =  1), curses.KEY_RIGHT, ctrl('f'))
+	cl.bind(curry(WConsole.move, absolute = 0), curses.KEY_HOME, ctrl('a'))
+	cl.bind(curry(WConsole.move, absolute = -1), curses.KEY_END, ctrl('e'))
+	cl.bind(curry(WConsole.delete, 0), curses.KEY_DC, ctrl('d'))
+	cl.bind(curry(WConsole.delete, -1), curses.KEY_BACKSPACE, 127, ctrl('h'))
+	cl.bind(curry(WConsole.delete_rest, -1), ctrl('U'))
+	cl.bind(curry(WConsole.delete_rest,  1), ctrl('K'))
+
+	# system functions
+	cl.bind(curry(WConsole.close),    ESC, ctrl('C'))
+	cl.bind(curry(WConsole.execute),  curses.KEY_ENTER, ctrl('j'))
+	cl.bind(curry_fm(FM.redraw), ctrl('L'))
+	cl.bind(curry_fm(FM.resize), curses.KEY_RESIZE)
+
+	for i in range(ord(' '), ord('~')):
+		cl.bind(type_key(i), i)
+
diff --git a/ranger/conf/options.py b/ranger/conf/options.py
index e8baa60d..00d2f9f3 100644
--- a/ranger/conf/options.py
+++ b/ranger/conf/options.py
@@ -5,9 +5,9 @@ def get():
 def dummy():
 	""" provide a way of getting options until get() is implemented """
 	return {
-			'show_hidden': False,
-			'scroll_offset': 2,
-			'directories_first': True,
-			'preview_files' : False,
-			'max_history_size': 20
-			}
+		'show_hidden': False,
+		'scroll_offset': 2,
+		'directories_first': True,
+		'preview_files' : False,
+		'max_history_size': 20
+	}
diff --git a/ranger/fm.py b/ranger/fm.py
index d314fea4..05c1e262 100644
--- a/ranger/fm.py
+++ b/ranger/fm.py
@@ -7,8 +7,6 @@ class FM():
 		self.ui = ui
 
 	def run(self):
-		import time
-
 		self.env.enter_dir(self.env.path)
 
 		while 1:
@@ -17,10 +15,17 @@ class FM():
 				key = self.ui.get_next_key()
 				self.ui.press(key, self)
 			except KeyboardInterrupt:
-				self.env.key_clear()
-				time.sleep(0.2)
+				self.ui.press(3, self)
 			except:
 				raise
+	
+	def interrupt(self):
+		import time
+		self.env.key_clear()
+		try:
+			time.sleep(0.2)
+		except KeyboardInterrupt:
+			raise SystemExit()
 
 	def resize(self):
 		self.ui.resize()
@@ -64,6 +69,10 @@ class FM():
 
 		self.ui.initialize()
 
+	def open_console(self, mode = ':'):
+		if self.ui.can('open_console'):
+			self.ui.open_console(mode)
+
 	def move_pointer(self, relative = 0, absolute = None):
 		self.env.cf = self.env.pwd.move_pointer(relative, absolute)
 
@@ -72,8 +81,9 @@ class FM():
 				relative = int(relative * self.env.termsize[0]))
 
 	def scroll(self, relative):
-		self.ui.scroll(relative)
-		self.env.cf = self.env.pwd.pointed_file
+		if self.ui.can('scroll'):
+			self.ui.scroll(relative)
+			self.env.cf = self.env.pwd.pointed_file
 
 	def redraw(self):
 		self.ui.redraw()
diff --git a/ranger/gui/defaultui.py b/ranger/gui/defaultui.py
index d4d89047..547f20ff 100644
--- a/ranger/gui/defaultui.py
+++ b/ranger/gui/defaultui.py
@@ -1,11 +1,12 @@
-from ranger.gui.ui import UI as SuperClass
-from ranger.gui.wdisplay import WDisplay
-from ranger.gui.wtitlebar import WTitleBar
 
 RATIO = ( 0.15, 0.15, 0.4, 0.3 )
 
+from ranger.gui.ui import UI as SuperClass
 class DefaultUI(SuperClass):
 	def setup(self):
+		from ranger.gui.wdisplay import WDisplay
+		from ranger.gui.wtitlebar import WTitleBar
+		from ranger.gui.wconsole import WConsole
 		self.titlebar = WTitleBar(self.win, self.colorscheme)
 		self.add_widget(self.titlebar)
 
@@ -19,9 +20,9 @@ class DefaultUI(SuperClass):
 		self.displays[2].main_display = True
 		for disp in self.displays:
 			self.add_widget(disp)
-	
-	def scroll(self, relative):
-		self.main_display.scroll(relative)
+
+		self.console = WConsole(self.win, self.colorscheme)
+		self.add_widget(self.console)
 
 	def resize(self):
 		SuperClass.resize(self)
@@ -33,11 +34,24 @@ class DefaultUI(SuperClass):
 		for ratio in RATIO:
 			wid = int(ratio * x)
 			try:
-				self.displays[i].setdim(1, leftborder, y-1, wid - 1)
+				self.displays[i].setdim(1, leftborder, y-2, wid - 1)
 			except KeyError:
 				pass
 			leftborder += wid
 			i += 1
 
 		self.titlebar.setdim(0, 0, 1, x)
+		self.console.setdim(y-1, 0, 1, x)
+
+	# ---specials---
+	def open_console(self, mode):
+		if self.console.open(mode):
+			self.console.on_close = self.close_console
+			self.console.visible = True
+
+	def close_console(self):
+		self.console.visible = False
+
+	def scroll(self, relative):
+		self.main_display.scroll(relative)
 
diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py
index a04455ab..79077cbc 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -1,5 +1,22 @@
 import curses
 
+class MouseEvent():
+	import curses
+	PRESSED = [ 0,
+			curses.BUTTON1_PRESSED,
+			curses.BUTTON2_PRESSED,
+			curses.BUTTON3_PRESSED,
+			curses.BUTTON4_PRESSED ]
+
+	def __init__(self, getmouse):
+		_, self.x, self.y, _, self.bstate = getmouse
+	
+	def pressed(self, n):
+		try:
+			return (self.bstate & MouseEvent.PRESSED[n]) != 0
+		except:
+			return False
+
 class UI():
 	def __init__(self, env, commandlist, colorscheme):
 		self.env = env
@@ -15,7 +32,7 @@ class UI():
 		os.environ['ESCDELAY'] = '25'
 
 		self.win = curses.initscr()
-		self.win.leaveok(1)
+		self.win.leaveok(0)
 		self.win.keypad(1)
 
 		curses.noecho()
@@ -51,10 +68,10 @@ class UI():
 			else:
 				fm.scroll(relative = 3)
 
-	def setup(self):
-		pass
+	def can(self, attr):
+		return hasattr(self, attr)
 
-	def scroll(self, relative):
+	def setup(self):
 		pass
 
 	def resize(self):
@@ -74,8 +91,10 @@ class UI():
 	def press(self, key, fm):
 		self.env.key_append(key)
 
-#		from ranger.helper import log
-#		log(self.env.keybuffer)
+		for widg in self.widgets:
+			if widg.focused:
+				widg.press(key, fm, self.env)
+				return
 
 		try:
 			cmd = self.commandlist.paths[self.env.keybuffer]
@@ -98,28 +117,14 @@ class UI():
 		self.win.erase()
 		for widg in self.widgets:
 			widg.feed_env(self.env)
-			widg.draw()
+			if widg.visible:
+				widg.draw()
+		for widg in self.widgets:
+			if widg.visible:
+				widg.finalize()
 		self.win.refresh()
 
 	def get_next_key(self):
 		key = self.win.getch()
 		curses.flushinp()
 		return key
-
-
-class MouseEvent():
-	import curses
-	PRESSED = [ 0,
-			curses.BUTTON1_PRESSED,
-			curses.BUTTON2_PRESSED,
-			curses.BUTTON3_PRESSED,
-			curses.BUTTON4_PRESSED ]
-
-	def __init__(self, getmouse):
-		_, self.x, self.y, _, self.bstate = getmouse
-	
-	def pressed(self, n):
-		try:
-			return (self.bstate & MouseEvent.PRESSED[n]) != 0
-		except:
-			return False
diff --git a/ranger/gui/wconsole.py b/ranger/gui/wconsole.py
new file mode 100644
index 00000000..4411e83b
--- /dev/null
+++ b/ranger/gui/wconsole.py
@@ -0,0 +1,105 @@
+from ranger.gui.widget import Widget as SuperClass
+import curses
+
+CONSOLE_MODES = tuple(':/?>!')
+
+class WConsole(SuperClass):
+	def __init__(self, win, colorscheme):
+		from ranger.command import CommandList
+		from ranger.conf.keys import initialize_console_commands
+		SuperClass.__init__(self, win, colorscheme)
+		self.mode = None
+		self.visible = False
+		self.commandlist = CommandList()
+		initialize_console_commands(self.commandlist)
+		self.last_cursor_mode = 1
+		self.clear()
+
+	def draw(self):
+		if self.mode is None:
+			return
+
+		self.win.addstr(self.y, self.x, ":" + self.line)
+
+	def finalize(self):
+		try:
+			self.win.move(self.y, self.x + self.pos + 1)
+		except:
+			pass
+
+	def open(self, mode):
+		if mode not in CONSOLE_MODES:
+			return False
+
+		self.last_cursor_mode = curses.curs_set(1)
+		self.mode = mode
+		self.focused = True
+		self.visible = True
+		return True
+
+	def close(self):
+		curses.curs_set(self.last_cursor_mode)
+		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, fm, env):
+		from curses.ascii import ctrl, ESC
+		from ranger.helper import log
+		log(key)
+
+		try:
+			cmd = self.commandlist.paths[env.keybuffer]
+		except KeyError:
+			env.key_clear()
+			return
+
+		if cmd == self.commandlist.dummy_object:
+			return
+
+		cmd.execute(self, fm)
+		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(self, mod):
+		pos = self.pos + mod
+
+		self.line = self.line[0:pos] + self.line[pos+1:]
+		self.move(relative = mod)
+
+	def execute(self):
+		self.line = ''
+		self.pos = 0
+		self.close()
+
diff --git a/ranger/gui/widget.py b/ranger/gui/widget.py
index f9a0651f..fa1ca585 100644
--- a/ranger/gui/widget.py
+++ b/ranger/gui/widget.py
@@ -11,7 +11,9 @@ def combine(keylist, keys):
 class Widget():
 	def __init__(self, win, colorscheme):
 		self.win = win
+		self.focused = False
 		self.colorscheme = colorscheme
+		self.visible = True
 		self.setdim(0, 0, 0, 0)
 
 	def color(self, keylist = None, *keys):
@@ -49,7 +51,7 @@ class Widget():
 		return (x >= self.x and x < self.x + self.wid) and \
 				(y >= self.y and y < self.y + self.hei)
 
-	def feed_env(self):
+	def feed_env(self, env):
 		pass
 
 	def feed(self):
@@ -57,9 +59,15 @@ class Widget():
 
 	def click(self, event, fm):
 		pass
+
+	def press(self, key, fm):
+		pass
 	
 	def draw(self):
 		pass
 
+	def finalize(self):
+		pass
+
 	def destroy(self):
 		pass