diff options
Diffstat (limited to 'ranger/applications.py')
-rw-r--r-- | ranger/applications.py | 201 |
1 files changed, 11 insertions, 190 deletions
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): |