From 23236d0cfd081305a8fd93428ab842d7814df380 Mon Sep 17 00:00:00 2001 From: hut Date: Fri, 1 Jan 2010 04:22:32 +0100 Subject: improved procedures of spawning processes --- TODO | 2 +- ranger/actions.py | 31 ++------- ranger/applications.py | 174 +++++++++++++++++++++++++++++------------------- ranger/defaults/apps.py | 101 +++++++++++++--------------- ranger/defaults/keys.py | 6 +- 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)') -- cgit 1.4.1-2-gfad0