summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/__init__.py1
-rw-r--r--ranger/api/commands.py26
-rwxr-xr-xranger/config/commands.py6
-rw-r--r--ranger/gui/widgets/console.py8
4 files changed, 31 insertions, 10 deletions
diff --git a/ranger/__init__.py b/ranger/__init__.py
index e497ae06..0cb94a69 100644
--- a/ranger/__init__.py
+++ b/ranger/__init__.py
@@ -25,6 +25,7 @@ TICKS_BEFORE_COLLECTING_GARBAGE = 100
 TIME_BEFORE_FILE_BECOMES_GARBAGE = 1200
 MAX_RESTORABLE_TABS = 3
 MACRO_DELIMITER = '%'
+MACRO_DELIMITER_ESC = '%%'
 DEFAULT_PAGER = 'less'
 USAGE = '%prog [options] [path]'
 VERSION = 'ranger-master %s\n\nPython %s' % (__version__, sys.version)
diff --git a/ranger/api/commands.py b/ranger/api/commands.py
index 7f5ce810..e486d234 100644
--- a/ranger/api/commands.py
+++ b/ranger/api/commands.py
@@ -13,6 +13,7 @@ from ranger.api import LinemodeBase, hook_init, hook_ready, register_linemode  #
 # pylint: enable=unused-import
 
 import ranger
+from ranger import MACRO_DELIMITER, MACRO_DELIMITER_ESC
 from ranger.core.shared import FileManagerAware
 from ranger.ext.lazy_property import lazy_property
 
@@ -22,6 +23,25 @@ _SETTINGS_RE = re.compile(r'^\s*([^\s]+?)=(.*)$')
 _ALIAS_LINE_RE = re.compile(r'(\s+)')
 
 
+def _command_init(cls):
+    # Escape macros for tab completion
+    if cls.resolve_macros:
+        tab_old = cls.tab
+
+        def tab(self, tabnum):
+            results = tab_old(self, tabnum)
+            if results is None:
+                return None
+            elif isinstance(results, str):
+                return results.replace(MACRO_DELIMITER, MACRO_DELIMITER_ESC)
+            elif hasattr(results, '__iter__'):
+                return (result.replace(MACRO_DELIMITER, MACRO_DELIMITER_ESC) for result in results)
+            return None
+        setattr(cls, 'tab', tab)
+
+    return cls
+
+
 class CommandContainer(FileManagerAware):
 
     def __init__(self):
@@ -37,13 +57,13 @@ class CommandContainer(FileManagerAware):
         except KeyError:
             self.fm.notify('alias failed: No such command: {0}'.format(cmd_name), bad=True)
             return None
-        self.commands[name] = command_alias_factory(name, cmd, full_command)
+        self.commands[name] = _command_init(command_alias_factory(name, cmd, full_command))
 
     def load_commands_from_module(self, module):
         for var in vars(module).values():
             try:
                 if issubclass(var, Command) and var != Command:
-                    self.commands[var.get_name()] = var
+                    self.commands[var.get_name()] = _command_init(var)
             except TypeError:
                 pass
 
@@ -53,7 +73,7 @@ class CommandContainer(FileManagerAware):
                 continue
             attribute = getattr(obj, attribute_name)
             if hasattr(attribute, '__call__'):
-                self.commands[attribute_name] = command_function_factory(attribute)
+                self.commands[attribute_name] = _command_init(command_function_factory(attribute))
 
     def get_command(self, name, abbrev=True):
         if abbrev:
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 6fa5b904..aa955605 100755
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -852,9 +852,11 @@ class rename_append(Command):
         self._flag_remove = 'r' in flags
 
     def execute(self):
+        from ranger import MACRO_DELIMITER, MACRO_DELIMITER_ESC
+
         tfile = self.fm.thisfile
-        relpath = tfile.relative_path.replace('%', '%%')
-        basename = tfile.basename.replace('%', '%%')
+        relpath = tfile.relative_path.replace(MACRO_DELIMITER, MACRO_DELIMITER_ESC)
+        basename = tfile.basename.replace(MACRO_DELIMITER, MACRO_DELIMITER_ESC)
 
         if basename.find('.') <= 0:
             self.fm.open_console('rename ' + relpath)
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index 5d7f6b0e..b3fa7151 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -465,14 +465,12 @@ class Console(Widget):  # pylint: disable=too-many-instance-attributes,too-many-
         if self.tab_deque is None:
             tab_result = self._get_tab(tabnum)
 
-            if isinstance(tab_result, str):
+            if tab_result is None:
+                pass
+            elif isinstance(tab_result, str):
                 self.line = tab_result
                 self.pos = len(tab_result)
                 self.on_line_change()
-
-            elif tab_result is None:
-                pass
-
             elif hasattr(tab_result, '__iter__'):
                 self.tab_deque = deque(tab_result)
                 self.tab_deque.appendleft(self.line)