about summary refs log tree commit diff stats
path: root/ranger/ext/rifle.py
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2012-03-16 00:18:34 +0100
committerhut <hut@lavabit.com>2012-03-16 00:18:34 +0100
commit6f8ca83b677412aee792e55d24c62b7d24d4ea84 (patch)
tree5d57326482702b964281545f82ee289f8aa2cb77 /ranger/ext/rifle.py
parent4dc87fa8ab83844707659e1f82e1e9726279a8a2 (diff)
downloadranger-6f8ca83b677412aee792e55d24c62b7d24d4ea84.tar.gz
implemented "rifle", a new file launcher
ranger/ext/rifle.py is a standalone program that works without ranger.
The configuration is not in python anymore, thus is easier to
understand, modify and parse.
Diffstat (limited to 'ranger/ext/rifle.py')
-rw-r--r--ranger/ext/rifle.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/ranger/ext/rifle.py b/ranger/ext/rifle.py
new file mode 100644
index 00000000..563968ef
--- /dev/null
+++ b/ranger/ext/rifle.py
@@ -0,0 +1,145 @@
+# Copyright (C) 2012  Roman Zimbelmann <romanz@lavabit.com>
+# This software is distributed under the terms of the GNU GPL version 3.
+
+import os.path
+import re, sys
+from subprocess import Popen, PIPE
+from ranger.ext.shell_escape import shell_quote
+from ranger.ext.spawn import spawn
+from ranger.ext.get_executables import get_executables
+import time
+
+def _is_terminal():
+	try:
+		os.ttyname(0)
+		os.ttyname(1)
+		os.ttyname(2)
+	except:
+		return False
+	return True
+
+class Rifle(object):
+	delimiter1 = '='
+	delimiter2 = ','
+
+	def __init__(self, config_file):
+		self.config_file = config_file
+		self._app_flags = False
+
+	def reload_config(self, config_file=None):
+		if config_file is None:
+			config_file = self.config_file
+		f = open(config_file, 'r')
+		self.rules = []
+		for line in f:
+			if line.startswith('#') or line == '\n':
+				continue
+			line = line.strip()
+			if self.delimiter1 not in line:
+				print("Syntax error foo")
+			tests, command = line.split(self.delimiter1, 1)
+			tests = tests.split(self.delimiter2)
+			tests = tuple(tuple(f.strip().split(None, 1)) for f in tests)
+			tests = tuple(tests)
+			command = command.strip()
+			self.rules.append((command, tests))
+
+	def _eval_rule(self, rule, files, label):
+		function = rule[0]
+		argument = rule[1] if len(rule) > 1 else ''
+
+		self._app_flags = ''
+
+		if function == 'ext':
+			extension = os.path.basename(files[0]).rsplit('.', 1)[-1]
+			return bool(re.search('^' + argument + '$', extension))
+		if function == 'name':
+			return bool(re.search(argument, os.path.basename(files[0])))
+		if function == 'path':
+			return bool(re.search(argument, os.path.abspath(files[0])))
+		if function == 'mime':
+			return bool(re.search(argument, self._get_mimetype(files[0])))
+		if function == 'has':
+			return argument in get_executables()
+		if function == 'terminal':
+			return _is_terminal()
+		if function == 'label':
+			if label:
+				self._found_label = argument == label
+			else:
+				# don't care about label in this case
+				self._found_label = True
+			return self._found_label
+		if function == 'flag':
+			self._app_flags = argument
+			return True
+		if function == 'X':
+			return 'DISPLAY' in os.environ
+		if function == 'else':
+			return True
+
+	def _get_mimetype(self, fname):
+		if self._mimetype:
+			return self._mimetype
+		mimetype = spawn("file", "--mime-type", "-Lb", fname)
+		self._mimetype = mimetype
+		return mimetype
+
+	def _build_command(self, files, action):
+		flags = self._app_flags
+		_filenames = "' '".join(f.replace("'", "'\\\''") for f in files)
+		command = "set -- '%s'" % _filenames + '\n'
+		if 'p' in flags and not 'f' in flags and is_terminal():
+			action += '| less'
+		if 'f' in flags:
+			action = "nohup %s >&/dev/null &" % action
+		command += action
+		return command
+
+	def list_commands(self, files, mimetype=None):
+		self._mimetype = mimetype
+		command = None
+		count = 0
+		result = []
+		t = time.time()
+		for cmd, tests in self.rules:
+			for test in tests:
+				if not self._eval_rule(test, files, None):
+					break
+			else:
+				result.append((count, cmd, self._app_flags))
+				count += 1
+		#sys.stderr.write("%f\n" % (time.time() - t))
+		return result
+
+	def execute(self, files, number=0, label=None, mimetype=None):
+		self._mimetype = mimetype
+		self._found_label = True
+		command = None
+		count = 0
+		for cmd, tests in self.rules:
+			if label:
+				self._found_label = False
+			for test in tests:
+				if not self._eval_rule(test, files, label):
+					#print("fails on test %s" % str(test))
+					break
+			else:
+				if not self._found_label:
+					pass
+				elif count != number:
+					count += 1
+				else:
+					command = self._build_command(files, cmd)
+					break
+		#print(command)
+		if command is not None:
+			p = Popen(command, shell=True)
+			p.wait()
+
+if __name__ == '__main__':
+	import sys
+	rifle = Rifle(os.environ['HOME'] + '/.config/ranger/rifle.conf')
+	rifle.reload_config()
+	#print(rifle.list_commands(sys.argv[1:]))
+	rifle.execute(sys.argv[1:], number=0)