about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2011-09-30 01:43:27 +0200
committerhut <hut@lavabit.com>2011-09-30 01:46:09 +0200
commitb1d25114617f41538f1e9e1740229f5e326c9f88 (patch)
tree5fe8b438759ea2a9a6495e57d7266a7bd36f340a
parent5e41c8479cfba986f6dad0e68aed3c1d7b51d3ae (diff)
downloadranger-b1d25114617f41538f1e9e1740229f5e326c9f88.tar.gz
define keybindings in rc.conf (list of commands, loaded on startup)
-rw-r--r--ranger/api/commands.py49
-rw-r--r--ranger/container/settingobject.py1
-rw-r--r--ranger/core/actions.py40
-rw-r--r--ranger/core/helper.py26
-rw-r--r--ranger/defaults/commands.py31
-rw-r--r--ranger/defaults/options.py4
-rw-r--r--ranger/defaults/rc.conf15
-rw-r--r--ranger/gui/ui.py3
8 files changed, 151 insertions, 18 deletions
diff --git a/ranger/api/commands.py b/ranger/api/commands.py
index 9a353eef..94b7f341 100644
--- a/ranger/api/commands.py
+++ b/ranger/api/commands.py
@@ -17,6 +17,7 @@ import os
 from collections import deque
 from ranger.api import *
 from ranger.core.shared import FileManagerAware
+from ranger.ext.lazy_property import lazy_property
 from ranger.ext.command_parser import LazyParser as parse
 
 # A dummy that allows the generation of docstrings in ranger.defaults.commands
@@ -73,8 +74,11 @@ class Command(FileManagerAware):
 	"""Abstract command class"""
 	name = None
 	allow_abbrev = True
+	_shifted = 0
+
 	def __init__(self, line):
 		self.line = line
+		self.args = line.split()
 
 	def execute(self):
 		"""Override this"""
@@ -88,6 +92,51 @@ class Command(FileManagerAware):
 	def cancel(self):
 		"""Override this"""
 
+	# Easy ways to get information
+	def arg(self, n):
+		"""Returns the nth space separated word"""
+		try:
+			return self.args[n]
+		except IndexError:
+			return ""
+
+	def rest(self, n):
+		"""Returns everything from and after arg(n)"""
+		got_space = False
+		word_count = 0
+		for i in range(len(self.line)):
+			if self.line[i] == " ":
+				if not got_space:
+					got_space = True
+					word_count += 1
+			elif got_space:
+				got_space = False
+				if word_count == n + self._shifted:
+					return self.line[i:]
+		return ""
+
+	def start(self, n):
+		"""Returns everything until (inclusively) arg(n)"""
+		return ' '.join(self.args[:n]) + " " # XXX
+
+	def shift(self):
+		del self.args[0]
+		self._shifted += 1
+
+	def tabinsert(self, word):
+		return ''.join([self._tabinsert_left, word, self._tabinsert_right])
+
+	@lazy_property
+	def _tabinsert_left(self):
+		try:
+			return self.line[:self.line[0:self.pos].rindex(' ') + 1]
+		except ValueError:
+			return ''
+
+	@lazy_property
+	def _tabinsert_right(self):
+		return self.line[self.pos:]
+
 	# COMPAT: this is still used in old commands.py configs
 	def _tab_only_directories(self):
 		from os.path import dirname, basename, expanduser, join, isdir
diff --git a/ranger/container/settingobject.py b/ranger/container/settingobject.py
index 6b6fbae7..a245db21 100644
--- a/ranger/container/settingobject.py
+++ b/ranger/container/settingobject.py
@@ -31,6 +31,7 @@ ALLOWED_SETTINGS = {
 	'draw_borders': bool,
 	'flushinput': bool,
 	'hidden_filter': lambda x: isinstance(x, str) or hasattr(x, 'match'),
+	'load_default_rc': bool,
 	'max_console_history_size': (int, type(None)),
 	'max_history_size': (int, type(None)),
 	'mouse_enabled': bool,
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 96e23189..0314888d 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -70,7 +70,19 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 			bad = True
 		text = str(text)
 		self.log.appendleft(text)
-		self.ui.status.notify(text, duration=duration, bad=bad)
+		if self.ui and self.ui.is_on:
+			self.ui.status.notify(text, duration=duration, bad=bad)
+		else:
+			print(text)
+
+	def abort(self):
+		try:
+			item = self.loader.queue[0]
+		except:
+			self.notify("Type Q or :quit<Enter> to exit Ranger")
+		else:
+			self.notify("Aborting: " + item.get_description())
+			self.loader.remove(index=0)
 
 	def redraw_window(self):
 		"""Redraw the window"""
@@ -78,14 +90,20 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 
 	def open_console(self, string='', prompt=None, position=None):
 		"""Open the console if the current UI supports that"""
-		if hasattr(self.ui, 'open_console'):
-			self.ui.open_console(string, prompt=prompt, position=position)
+		self.ui.open_console(string, prompt=prompt, position=position)
 
 	def execute_console(self, string=''):
 		"""Execute a command for the console"""
-		self.open_console(string=string)
-		self.ui.console.line = string
-		self.ui.console.execute()
+		command_name = string.split()[0]
+		try:
+			cmd_class = self.commands.get_command(command_name)
+		except:
+			self.notify("Command not found: `%s'" % command_name)
+		else:
+			try:
+				cmd_class(string).execute()
+			except Exception as error:
+				self.notify(error)
 
 	def substitute_macros(self, string):
 		return _MacroTemplate(string).safe_substitute(self._get_macros())
@@ -149,6 +167,16 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 
 		return macros
 
+	def source_cmdlist(self, filename, narg=None):
+		for line in open(filename, 'r'):
+			line = line.rstrip("\r\n")
+			try:
+				self.execute_console(line)
+			except Exception as e:
+				if ranger.arg.debug:
+					raise
+				else:
+					self.notify('Error in line `%s\':\n  %s' % (line, str(e)), bad=True)
 
 	def execute_file(self, files, **kw):
 		"""Execute a file.
diff --git a/ranger/core/helper.py b/ranger/core/helper.py
index 910c0241..62ab9091 100644
--- a/ranger/core/helper.py
+++ b/ranger/core/helper.py
@@ -103,22 +103,27 @@ def load_settings(fm, clean):
 			pass
 		from ranger.defaults import commands
 		comcont.load_commands_from_module(commands)
-		commands = comcont
+		fm.commands = comcont
 
 		# Load apps
 		try:
 			import apps
 		except ImportError:
 			from ranger.defaults import apps
+		fm.apps = apps.CustomApplications()
 
-		# Load keys
+		# Setup keymanager
 		keymanager = ranger.core.shared.EnvironmentAware.env.keymanager
 		ranger.api.keys.keymanager = keymanager
-		from ranger.defaults import keys
-		try:
-			import keys
-		except ImportError:
-			pass
+
+		# Load rc.conf
+		conf = fm.confpath('rc.conf')
+		if os.access(conf, os.R_OK):
+			fm.source_cmdlist(conf)
+		if fm.settings.load_default_rc:
+			conf = fm.relpath('defaults', 'rc.conf')
+			if os.access(conf, os.R_OK):
+				fm.source_cmdlist(conf)
 
 		# Load plugins
 		try:
@@ -148,15 +153,12 @@ def load_settings(fm, clean):
 	else:
 		comcont = ranger.api.commands.CommandContainer()
 		ranger.api.commands.alias = comcont.alias
-		from ranger.api import keys
 		keymanager = ranger.core.shared.EnvironmentAware.env.keymanager
 		ranger.api.keys.keymanager = keymanager
 		from ranger.defaults import commands, keys, apps
 		comcont.load_commands_from_module(commands)
-		commands = comcont
-	fm.commands = commands
-	fm.keys = keys
-	fm.apps = apps.CustomApplications()
+		fm.commands = comcont
+		fm.apps = apps.CustomApplications()
 
 
 def load_apps(fm, clean):
diff --git a/ranger/defaults/commands.py b/ranger/defaults/commands.py
index 2c85226b..d2c02865 100644
--- a/ranger/defaults/commands.py
+++ b/ranger/defaults/commands.py
@@ -755,6 +755,37 @@ class bulkrename(Command):
 		cmdfile.close()
 
 
+class help_(Command):
+	"""
+	:help
+	
+	Display ranger's manual page.
+	"""
+	name = 'help'
+	def execute(self):
+		self.fm.display_help()
+
+
+class map_(Command):
+	"""
+	:map <keysequence> <command>
+	Maps a command to a keysequence in the "browser" context.
+
+	Example:
+	map j move down
+	map J move down 10
+	"""
+	name = 'map'
+	context = 'browser'
+	resolve_macros = False
+	def execute(self):
+		command = self.rest(2)
+		self.fm.env.keymanager.map(self.context, self.arg(1),
+			func=lambda arg: arg.fm.execute_console(command),
+#			func=lambda arg: arg.fm.cmd(command, n=arg.n, any=arg.matches),
+			help=command)
+
+
 class filter(Command):
 	"""
 	:filter <string>
diff --git a/ranger/defaults/options.py b/ranger/defaults/options.py
index c9cbf8ad..8b2395da 100644
--- a/ranger/defaults/options.py
+++ b/ranger/defaults/options.py
@@ -33,6 +33,10 @@ of the values stay the same.
 
 from ranger.api.options import *
 
+# Load the deault rc.conf file?  If you've copied it to your configuration
+# direcory, then you should deactivate this option.
+load_default_rc = True
+
 # Which files should be hidden?  Toggle this by typing `zh' or
 # changing the setting `show_hidden'
 hidden_filter = regexp(
diff --git a/ranger/defaults/rc.conf b/ranger/defaults/rc.conf
new file mode 100644
index 00000000..c462bb65
--- /dev/null
+++ b/ranger/defaults/rc.conf
@@ -0,0 +1,15 @@
+# VIM
+map j eval fm.move(down=1)
+map k eval fm.move(up=1)
+map h eval fm.move(left=1)
+map l eval fm.move(right=1)
+map q quit
+map Q quit
+
+map R eval fm.reload_cwd()
+map <c-r> eval fm.reset()
+map <c-l> eval fm.redraw_window()
+map H eval fm.history_go(-1)
+map L eval fm.history_go(1)
+map <c-c> eval fm.abort()
+map ? help
diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py
index 128a3434..cd11a0d0 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -48,6 +48,7 @@ def _setup_mouse(signal):
 class UI(DisplayableContainer):
 	is_set_up = False
 	load_mode = False
+	is_on = False
 	def __init__(self, env=None, fm=None):
 		self._draw_title = os.environ["TERM"] in TERMINALS_WITH_TITLE
 		os.environ['ESCDELAY'] = '25'   # don't know a cleaner way
@@ -86,6 +87,7 @@ class UI(DisplayableContainer):
 			self.is_set_up = True
 			self.setup()
 		self.update_size()
+		self.is_on = True
 
 	def suspend(self):
 		"""Turn off curses"""
@@ -99,6 +101,7 @@ class UI(DisplayableContainer):
 		if self.settings.mouse_enabled:
 			_setup_mouse(dict(value=False))
 		curses.endwin()
+		self.is_on = False
 
 	def set_load_mode(self, boolean):
 		boolean = bool(boolean)