about 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:
' href='#n627'>627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895