summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2010-01-01 04:22:32 +0100
committerhut <hut@lavabit.com>2010-01-01 04:22:32 +0100
commit23236d0cfd081305a8fd93428ab842d7814df380 (patch)
treeb3a6dca21f5265a664f5cce4971a86c38a88fb13
parentad1a420413bdff0f07bdc7023662ef8e6f7a5fff (diff)
downloadranger-23236d0cfd081305a8fd93428ab842d7814df380.tar.gz
improved procedures of spawning processes
-rw-r--r--TODO2
-rw-r--r--ranger/actions.py31
-rw-r--r--ranger/applications.py174
-rw-r--r--ranger/defaults/apps.py101
-rw-r--r--ranger/defaults/keys.py6
5 files changed, 163 insertions, 151 deletions
diff --git a/TODO b/TODO
index 7b92c24b..851ff916 100644
--- a/TODO
+++ b/TODO
@@ -18,4 +18,4 @@ General
    (X) #11  09/12/27  filter
    (X) #12  09/12/27  jump through the list in a specific order
    (X) #14  09/12/29  make filelists inherit from pagers
-   ( ) #15  09/12/29  better way of running processes!!~
+   (X) #15  09/12/29  better way of running processes!!~
diff --git a/ranger/actions.py b/ranger/actions.py
index e0798344..d379c6cf 100644
--- a/ranger/actions.py
+++ b/ranger/actions.py
@@ -5,6 +5,8 @@ from ranger.shared import EnvironmentAware, SettingsAware
 from ranger import fsobject
 from ranger.ext.trim import trimmed_lines_of_docstring
 
+from ranger.applications import run
+
 class Actions(EnvironmentAware, SettingsAware):
 	search_method = 'ctime'
 	search_forward = False
@@ -188,7 +190,7 @@ class Actions(EnvironmentAware, SettingsAware):
 			pager = self.ui.open_embedded_pager()
 			pager.set_source(f)
 
-	def execute_file(self, files, app='', flags='', mode=0):
+	def execute_file(self, files, **kw):
 		"""Execute a file.
 		app is the name of a method in Applications, without the "app_"
 		flags is a string consisting of applications.ALLOWED_FLAGS
@@ -200,14 +202,10 @@ class Actions(EnvironmentAware, SettingsAware):
 		elif type(files) not in (list, tuple):
 			files = [files]
 
-		return self.apps.get(app)(
-				mainfile = files[0],
-				files = list(files),
-				flags = flags,
-				mode = mode,
-				fm = self,
-				stdin = None,
-				apps = self.apps)
+		return run(fm=self, files=list(files), **kw)
+
+	def execute_command(self, cmd, **kw):
+		return run(fm=self, action=cmd, **kw)
 	
 	def edit_file(self):
 		"""Calls execute_file with the current file and app='editor'"""
@@ -266,21 +264,6 @@ class Actions(EnvironmentAware, SettingsAware):
 		if func is not None:
 			self.env.settings['sort'] = str(func)
 	
-	def spawn(self, cmd, suspend=False, wait=False):
-		from ranger.applications import spawn
-		spawn(cmd, fm=self, suspend=wait, wait=wait)
-	
-	def runcmd(self, cmd, suspend=True, wait=True):
-		from ranger.applications import spawn
-		spawn(cmd, fm=self, suspend=wait, wait=wait)
-	
-	def spawn_shell(self):
-		from ranger.applications import run
-		from subprocess import STDOUT
-		run("bash", flags='', fm=self,
-				mode=0, shell=True, stdin=None,
-				apps=self.apps, stderr=STDOUT)
-	
 	def force_load_preview(self):
 		cf = self.env.cf
 		if cf is not None:
diff --git a/ranger/applications.py b/ranger/applications.py
index beefba9f..499e8b2c 100644
--- a/ranger/applications.py
+++ b/ranger/applications.py
@@ -9,6 +9,9 @@ An uppercase key ensures that a certain flag will not be used.
 
 import os, sys
 from ranger.ext.waitpid_no_intr import waitpid_no_intr
+from subprocess import Popen, PIPE
+
+devnull = open(os.devnull, 'a')
 
 ALLOWED_FLAGS = 'sdpSDP'
 
@@ -26,79 +29,114 @@ class Applications(object):
 
 	def all(self):
 		"""Returns a list with all application functions"""
-		return [x[4:] for x in self.__class__.__dict__ if x.startswith('app_')]
+		methods = self.__class__.__dict__
+		return [meth[4:] for meth in methods if meth.startswith('app_')]
 
-null = open(os.devnull, 'a')
+class AppContext(object):
+	def __init__(self, app='default', files=None, mode=0, flags='', fm=None,
+			stdout=None, stderr=None, stdin=None, shell=None,
+			wait=True, action=None):
 
-def run(*args, **kw):
-	"""Run files with the specified parameters"""
-	from subprocess import Popen
-	from subprocess import PIPE
+		if files is None:
+			self.files = []
+		else:
+			self.files = list(files)
 
-	flags, fm = kw['flags'], kw['fm']
-	for flag in flags:
-		if ord(flag) <= 90:
-			bad = flag + flag.lower()
-			flags = ''.join(c for c in flags if c not in bad)
+		try:
+			self.file = self.files[0]
+		except IndexError:
+			self.file = None
+
+		self.app = app
+		self.action = action
+		self.mode = mode
+		self.flags = flags
+		self.fm = fm
+		self.stdout = stdout
+		self.stderr = stderr
+		self.stdin = stdin
+		self.wait = wait
+
+		if shell is None:
+			self.shell = isinstance(action, str)
+		else:
+			self.shell = shell
+	
+	def __getitem__(self, key):
+		return self.files[key]
+	
+	def __iter__(self):
+		if self.files:
+			for f in self.files:
+				yield f.path
+	
+	def squash_flags(self):
+		for flag in self.flags:
+			if ord(flag) <= 90:
+				bad = flag + flag.lower()
+				self.flags = ''.join(c for c in self.flags if c not in bad)
+
+	def get_action(self, apps=None):
+		if apps is None and self.fm:
+			apps = self.fm.apps
+
+		if apps is None:
+			raise RuntimeError("AppContext has no source for applications!")
+
+		app = apps.get(self.app)
+		self.action = app(self)
+		self.shell = isinstance(self.action, str)
+	
+	def run(self):
+		self.squash_flags()
+		if self.action is None:
+			self.get_action()
 
-	args = map(str, args)
-	popen_kw = {}
-	popen_kw['stdout'] = sys.stderr
-	popen_kw['stderr'] = sys.stderr
+		# ---------------------------- determine keywords for Popen()
 
-	for word in ('shell', 'stdout', 'stdin', 'stderr'):
-		if word in kw:
-			popen_kw[word] = kw[word]
+		kw = {}
+		kw['stdout'] = sys.stderr
+		kw['stderr'] = sys.stderr
+		kw['args'] = self.action
 
-	if kw['stdin'] is not None:
-		popen_kw['stdin'] = kw['stdin']
+		for word in ('shell', 'stdout', 'stdin', 'stderr'):
+			if getattr(self, word) is not None:
+				kw[word] = getattr(self, word)
+
+		if 's' in self.flags or 'd' in self.flags:
+			kw['stdout'] = kw['stderr'] = kw['stdin'] = devnull
+
+		# --------------------------- run them
+		if 'p' in self.flags:
+			kw['stdout'] = PIPE
+			kw['stderr'] = PIPE
+			process1 = Popen(**kw)
+			process2 = run(app='pager', stdin=process1.stdout, fm=self.fm)
+			return process2
+
+		elif 'd' in self.flags:
+			process = Popen(**kw)
+			return process
 
-	if 's' in flags or 'd' in flags:
-		popen_kw['stdout'] = popen_kw['stderr'] = popen_kw['stdin'] = null
-	
-	if 'p' in flags:
-		popen_kw['stdout'] = PIPE
-		process1 = Popen(args, **popen_kw)
-		kw['stdin'] = process1.stdout
-		kw['files'] = ()
-		kw['flags'] = ''.join(f for f in kw['flags'] if f in 'd')
-		process2 = kw['apps'].app_pager(**kw)
-		return process2
-
-	if 'd' in flags:
-		process = Popen(args, **popen_kw)
-		return process
-
-	else:
-		if fm.ui:
-			fm.ui.suspend()
-		try:
-			p = Popen(args, **popen_kw)
-			waitpid_no_intr(p.pid)
-		finally:
-			if fm.ui:
-				fm.ui.initialize()
-		return p
-
-def spawn(command, fm=None, suspend=True, wait=True):
-	from subprocess import Popen, STDOUT
-	from ranger.ext.waitpid_no_intr import waitpid_no_intr
-
-	if suspend and fm and fm.ui:
-		fm.ui.suspend()
-
-	try:
-		if wait:
-			kw = {}
 		else:
-			kw = {'stdout':null, 'stderr':null, 'stdin':null}
-
-		if fm and fm.stderr_to_out:
-			if 'stderr' not in kw:
-				kw['stderr'] = STDOUT
-		process = Popen(command, shell=True, **kw)
-		if wait:
-			waitpid_no_intr(process.pid)
-	finally:
-		if suspend and fm and fm.ui:
-			fm.ui.initialize()
+			self._activate_ui(False)
+			try:
+				p = Popen(**kw)
+				if self.wait:
+					waitpid_no_intr(p.pid)
+			finally:
+				self._activate_ui(True)
+
+	def _activate_ui(self, boolean):
+		if self.fm and self.fm.ui:
+			if boolean:
+				self.fm.ui.initialize()
+			else:
+				self.fm.ui.suspend()
+
+def run(action=None, **kw):
+	app = AppContext(action=action, **kw)
+	return app.run()
+
+def tup(*args):
+	return tuple(args)
diff --git a/ranger/defaults/apps.py b/ranger/defaults/apps.py
index 37422a6e..9b84c5de 100644
--- a/ranger/defaults/apps.py
+++ b/ranger/defaults/apps.py
@@ -1,78 +1,69 @@
-from ranger.applications import Applications, run
+from ranger.applications import *
 
 class CustomApplications(Applications):
-	# How to determine the default application? {{{
-	def app_default(self, **kw):
-		f = kw['mainfile']
+	def app_default(self, c):
+		"""How to determine the default application?"""
+		f = c.file
 
 		if f.extension is not None and f.extension in ('pdf'):
-			return self.app_evince(**kw)
+			return self.app_evince(c)
 
 		if f.container:
-			return self.app_aunpack(**kw)
+			return self.app_aunpack(c)
 
 		if f.video or f.audio:
 			if f.video:
-				kw['flags'] += 'd'
-			return self.app_mplayer(**kw)
+				c.flags += 'd'
+			return self.app_mplayer(c)
 		
 		if f.image:
-			return self.app_feh(**kw)
+			return self.app_feh(c)
 
 		if f.document:
-			return self.app_editor(**kw)
-	# }}}
+			return self.app_editor(c)
 
-	def app_pager(self, **kw):
-		return run('less', *kw['files'], **kw)
+	# ----------------------------------------- application definitions
+	def app_pager(self, c):
+		return tup('less', *c)
 
-	def app_vim(self, **kw):
-		return run('vim', *kw['files'], **kw)
+	def app_vim(self, c):
+		return tup('vim', *c)
 
 	app_editor = app_vim
 
-	def app_mplayer(self, **kw):
-		if kw['mode'] == 1:
-			return run('mplayer', *kw['files'], **kw)
+	def app_mplayer(self, c):
+		if c.mode is 1:
+			return tup('mplayer', *c)
 
-		elif kw['mode'] == 2:
-			return run('mplayer', '-fs',
-					'-sid', '0',
-					'-vfm', 'ffmpeg',
-					'-lavdopts', 'lowres=1:fast:skiploopfilter=all:threads=8',
-					*kw['files'], **kw)
+		elif c.mode is 2:
+			args = "mplayer -fs -sid 0 -vfm ffmpeg -lavdopts" \
+					"lowres=1:fast:skiploopfilter=all:threads=8".split()
+			args.extend(c)
+			return tup(*args)
 
-		elif kw['mode'] == 3:
-			return run('mplayer',
-					'-mixer', 'software',
-					*kw['files'], **kw)
+		elif c.mode is 3:
+			return tup('mplayer', '-mixer', 'software', *c)
 
 		else:
-			return run('mplayer', '-fs', *kw['files'], **kw)
-
-	def app_feh(self, **kw):
-		if kw['files']:
-			if kw['mode'] == 1:
-				kw['flags'] += 'd'
-				return run('feh', '--bg-scale', kw['files'][0], **kw)
-			if kw['mode'] == 2:
-				kw['flags'] += 'd'
-				return run('feh', '--bg-tile', kw['files'][0], **kw)
-			if kw['mode'] == 3:
-				kw['flags'] += 'd'
-				return run('feh', '--bg-center', kw['files'][0], **kw)
-			if kw['mode'] == 4:
-				kw['flags'] += 'd'
-				return run('gimp', *kw['files'], **kw)
-		return run('feh', *kw['files'], **kw)
-
-	def app_aunpack(self, **kw):
-		m = kw['mode']
-		if m == 0:
-			kw['flags'] += 'p'
-			return run('aunpack', '-l', *kw['files'], **kw)
-		elif m == 1:
-			return run('aunpack', *kw['files'], **kw)
+			return tup('mplayer', '-fs', *c)
+
+	def app_feh(self, c):
+		arg = {1: '--bg-scale', 2: '--bg-tile', 3: '--bg-center'}
+
+		c.flags += 'd'
+
+		if c.mode in arg:
+			return tup('feh', arg[c.mode], c.file.path)
+		if c.mode is 4:
+			return tup('gimp', *c)
+		return tup('feh', *c)
+
+	def app_aunpack(self, c):
+		if c.mode is 0:
+			c.flags += 'p'
+			return tup('aunpack', '-l', c.file.path)
+		return tup('aunpack', c.file.path)
 	
-	def app_evince(self, **kw):
-		return run('evince', *kw['files'], **kw)
+	def app_evince(self, c):
+		c.flags += 'd'
+		return tup('evince', *c)
diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py
index 7d1db7d2..5732b793 100644
--- a/ranger/defaults/keys.py
+++ b/ranger/defaults/keys.py
@@ -55,7 +55,7 @@ def initialize_commands(command_list):
 	bind('dd', fm.cut())
 	bind('p', fm.paste())
 
-	bind('s', fm.spawn_shell())
+	bind('s', fm.execute_command('bash'))
 
 	bind(TAB, fm.search(order='tag'))
 
@@ -98,8 +98,8 @@ def initialize_commands(command_list):
 	bind('cd', fm.open_console(cmode.COMMAND, 'cd '))
 	bind('f', fm.open_console(cmode.COMMAND_QUICK, 'find '))
 
-	bind('term', fm.spawn('x-terminal-emulator'))
-	bind('du', fm.runcmd('du --max-depth=1 -h | less'))
+	bind('term', fm.execute_command('x-terminal-emulator', flags='d'))
+	bind('du', fm.execute_command('du --max-depth=1 -h | less'))
 	bind('tf', fm.open_console(cmode.COMMAND, 'filter '))
 	hint('d', 'd//u// (disk usage) d//d// (cut)')