diff options
-rw-r--r-- | ranger/ext/shell_escape.py | 20 | ||||
-rw-r--r-- | ranger/gui/widgets/console.py | 36 |
2 files changed, 51 insertions, 5 deletions
diff --git a/ranger/ext/shell_escape.py b/ranger/ext/shell_escape.py new file mode 100644 index 00000000..8a78fc53 --- /dev/null +++ b/ranger/ext/shell_escape.py @@ -0,0 +1,20 @@ +# Copyright (c) 2009, 2010 hut <hut@lavabit.com> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +""" +A function to escape metacharacters of arguments for shell commands. +""" + +def shell_escape(string): + return "'" + str(string).replace("'", "'\\''") + "'" diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py index fc413c33..2e0a4ffb 100644 --- a/ranger/gui/widgets/console.py +++ b/ranger/gui/widgets/console.py @@ -14,9 +14,12 @@ """The Console widget implements a vim-like console for entering commands, searching and executing files.""" +import string from . import Widget from ranger import commands from ranger.gui.widgets.console_mode import is_valid_mode, mode_to_class +from ranger import log +from ranger.ext.shell_escape import shell_escape import curses from collections import deque @@ -25,6 +28,12 @@ SEARCH_HISTORY = 1 QUICKOPEN_HISTORY = 2 OPEN_HISTORY = 3 +class CustomTemplate(string.Template): + """A string.Template subclass for use in the OpenConsole""" + delimiter = '%' + idpattern = '[a-z]' + + class Console(Widget): mode = None visible = False @@ -329,10 +338,14 @@ class OpenConsole(Console): The OpenConsole allows you to execute shell commands: !vim * will run vim and open all files in the directory. + %f will be replaced with the basename of the highlighted file + %s will be selected with all files in the selection + There is a special syntax for more control: !d! mplayer will run mplayer with flags (d means detached) !@ mplayer will open the selected files with mplayer + (equivalent to !mplayer %s) those two can be combinated: @@ -351,9 +364,25 @@ class OpenConsole(Console): from subprocess import STDOUT, PIPE command, flags = self._parse() if command: + if CustomTemplate.delimiter in command: + command = self._substitute_metachars(command) + log(command) self.fm.execute_command(command, flags=flags) Console.execute(self) + def _substitute_metachars(self, command): + dct = {} + + if self.fm.env.cf: + dct['f'] = shell_escape(self.fm.env.cf.basename) + else: + dct['f'] = '' + + dct['s'] = ' '.join(shell_escape(fl.basename) \ + for fl in self.fm.env.get_selection()) + + return CustomTemplate(command).safe_substitute(dct) + def _parse(self): if '!' in self.line: flags, cmd = self.line.split('!', 1) @@ -369,14 +398,11 @@ class OpenConsole(Console): add_selection = True if add_selection: - cmd += ' ' + ' '.join(tuple(map(self._shellify, - self.env.get_selection()))) + cmd += ' ' + ' '.join(shell_escape(fl.basename) \ + for fl in self.env.get_selection()) return (cmd, flags) - def _shellify(self, string): - return "'" + str(string).replace("'","'\"'\"'") + "'" - class QuickOpenConsole(ConsoleWithTab): """ |