diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index c4749e2593320bffd6f9ed001bd8f5d3da282cf1..1a279f8ff62d275324ee4a3fe853a7e5ee76af27 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -30,15 +30,294 @@ #include "macroexpander.h" +#include +#include +#include +#include + namespace Utils { +namespace Internal { + +const char kFilePathPostfix[] = ":FilePath"; +const char kPathPostfix[] = ":Path"; +const char kFileNamePostfix[] = ":FileName"; +const char kFileBaseNamePostfix[] = ":FileBaseName"; + +class MacroExpanderPrivate +{ +public: + QHash m_map; + QHash m_prefixMap; + QMap m_descriptions; +}; + +} // Internal + +using namespace Internal; + +/*! + \class Utils::MacroExpander + \brief The MacroExpander class manages \QC wide variables, that a user + can enter into many string settings. The variables are replaced by an actual value when the string + is used, similar to how environment variables are expanded by a shell. + + \section1 Variables + + Variable names can be basically any string without dollar sign and braces, + though it is recommended to only use 7-bit ASCII without special characters and whitespace. + + If there are several variables that contain different aspects of the same object, + it is convention to give them the same prefix, followed by a colon and a postfix + that describes the aspect. + Examples of this are \c{CurrentDocument:FilePath} and \c{CurrentDocument:Selection}. + + When the variable manager is requested to replace variables in a string, it looks for + variable names enclosed in %{ and }, like %{CurrentDocument:FilePath}. + + Environment variables are accessible using the %{Env:...} notation. + For example, to access the SHELL environment variable, use %{Env:SHELL}. + + \note The names of the variables are stored as QByteArray. They are typically + 7-bit-clean. In cases where this is not possible, UTF-8 encoding is + assumed. + + \section1 Providing Variable Values + + Plugins can register variables together with a description through registerVariable(). + A typical setup is to register variables in the Plugin::initialize() function. + + \code + bool MyPlugin::initialize(const QStringList &arguments, QString *errorString) + { + [...] + MacroExpander::registerVariable( + "MyVariable", + tr("The current value of whatever I want.")); + []() -> QString { + QString value; + // do whatever is necessary to retrieve the value + [...] + return value; + } + ); + [...] + } + \endcode -MacroExpander::MacroExpander(const MacroExpander::Resolver &resolver) - : m_resolver(resolver) -{} + For variables that refer to a file, you should use the convenience function + MacroExpander::registerFileVariables(). + The functions take a variable prefix, like \c MyFileVariable, + and automatically handle standardized postfixes like \c{:FilePath}, + \c{:Path} and \c{:FileBaseName}, resulting in the combined variables, such as + \c{MyFileVariable:FilePath}. + + \section1 Providing and Expanding Parametrized Strings + + Though it is possible to just ask the variable manager for the value of some variable in your + code, the preferred use case is to give the user the possibility to parametrize strings, for + example for settings. + + (If you ever think about doing the former, think twice. It is much more efficient + to just ask the plugin that provides the variable value directly, without going through + string conversions, and through the variable manager which will do a large scale poll. To be + more concrete, using the example from the Providing Variable Values section: instead of + calling \c{MacroExpander::value("MyVariable")}, it is much more efficient to just ask directly + with \c{MyPlugin::variableValue()}.) + + \section2 User Interface + + If the string that you want to parametrize is settable by the user, through a QLineEdit or + QTextEdit derived class, you should add a variable chooser to your UI, which allows adding + variables to the string by browsing through a list. See Core::VariableChooser for more + details. + + \section2 Expanding Strings + + Expanding variable values in strings is done by "macro expanders". + Utils::AbstractMacroExpander is the base class for these, and the variable manager + provides an implementation that expands \QC variables through + MacroExpander::macroExpander(). + + There are several different ways to expand a string, covering the different use cases, + listed here sorted by relevance: + \list + \li Using MacroExpander::expandedString(). This is the most comfortable way to get a string + with variable values expanded, but also the least flexible one. If this is sufficient for + you, use it. + \li Using the Utils::expandMacros() functions. These take a string and a macro expander (for which + you would use the one provided by the variable manager). Mostly the same as + MacroExpander::expandedString(), but also has a variant that does the replacement inline + instead of returning a new string. + \li Using Utils::QtcProcess::expandMacros(). This expands the string while conforming to the + quoting rules of the platform it is run on. Use this function with the variable manager's + macro expander if your string will be passed as a command line parameter string to an + external command. + \li Writing your own macro expander that nests the variable manager's macro expander. And then + doing one of the above. This allows you to expand additional "local" variables/macros, + that do not come from the variable manager. + \endlist + +*/ + +/*! + * \internal + */ +MacroExpander::MacroExpander() +{ + d = new MacroExpanderPrivate; +} + +/*! + * \internal + */ +MacroExpander::~MacroExpander() +{ + delete d; +} + +/*! + * \internal + */ bool MacroExpander::resolveMacro(const QString &name, QString *ret) { - return m_resolver(name, ret); + bool found; + *ret = value(name.toUtf8(), &found); + return found; +} + +/*! + * Returns the value of the given \a variable. If \a found is given, it is + * set to true if the variable has a value at all, false if not. + */ +QString MacroExpander::value(const QByteArray &variable, bool *found) +{ + StringFunction sf = d->m_map.value(variable); + if (sf) { + if (found) + *found = true; + return sf(); + } + + for (auto it = d->m_prefixMap.constBegin(); it != d->m_prefixMap.constEnd(); ++it) { + if (variable.startsWith(it.key())) { + PrefixFunction pf = it.value(); + if (found) + *found = true; + return pf(QString::fromUtf8(variable.mid(it.key().count()))); + } + } + if (found) + *found = false; + + return QString(); +} + +/*! + * Returns \a stringWithVariables with all variables replaced by their values. + * See the MacroExpander overview documentation for other ways to expand variables. + * + * \sa MacroExpander + * \sa macroExpander() + */ +QString MacroExpander::expandedString(const QString &stringWithVariables) +{ + return Utils::expandMacros(stringWithVariables, this); +} + +/*! + * Makes the given string-valued \a prefix known to the variable manager, + * together with a localized \a description. + * + * The \a value PrefixFunction will be called and gets the full variable name + * with the prefix stripped as input. + * + * \sa registerVariables(), registerIntVariable(), registerFileVariables() + */ +void MacroExpander::registerPrefix(const QByteArray &prefix, const QString &description, + const MacroExpander::PrefixFunction &value) +{ + QByteArray tmp = prefix; + if (!tmp.endsWith(':')) + tmp.append(':'); + d->m_descriptions.insert(tmp + "", description); + d->m_prefixMap.insert(tmp, value); +} + +/*! + * Makes the given string-valued \a variable known to the variable manager, + * together with a localized \a description. + * + * \sa registerFileVariables(), registerIntVariable(), registerPrefix() + */ +void MacroExpander::registerVariable(const QByteArray &variable, + const QString &description, const StringFunction &value) +{ + d->m_descriptions.insert(variable, description); + d->m_map.insert(variable, value); +} + +/*! + * Makes the given integral-valued \a variable known to the variable manager, + * together with a localized \a description. + * + * \sa registerVariable(), registerFileVariables(), registerPrefix() + */ +void MacroExpander::registerIntVariable(const QByteArray &variable, + const QString &description, const MacroExpander::IntFunction &value) +{ + const MacroExpander::IntFunction valuecopy = value; // do not capture a reference in a lambda + registerVariable(variable, description, + [valuecopy]() { return QString::number(valuecopy ? valuecopy() : 0); }); +} + +/*! + * Convenience function to register several variables with the same \a prefix, that have a file + * as a value. Takes the prefix and registers variables like \c{prefix:FilePath} and + * \c{prefix:Path}, with descriptions that start with the given \a heading. + * For example \c{registerFileVariables("CurrentDocument", tr("Current Document"))} registers + * variables such as \c{CurrentDocument:FilePath} with description + * "Current Document: Full path including file name." + * + * \sa registerVariable(), registerIntVariable(), registerPrefix() + */ +void MacroExpander::registerFileVariables(const QByteArray &prefix, + const QString &heading, const StringFunction &base) +{ + registerVariable(prefix + kFilePathPostfix, + QCoreApplication::translate("Utils::MacroExpander", "%1: Full path including file name.").arg(heading), + [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).filePath(); }); + + registerVariable(prefix + kPathPostfix, + QCoreApplication::translate("Utils::MacroExpander", "%1: Full path excluding file name.").arg(heading), + [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).path(); }); + + registerVariable(prefix + kFileNamePostfix, + QCoreApplication::translate("Utils::MacroExpander", "%1: File name without path.").arg(heading), + [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).fileName(); }); + + registerVariable(prefix + kFileBaseNamePostfix, + QCoreApplication::translate("Utils::MacroExpander", "%1: File base name without path and suffix.").arg(heading), + [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).baseName(); }); +} + +/*! + * Returns all registered variable names. + * + * \sa registerVariable() + * \sa registerFileVariables() + */ +QList MacroExpander::variables() +{ + return d->m_descriptions.keys(); +} + +/*! + * Returns the description that was registered for the \a variable. + */ +QString MacroExpander::variableDescription(const QByteArray &variable) +{ + return d->m_descriptions.value(variable); } } // namespace Utils diff --git a/src/libs/utils/macroexpander.h b/src/libs/utils/macroexpander.h index f0f710fde93329d3bff7e15986a8cc3fc604d8cf..2405659dc54ca9b55e12dbb5befb333a1ec9c7bf 100644 --- a/src/libs/utils/macroexpander.h +++ b/src/libs/utils/macroexpander.h @@ -37,17 +37,44 @@ namespace Utils { +namespace Internal { class MacroExpanderPrivate; } + class QTCREATOR_UTILS_EXPORT MacroExpander : public AbstractMacroExpander { public: - typedef std::function Resolver; - - explicit MacroExpander(const Resolver &resolver); + explicit MacroExpander(); + ~MacroExpander(); bool resolveMacro(const QString &name, QString *ret); + QString value(const QByteArray &variable, bool *found = 0); + + QString expandedString(const QString &stringWithVariables); + + typedef std::function PrefixFunction; + typedef std::function StringFunction; + typedef std::function IntFunction; + + void registerPrefix(const QByteArray &prefix, + const QString &description, const PrefixFunction &value); + + void registerVariable(const QByteArray &variable, + const QString &description, const StringFunction &value); + + void registerIntVariable(const QByteArray &variable, + const QString &description, const IntFunction &value); + + void registerFileVariables(const QByteArray &prefix, + const QString &heading, const StringFunction &value); + + QList variables(); + QString variableDescription(const QByteArray &variable); + private: - Resolver m_resolver; + MacroExpander(const MacroExpander &) Q_DECL_EQ_DELETE; + void operator=(const MacroExpander &) Q_DECL_EQ_DELETE; + + Internal::MacroExpanderPrivate *d; }; } // namespace Utils diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp index 2ffd9a4e7ec7c6286ffe5156948cb737c51bfe66..9699b8359b2cc119bdb4758249012e745eba9cdc 100644 --- a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp +++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp @@ -595,5 +595,5 @@ void ExternalToolConfig::addCategory() void ExternalToolConfig::updateEffectiveArguments() { ui->arguments->setToolTip(Utils::QtcProcess::expandMacros(ui->arguments->text(), - Core::VariableManager::macroExpander())); + globalMacroExpander())); } diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index d5f66d27314732b6826a7b2f876bd1a33ed63ad8..68fb7c82824c87df4aa16a0df1011b6bd027b0e5 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -483,20 +483,20 @@ void EditorManagerPrivate::init() d->m_openEditorsFactory = new OpenEditorsViewFactory(); ExtensionSystem::PluginManager::addObject(d->m_openEditorsFactory); - VariableManager::registerFileVariables(kCurrentDocumentPrefix, tr("Current document"), + globalMacroExpander()->registerFileVariables(kCurrentDocumentPrefix, tr("Current document"), []() -> QString { IDocument *document = EditorManager::currentDocument(); return document ? document->filePath() : QString(); }); - VariableManager::registerIntVariable(kCurrentDocumentXPos, + globalMacroExpander()->registerIntVariable(kCurrentDocumentXPos, tr("X-coordinate of the current editor's upper left corner, relative to screen."), []() -> int { IEditor *editor = EditorManager::currentEditor(); return editor ? editor->widget()->mapToGlobal(QPoint(0, 0)).x() : 0; }); - VariableManager::registerIntVariable(kCurrentDocumentYPos, + globalMacroExpander()->registerIntVariable(kCurrentDocumentYPos, tr("Y-coordinate of the current editor's upper left corner, relative to screen."), []() -> int { IEditor *editor = EditorManager::currentEditor(); diff --git a/src/plugins/coreplugin/externaltool.cpp b/src/plugins/coreplugin/externaltool.cpp index 069012ec72d3fae2c1e113da2b4121786213b48c..fc8e375934096d0bb627297c603cac286c6a2fcf 100644 --- a/src/plugins/coreplugin/externaltool.cpp +++ b/src/plugins/coreplugin/externaltool.cpp @@ -550,10 +550,12 @@ bool ExternalToolRunner::resolve() m_resolvedExecutable.clear(); m_resolvedArguments.clear(); m_resolvedWorkingDirectory.clear(); + + Utils::MacroExpander *expander = globalMacroExpander(); { // executable QStringList expandedExecutables; /* for error message */ foreach (const QString &executable, m_tool->executables()) { - QString expanded = Core::VariableManager::expandedString(executable); + QString expanded = expander->expandedString(executable); expandedExecutables << expanded; m_resolvedExecutable = Utils::Environment::systemEnvironment().searchInPath(expanded); @@ -574,14 +576,13 @@ bool ExternalToolRunner::resolve() } } { // arguments - m_resolvedArguments = Utils::QtcProcess::expandMacros(m_tool->arguments(), - Core::VariableManager::macroExpander()); + m_resolvedArguments = Utils::QtcProcess::expandMacros(m_tool->arguments(), expander); } { // input - m_resolvedInput = Core::VariableManager::expandedString(m_tool->input()); + m_resolvedInput = expander->expandedString(m_tool->input()); } { // working directory - m_resolvedWorkingDirectory = Core::VariableManager::expandedString(m_tool->workingDirectory()); + m_resolvedWorkingDirectory = expander->expandedString(m_tool->workingDirectory()); } return true; } diff --git a/src/plugins/coreplugin/jsexpander.cpp b/src/plugins/coreplugin/jsexpander.cpp index 98bc0e9d3fd64c9098128a182afb4e208415714d..6e8c95f4045a25b67831526eb07e84d92ad930de 100644 --- a/src/plugins/coreplugin/jsexpander.cpp +++ b/src/plugins/coreplugin/jsexpander.cpp @@ -90,7 +90,7 @@ QString JsExpander::evaluate(const QString &expression, QString *errorMessage) JsExpander::JsExpander() { d = new Internal::JsExpanderPrivate; - VariableManager::registerPrefix("JS", + globalMacroExpander()->registerPrefix("JS", QCoreApplication::translate("Core::JsExpander", "Evaluate simple Javascript statements.\n" "The statements may not contain '{' nor '}' characters."), diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index fb14c10d9a839a1ae7a868a430c7b5b3667b7933..75cbe0940b0f084ae80110b325bfdda352db7f22 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -91,9 +91,9 @@ void ExecuteFilter::accept(LocatorFilterEntry selection) const p->m_commandHistory.prepend(value); bool found; - QString workingDirectory = Core::VariableManager::value("CurrentDocument:Path", &found); + QString workingDirectory = globalMacroExpander()->value("CurrentDocument:Path", &found); if (!found || workingDirectory.isEmpty()) - workingDirectory = Core::VariableManager::value("CurrentProject:Path", &found); + workingDirectory = globalMacroExpander()->value("CurrentProject:Path", &found); ExecuteData d; d.workingDirectory = workingDirectory; diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 1349015074b6a32312ab19976374efa5da0d7c9c..df0c4a870375668d5e4d82150e6d998e835397a4 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -120,8 +120,7 @@ MainWindow::MainWindow() : m_editorManager(0), m_externalToolManager(0), m_progressManager(new ProgressManagerPrivate), - m_variableManager(new VariableManager), - m_jsExpander(new JsExpander), // must be initialized after the VariableManager + m_jsExpander(new JsExpander), m_vcsManager(new VcsManager), m_statusBarManager(0), m_modeManager(0), @@ -305,8 +304,6 @@ MainWindow::~MainWindow() delete m_helpManager; m_helpManager = 0; - delete m_variableManager; - m_variableManager = 0; delete m_jsExpander; m_jsExpander = 0; } diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h index cbf47781d70c0ad68457e7e5dd5435590e2c292e..267ca3413a6391a5f454a1d510b76f5a6b434e00 100644 --- a/src/plugins/coreplugin/mainwindow.h +++ b/src/plugins/coreplugin/mainwindow.h @@ -65,7 +65,6 @@ class ProgressManager; class NavigationWidget; class RightPaneWidget; class SettingsDatabase; -class VariableManager; class VcsManager; namespace Internal { @@ -174,7 +173,6 @@ private: ExternalToolManager *m_externalToolManager; MessageManager *m_messageManager; ProgressManagerPrivate *m_progressManager; - VariableManager *m_variableManager; JsExpander *m_jsExpander; VcsManager *m_vcsManager; StatusBarManager *m_statusBarManager; diff --git a/src/plugins/coreplugin/variablechooser.cpp b/src/plugins/coreplugin/variablechooser.cpp index c2c14c9f7be77678d5b1c2a98c0f0a0f9da55a9a..05d853ef24e45c40168046d7b7849a2a78c40e22 100644 --- a/src/plugins/coreplugin/variablechooser.cpp +++ b/src/plugins/coreplugin/variablechooser.cpp @@ -67,7 +67,7 @@ public: m_variableList = new QListWidget(q); m_variableList->setAttribute(Qt::WA_MacSmallSize); m_variableList->setAttribute(Qt::WA_MacShowFocusRect, false); - foreach (const QByteArray &variable, VariableManager::variables()) + foreach (const QByteArray &variable, globalMacroExpander()->variables()) m_variableList->addItem(QString::fromLatin1(variable)); m_variableDescription = new QLabel(q); @@ -209,8 +209,8 @@ void VariableChooserPrivate::updateDescription(const QString &variable) if (variable.isNull()) m_variableDescription->setText(m_defaultDescription); else - m_variableDescription->setText(VariableManager::variableDescription(variable.toUtf8()) - + QLatin1String("

") + tr("Current Value: %1").arg(VariableManager::value(variable.toUtf8()))); + m_variableDescription->setText(globalMacroExpander()->variableDescription(variable.toUtf8()) + + QLatin1String("

") + tr("Current Value: %1").arg(globalMacroExpander()->value(variable.toUtf8()))); } /*! diff --git a/src/plugins/coreplugin/variablemanager.cpp b/src/plugins/coreplugin/variablemanager.cpp index 2a683de7fd1c24f9ba5da43345875abf8c4aef88..d9e91d6266e93ddf9bcd45336ce8c918c5fa12cc 100644 --- a/src/plugins/coreplugin/variablemanager.cpp +++ b/src/plugins/coreplugin/variablemanager.cpp @@ -30,312 +30,27 @@ #include "variablemanager.h" -#include #include -#include -#include -#include -static const char kFilePathPostfix[] = ":FilePath"; -static const char kPathPostfix[] = ":Path"; -static const char kFileNamePostfix[] = ":FileName"; -static const char kFileBaseNamePostfix[] = ":FileBaseName"; +using namespace Utils; namespace Core { -class VMMapExpander : public Utils::AbstractMacroExpander +class GlobalMacroExpander : public MacroExpander { public: - virtual bool resolveMacro(const QString &name, QString *ret) + GlobalMacroExpander() { - bool found; - *ret = Core::VariableManager::value(name.toUtf8(), &found); - return found; + registerPrefix("Env", QCoreApplication::translate("Core::VariableManager", "Access environment variables."), + [](const QString &value) { return QString::fromLocal8Bit(qgetenv(value.toLocal8Bit())); }); } }; -class VariableManagerPrivate +MacroExpander *globalMacroExpander() { -public: - QHash m_map; - QHash m_prefixMap; - VMMapExpander m_macroExpander; - QMap m_descriptions; -}; - -/*! - \class Core::VariableManager - \brief The VariableManager class manages \QC wide variables, that a user - can enter into many string settings. The variables are replaced by an actual value when the string - is used, similar to how environment variables are expanded by a shell. - - \section1 Variables - - Variable names can be basically any string without dollar sign and braces, - though it is recommended to only use 7-bit ASCII without special characters and whitespace. - - If there are several variables that contain different aspects of the same object, - it is convention to give them the same prefix, followed by a colon and a postfix - that describes the aspect. - Examples of this are \c{CurrentDocument:FilePath} and \c{CurrentDocument:Selection}. - - When the variable manager is requested to replace variables in a string, it looks for - variable names enclosed in %{ and }, like %{CurrentDocument:FilePath}. - - Environment variables are accessible using the %{Env:...} notation. - For example, to access the SHELL environment variable, use %{Env:SHELL}. - - \note The names of the variables are stored as QByteArray. They are typically - 7-bit-clean. In cases where this is not possible, UTF-8 encoding is - assumed. - - \section1 Providing Variable Values - - Plugins can register variables together with a description through registerVariable(). - A typical setup is to register variables in the Plugin::initialize() function. - - \code - bool MyPlugin::initialize(const QStringList &arguments, QString *errorString) - { - [...] - VariableManager::registerVariable( - "MyVariable", - tr("The current value of whatever I want.")); - []() -> QString { - QString value; - // do whatever is necessary to retrieve the value - [...] - return value; - } - ); - [...] - } - \endcode - - - For variables that refer to a file, you should use the convenience function - VariableManager::registerFileVariables(). - The functions take a variable prefix, like \c MyFileVariable, - and automatically handle standardized postfixes like \c{:FilePath}, - \c{:Path} and \c{:FileBaseName}, resulting in the combined variables, such as - \c{MyFileVariable:FilePath}. - - \section1 Providing and Expanding Parametrized Strings - - Though it is possible to just ask the variable manager for the value of some variable in your - code, the preferred use case is to give the user the possibility to parametrize strings, for - example for settings. - - (If you ever think about doing the former, think twice. It is much more efficient - to just ask the plugin that provides the variable value directly, without going through - string conversions, and through the variable manager which will do a large scale poll. To be - more concrete, using the example from the Providing Variable Values section: instead of - calling \c{VariableManager::value("MyVariable")}, it is much more efficient to just ask directly - with \c{MyPlugin::variableValue()}.) - - \section2 User Interface - - If the string that you want to parametrize is settable by the user, through a QLineEdit or - QTextEdit derived class, you should add a variable chooser to your UI, which allows adding - variables to the string by browsing through a list. See Core::VariableChooser for more - details. - - \section2 Expanding Strings - - Expanding variable values in strings is done by "macro expanders". - Utils::AbstractMacroExpander is the base class for these, and the variable manager - provides an implementation that expands \QC variables through - VariableManager::macroExpander(). - - There are several different ways to expand a string, covering the different use cases, - listed here sorted by relevance: - \list - \li Using VariableManager::expandedString(). This is the most comfortable way to get a string - with variable values expanded, but also the least flexible one. If this is sufficient for - you, use it. - \li Using the Utils::expandMacros() functions. These take a string and a macro expander (for which - you would use the one provided by the variable manager). Mostly the same as - VariableManager::expandedString(), but also has a variant that does the replacement inline - instead of returning a new string. - \li Using Utils::QtcProcess::expandMacros(). This expands the string while conforming to the - quoting rules of the platform it is run on. Use this function with the variable manager's - macro expander if your string will be passed as a command line parameter string to an - external command. - \li Writing your own macro expander that nests the variable manager's macro expander. And then - doing one of the above. This allows you to expand additional "local" variables/macros, - that do not come from the variable manager. - \endlist - -*/ - -static VariableManagerPrivate *d; - -/*! - * \internal - */ -VariableManager::VariableManager() -{ - d = new VariableManagerPrivate; - - registerPrefix("Env", QCoreApplication::translate("Core::VariableManager", "Access environment variables."), - [](const QString &value) - { return QString::fromLocal8Bit(qgetenv(value.toLocal8Bit())); }); -} - -/*! - * \internal - */ -VariableManager::~VariableManager() -{ - delete d; -} - -/*! - * Returns the value of the given \a variable. If \a found is given, it is - * set to true if the variable has a value at all, false if not. - */ -QString VariableManager::value(const QByteArray &variable, bool *found) -{ - StringFunction sf = d->m_map.value(variable); - if (sf) { - if (found) - *found = true; - return sf(); - } - - for (auto it = d->m_prefixMap.constBegin(); it != d->m_prefixMap.constEnd(); ++it) { - if (variable.startsWith(it.key())) { - PrefixFunction pf = it.value(); - if (found) - *found = true; - return pf(QString::fromUtf8(variable.mid(it.key().count()))); - } - } - if (found) - *found = false; - - return QString(); -} - -/*! - * Returns \a stringWithVariables with all variables replaced by their values. - * See the VariableManager overview documentation for other ways to expand variables. - * - * \sa VariableManager - * \sa macroExpander() - */ -QString VariableManager::expandedString(const QString &stringWithVariables) -{ - return Utils::expandMacros(stringWithVariables, macroExpander()); -} - -/*! - * Returns a macro expander that is used to expand all variables from the variable manager - * in a string. - * See the VariableManager overview documentation for other ways to expand variables. - * - * \sa VariableManager - * \sa expandedString() - */ -Utils::AbstractMacroExpander *VariableManager::macroExpander() -{ - return &d->m_macroExpander; -} - -/*! - * Makes the given string-valued \a prefix known to the variable manager, - * together with a localized \a description. - * - * The \a value PrefixFunction will be called and gets the full variable name - * with the prefix stripped as input. - * - * \sa registerVariables(), registerIntVariable(), registerFileVariables() - */ -void VariableManager::registerPrefix(const QByteArray &prefix, const QString &description, - const VariableManager::PrefixFunction &value) -{ - QByteArray tmp = prefix; - if (!tmp.endsWith(':')) - tmp.append(':'); - d->m_descriptions.insert(tmp + "", description); - d->m_prefixMap.insert(tmp, value); -} - -/*! - * Makes the given string-valued \a variable known to the variable manager, - * together with a localized \a description. - * - * \sa registerFileVariables(), registerIntVariable(), registerPrefix() - */ -void VariableManager::registerVariable(const QByteArray &variable, - const QString &description, const StringFunction &value) -{ - d->m_descriptions.insert(variable, description); - d->m_map.insert(variable, value); -} - -/*! - * Makes the given integral-valued \a variable known to the variable manager, - * together with a localized \a description. - * - * \sa registerVariable(), registerFileVariables(), registerPrefix() - */ -void VariableManager::registerIntVariable(const QByteArray &variable, - const QString &description, const VariableManager::IntFunction &value) -{ - const VariableManager::IntFunction valuecopy = value; // do not capture a reference in a lambda - registerVariable(variable, description, - [valuecopy]() { return QString::number(valuecopy ? valuecopy() : 0); }); -} - -/*! - * Convenience function to register several variables with the same \a prefix, that have a file - * as a value. Takes the prefix and registers variables like \c{prefix:FilePath} and - * \c{prefix:Path}, with descriptions that start with the given \a heading. - * For example \c{registerFileVariables("CurrentDocument", tr("Current Document"))} registers - * variables such as \c{CurrentDocument:FilePath} with description - * "Current Document: Full path including file name." - * - * \sa registerVariable(), registerIntVariable(), registerPrefix() - */ -void VariableManager::registerFileVariables(const QByteArray &prefix, - const QString &heading, const StringFunction &base) -{ - registerVariable(prefix + kFilePathPostfix, - QCoreApplication::translate("Core::VariableManager", "%1: Full path including file name.").arg(heading), - [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).filePath(); }); - - registerVariable(prefix + kPathPostfix, - QCoreApplication::translate("Core::VariableManager", "%1: Full path excluding file name.").arg(heading), - [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).path(); }); - - registerVariable(prefix + kFileNamePostfix, - QCoreApplication::translate("Core::VariableManager", "%1: File name without path.").arg(heading), - [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).fileName(); }); - - registerVariable(prefix + kFileBaseNamePostfix, - QCoreApplication::translate("Core::VariableManager", "%1: File base name without path and suffix.").arg(heading), - [base]() -> QString { QString tmp = base(); return tmp.isEmpty() ? QString() : QFileInfo(tmp).baseName(); }); -} - -/*! - * Returns all registered variable names. - * - * \sa registerVariable() - * \sa registerFileVariables() - */ -QList VariableManager::variables() -{ - return d->m_descriptions.keys(); -} - -/*! - * Returns the description that was registered for the \a variable. - */ -QString VariableManager::variableDescription(const QByteArray &variable) -{ - return d->m_descriptions.value(variable); + static MacroExpander theGlobalExpander; + return &theGlobalExpander; } } // namespace Core diff --git a/src/plugins/coreplugin/variablemanager.h b/src/plugins/coreplugin/variablemanager.h index fd8ca0d769b728fa3510d934d877350cf461050c..fd36d8c3c6966c73194100081bd5e34c33e3d29c 100644 --- a/src/plugins/coreplugin/variablemanager.h +++ b/src/plugins/coreplugin/variablemanager.h @@ -33,50 +33,11 @@ #include "core_global.h" -#include - -#include -#include - -namespace Utils { class AbstractMacroExpander; } +#include namespace Core { -namespace Internal { class MainWindow; } - -class CORE_EXPORT VariableManager -{ -public: - static QString value(const QByteArray &variable, bool *found = 0); - - static QString expandedString(const QString &stringWithVariables); - static Utils::AbstractMacroExpander *macroExpander(); - - typedef std::function PrefixFunction; - typedef std::function StringFunction; - typedef std::function IntFunction; - - static void registerPrefix(const QByteArray &prefix, - const QString &description, const PrefixFunction &value); - - static void registerVariable(const QByteArray &variable, - const QString &description, const StringFunction &value); - - static void registerIntVariable(const QByteArray &variable, - const QString &description, const IntFunction &value); - - static void registerFileVariables(const QByteArray &prefix, - const QString &heading, const StringFunction &value); - - static QList variables(); - static QString variableDescription(const QByteArray &variable); - -private: - VariableManager(); - ~VariableManager(); - - friend class Core::Internal::MainWindow; -}; +CORE_EXPORT Utils::MacroExpander *globalMacroExpander(); } // namespace Core diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp index 34787ff9c7d599641c1c8254532d160d3f4cf8f6..757d3c9aca9e93ee27946f3b10fee8bd3029c10a 100644 --- a/src/plugins/cpptools/cpptoolsplugin.cpp +++ b/src/plugins/cpptools/cpptoolsplugin.cpp @@ -191,12 +191,13 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error) mcpptools->addAction(command); connect(openInNextSplitAction, SIGNAL(triggered()), this, SLOT(switchHeaderSourceInNextSplit())); - Core::VariableManager::registerVariable("Cpp:LicenseTemplate", - tr("The license template."), - [this]() { return CppToolsPlugin::licenseTemplate(); }); - Core::VariableManager::registerFileVariables("Cpp:LicenseTemplatePath", - tr("The configured path to the license template"), - [this]() { return CppToolsPlugin::licenseTemplatePath().toString(); }); + Utils::MacroExpander *expander = globalMacroExpander(); + expander->registerVariable("Cpp:LicenseTemplate", + tr("The license template."), + [this]() { return CppToolsPlugin::licenseTemplate(); }); + expander->registerFileVariables("Cpp:LicenseTemplatePath", + tr("The configured path to the license template"), + [this]() { return CppToolsPlugin::licenseTemplatePath().toString(); }); return true; } diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 33a82c5ed5162e5e12dcc488c7fe03080a172362..13db85c5875dde57cb6b6a3d804bd2ac49d213c5 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -178,7 +178,7 @@ public: connect(action(IntelFlavor), SIGNAL(valueChanged(QVariant)), SLOT(reloadDisassembly())); - VariableManager::registerFileVariables(PrefixDebugExecutable, + globalMacroExpander()->registerFileVariables(PrefixDebugExecutable, tr("Debugged executable"), [this]() { return m_startParameters.executable; }); } @@ -1835,7 +1835,7 @@ void DebuggerEngine::validateExecutable(DebuggerStartParameters *sp) SourcePathRegExpMap globalRegExpSourceMap; globalRegExpSourceMap.reserve(options->sourcePathRegExpMap.size()); foreach (auto entry, options->sourcePathRegExpMap) { - const QString expanded = VariableManager::expandedString(entry.second); + const QString expanded = globalMacroExpander()->expandedString(entry.second); if (!expanded.isEmpty()) globalRegExpSourceMap.push_back(qMakePair(entry.first, expanded)); } diff --git a/src/plugins/debugger/debuggeritem.h b/src/plugins/debugger/debuggeritem.h index a694f1ab5fbb0cf24d877daf52f1e356077904a7..fbe9d335ba76905d1e1038cb04c9b4b2b5c771e7 100644 --- a/src/plugins/debugger/debuggeritem.h +++ b/src/plugins/debugger/debuggeritem.h @@ -37,6 +37,7 @@ #include #include +#include #include #include diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp index 3675805977588a5934ce26ef7f865d9183607002..6a9bb7edb3450f575b152c6b3a708afaf240f749 100644 --- a/src/plugins/debugger/debuggerkitinformation.cpp +++ b/src/plugins/debugger/debuggerkitinformation.cpp @@ -302,18 +302,15 @@ KitConfigWidget *DebuggerKitInformation::createConfigWidget(Kit *k) const return new Internal::DebuggerKitConfigWidget(k, this); } -AbstractMacroExpander *DebuggerKitInformation::createMacroExpander(const Kit *k) const +bool DebuggerKitInformation::resolveMacro(const Kit *kit, const QString &name, QString *ret) const { - return new MacroExpander([k, this](const QString &name, QString *ret) -> bool { - const DebuggerItem *item = DebuggerKitInformation::debugger(k); - - if (name == QLatin1String("Debugger:engineType")) { - *ret = item ? item->engineTypeName() : tr("none"); - return true; - } + const DebuggerItem *item = debugger(kit); + if (name == QLatin1String("Debugger:engineType")) { + *ret = item ? item->engineTypeName() : tr("none"); + return true; + } - return false; - }); + return false; } KitInformation::ItemList DebuggerKitInformation::toUserOutput(const Kit *k) const diff --git a/src/plugins/debugger/debuggerkitinformation.h b/src/plugins/debugger/debuggerkitinformation.h index bd84cb7a502a1c242cb64816ed58954e5022e02b..026ba180c9ee3290d3cf775d089a6239c8b50e99 100644 --- a/src/plugins/debugger/debuggerkitinformation.h +++ b/src/plugins/debugger/debuggerkitinformation.h @@ -63,7 +63,7 @@ public: static bool isValidDebugger(const ProjectExplorer::Kit *k); ProjectExplorer::KitConfigWidget *createConfigWidget(ProjectExplorer::Kit *k) const; - Utils::AbstractMacroExpander *createMacroExpander(const ProjectExplorer::Kit *k) const; + bool resolveMacro(const ProjectExplorer::Kit *kit, const QString &name, QString *ret) const; ItemList toUserOutput(const ProjectExplorer::Kit *k) const; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 4094e2f76b59e9cc9f793ed59fd46ce8d3c5a5bc..d0bce30168d2de62df24999bc2751ae8c3dd9795 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -3334,7 +3334,7 @@ bool boolSetting(int code) QString stringSetting(int code) { QString raw = theDebuggerCore->m_debuggerSettings->item(code)->value().toString(); - return VariableManager::expandedString(raw); + return globalMacroExpander()->expandedString(raw); } QStringList stringListSetting(int code) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 176c35d8761bbcbcf05a61e7941894546d6a63f9..2c434e39ec26f23a834884e78f258f57b914b0dd 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4402,7 +4402,7 @@ void GdbEngine::abortDebugger() void GdbEngine::resetInferior() { if (!startParameters().commandsForReset.isEmpty()) { - QByteArray substitutedCommands = VariableManager::expandedString( + QByteArray substitutedCommands = globalMacroExpander()->expandedString( QString::fromLatin1(startParameters().commandsForReset)).toLatin1(); foreach (QByteArray command, substitutedCommands.split('\n')) { command = command.trimmed(); @@ -4453,7 +4453,7 @@ void GdbEngine::handleInferiorPrepared() QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state()); if (!sp.commandsAfterConnect.isEmpty()) { - QByteArray substitutedCommands = VariableManager::expandedString(QString::fromLatin1(sp.commandsAfterConnect)).toLatin1(); + QByteArray substitutedCommands = globalMacroExpander()->expandedString(QString::fromLatin1(sp.commandsAfterConnect)).toLatin1(); foreach (QByteArray command, substitutedCommands.split('\n')) { postCommand(command); } diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardexpander.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardexpander.cpp index f41e8ee6ea540f57865925d8302ead0734a4f2a9..c9e50500755681b8d26a5360b18c0a735af8b1f2 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardexpander.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardexpander.cpp @@ -59,7 +59,7 @@ bool JsonWizardExpander::resolveMacro(const QString &name, QString *ret) return true; } - return Core::VariableManager::macroExpander()->resolveMacro(name, ret); + return Core::globalMacroExpander()->resolveMacro(name, ret); } } // namespace Internal diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp index ebbca09053c38c1bac27cc4a74442775099e4fa5..72e6d4b78ca5c7b116e4ce2e6fbeaf6dd72ec02f 100644 --- a/src/plugins/projectexplorer/kit.cpp +++ b/src/plugins/projectexplorer/kit.cpp @@ -36,8 +36,8 @@ #include #include +#include #include -#include #include #include @@ -66,29 +66,24 @@ namespace ProjectExplorer { // KitMacroExpander: // -------------------------------------------------------------------- -class KitMacroExpander : public AbstractMacroExpander +class KitMacroExpander : public MacroExpander { public: - KitMacroExpander(const QList &children) : - m_childExpanders(children) - { } - ~KitMacroExpander() { qDeleteAll(m_childExpanders); } + KitMacroExpander(Kit *kit) : m_kit(kit) {} - bool resolveMacro(const QString &name, QString *ret); + bool resolveMacro(const QString &name, QString *ret) + { + foreach (KitInformation *ki, KitManager::kitInformation()) + if (ki->resolveMacro(m_kit, name, ret)) + return true; + + return false; + } private: - QList m_childExpanders; + Kit *m_kit; }; -bool KitMacroExpander::resolveMacro(const QString &name, QString *ret) -{ - foreach (AbstractMacroExpander *expander, m_childExpanders) { - if (expander->resolveMacro(name, ret)) - return true; - } - return false; -} - // ------------------------------------------------------------------------- // KitPrivate // ------------------------------------------------------------------------- @@ -107,27 +102,15 @@ public: m_hasWarning(false), m_hasValidityInfo(false), m_mustNotify(false), - m_macroExpander(0) + m_macroExpander(k) { if (!id.isValid()) m_id = Id::fromString(QUuid::createUuid().toString()); m_unexpandedDisplayName = QCoreApplication::translate("ProjectExplorer::Kit", "Unnamed"); m_iconPath = FileName::fromLatin1(":///DESKTOP///"); - - QList expanders; - foreach (const KitInformation *ki, KitManager::kitInformation()) { - AbstractMacroExpander *tmp = ki->createMacroExpander(k); - if (tmp) - expanders.append(tmp); - } - - m_macroExpander = new KitMacroExpander(expanders); } - ~KitPrivate() - { delete m_macroExpander; } - QString m_unexpandedDisplayName; QString m_fileSystemFriendlyName; QString m_autoDetectionSource; @@ -145,7 +128,7 @@ public: QHash m_data; QSet m_sticky; QSet m_mutable; - AbstractMacroExpander *m_macroExpander; + KitMacroExpander m_macroExpander; }; } // namespace Internal @@ -317,7 +300,7 @@ QString Kit::unexpandedDisplayName() const QString Kit::displayName() const { - return Utils::expandMacros(unexpandedDisplayName(), macroExpander()); + return Utils::expandMacros(d->m_unexpandedDisplayName, &d->m_macroExpander); } static QString candidateName(const QString &name, const QString &postfix) @@ -682,8 +665,7 @@ bool Kit::hasFeatures(const FeatureSet &features) const AbstractMacroExpander *Kit::macroExpander() const { - QTC_CHECK(d->m_macroExpander); - return d->m_macroExpander; + return &d->m_macroExpander; } void Kit::kitUpdated() diff --git a/src/plugins/projectexplorer/kit.h b/src/plugins/projectexplorer/kit.h index 054999bba2659ba5c355026151656ad23d61ecca..50488550d8cda09bd998e189794a798396e31de8 100644 --- a/src/plugins/projectexplorer/kit.h +++ b/src/plugins/projectexplorer/kit.h @@ -129,9 +129,8 @@ public: Core::FeatureSet availableFeatures() const; bool hasFeatures(const Core::FeatureSet &features) const; - Utils::AbstractMacroExpander *macroExpander() const; - private: + Utils::AbstractMacroExpander *macroExpander() const; void setSdkProvided(bool sdkProvided); ~Kit(); diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index 21e861ba6cbbd155e4b33a3a03e272684f7fa989..ff8e482c273c53b686f8c3842390c28c5ce77af3 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -589,6 +589,14 @@ Core::FeatureSet KitInformation::availableFeatures(const Kit *k) const return Core::FeatureSet(); } +bool KitInformation::resolveMacro(const Kit *kit, const QString &name, QString *ret) const +{ + Q_UNUSED(kit); + Q_UNUSED(name); + Q_UNUSED(ret); + return false; +} + void KitInformation::notifyAboutUpdate(Kit *k) { if (k) diff --git a/src/plugins/projectexplorer/kitmanager.h b/src/plugins/projectexplorer/kitmanager.h index b6adf4332ea9c7097fcc5872145f85b63b00c327..e45d6cf042a692b3b98d7cfd08ff965ce1c28603 100644 --- a/src/plugins/projectexplorer/kitmanager.h +++ b/src/plugins/projectexplorer/kitmanager.h @@ -99,8 +99,7 @@ public: virtual QString displayNameForPlatform(const Kit *k, const QString &platform) const; virtual Core::FeatureSet availableFeatures(const Kit *k) const; - virtual Utils::AbstractMacroExpander *createMacroExpander(const Kit *k) const - { Q_UNUSED(k); return 0; } + virtual bool resolveMacro(const Kit *kit, const QString &name, QString *ret) const; protected: void setId(Core::Id id) { m_id = id; } diff --git a/src/plugins/projectexplorer/localapplicationrunconfiguration.cpp b/src/plugins/projectexplorer/localapplicationrunconfiguration.cpp index abfd028a402d8f2c25c6000260325d67aa469d3b..6d198f4e1dd10f089d9c688bb2adbd6b305aa0d3 100644 --- a/src/plugins/projectexplorer/localapplicationrunconfiguration.cpp +++ b/src/plugins/projectexplorer/localapplicationrunconfiguration.cpp @@ -40,7 +40,6 @@ #include namespace ProjectExplorer { - namespace Internal { class FallBackMacroExpander : public Utils::AbstractMacroExpander @@ -59,7 +58,7 @@ bool FallBackMacroExpander::resolveMacro(const QString &name, QString *ret) return true; } bool found; - *ret = Core::VariableManager::value(name.toUtf8(), &found); + *ret = Core::globalMacroExpander()->value(name.toUtf8(), &found); return found; } } // namespace Internal diff --git a/src/plugins/projectexplorer/processstep.cpp b/src/plugins/projectexplorer/processstep.cpp index 9410b8f350790bd3b43a84f2759dac925a4e9c8e..cd16683b403343131cf797c90a7041d783152310 100644 --- a/src/plugins/projectexplorer/processstep.cpp +++ b/src/plugins/projectexplorer/processstep.cpp @@ -82,7 +82,7 @@ bool ProcessStep::init() if (!bc) bc = target()->activeBuildConfiguration(); ProcessParameters *pp = processParameters(); - pp->setMacroExpander(bc ? bc->macroExpander() : Core::VariableManager::macroExpander()); + pp->setMacroExpander(bc ? bc->macroExpander() : Core::globalMacroExpander()); pp->setEnvironment(bc ? bc->environment() : Utils::Environment::systemEnvironment()); pp->setWorkingDirectory(workingDirectory()); pp->setCommand(m_command); @@ -272,7 +272,7 @@ void ProcessStepConfigWidget::updateDetails() BuildConfiguration *bc = m_step->buildConfiguration(); if (!bc) // iff the step is actually in the deploy list bc = m_step->target()->activeBuildConfiguration(); - param.setMacroExpander(bc ? bc->macroExpander() : Core::VariableManager::macroExpander()); + param.setMacroExpander(bc ? bc->macroExpander() : Core::globalMacroExpander()); param.setEnvironment(bc ? bc->environment() : Utils::Environment::systemEnvironment()); param.setWorkingDirectory(m_step->workingDirectory()); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index dfa33eb513b6a068a0a303aa7b687b7e0b7dd0f1..1f9f9b3ff0c1ce13c94ec2b67b8c2e16a25d8bf2 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1135,7 +1135,8 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er updateWelcomePage(); - VariableManager::registerFileVariables(Constants::VAR_CURRENTPROJECT_PREFIX, + Utils::MacroExpander *expander = globalMacroExpander(); + expander->registerFileVariables(Constants::VAR_CURRENTPROJECT_PREFIX, tr("Current project's main file"), [this]() -> QString { QString projectFilePath; @@ -1145,51 +1146,51 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er return projectFilePath; }); - VariableManager::registerVariable(Constants::VAR_CURRENTPROJECT_BUILDPATH, + expander->registerVariable(Constants::VAR_CURRENTPROJECT_BUILDPATH, tr("Full build path of the current project's active build configuration."), []() -> QString { BuildConfiguration *bc = activeBuildConfiguration(); return bc ? bc->buildDirectory().toUserOutput() : QString(); }); - VariableManager::registerVariable(Constants::VAR_CURRENTPROJECT_NAME, + expander->registerVariable(Constants::VAR_CURRENTPROJECT_NAME, tr("The current project's name."), []() { return variableValue(Constants::VAR_CURRENTPROJECT_NAME); }); - VariableManager::registerVariable(Constants::VAR_CURRENTKIT_NAME, + expander->registerVariable(Constants::VAR_CURRENTKIT_NAME, tr("The currently active kit's name."), []() { return variableValue(Constants::VAR_CURRENTKIT_NAME); }); - VariableManager::registerVariable(Constants::VAR_CURRENTKIT_FILESYSTEMNAME, + expander->registerVariable(Constants::VAR_CURRENTKIT_FILESYSTEMNAME, tr("The currently active kit's name in a filesystem friendly version."), []() { return variableValue(Constants::VAR_CURRENTKIT_FILESYSTEMNAME); }); - VariableManager::registerVariable(Constants::VAR_CURRENTKIT_ID, + expander->registerVariable(Constants::VAR_CURRENTKIT_ID, tr("The currently active kit's id."), []() { return variableValue(Constants::VAR_CURRENTKIT_ID); }); - VariableManager::registerVariable(Constants::VAR_CURRENTDEVICE_HOSTADDRESS, + expander->registerVariable(Constants::VAR_CURRENTDEVICE_HOSTADDRESS, tr("The host address of the device in the currently active kit."), []() { return variableValue(Constants::VAR_CURRENTDEVICE_HOSTADDRESS); }); - VariableManager::registerVariable(Constants::VAR_CURRENTDEVICE_SSHPORT, + expander->registerVariable(Constants::VAR_CURRENTDEVICE_SSHPORT, tr("The SSH port of the device in the currently active kit."), []() { return variableValue(Constants::VAR_CURRENTDEVICE_SSHPORT); }); - VariableManager::registerVariable(Constants::VAR_CURRENTDEVICE_USERNAME, + expander->registerVariable(Constants::VAR_CURRENTDEVICE_USERNAME, tr("The username with which to log into the device in the currently active kit."), []() { return variableValue(Constants::VAR_CURRENTDEVICE_USERNAME); }); - VariableManager::registerVariable(Constants::VAR_CURRENTDEVICE_PRIVATEKEYFILE, + expander->registerVariable(Constants::VAR_CURRENTDEVICE_PRIVATEKEYFILE, tr("The private key file with which to authenticate when logging into the device " "in the currently active kit."), []() { return variableValue(Constants::VAR_CURRENTDEVICE_PRIVATEKEYFILE); }); - VariableManager::registerVariable(Constants::VAR_CURRENTBUILD_NAME, + expander->registerVariable(Constants::VAR_CURRENTBUILD_NAME, tr("The currently active build configuration's name."), []() { return variableValue(Constants::VAR_CURRENTBUILD_NAME); }); - VariableManager::registerVariable(Constants::VAR_CURRENTBUILD_TYPE, + expander->registerVariable(Constants::VAR_CURRENTBUILD_TYPE, tr("The currently active build configuration's type."), [&]() -> QString { if (BuildConfiguration *bc = activeBuildConfiguration()) { @@ -1202,11 +1203,11 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er return tr("unknown"); }); - VariableManager::registerFileVariables(Constants::VAR_CURRENTSESSION_PREFIX, + expander->registerFileVariables(Constants::VAR_CURRENTSESSION_PREFIX, tr("File where current session is saved."), []() { return SessionManager::sessionNameToFileName(SessionManager::activeSession()).toString(); }); - VariableManager::registerVariable(Constants::VAR_CURRENTSESSION_NAME, + expander->registerVariable(Constants::VAR_CURRENTSESSION_NAME, tr("Name of current session."), []() { return SessionManager::activeSession(); }); diff --git a/src/plugins/projectexplorer/projectmacroexpander.cpp b/src/plugins/projectexplorer/projectmacroexpander.cpp index bdf25366ff99077ed1b3b6f7db7ef757a2db59ec..63c9747c62a22767e96dc9f41eeca0260d20a900 100644 --- a/src/plugins/projectexplorer/projectmacroexpander.cpp +++ b/src/plugins/projectexplorer/projectmacroexpander.cpp @@ -99,7 +99,7 @@ bool ProjectMacroExpander::resolveMacro(const QString &name, QString *ret) { bool found = resolveProjectMacro(name, ret); if (!found) { - QString result = Core::VariableManager::value(name.toUtf8(), &found); + QString result = Core::globalMacroExpander()->value(name.toUtf8(), &found); if (ret) *ret = result; } diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index cfc8d8f1f17eeb1a9f2cb68461b4050693b7a9cc..b8e7c41588caebd3490270058a83bd9d82caf663 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -192,9 +192,10 @@ BaseQtVersion::BaseQtVersion(const BaseQtVersion &other) : m_linguistCommand(other.m_linguistCommand), m_qmlsceneCommand(other.m_qmlsceneCommand), m_qmlviewerCommand(other.m_qmlviewerCommand), - m_qtAbis(other.m_qtAbis), - m_expander(0) -{ } + m_qtAbis(other.m_qtAbis) +{ + setupExpander(); +} BaseQtVersion::BaseQtVersion() : m_id(-1), m_isAutodetected(false), @@ -228,12 +229,31 @@ void BaseQtVersion::ctor(const FileName &qmakePath) m_hasQtAbis = false; m_qtVersionString.clear(); m_sourcePath.clear(); - m_expander = 0; + setupExpander(); +} + +void BaseQtVersion::setupExpander() +{ + m_expander.registerVariable("Qt:version", + QCoreApplication::translate("QtSupport::QtKitInformation", "The version string of the current Qt version."), + [this]() { return qtVersionString(); }); + + m_expander.registerVariable("Qt:type", + QCoreApplication::translate("QtSupport::QtKitInformation", "The type of the current Qt version."), + [this]() { return type(); }); + + m_expander.registerVariable("Qt:mkspec", + QCoreApplication::translate("QtSupport::QtKitInformation", "The mkspec of the current Qt version."), + [this]() { return mkspec().toUserOutput(); }); + +// FIXME: Re-enable once we can detect expansion loops. +// m_expander.registerVariable("Qt:name", +// QCoreApplication::translate("QtSupport::QtKitInformation", "The display name of the current Qt version."), +// [this]() { return displayName(); }); } BaseQtVersion::~BaseQtVersion() { - delete m_expander; } QString BaseQtVersion::defaultUnexpandedDisplayName(const FileName &qmakePath, bool fromPath) @@ -586,7 +606,7 @@ void BaseQtVersion::setAutoDetectionSource(const QString &autodetectionSource) QString BaseQtVersion::displayName() const { - return Utils::expandMacros(unexpandedDisplayName(), macroExpander()); + return Utils::expandMacros(m_unexpandedDisplayName, &m_expander); } QString BaseQtVersion::unexpandedDisplayName() const @@ -894,15 +914,6 @@ void BaseQtVersion::parseMkSpec(ProFileEvaluator *evaluator) const m_mkspecValues.insert(ns, evaluator->value(ns)); } -AbstractMacroExpander *BaseQtVersion::createMacroExpander() const -{ - return new MacroExpander([this](const QString &name, QString *ret) -> bool { - if (name == QLatin1String("Qt:name")) - return false; - return QtKitInformation::resolveQtMacro(this, name, ret); - }); -} - FileName BaseQtVersion::mkspec() const { updateMkspec(); @@ -1112,11 +1123,9 @@ QStringList BaseQtVersion::qtConfigValues() const return m_qtConfigValues; } -AbstractMacroExpander *BaseQtVersion::macroExpander() const +MacroExpander *BaseQtVersion::macroExpander() const { - if (!m_expander) - m_expander = createMacroExpander(); - return m_expander; + return &m_expander; } QList BaseQtVersion::systemHeaderPathes(const Kit *k) const diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h index 8ca3606e46117d57a781e835330ce45c65eb9b52..d6f3d757c21bca65db13accd114c61af98b74c17 100644 --- a/src/plugins/qtsupport/baseqtversion.h +++ b/src/plugins/qtsupport/baseqtversion.h @@ -34,17 +34,14 @@ #include "qtsupport_global.h" #include +#include #include #include #include -namespace Utils { -class Environment; -class AbstractMacroExpander; -} // namespace Utils - +namespace Utils { class Environment; } namespace Core { class FeatureSet; } namespace ProjectExplorer { @@ -226,7 +223,7 @@ public: QStringList configValues() const; QStringList qtConfigValues() const; - Utils::AbstractMacroExpander *macroExpander() const; // owned by the Qt version + Utils::MacroExpander *macroExpander() const; // owned by the Qt version protected: BaseQtVersion(); @@ -246,14 +243,11 @@ protected: void ensureMkSpecParsed() const; virtual void parseMkSpec(ProFileEvaluator *) const; - // Create the macro expander. This pointer will be cached by the Qt version (which will take - // ownership). - virtual Utils::AbstractMacroExpander *createMacroExpander() const; - private: void setAutoDetectionSource(const QString &autodetectionSource); static int getUniqueId(); void ctor(const Utils::FileName &qmakePath); + void setupExpander(); void updateSourcePath() const; void updateVersionInfo() const; enum Binaries { QmlViewer, QmlScene, Designer, Linguist, Uic }; @@ -303,7 +297,7 @@ private: mutable QList m_qtAbis; - mutable Utils::AbstractMacroExpander *m_expander; + mutable Utils::MacroExpander m_expander; }; } diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp index 537f7d2ae7b7b87d41097a83a98205bc9e4e1aa3..4879ff91acf4de19318cd42d02e1a6f5f5fcf6dd 100644 --- a/src/plugins/qtsupport/qtkitinformation.cpp +++ b/src/plugins/qtsupport/qtkitinformation.cpp @@ -38,28 +38,13 @@ #include #include +#include #include using namespace ProjectExplorer; using namespace Utils; namespace QtSupport { -namespace Internal { - -class QtKitInformationMacroExpander : public ProjectExplorer::KitInformationMacroExpander -{ -public: - QtKitInformationMacroExpander(const ProjectExplorer::Kit *k) : - ProjectExplorer::KitInformationMacroExpander(k) - { } - - bool resolveMacro(const QString &name, QString *ret) - { - return QtKitInformation::resolveQtMacro(QtKitInformation::qtVersion(kit()), name, ret); - } -}; - -} // namespace Internal QtKitInformation::QtKitInformation() { @@ -71,26 +56,6 @@ QtKitInformation::QtKitInformation() this, SLOT(kitsWereLoaded())); } -bool QtKitInformation::resolveQtMacro(const BaseQtVersion *version, const QString &name, QString *ret) -{ - const QString noInfo = QCoreApplication::translate("QtSupport::QtKitInformation", "none"); - - if (name == QLatin1String("Qt:version")) { - *ret = version ? version->qtVersionString() : noInfo; - return true; - } else if (name == QLatin1String("Qt:name")) { - *ret = version ? version->displayName() : noInfo; - return true; - } else if (name == QLatin1String("Qt:type")) { - *ret = version ? version->type() : noInfo; - return true; - } else if (name == QLatin1String("Qt:mkspec")) { - *ret = version ? version->mkspec().toUserOutput() : noInfo; - return true; - } - return false; -} - QVariant QtKitInformation::defaultValue(ProjectExplorer::Kit *k) const { Q_UNUSED(k); @@ -167,9 +132,21 @@ ProjectExplorer::IOutputParser *QtKitInformation::createOutputParser(const Proje return 0; } -Utils::AbstractMacroExpander *QtKitInformation::createMacroExpander(const ProjectExplorer::Kit *k) const +bool QtKitInformation::resolveMacro(const ProjectExplorer::Kit *kit, const QString &name, QString *ret) const { - return new Internal::QtKitInformationMacroExpander(k); + if (BaseQtVersion *version = qtVersion(kit)) { + MacroExpander *expander = version->macroExpander(); + if (expander->resolveMacro(name, ret)) + return true; + + // FIXME: Handle in version expander once we can detect loops. + if (name == QLatin1String("Qt:name")) { + *ret = version->displayName(); + return true; + } + } + + return false; } Core::Id QtKitInformation::id() diff --git a/src/plugins/qtsupport/qtkitinformation.h b/src/plugins/qtsupport/qtkitinformation.h index 2ccc7b28f9e8eb392461c10623c1afe58c20832f..9df94990eec252f7e00116a3a583adcbaa51397a 100644 --- a/src/plugins/qtsupport/qtkitinformation.h +++ b/src/plugins/qtsupport/qtkitinformation.h @@ -38,6 +38,8 @@ #include #include +namespace Utils { class MacroExpander; } + namespace QtSupport { class QTSUPPORT_EXPORT QtKitInformation : public ProjectExplorer::KitInformation @@ -61,9 +63,7 @@ public: void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const; ProjectExplorer::IOutputParser *createOutputParser(const ProjectExplorer::Kit *k) const; - Utils::AbstractMacroExpander *createMacroExpander(const ProjectExplorer::Kit *k) const; - - static bool resolveQtMacro(const BaseQtVersion *version, const QString &name, QString *ret); + bool resolveMacro(const ProjectExplorer::Kit *kit, const QString &name, QString *ret) const; static Core::Id id(); static int qtVersionId(const ProjectExplorer::Kit *k); diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index 39cc65d1a4ee9c932256185dea104b23c263b741..03e7c7b93dc5d079557ae0ad856e02b2e9666725 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -114,11 +114,13 @@ static QString qmakeProperty(const char *propertyName) void QtSupportPlugin::extensionsInitialized() { - VariableManager::registerVariable(kHostBins, + Utils::MacroExpander *expander = globalMacroExpander(); + + expander->registerVariable(kHostBins, tr("Full path to the host bin directory of the current project's Qt version."), []() { return qmakeProperty("QT_HOST_BINS"); }); - VariableManager::registerVariable(kInstallBins, + expander->registerVariable(kInstallBins, tr("Full path to the target bin directory of the current project's Qt version." " You probably want %1 instead.").arg(QString::fromLatin1(kHostBins)), []() { return qmakeProperty("QT_INSTALL_BINS"); }); diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp index 28a3998b65300630d810235b3f91803cf7fc760d..c2ce283f413c3eb1421a49a46e46c9939f90f3b5 100644 --- a/src/plugins/texteditor/texteditorplugin.cpp +++ b/src/plugins/texteditor/texteditorplugin.cpp @@ -147,7 +147,9 @@ void TextEditorPlugin::extensionsInitialized() addAutoReleasedObject(new FindInCurrentFile); addAutoReleasedObject(new FindInOpenFiles); - VariableManager::registerVariable(kCurrentDocumentSelection, + Utils::MacroExpander *expander = globalMacroExpander(); + + expander->registerVariable(kCurrentDocumentSelection, tr("Selected text within the current document."), []() -> QString { QString value; @@ -158,35 +160,35 @@ void TextEditorPlugin::extensionsInitialized() return value; }); - VariableManager::registerIntVariable(kCurrentDocumentRow, + expander->registerIntVariable(kCurrentDocumentRow, tr("Line number of the text cursor position in current document (starts with 1)."), []() -> int { BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); return editor ? editor->currentLine() : 0; }); - VariableManager::registerIntVariable(kCurrentDocumentColumn, + expander->registerIntVariable(kCurrentDocumentColumn, tr("Column number of the text cursor position in current document (starts with 0)."), []() -> int { BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); return editor ? editor->currentColumn() : 0; }); - VariableManager::registerIntVariable(kCurrentDocumentRowCount, + expander->registerIntVariable(kCurrentDocumentRowCount, tr("Number of lines visible in current document."), []() -> int { BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); return editor ? editor->rowCount() : 0; }); - VariableManager::registerIntVariable(kCurrentDocumentColumnCount, + expander->registerIntVariable(kCurrentDocumentColumnCount, tr("Number of columns visible in current document."), []() -> int { BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); return editor ? editor->columnCount() : 0; }); - VariableManager::registerIntVariable(kCurrentDocumentFontSize, + expander->registerIntVariable(kCurrentDocumentFontSize, tr("Current document's font size in points."), []() -> int { BaseTextEditor *editor = BaseTextEditor::currentTextEditor(); diff --git a/src/plugins/vcsbase/vcsplugin.cpp b/src/plugins/vcsbase/vcsplugin.cpp index 10f3e7ceeb402f58b77bbb3eea4b168b5fb4eba6..be47027f24a08ead055c093fba0c24811be29d76 100644 --- a/src/plugins/vcsbase/vcsplugin.cpp +++ b/src/plugins/vcsbase/vcsplugin.cpp @@ -87,7 +87,8 @@ bool VcsPlugin::initialize(const QStringList &arguments, QString *errorMessage) this, SLOT(slotSettingsChanged())); slotSettingsChanged(); - VariableManager::registerVariable(Constants::VAR_VCS_NAME, + Utils::MacroExpander *expander = globalMacroExpander(); + expander->registerVariable(Constants::VAR_VCS_NAME, tr("Name of the version control system in use by the current project."), []() -> QString { IVersionControl *vc = 0; @@ -96,7 +97,7 @@ bool VcsPlugin::initialize(const QStringList &arguments, QString *errorMessage) return vc ? vc->displayName() : QString(); }); - VariableManager::registerVariable(Constants::VAR_VCS_TOPIC, + expander->registerVariable(Constants::VAR_VCS_TOPIC, tr("The current version control topic (branch or tag) identification of the current project."), []() -> QString { IVersionControl *vc = 0; @@ -106,7 +107,7 @@ bool VcsPlugin::initialize(const QStringList &arguments, QString *errorMessage) return vc ? vc->vcsTopic(topLevel) : QString(); }); - VariableManager::registerVariable(Constants::VAR_VCS_TOPLEVELPATH, + expander->registerVariable(Constants::VAR_VCS_TOPLEVELPATH, tr("The top level path to the repository the current project is in."), []() -> QString { if (Project *project = ProjectExplorerPlugin::currentProject())