summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/actions.py5
-rw-r--r--ranger/applications.py201
-rw-r--r--ranger/commands.py3
-rw-r--r--ranger/fm.py6
-rw-r--r--ranger/gui/widgets/console.py2
5 files changed, 20 insertions, 197 deletions
diff --git a/ranger/actions.py b/ranger/actions.py
index f773a79b..f02e3cb4 100644
--- a/ranger/actions.py
+++ b/ranger/actions.py
@@ -20,7 +20,6 @@ import ranger
 from ranger.shared import EnvironmentAware, SettingsAware
 from ranger import fsobject
 from ranger.gui.widgets import console_mode as cmode
-from ranger.applications import run
 from ranger.fsobject import File
 
 class Actions(EnvironmentAware, SettingsAware):
@@ -247,10 +246,10 @@ class Actions(EnvironmentAware, SettingsAware):
 		elif type(files) not in (list, tuple):
 			files = [files]
 
-		return run(fm=self, files=list(files), **kw)
+		return self.run(files=list(files), **kw)
 
 	def execute_command(self, cmd, **kw):
-		return run(fm=self, action=cmd, **kw)
+		return self.run(cmd, **kw)
 	
 	def edit_file(self, file=None):
 		"""Calls execute_file with the current file and app='editor'"""
diff --git a/ranger/applications.py b/ranger/applications.py
index 736f562e..1847c6d0 100644
--- a/ranger/applications.py
+++ b/ranger/applications.py
@@ -13,19 +13,14 @@
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 """
-This module faciliates starting of new processes.
+This module provides helper functions/classes for ranger.defaults.apps.
 """
 
 import os, sys
-from ranger.ext.waitpid_no_intr import waitpid_no_intr
 from subprocess import Popen, PIPE
-from ranger.ext.shell_escape import shell_escape
 from ranger.ext.iter_tools import flatten
 from ranger.shared import FileManagerAware
 
-devnull = open(os.devnull, 'a')
-
-ALLOWED_FLAGS = 'sdpSDP'
 
 class Applications(FileManagerAware):
 	"""
@@ -96,6 +91,15 @@ class Applications(FileManagerAware):
 			return getattr(self, 'app_' + app)
 		except AttributeError:
 			return self.app_default
+	
+	def apply(self, app, context):
+		if not app:
+			app = 'default'
+		try:
+			handler = getattr(self, 'app_' + app)
+		except AttributeError:
+			handler = self.app_default
+		return handler(context)
 
 	def has(self, app):
 		"""Returns whether an application is defined"""
@@ -107,190 +111,6 @@ class Applications(FileManagerAware):
 		return [meth[4:] for meth in methods if meth.startswith('app_')]
 
 
-class AppContext(object):
-	"""
-	An AppContext object abstracts the spawning of processes.
-
-	At initialization of the object you can define many high-level options.
-	When you call the run() function, those options are evaluated and
-	translated into Popen() calls.
-
-	An instances of this class is passed as the only argument to
-	app_xyz calls of the Applications object.
-	
-	Attributes:
-	action -- a string with a command or a list of arguments for
-		the Popen call.
-	app -- the name of the app function. ("vim" for app_vim.)
-		app is used to get an action if the user didn't specify one.
-	mode -- a number, mainly used in determining the action in app_xyz()
-	flags -- a string with flags which change the way programs are run
-	files -- a list containing files, mainly used in app_xyz
-	file -- an arbitrary file from that list (or None)
-	fm -- the filemanager instance
-	wait -- boolean, wait for the end or execute programs in parallel?
-	stdout -- directly passed to Popen
-	stderr -- directly passed to Popen
-	stdin -- directly passed to Popen
-	shell -- directly passed to Popen. Should the string be shell-interpreted?
-
-	List of allowed flags:
-	s: silent mode. output will be discarded.
-	d: detach the process.
-	p: redirect output to the pager
-
-	An uppercase key ensures that a certain flag will not be used.
-	"""
-
-	def __init__(self, app='default', files=None, mode=0, flags='', fm=None,
-			stdout=None, stderr=None, stdin=None, shell=None,
-			wait=True, action=None):
-		"""
-		The necessary parameters are fm and action or app.
-		"""
-
-		if files is None:
-			self.files = []
-		else:
-			self.files = list(files)
-
-		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 __iter__(self):
-		"""Iterates over all file paths"""
-		if self.files:
-			for f in self.files:
-				yield f.path
-	
-	def squash_flags(self):
-		"""Remove duplicates and lowercase counterparts of uppercase flags"""
-		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):
-		"""Get the action from app_xyz"""		
-		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)
-		if isinstance(self.action, str):
-			self.shell = True
-			self.action = shell_escape(self.action)
-		else:
-			self.shell = False
-	
-	def run(self):
-		"""
-		Run the application in the way specified by the options.
-
-		Returns False if nothing can be done, None if there was an error,
-		otherwise the process object returned by Popen().
-
-		This function tries to find an action if none is defined.
-		"""
-
-		# Try to find an action
-
-		if self.action is None:
-			self.get_action()
-
-		if self.action is None:
-			return False
-
-		# Define some preconditions
-
-		toggle_ui = True
-		pipe_output = False
-
-		self.squash_flags()
-
-		kw = {}
-		kw['stdout'] = sys.stdout
-		kw['stderr'] = sys.stderr
-		kw['args'] = self.action
-
-		for word in ('shell', 'stdout', 'stdin', 'stderr'):
-			if getattr(self, word) is not None:
-				kw[word] = getattr(self, word)
-
-		# Evaluate the flags to determine keywords
-		# for Popen() and other variables
-
-		if 's' in self.flags or 'd' in self.flags:
-			kw['stdout'] = kw['stderr'] = kw['stdin'] = devnull
-
-		if 'p' in self.flags:
-			kw['stdout'] = PIPE
-			kw['stderr'] = PIPE
-			toggle_ui = False
-			pipe_output = True
-			self.wait = False
-
-		if 'd' in self.flags:
-			toggle_ui = False
-			self.wait = False
-
-		# Finally, run it
-
-		if toggle_ui:
-			self._activate_ui(False)
-
-		try:
-			process = None
-			try:
-				process = Popen(**kw)
-			except:
-				if self.fm:
-					self.fm.notify("Failed to run: " + \
-							' '.join(kw['args']), bad=True)
-			else:
-				if self.wait:
-					waitpid_no_intr(process.pid)
-		finally:
-			if toggle_ui:
-				self._activate_ui(True)
-			
-			if pipe_output and process:
-				return run(app='pager', stdin=process.stdout, fm=self.fm)
-
-			return process
-
-	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):
-	"""Shortcut for creating and immediately running an AppContext."""
-	app = AppContext(action=action, **kw)
-	return app.run()
-
 def tup(*args):
 	"""
 	This helper function creates a tuple out of the arguments.
@@ -301,6 +121,7 @@ def tup(*args):
 	"""
 	return args
 
+
 def depends_on(*args):
 	args = tuple(flatten(args))
 	def decorator(fnc):
diff --git a/ranger/commands.py b/ranger/commands.py
index afb5d42c..3b552a22 100644
--- a/ranger/commands.py
+++ b/ranger/commands.py
@@ -390,13 +390,12 @@ class grep(Command):
 	"""
 
 	def execute(self):
-		from ranger.applications import run
 		line = parse(self.line)
 		if line.rest(1):
 			action = ['grep', '--color=always', '--line-number']
 			action.extend(['-e', line.rest(1), '-r'])
 			action.extend(map(lambda x: x.path, self.fm.env.get_selection()))
-			run(fm=self.fm, action=action, flags='p')
+			self.fm.execute_command(action, flags='p')
 
 
 # -------------------------------- rest
diff --git a/ranger/fm.py b/ranger/fm.py
index f8b0284c..06240b8b 100644
--- a/ranger/fm.py
+++ b/ranger/fm.py
@@ -17,6 +17,7 @@ from collections import deque
 
 from ranger.actions import Actions
 from ranger.container import Bookmarks
+from ranger.runner import Runner
 from ranger.ext.relpath import relpath_conf
 from ranger.ext.get_executables import get_executables
 from ranger import __version__
@@ -40,6 +41,11 @@ class FM(Actions):
 		self._executables = None
 		self.apps = self.settings.apps.CustomApplications()
 
+		def mylogfunc(text):
+			self.notify(text, bad=True)
+		self.run = Runner(ui=self.ui, apps=self.apps,
+				logfunc=mylogfunc)
+
 		from ranger.shared import FileManagerAware
 		FileManagerAware.fm = self
 
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index b30b30b0..094a5c17 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -378,8 +378,6 @@ class OpenConsole(ConsoleWithTab):
 		self.history = self.histories[OPEN_HISTORY]
 	
 	def execute(self):
-		from ranger.applications import run
-		from subprocess import STDOUT, PIPE
 		command, flags = self._parse()
 		if command:
 			if _CustomTemplate.delimiter in command: