From befaf4f6dc218e2e3398bc587654982156e327fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sun, 14 Aug 2016 13:41:08 +0200 Subject: [PATCH] fix nested expansion of {variables} in command args --- qutebrowser/commands/runners.py | 27 +++++++++++++++++---------- tests/end2end/features/misc.feature | 8 ++++++++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py index 6a132598d..970fbadbe 100644 --- a/qutebrowser/commands/runners.py +++ b/qutebrowser/commands/runners.py @@ -21,6 +21,7 @@ import collections import traceback +import re from PyQt5.QtCore import pyqtSlot, QUrl, QObject @@ -50,26 +51,32 @@ def _current_url(tabbed_browser): def replace_variables(win_id, arglist): """Utility function to replace variables like {url} in a list of args.""" variables = { - '{url}': lambda: _current_url(tabbed_browser).toString( + 'url': lambda: _current_url(tabbed_browser).toString( QUrl.FullyEncoded | QUrl.RemovePassword), - '{url:pretty}': lambda: _current_url(tabbed_browser).toString( + 'url:pretty': lambda: _current_url(tabbed_browser).toString( QUrl.RemovePassword), - '{clipboard}': utils.get_clipboard, - '{primary}': lambda: utils.get_clipboard(selection=True), + 'clipboard': utils.get_clipboard, + 'primary': lambda: utils.get_clipboard(selection=True), } values = {} args = [] tabbed_browser = objreg.get('tabbed-browser', scope='window', window=win_id) + def repl_cb(matchobj): + """Return replacement for given match.""" + var = matchobj.group("var") + if var not in values: + values[var] = variables[var]() + return values[var] + repl_pattern = re.compile("{(?P" + "|".join(variables.keys()) + ")}") + try: for arg in arglist: - for var, func in variables.items(): - if var in arg: - if var not in values: - values[var] = func() - arg = arg.replace(var, values[var]) - args.append(arg) + # using re.sub with callback function replaces all variables in a + # single pass and avoids expansion of nested variables (e.g. + # "{url}" from clipboard is not expanded) + args.append(repl_pattern.sub(repl_cb, arg)) except utils.ClipboardError as e: raise cmdexc.CommandError(e) return args diff --git a/tests/end2end/features/misc.feature b/tests/end2end/features/misc.feature index 41b2e06f7..f7623f660 100644 --- a/tests/end2end/features/misc.feature +++ b/tests/end2end/features/misc.feature @@ -537,3 +537,11 @@ Feature: Various utility commands. And I put "foo" into the clipboard And I run :message-info {clipboard}bar{url} Then the message "foobarhttp://localhost:*/hello.txt" should be shown + + @xfail_norun + Scenario: {url} in clipboard should not be expanded + When I open data/hello.txt + # FIXME: {url} should be escaped, otherwise it is replaced before it enters clipboard + And I put "{url}" into the clipboard + And I run :message-info {clipboard}bar{url} + Then the message "{url}barhttp://localhost:*/hello.txt" should be shown