about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/api/commands.py1
-rw-r--r--ranger/core/actions.py90
-rw-r--r--ranger/defaults/commands.py2
-rw-r--r--ranger/gui/widgets/console.py10
4 files changed, 52 insertions, 51 deletions
diff --git a/ranger/api/commands.py b/ranger/api/commands.py
index 74a8ff99..1941de2c 100644
--- a/ranger/api/commands.py
+++ b/ranger/api/commands.py
@@ -86,6 +86,7 @@ class Command(FileManagerAware):
 	name = None
 	allow_abbrev = True
 	resolve_macros = True
+	escape_macros_for_shell = False
 	quantifier = None
 	_shifted = 0
 
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index d0e21fbc..cde80431 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -98,35 +98,46 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 	def execute_console(self, string='', wildcards=[], quantifier=None):
 		"""Execute a command for the console"""
 		command_name = string.split()[0]
-		try:
-			cmd_class = self.commands.get_command(command_name)
-		except:
+		cmd_class = self.commands.get_command(command_name, abbrev=False)
+		if cmd_class is None:
 			self.notify("Command not found: `%s'" % command_name, bad=True)
-		else:
-			cmd = cmd_class(string)
-			if cmd.resolve_macros and _MacroTemplate.delimiter in string:
-				macros = dict(('any%d'%i, key_to_string(char)) \
-						for i, char in enumerate(wildcards))
-				if 'any0' in macros:
-					macros['any'] = macros['any0']
-				try:
-					string = self.substitute_macros(string, additional=macros)
-				except ValueError as e:
-					if ranger.arg.debug:
-						raise
-					else:
-						return self.notify(e)
+			return
+		cmd = cmd_class(string)
+		if cmd.resolve_macros and _MacroTemplate.delimiter in string:
+			macros = dict(('any%d'%i, key_to_string(char)) \
+					for i, char in enumerate(wildcards))
+			if 'any0' in macros:
+				macros['any'] = macros['any0']
 			try:
-				cmd_class(string, quantifier=quantifier).execute()
-			except Exception as e:
+				string = self.substitute_macros(string, additional=macros,
+						escape=cmd.escape_macros_for_shell)
+			except ValueError as e:
 				if ranger.arg.debug:
 					raise
 				else:
-					self.notify(e)
-
-	def substitute_macros(self, string, additional=dict()):
-		result = _MacroTemplate(string).safe_substitute(self._get_macros(),
-				**additional)
+					return self.notify(e)
+		try:
+			cmd_class(string, quantifier=quantifier).execute()
+		except Exception as e:
+			if ranger.arg.debug:
+				raise
+			else:
+				self.notify(e)
+
+	def substitute_macros(self, string, additional=dict(), escape=False):
+		macros = self._get_macros()
+		macros.update(additional)
+		if escape:
+			for key, value in macros.items():
+				if isinstance(value, list):
+					macros[key] = " ".join(shell_quote(s) for s in value)
+				elif value != MACRO_FAIL:
+					macros[key] = shell_quote(value)
+		else:
+			for key, value in macros.items():
+				if isinstance(value, list):
+					macros[key] = " ".join(value)
+		result = _MacroTemplate(string).safe_substitute(macros)
 		if MACRO_FAIL in result:
 			raise ValueError("Could not apply macros to `%s'" % string)
 		return result
@@ -134,25 +145,22 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 	def _get_macros(self):
 		macros = {}
 
-		macros['rangerdir'] = shell_quote(ranger.RANGERDIR)
+		macros['rangerdir'] = ranger.RANGERDIR
 
 		if self.fm.env.cf:
-			macros['f'] = shell_quote(self.fm.env.cf.basename)
+			macros['f'] = self.fm.env.cf.basename
 		else:
 			macros['f'] = MACRO_FAIL
 
-		macros['s'] = ' '.join(shell_quote(fl.basename) \
-				for fl in self.fm.env.get_selection())
+		macros['s'] = [fl.basename for fl in self.fm.env.get_selection()]
 
-		macros['c'] = ' '.join(shell_quote(fl.path)
-				for fl in self.fm.env.copy)
+		macros['c'] = [fl.path for fl in self.fm.env.copy]
 
-		macros['t'] = ' '.join(shell_quote(fl.basename)
-				for fl in self.fm.env.cwd.files
-				if fl.realpath in self.fm.tags)
+		macros['t'] = [fl.basename for fl in self.fm.env.cwd.files
+				if fl.realpath in self.fm.tags]
 
 		if self.fm.env.cwd:
-			macros['d'] = shell_quote(self.fm.env.cwd.path)
+			macros['d'] = self.fm.env.cwd.path
 		else:
 			macros['d'] = '.'
 
@@ -165,11 +173,10 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 				continue
 			tab_dir = self.fm.env.get_directory(tab_dir_path)
 			i = str(i)
-			macros[i + 'd'] = shell_quote(tab_dir_path)
-			macros[i + 's'] = ' '.join(shell_quote(fl.path)
-				for fl in tab_dir.get_selection())
+			macros[i + 'd'] = tab_dir_path
+			macros[i + 's'] = [fl.path for fl in tab_dir.get_selection()]
 			if tab_dir.pointed_obj:
-				macros[i + 'f'] = shell_quote(tab_dir.pointed_obj.path)
+				macros[i + 'f'] = tab_dir.pointed_obj.path
 			else:
 				macros[i + 'f'] = MACRO_FAIL
 
@@ -189,13 +196,12 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 			next_tab_path = self.fm.tabs[first_tab]
 		next_tab = self.fm.env.get_directory(next_tab_path)
 
-		macros['D'] = shell_quote(next_tab)
+		macros['D'] = next_tab
 		if next_tab.pointed_obj:
-			macros['F'] = shell_quote(next_tab.pointed_obj.path)
+			macros['F'] = next_tab.pointed_obj.path
 		else:
 			macros['F'] = MACRO_FAIL
-		macros['S'] = ' '.join(shell_quote(fl.path)
-			for fl in next_tab.get_selection())
+		macros['S'] = [fl.path for fl in next_tab.get_selection()]
 
 		return macros
 
diff --git a/ranger/defaults/commands.py b/ranger/defaults/commands.py
index 55de33c1..cd76896c 100644
--- a/ranger/defaults/commands.py
+++ b/ranger/defaults/commands.py
@@ -171,6 +171,8 @@ class search_inc(Command):
 
 
 class shell(Command):
+	escape_macros_for_shell = True
+
 	def execute(self):
 		line = parse(self.line)
 		if line.chunk(1) and line.chunk(1)[0] == '-':
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index 5fcea9d3..ce801a7f 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -294,15 +294,7 @@ class Console(Widget):
 
 	def execute(self, cmd=None):
 		self.allow_close = True
-		if cmd is None:
-			cmd = self._get_cmd()
-
-		if cmd:
-			try:
-				cmd.execute()
-			except Exception as error:
-				self.fm.notify(error)
-
+		self.fm.execute_console(self.line)
 		if self.allow_close:
 			self.close(trigger_cancel_function=False)