about summary refs log tree commit diff stats
Commit message (Expand)AuthorAgeFilesLines
...
* 5681Kartik Agaram2019-09-201-0/+2
* 5680Kartik Agaram2019-09-203-3/+10
* 5679 - braces seem doneKartik Agaram2019-09-202-14/+331
* 5678Kartik Agaram2019-09-195-123/+123
* 5677Kartik Agaram2019-09-191-6/+12
* 5676Kartik Agaram2019-09-1916-410/+419
* 5675 - move helpers from subx-common into layersKartik Agaram2019-09-1948-2430/+2347
* 5674Kartik Agaram2019-09-191-0/+0
* 5673 - standardize a few knobsKartik Agaram2019-09-1922-35/+36
* 5672 - move hex out of appsKartik Agaram2019-09-1918-17/+42
* 5671Kartik Agaram2019-09-1910-0/+0
* 5670Kartik Agaram2019-09-198-0/+0
* 5669Kartik Agaram2019-09-1915-26/+28
* 5668 - start reorg to permit syntax sugar in layersKartik Agaram2019-09-1924-42/+42
* 5667Kartik Agaram2019-09-191-2/+0
* 5666 - start of sugar for structured control flowKartik Agaram2019-09-194-10/+357
* 5665Kartik Agaram2019-09-191-1/+2
* 5664Kartik Agaram2019-09-182-2/+0
* 5663Kartik Agaram2019-09-181-4/+63
* 5662Kartik Agaram2019-09-152-3/+3
* 5661Kartik Agaram2019-09-1528-34/+34
* 5660Kartik Agaram2019-09-151-1/+1
* 5659Kartik Agaram2019-09-1534-2128/+2128
* 5658Kartik Agaram2019-09-1512-12/+12
* 5657Kartik Agaram2019-09-141-0/+3
* 5656Kartik Agaram2019-09-1452-2499/+1252
* 5655Kartik Agaram2019-09-141-4/+4
* 5654Kartik Agaram2019-09-1411-70/+70
* 5653Kartik Agaram2019-09-141-1/+1
* 5652Kartik Agaram2019-09-141-1/+1
* 5651Kartik Agaram2019-09-141-2/+2
* 5650 - support a second OS: sosoKartik Agaram2019-09-14101-66/+33999
* 5649Kartik Agaram2019-09-141-4/+4
* 5648Kartik Agaram2019-09-111-2/+1
* 5647 - experimental support for swapping OSKartik Agaram2019-09-1140-146/+168
* 5646Kartik Agaram2019-09-111-1/+1
* 5645Kartik Agaram2019-09-081-1/+1
* 5644 - plan data structures for mulispKartik Agaram2019-09-081-7/+42
* 5643Kartik Agaram2019-09-081-9/+5
* 5642Kartik Agaram2019-09-071-1/+1
* 5641Kartik Agaram2019-09-071-8/+0
* 5640Kartik Agaram2019-09-071-3/+6
* 5639 - tmux support for running a single testKartik Agaram2019-09-071-18/+35
* 5638Kartik Agaram2019-09-071-6/+1
* 5637Kartik Agaram2019-09-074-15/+206
* 5636Kartik Agaram2019-09-073-10/+14
* 5635Kartik Agaram2019-09-073-10/+44
* 5634 - add read/eval/print phasesKartik Agaram2019-09-071-16/+78
* 5633 - start of a toy lisp interpreterKartik Agaram2019-09-071-0/+76
* 5632Kartik Agaram2019-09-061-1084/+1601
ist 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? popen_kws -- keyword arguments which are directly passed to Popen """ def __init__(self, **keywords): self.__dict__ = keywords @property def filepaths(self): try: return [f.path for f in self.files] except: return [] def __iter__(self): """Iterate over file paths""" for item in self.filepaths: yield item 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) class Runner(object): def __init__(self, ui=None, logfunc=None, fm=None): self.ui = ui self.fm = fm self.logfunc = logfunc self.zombies = set() def _log(self, text): try: self.logfunc(text) except TypeError: pass return False def _activate_ui(self, boolean): if self.ui is not None: if boolean: try: self.ui.initialize() except: self._log("Failed to initialize UI") else: try: self.ui.suspend() except: self._log("Failed to suspend UI") def __call__(self, action=None, try_app_first=False, app='default', files=None, mode=0, flags='', wait=True, **popen_kws): """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. """ # Find an action if none was supplied by # creating a Context object and passing it to # an Application object. context = Context(app=app, files=files, mode=mode, fm=self.fm, flags=flags, wait=wait, popen_kws=popen_kws, file=files and files[0] or None) if action is None: return self._log("No way of determining the action!") # Preconditions context.squash_flags() popen_kws = context.popen_kws # shortcut toggle_ui = True pipe_output = False wait_for_enter = False devnull = None if 'shell' not in popen_kws: popen_kws['shell'] = isinstance(action, str) if popen_kws['shell']: # Set default shell for Popen popen_kws['executable'] = os.environ['SHELL'] if 'stdout' not in popen_kws: popen_kws['stdout'] = sys.stdout if 'stderr' not in popen_kws: popen_kws['stderr'] = sys.stderr # Evaluate the flags to determine keywords # for Popen() and other variables if 'p' in context.flags: popen_kws['stdout'] = PIPE popen_kws['stderr'] = PIPE toggle_ui = False pipe_output = True context.wait = False if 's' in context.flags: devnull_writable = open(os.devnull, 'w') devnull_readable = open(os.devnull, 'r') for key in ('stdout', 'stderr'): popen_kws[key] = devnull_writable toggle_ui = False popen_kws['stdin'] = devnull_readable if 'f' in context.flags: toggle_ui = False context.wait = False if 'w' in context.flags: if not pipe_output and context.wait: # <-- sanity check wait_for_enter = True if 'r' in context.flags: # TODO: make 'r' flag work with pipes if 'sudo' not in get_executables(): return self._log("Can not run with 'r' flag, sudo is not installed!") f_flag = ('f' in context.flags) if isinstance(action, str): action = 'sudo ' + (f_flag and '-b ' or '') + action else: action = ['sudo'] + (f_flag and ['-b'] or []) + action toggle_ui = True context.wait = True if 't' in context.flags: if 'DISPLAY' not in os.environ: return self._log("Can not run with 't' flag, no display found!") term = os.environ.get('TERMCMD', os.environ.get('TERM')) if term not in get_executables(): term = 'x-terminal-emulator' if term not in get_executables(): term = 'xterm' if isinstance(action, str): action = term + ' -e ' + action else: action = [term, '-e'] + action toggle_ui = False context.wait = False popen_kws['args'] = action # Finally, run it if toggle_ui: self._activate_ui(False) try: error = None process = None self.fm.signal_emit('runner.execute.before', popen_kws=popen_kws, context=context) try: if 'f' in context.flags: # This can fail and return False if os.fork() is not # supported, but we assume it is, since curses is used. Popen_forked(**popen_kws) else: process = Popen(**popen_kws) except Exception as e: error = e self._log("Failed to run: %s\n%s" % (str(action), str(e))) else: if context.wait: process.wait() elif process: self.zombies.add(process) if wait_for_enter: press_enter() finally: self.fm.signal_emit('runner.execute.after', popen_kws=popen_kws, context=context, error=error) if devnull: devnull.close() if toggle_ui: self._activate_ui(True) if pipe_output and process: return self(action='less', app='pager', try_app_first=True, stdin=process.stdout) return process