diff options
author | hut <hut@lavabit.com> | 2012-03-16 00:18:34 +0100 |
---|---|---|
committer | hut <hut@lavabit.com> | 2012-03-16 00:18:34 +0100 |
commit | 6f8ca83b677412aee792e55d24c62b7d24d4ea84 (patch) | |
tree | 5d57326482702b964281545f82ee289f8aa2cb77 | |
parent | 4dc87fa8ab83844707659e1f82e1e9726279a8a2 (diff) | |
download | ranger-6f8ca83b677412aee792e55d24c62b7d24d4ea84.tar.gz |
implemented "rifle", a new file launcher
ranger/ext/rifle.py is a standalone program that works without ranger. The configuration is not in python anymore, thus is easier to understand, modify and parse.
-rw-r--r-- | ranger/core/actions.py | 24 | ||||
-rw-r--r-- | ranger/core/fm.py | 15 | ||||
-rw-r--r-- | ranger/defaults/rc.conf | 2 | ||||
-rw-r--r-- | ranger/defaults/rifle.conf | 122 | ||||
-rw-r--r-- | ranger/ext/rifle.py | 145 | ||||
-rw-r--r-- | ranger/gui/widgets/browserview.py | 16 | ||||
-rw-r--r-- | ranger/gui/widgets/console.py | 1 |
7 files changed, 317 insertions, 8 deletions
diff --git a/ranger/core/actions.py b/ranger/core/actions.py index 91261207..5b824476 100644 --- a/ranger/core/actions.py +++ b/ranger/core/actions.py @@ -273,8 +273,10 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): mode is a positive integer. Both flags and mode specify how the program is run.""" + mode = kw['mode'] if 'mode' in kw else 0 + # ranger can act as a file chooser when running with --choosefile=... - if ('mode' not in kw or kw['mode'] == 0) and 'app' not in kw: + if mode == 0 and 'label' not in kw: if ranger.arg.choosefile: open(ranger.arg.choosefile, 'w').write(self.fm.env.cf.path) @@ -298,9 +300,14 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): files = [self.fm.env.cf] self.signal_emit('execute.before', keywords=kw) + filenames = [f.path for f in files] + mimetype = files[0].mimetype if files else None + label = kw['label'] if 'label' in kw else None try: - return self.run(files=list(files), **kw) + self.ui.suspend() + return self.rifle.execute(filenames, mode, label, mimetype) finally: + self.ui.initialize() self.signal_emit('execute.after') # -------------------------- @@ -467,14 +474,14 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): return self.run(cmd, **kw) def edit_file(self, file=None): - """Calls execute_file with the current file and app='editor'""" + """Calls execute_file with the current file and label='editor'""" if file is None: file = self.env.cf elif isinstance(file, str): file = File(os.path.expanduser(file)) if file is None: return - self.execute_file(file, app = 'editor') + self.execute_file(file, label='editor') def toggle_option(self, string): """Toggle a boolean option named <string>""" @@ -679,6 +686,15 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): def hide_bookmarks(self): self.ui.browser.draw_bookmarks = False + def draw_possible_programs(self): + selection = [f.path for f in self.env.get_selection()] + programs = self.rifle.list_commands(selection) + programs = ['%s | %s' % program[0:2] for program in programs] + self.ui.browser.draw_info = programs + + def hide_console_info(self): + self.ui.browser.draw_info = False + # -------------------------- # -- Pager # -------------------------- diff --git a/ranger/core/fm.py b/ranger/core/fm.py index 83eec582..77c0d7cc 100644 --- a/ranger/core/fm.py +++ b/ranger/core/fm.py @@ -20,6 +20,7 @@ from ranger.gui.ui import UI from ranger.container.bookmarks import Bookmarks from ranger.core.runner import Runner from ranger.ext.get_executables import get_executables +from ranger.ext.rifle import Rifle from ranger.fsobject import Directory from ranger.ext.signals import SignalDispatcher from ranger import __version__ @@ -52,6 +53,14 @@ class FM(Actions, SignalDispatcher): def initialize(self): """If ui/bookmarks are None, they will be initialized here.""" + + if not ranger.arg.clean and os.path.isfile(self.confpath('rifle.conf')): + rifleconf = self.confpath('rifle.conf') + else: + rifleconf = self.relpath('defaults/rifle.conf') + self.rifle = Rifle(rifleconf) + self.rifle.reload_config() + if self.bookmarks is None: if ranger.arg.clean: bookmarkfile = None @@ -118,8 +127,8 @@ class FM(Actions, SignalDispatcher): shutil.copy(self.relpath(_from), self.confpath(to)) except Exception as e: sys.stderr.write(" ERROR: %s\n" % str(e)) - if which == 'apps' or which == 'all': - copy('defaults/apps.py', 'apps.py') + if which == 'rifle' or which == 'all': + copy('defaults/rifle.conf', 'rifle.conf') if which == 'commands' or which == 'all': copy('defaults/commands.py', 'commands.py') if which == 'rc' or which == 'all': @@ -131,7 +140,7 @@ class FM(Actions, SignalDispatcher): os.chmod(self.confpath('scope.sh'), os.stat(self.confpath('scope.sh')).st_mode | stat.S_IXUSR) if which not in \ - ('all', 'apps', 'scope', 'commands', 'rc', 'options'): + ('all', 'rifle', 'scope', 'commands', 'rc', 'options'): sys.stderr.write("Unknown config file `%s'\n" % which) def confpath(self, *paths): diff --git a/ranger/defaults/rc.conf b/ranger/defaults/rc.conf index 77ffa5c3..5ac2763a 100644 --- a/ranger/defaults/rc.conf +++ b/ranger/defaults/rc.conf @@ -53,7 +53,7 @@ map ! console shell map @ console -p6 shell %%s map # console shell -p map s console shell -map r console open_with +map r chain draw_possible_programs; console open_with map f console find map cd console cd diff --git a/ranger/defaults/rifle.conf b/ranger/defaults/rifle.conf new file mode 100644 index 00000000..5af05a99 --- /dev/null +++ b/ranger/defaults/rifle.conf @@ -0,0 +1,122 @@ +#------------------------------------------- +# Misc +#------------------------------------------- +name [xX]modmap = xmodmap "$1" +ext 1 = man "$1" +ext s[wmf]c, has zsnes, X = zsnes "$1" +ext nes, has fceux, X = fceux "$1" +ext exe = wine "$1" +name ^[mM]akefile$ = make + +mime ^text = "$EDITOR" -- "$@" +ext xml|csv|tex = "$EDITOR" -- "$@" + +#-------------------------------------------- +# Code +#------------------------------------------- + +label execute, ext py = python -- "$1" +label execute, ext pl = perl -- "$1" +label execute, ext rb = ruby -- "$1" +label execute, ext sh = bash -- "$1" +label execute, ext c = gcc -o /tmp/a.out "$1" && /tmp/a.out +label execute, ext tex = pdflatex -- "$1" && "$rifle" "$(echo -n "$1" | sed 's/\..*$//')".pdf + +label compile, ext c = gcc -o /tmp/a.out "$1" + +#-------------------------------------------- +# Audio without X +#------------------------------------------- +mime ^audio, terminal, has mplayer = mplayer -- "$@" +mime ^audio, terminal, has mplayer2 = mplayer2 -- "$@" + +#-------------------------------------------- +# Video/Audio with a GUI +#------------------------------------------- + +mime ^video|audio, has gmplayer, X, flag f = gmplayer -- "$@" +mime ^video|audio, has smplayer, X, flag f = smplayer -- "$@" +mime ^video, has mplayer2, X, flag f = mplayer2 -- "$@" +mime ^video, has mplayer, X, flag f = mplayer -- "$@" +mime ^video, has mplayer, X, flag f = mplayer -fs -- "$@" +mime ^video, has mplayer, X, flag f = mplayer -mixer software -- "$@" +mime ^video|audio, has vlc, X, flag f = vlc -- "$@" +mime ^video|audio, has totem, X, flag f = totem -- "$@" +mime ^video|audio, has totem, X, flag f = totem --fullscreen -- "$@" + +#-------------------------------------------- +# Video without X: +#------------------------------------------- +mime ^video, terminal, has mplayer2 = mplayer2 -- "$@" +mime ^video, terminal, has mplayer = mplayer -- "$@" + +ext midi?, terminal, has wildmidi = wildmidi -- "$@" + +#------------------------------------------- +# Image Viewing: +#------------------------------------------- +mime ^image, has eog, X, flag f = eog -- "$@" +mime ^image, has sxiv, X, flag f = sxiv -- "$@" +mime ^image, has feh, X, flag f = feh -- "$@" +mime ^image, has mirage, X, flag f = mirage -- "$@" +mime ^image, has gimp, X, flag f = gimp -- "$@" + +#------------------------------------------- +# Documents +#------------------------------------------- +ext pdf, has llpp, X, flag f = llpp "$@" +ext pdf, has zathura, X, flag f = zathura -- "$@" +ext pdf, has mupdf, X, flag f = mupdf -- "$@" +ext pdf, has apvlv, X, flag f = apvlv -- "$@" +ext pdf, has xpdf, X, flag f = xpdf -- "$@" +ext pdf, has evince, X, flag f = evince -- "$@" +ext pdf, has okular, X, flag f = okular -- "$@" +ext pdf, has epdfview, X, flag f = epdfview -- "$@" + +ext od[tspfg]|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has gnumeric, X, flag f = gnumeric -- "$@" +ext od[tspfg]|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has kspread, X, flag f = kspread -- "$@" +ext od[tspfg]|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has libreoffice, X, flag f = libreoffice -- "$@" +ext od[tspfg]|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has soffice, X, flag f = soffice -- "$@" +ext od[tspfg]|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has ooffice, X, flag f = ooffice -- "$@" + +ext djvu, has evince, X, flag f = evince -- "$@" + +#------------------------------------------- +# Archives +#------------------------------------------- +ext 7z|ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz|iso|jar|msi|pkg|rar|shar|tar|tgz|xar|xpi|xz|zip, has aunpack, flag p = als -- "$@" +ext 7z|ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz|iso|jar|msi|pkg|rar|shar|tar|tgz|xar|xpi|xz|zip, has aunpack = aunpack -- "$@" +ext tar|gz, has tar = tar vvtf "$@" +ext tar|gz, has tar = tar vvxf "$@" + +#------------------------------------------- +# Websites +#------------------------------------------- +ext x?html?, has surf, X, flag f = surf -- "$@" +ext x?html?, has vimprobable, X, flag f = vimprobable -- "$@" +ext x?html?, has vimprobable2, X, flag f = vimprobable2 -- "$@" +ext x?html?, has jumanji, X, flag f = jumanji -- "$@" +ext x?html?, has luakit, X, flag f = luakit -- "$@" +ext x?html?, has uzbl, X, flag f = uzbl -- "$@" +ext x?html?, has firefox, X, flag f = firefox -- "$@" +ext x?html?, has seamonkey, X, flag f = seamonkey -- "$@" +ext x?html?, has iceweasel, X, flag f = iceweasel -- "$@" +ext x?html?, has opera, X, flag f = opera -- "$@" +ext x?html?, has midori, X, flag f = midori -- "$@" +ext x?html?, has epiphany, X, flag f = epiphany -- "$@" +ext x?html?, has konqueror, X, flag f = konqueror -- "$@" +ext x?html?, has elinks, terminal = elinks "$@" +ext x?html?, has links2, terminal = links2 -- "$@" +ext x?html?, has links, terminal = links -- "$@" +ext x?html?, has lynx, terminal = lynx -- "$@" +ext x?html?, has w3m, terminal = w3m -- "$@" + +#------------------------------------------- +# Misc +#------------------------------------------- +label wallpaper, mime ^image, X = feh --bg-scale "$1" +label wallpaper, mime ^image, X = feh --bg-tile "$1" +label wallpaper, mime ^image, X = feh --bg-center "$1" +label wallpaper, mime ^image, X = feh --bg-fill "$1" + +label editor = "$EDITOR" -- "$@" diff --git a/ranger/ext/rifle.py b/ranger/ext/rifle.py new file mode 100644 index 00000000..563968ef --- /dev/null +++ b/ranger/ext/rifle.py @@ -0,0 +1,145 @@ +# Copyright (C) 2012 Roman Zimbelmann <romanz@lavabit.com> +# This software is distributed under the terms of the GNU GPL version 3. + +import os.path +import re, sys +from subprocess import Popen, PIPE +from ranger.ext.shell_escape import shell_quote +from ranger.ext.spawn import spawn +from ranger.ext.get_executables import get_executables +import time + +def _is_terminal(): + try: + os.ttyname(0) + os.ttyname(1) + os.ttyname(2) + except: + return False + return True + +class Rifle(object): + delimiter1 = '=' + delimiter2 = ',' + + def __init__(self, config_file): + self.config_file = config_file + self._app_flags = False + + def reload_config(self, config_file=None): + if config_file is None: + config_file = self.config_file + f = open(config_file, 'r') + self.rules = [] + for line in f: + if line.startswith('#') or line == '\n': + continue + line = line.strip() + if self.delimiter1 not in line: + print("Syntax error foo") + tests, command = line.split(self.delimiter1, 1) + tests = tests.split(self.delimiter2) + tests = tuple(tuple(f.strip().split(None, 1)) for f in tests) + tests = tuple(tests) + command = command.strip() + self.rules.append((command, tests)) + + def _eval_rule(self, rule, files, label): + function = rule[0] + argument = rule[1] if len(rule) > 1 else '' + + self._app_flags = '' + + if function == 'ext': + extension = os.path.basename(files[0]).rsplit('.', 1)[-1] + return bool(re.search('^' + argument + '$', extension)) + if function == 'name': + return bool(re.search(argument, os.path.basename(files[0]))) + if function == 'path': + return bool(re.search(argument, os.path.abspath(files[0]))) + if function == 'mime': + return bool(re.search(argument, self._get_mimetype(files[0]))) + if function == 'has': + return argument in get_executables() + if function == 'terminal': + return _is_terminal() + if function == 'label': + if label: + self._found_label = argument == label + else: + # don't care about label in this case + self._found_label = True + return self._found_label + if function == 'flag': + self._app_flags = argument + return True + if function == 'X': + return 'DISPLAY' in os.environ + if function == 'else': + return True + + def _get_mimetype(self, fname): + if self._mimetype: + return self._mimetype + mimetype = spawn("file", "--mime-type", "-Lb", fname) + self._mimetype = mimetype + return mimetype + + def _build_command(self, files, action): + flags = self._app_flags + _filenames = "' '".join(f.replace("'", "'\\\''") for f in files) + command = "set -- '%s'" % _filenames + '\n' + if 'p' in flags and not 'f' in flags and is_terminal(): + action += '| less' + if 'f' in flags: + action = "nohup %s >&/dev/null &" % action + command += action + return command + + def list_commands(self, files, mimetype=None): + self._mimetype = mimetype + command = None + count = 0 + result = [] + t = time.time() + for cmd, tests in self.rules: + for test in tests: + if not self._eval_rule(test, files, None): + break + else: + result.append((count, cmd, self._app_flags)) + count += 1 + #sys.stderr.write("%f\n" % (time.time() - t)) + return result + + def execute(self, files, number=0, label=None, mimetype=None): + self._mimetype = mimetype + self._found_label = True + command = None + count = 0 + for cmd, tests in self.rules: + if label: + self._found_label = False + for test in tests: + if not self._eval_rule(test, files, label): + #print("fails on test %s" % str(test)) + break + else: + if not self._found_label: + pass + elif count != number: + count += 1 + else: + command = self._build_command(files, cmd) + break + #print(command) + if command is not None: + p = Popen(command, shell=True) + p.wait() + +if __name__ == '__main__': + import sys + rifle = Rifle(os.environ['HOME'] + '/.config/ranger/rifle.conf') + rifle.reload_config() + #print(rifle.list_commands(sys.argv[1:])) + rifle.execute(sys.argv[1:], number=0) diff --git a/ranger/gui/widgets/browserview.py b/ranger/gui/widgets/browserview.py index b5e7210c..89d099ea 100644 --- a/ranger/gui/widgets/browserview.py +++ b/ranger/gui/widgets/browserview.py @@ -19,6 +19,7 @@ class BrowserView(Widget, DisplayableContainer): need_clear = False old_collapse = False draw_hints = False + draw_info = False def __init__(self, win, ratios, preview = True): DisplayableContainer.__init__(self, win) @@ -98,6 +99,8 @@ class BrowserView(Widget, DisplayableContainer): self._draw_bookmarks() elif self.draw_hints: self._draw_hints() + elif self.draw_info: + self._draw_info(self.draw_info) def finalize(self): if self.pager.visible: @@ -185,6 +188,19 @@ class BrowserView(Widget, DisplayableContainer): self.win.chgat(ystart - 1, 0, curses.A_UNDERLINE) + def _draw_info(self, lines): + self.need_clear = True + hei = min(self.hei - 1, len(lines)) + ystart = self.hei - hei + i = ystart + whitespace = " " * self.wid + for line in lines: + if i >= self.hei: + break + self.addstr(i, 0, whitespace) + self.addnstr(i, 0, line, self.wid) + i += 1 + def _draw_hints(self): self.need_clear = True hints = [] diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py index c3623c51..06552ef6 100644 --- a/ranger/gui/widgets/console.py +++ b/ranger/gui/widgets/console.py @@ -119,6 +119,7 @@ class Console(Widget): except: pass self.last_cursor_mode = None + self.fm.hide_console_info() self.add_to_history() self.tab_deque = None self.clear() |