summary refs log blame commit diff stats
path: root/README
blob: 98efc97db10b7e0fc1e4cdfc64a7dccd950bb8ec (plain) (tree)
ass="k">elif function == 'directory': return os.path.isdir(files[0]) elif function == 'path': return bool(re.search(argument, os.path.abspath(files[0]))) elif function == 'mime': return bool(re.search(argument, self._get_mimetype(files[0]))) elif function == 'has': return argument in get_executables() elif function == 'terminal': return _is_terminal() elif function == 'number': if argument.isdigit(): self._skip = int(argument) return True elif function == 'label': self._app_label = argument if label: return argument == label return True elif function == 'flag': self._app_flags = argument return True elif function == 'X': return 'DISPLAY' in os.environ elif function == 'else': return True def _get_mimetype(self, fname): # Spawn "file" to determine the mime-type of the given file. if self._mimetype: return self._mimetype process = Popen(["file", "--mime-type", "-Lb", fname], stdout=PIPE, stderr=PIPE) mimetype, _ = process.communicate() self._mimetype = mimetype.decode(ENCODING).strip() return self._mimetype def _build_command(self, files, action, flags): # Get the flags if isinstance(flags, str): self._app_flags += flags self._app_flags = squash_flags(self._app_flags) filenames = "' '".join(f.replace("'", "'\\\''") for f in files if "\x00" not in f) return "set -- '%s'; %s" % (filenames, action) def list_commands(self, files, mimetype=None): """ Returns one 4-tuple for all currently applicable commands The 4-tuple contains (count, command, label, flags). count is the index, counted from 0 upwards, command is the command that will be executed. label and flags are the label and flags specified in the rule. """ self._mimetype = mimetype count = -1 for cmd, tests in self.rules: self._skip = None self._app_flags = '' self._app_label = None for test in tests: if not self._eval_condition(test, files, None): break else: if self._skip is None: count += 1 else: count = self._skip yield (count, cmd, self._app_label, self._app_flags) def execute(self, files, number=0, label=None, flags="", mimetype=None): """ Executes the given list of files. By default, this executes the first command where all conditions apply, but by specifying number=N you can run the 1+Nth command. If a label is specified, only rules with this label will be considered. If you specify the mimetype, rifle will not try to determine it itself. By specifying a flag, you extend the flag that is defined in the rule. Uppercase flags negate the respective lowercase flags. For example: if the flag in the rule is "pw" and you specify "Pf", then the "p" flag is negated and the "f" flag is added, resulting in "wf". """ command = None found_at_least_one = None # Determine command for count, cmd, lbl, flgs in self.list_commands(files, mimetype): if label and label == lbl or not label and count == number: cmd = self.hook_command_preprocessing(cmd) if cmd == ASK_COMMAND: return ASK_COMMAND command = self._build_command(files, cmd, flags + flgs) flags = self._app_flags break else: found_at_least_one = True else: if label and label in get_executables(): cmd = '%s "$@"' % label command = self._build_command(files, cmd, flags) # Execute command if command is None: if found_at_least_one: if label: self.hook_logger("Label '%s' is undefined" % label) else: self.hook_logger("Method number %d is undefined." % number) else: self.hook_logger("No action found.") else: if 'PAGER' not in os.environ: os.environ['PAGER'] = DEFAULT_PAGER if 'EDITOR' not in os.environ: os.environ['EDITOR'] = DEFAULT_EDITOR command = self.hook_command_postprocessing(command) self.hook_before_executing(command, self._mimetype, self._app_flags) try: if 'r' in flags: prefix = ['sudo', '-E', 'su', '-mc'] else: prefix = ['/bin/sh', '-c'] cmd = prefix + [command] if 't' in flags: if 'TERMCMD' not in os.environ: term = os.environ['TERM'] if term.startswith('rxvt-unicode'): term = 'urxvt' if term not in get_executables(): self.hook_logger("Can not determine terminal command. " "Please set $TERMCMD manually.") os.environ['TERMCMD'] = term cmd = [os.environ['TERMCMD'], '-e'] + cmd if 'f' in flags or 't' in flags: devnull_r = open(os.devnull, 'r') devnull_w = open(os.devnull, 'w') try: pid = os.fork() except: # fall back to not detaching if fork() is not supported p = Popen(cmd, env=self.hook_environment(os.environ)) p.wait() else: if pid == 0: os.setsid() p = Popen(cmd, env=self.hook_environment(os.environ), stdin=devnull_r, stdout=devnull_w, stderr=devnull_w) os._exit(0) else: p = Popen(cmd, env=self.hook_environment(os.environ)) p.wait() finally: self.hook_after_executing(command, self._mimetype, self._app_flags) def main(): """The main function which is run when you start this program direectly.""" import sys # Find configuration file path if 'XDG_CONFIG_HOME' in os.environ and os.environ['XDG_CONFIG_HOME']: conf_path = os.environ['XDG_CONFIG_HOME'] + '/ranger/rifle.conf' else: conf_path = os.path.expanduser('~/.config/ranger/rifle.conf') if not os.path.isfile(conf_path): conf_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '../config/rifle.conf')) # Evaluate arguments from optparse import OptionParser parser = OptionParser(usage="%prog [-fhlpw] [files]") parser.add_option('-f', type="string", default="", metavar="FLAGS", help="use additional flags: f=fork, r=root, t=terminal. " "Uppercase flag negates respective lowercase flags.") parser.add_option('-l', action="store_true", help="list possible ways to open the files (id:label:flags:command)") parser.add_option('-p', type='string', default='0', metavar="KEYWORD", help="pick a method to open the files. KEYWORD is either the " "number listed by 'rifle -l' or a string that matches a label in " "the configuration file") parser.add_option('-w', type='string', default=None, metavar="PROGRAM", help="open the files with PROGRAM") options, positional = parser.parse_args() if not positional: parser.print_help() raise SystemExit(1) if options.p.isdigit(): number = int(options.p) label = None else: number = 0 label = options.p if options.w is not None and not options.l: p = Popen([options.w] + list(positional)) p.wait() else: # Start up rifle rifle = Rifle(conf_path) rifle.reload_config() #print(rifle.list_commands(sys.argv[1:])) if options.l: for count, cmd, label, flags in rifle.list_commands(positional): print("%d:%s:%s:%s" % (count, label or '', flags, cmd)) else: result = rifle.execute(positional, number=number, label=label, flags=options.f) if result == ASK_COMMAND: # TODO: implement interactive asking for file type? print("Unknown file type: %s" % rifle._get_mimetype(positional[0])) if __name__ == '__main__': if 'RANGER_DOCTEST' in os.environ: import doctest doctest.testmod() else: main()