diff --git a/share/qtcreator/templates/wizards/projects/cpplibrary/lib.cpp b/share/qtcreator/templates/wizards/projects/cpplibrary/lib.cpp index dcdacae6d34..6eb6c86faab 100644 --- a/share/qtcreator/templates/wizards/projects/cpplibrary/lib.cpp +++ b/share/qtcreator/templates/wizards/projects/cpplibrary/lib.cpp @@ -11,7 +11,7 @@ : %{BaseClassName}(parent) { } -%{JS: '%{PluginMethods}'.split('|').map(s => '\n' + s.replace(/([a-zA-Z0-9]+\()/, '%{CN}::$1') + '\n\u007B\n static_assert(false, "You need to implement this function");\n\u007D').join('\n')}\ +%{JS: '%{PluginMethods}'.split('|').map(function(s) { return '\\n' + s.replace(/([a-zA-Z0-9]+\\()/, '%{CN}::$1') + '\\n\{\\n static_assert(false, "You need to implement this function");\\n\}'; \}).join('\\n')}\ @endif %{JS: Cpp.closeNamespaces('%{Class}')}\ diff --git a/share/qtcreator/templates/wizards/projects/cpplibrary/lib.h b/share/qtcreator/templates/wizards/projects/cpplibrary/lib.h index 4a5d1247a4a..ae2c90a3131 100644 --- a/share/qtcreator/templates/wizards/projects/cpplibrary/lib.h +++ b/share/qtcreator/templates/wizards/projects/cpplibrary/lib.h @@ -36,7 +36,7 @@ public: explicit %{CN}(QObject *parent = nullptr); private: -%{JS: '%{PluginMethods}'.split('|').map(s => ' ' + s + ' override;').join('\n')} +%{JS: '%{PluginMethods}'.split('|').map(function(s) { return ' ' + s + ' override;'; \}).join('\\n')} }; @endif %{JS: Cpp.closeNamespaces('%{Class}')}\ diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp index b39af367d59..161cf44e740 100644 --- a/src/libs/utils/stringutils.cpp +++ b/src/libs/utils/stringutils.cpp @@ -143,7 +143,7 @@ bool AbstractMacroExpander::expandNestedMacros(const QString &str, int *pos, QSt varName.reserve(strLen - i); for (; i < strLen; prev = c) { c = str.at(i++); - if (c == '\\' && i < strLen && validateVarName(varName)) { + if (c == '\\' && i < strLen) { c = str.at(i++); // For the replacement, do not skip the escape sequence when followed by a digit. // This is needed for enabling convenient capture group replacement, diff --git a/src/plugins/coreplugin/jsexpander.cpp b/src/plugins/coreplugin/jsexpander.cpp index 5aa9279c7c6..4ee72752e59 100644 --- a/src/plugins/coreplugin/jsexpander.cpp +++ b/src/plugins/coreplugin/jsexpander.cpp @@ -111,7 +111,9 @@ void JsExpander::registerForExpander(Utils::MacroExpander *macroExpander) "JS", QCoreApplication::translate("Core::JsExpander", "Evaluate simple JavaScript statements.
" - "The statements may not contain '{' nor '}' characters."), + "Literal '}' characters must be escaped as \"\\}\", " + "'\\' characters must be escaped as \"\\\\\", " + "and \"%{\" must be escaped as \"%\\{\"."), [this](QString in) -> QString { QString errorMessage; QString result = evaluate(in, &errorMessage); diff --git a/tests/auto/utils/stringutils/tst_stringutils.cpp b/tests/auto/utils/stringutils/tst_stringutils.cpp index 8e51c893009..98e04185ab3 100644 --- a/tests/auto/utils/stringutils/tst_stringutils.cpp +++ b/tests/auto/utils/stringutils/tst_stringutils.cpp @@ -68,6 +68,14 @@ public: *ret = "bar"; return true; } + if (name == "JS:with } inside") { + *ret = "yay"; + return true; + } + if (name == "JS:literal%{") { + *ret = "hurray"; + return true; + } return false; } }; @@ -158,7 +166,9 @@ void tst_StringUtils::testMacroExpander_data() {"%{hihi//./c}", "ccc"}, {"%{hihi/(.)(.)r/\\2\\1c}", "abc"}, // no escape for capture groups {"%{hihi/b/c/d}", "c/dar"}, - {"%{hihi/a/e{\\}e}", "be{}er"}, // escape closing brace + {"%{hihi/a/e{\\}e}", "be{}er"}, // escape closing brace + {"%{JS:with \\} inside}", "yay"}, // escape closing brace also in JS: + {"%{JS:literal%\\{}", "hurray"}, {"%{slash/o\\/b/ol's c}", "fool's car"}, {"%{sl\\/sh/(.)(a)(.)/\\2\\1\\3as}", "salsash"}, // escape in variable name {"%{JS:foo/b/c}", "%{JS:foo/b/c}"}, // No replacement for JS (all considered varName)