about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/ext/shell_escape.py20
-rw-r--r--ranger/gui/widgets/console.py36
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):
 	"""