diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py index 4ac053eb559..c16467915a0 100644 --- a/share/qtcreator/debugger/cdbbridge.py +++ b/share/qtcreator/debugger/cdbbridge.py @@ -7,6 +7,7 @@ import sys import cdbext import re import threading +import time from utils import TypeCode sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) @@ -421,6 +422,7 @@ class Dumper(DumperBase): return ptr def fetchVariables(self, args): + start_time = time.perf_counter() self.resetStats() (ok, res) = self.tryFetchInterpreterVariables(args) if ok: @@ -458,6 +460,8 @@ class Dumper(DumperBase): self.put(',qtnamespace="%s"' % self.qtNamespaceToReport) self.qtNamespaceToReport = None + runtime = time.perf_counter() - start_time + self.put(',runtime="%s"' % runtime) self.reportResult(''.join(self.output), args) self.output = [] diff --git a/src/libs/languageutils/componentversion.cpp b/src/libs/languageutils/componentversion.cpp index f041740d3b2..edfa2c552bb 100644 --- a/src/libs/languageutils/componentversion.cpp +++ b/src/libs/languageutils/componentversion.cpp @@ -6,8 +6,6 @@ #include #include -#include - namespace LanguageUtils { // QTC_TEMP @@ -42,8 +40,8 @@ QString ComponentVersion::toString() const void ComponentVersion::addToHash(QCryptographicHash &hash) const { - hash.addData(reinterpret_cast(&_major), sizeof(_major)); - hash.addData(reinterpret_cast(&_minor), sizeof(_minor)); + hash.addData(QByteArrayView(reinterpret_cast(&_major), sizeof(_major))); + hash.addData(QByteArrayView(reinterpret_cast(&_minor), sizeof(_minor))); } } // namespace LanguageUtils diff --git a/src/libs/languageutils/fakemetaobject.cpp b/src/libs/languageutils/fakemetaobject.cpp index 4c553cdc7b5..da7877c1b63 100644 --- a/src/libs/languageutils/fakemetaobject.cpp +++ b/src/libs/languageutils/fakemetaobject.cpp @@ -6,6 +6,21 @@ using namespace LanguageUtils; +static QByteArrayView asData(const void *mem, size_t len) +{ + return QByteArrayView(reinterpret_cast(mem), len); +} + +static void addData(QCryptographicHash &hash, int x) +{ + hash.addData(asData(&x, sizeof(int))); +} + +static void addData(QCryptographicHash &hash, const QString &x) +{ + hash.addData(asData(x.constData(), x.size() * sizeof(QChar))); +} + FakeMetaEnum::FakeMetaEnum() {} @@ -39,15 +54,12 @@ bool FakeMetaEnum::hasKey(const QString &key) const void FakeMetaEnum::addToHash(QCryptographicHash &hash) const { - int len = m_name.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(m_name.constData()), len * sizeof(QChar)); - len = m_keys.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); + addData(hash, m_name.size()); + addData(hash, m_name); + addData(hash, m_keys.size()); for (const QString &key : std::as_const(m_keys)) { - len = key.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(key.constData()), len * sizeof(QChar)); + addData(hash, key.size()); + addData(hash, key); } } @@ -121,29 +133,23 @@ void FakeMetaMethod::setRevision(int r) void FakeMetaMethod::addToHash(QCryptographicHash &hash) const { - int len = m_name.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(m_name.constData()), len * sizeof(QChar)); - hash.addData(reinterpret_cast(&m_methodAccess), sizeof(m_methodAccess)); - hash.addData(reinterpret_cast(&m_methodTy), sizeof(m_methodTy)); - hash.addData(reinterpret_cast(&m_revision), sizeof(m_revision)); - len = m_paramNames.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); + addData(hash, m_name.size()); + addData(hash, m_name); + addData(hash, m_methodAccess); + addData(hash, m_methodTy); + addData(hash, m_revision); + addData(hash, m_paramNames.size()); for (const QString &pName : std::as_const(m_paramNames)) { - len = pName.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(pName.constData()), len * sizeof(QChar)); + addData(hash, pName.size()); + addData(hash, pName); } - len = m_paramTypes.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); + addData(hash, m_paramTypes.size()); for (const QString &pType : std::as_const(m_paramTypes)) { - len = pType.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(pType.constData()), len * sizeof(QChar)); + addData(hash, pType.size()); + addData(hash, pType); } - len = m_returnType.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(m_returnType.constData()), len * sizeof(QChar)); + addData(hash, m_returnType.size()); + addData(hash, m_returnType); } QString FakeMetaMethod::describe(int baseIndent) const @@ -213,17 +219,15 @@ int FakeMetaProperty::revision() const void FakeMetaProperty::addToHash(QCryptographicHash &hash) const { - int len = m_propertyName.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(m_propertyName.constData()), len * sizeof(QChar)); - hash.addData(reinterpret_cast(&m_revision), sizeof(m_revision)); + addData(hash, m_propertyName.size()); + addData(hash, m_propertyName); + addData(hash, m_revision); int flags = (m_isList ? (1 << 0) : 0) + (m_isPointer ? (1 << 1) : 0) + (m_isWritable ? (1 << 2) : 0); - hash.addData(reinterpret_cast(&flags), sizeof(flags)); - len = m_type.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(m_type.constData()), len * sizeof(QChar)); + addData(hash, flags); + addData(hash, m_type.size()); + addData(hash, m_type); } QString FakeMetaProperty::describe(int baseIndent) const @@ -361,34 +365,34 @@ QByteArray FakeMetaObject::calculateFingerprint() const { QCryptographicHash hash(QCryptographicHash::Sha1); int len = m_className.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(m_className.constData()), len * sizeof(QChar)); + addData(hash, len); + addData(hash, m_className); len = m_attachedTypeName.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(m_attachedTypeName.constData()), len * sizeof(QChar)); + addData(hash, len); + addData(hash, m_attachedTypeName); len = m_defaultPropertyName.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(m_defaultPropertyName.constData()), len * sizeof(QChar)); + addData(hash, len); + addData(hash, m_defaultPropertyName); len = m_enumNameToIndex.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); + addData(hash, len); { QStringList keys(m_enumNameToIndex.keys()); keys.sort(); for (const QString &key : std::as_const(keys)) { len = key.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(key.constData()), len * sizeof(QChar)); + addData(hash, len); + addData(hash, key); int value = m_enumNameToIndex.value(key); - hash.addData(reinterpret_cast(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint... + addData(hash, value); m_enums.at(value).addToHash(hash); } } len = m_exports.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); + addData(hash, len); for (const Export &e : std::as_const(m_exports)) e.addToHash(hash); // normalize order? len = m_exports.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); + addData(hash, len); for (const FakeMetaMethod &m : std::as_const(m_methods)) m.addToHash(hash); // normalize order? { @@ -396,16 +400,16 @@ QByteArray FakeMetaObject::calculateFingerprint() const keys.sort(); for (const QString &key : std::as_const(keys)) { len = key.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(key.constData()), len * sizeof(QChar)); + addData(hash, len); + addData(hash, key); int value = m_propNameToIdx.value(key); - hash.addData(reinterpret_cast(&value), sizeof(value)); // avoid? this adds order dependency to fingerprint... + addData(hash, value); m_props.at(value).addToHash(hash); } } len = m_superName.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(m_superName.constData()), len * sizeof(QChar)); + addData(hash, len); + addData(hash, m_superName); QByteArray res = hash.result(); res.append('F'); @@ -540,14 +544,12 @@ bool FakeMetaObject::Export::isValid() const void FakeMetaObject::Export::addToHash(QCryptographicHash &hash) const { - int len = package.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(package.constData()), len * sizeof(QChar)); - len = type.size(); - hash.addData(reinterpret_cast(&len), sizeof(len)); - hash.addData(reinterpret_cast(type.constData()), len * sizeof(QChar)); + addData(hash, package.size()); + addData(hash, package); + addData(hash, type.size()); + addData(hash, type); version.addToHash(hash); - hash.addData(reinterpret_cast(&metaObjectRevision), sizeof(metaObjectRevision)); + addData(hash, metaObjectRevision); } QString FakeMetaObject::Export::describe(int baseIndent) const diff --git a/src/libs/qmljs/qmljsimportdependencies.cpp b/src/libs/qmljs/qmljsimportdependencies.cpp index f1c4181a830..8e725fa521f 100644 --- a/src/libs/qmljs/qmljsimportdependencies.cpp +++ b/src/libs/qmljs/qmljsimportdependencies.cpp @@ -185,14 +185,14 @@ ImportKey::ImportKey(ImportType::Enum type, const QString &path, int majorVersio void ImportKey::addToHash(QCryptographicHash &hash) const { - hash.addData(reinterpret_cast(&type), sizeof(type)); - hash.addData(reinterpret_cast(&majorVersion), sizeof(majorVersion)); - hash.addData(reinterpret_cast(&minorVersion), sizeof(minorVersion)); + hash.addData(QByteArrayView(reinterpret_cast(&type), sizeof(type))); + hash.addData(QByteArrayView(reinterpret_cast(&majorVersion), sizeof(majorVersion))); + hash.addData(QByteArrayView(reinterpret_cast(&minorVersion), sizeof(minorVersion))); for (const QString &s : splitPath) { - hash.addData("/", 1); - hash.addData(reinterpret_cast(s.constData()), sizeof(QChar) * s.size()); + hash.addData("/"); + hash.addData(QByteArrayView(reinterpret_cast(s.constData()), sizeof(QChar) * s.size())); } - hash.addData("/", 1); + hash.addData("/"); } ImportKey ImportKey::flatKey() const { @@ -547,11 +547,11 @@ QByteArray DependencyInfo::calculateFingerprint(const ImportDependencies &deps) QStringList coreImports = Utils::toList(allCoreImports); coreImports.sort(); for (const QString &importId : std::as_const(coreImports)) { - hash.addData(reinterpret_cast(importId.constData()), importId.size() * sizeof(QChar)); + hash.addData(QByteArrayView(reinterpret_cast(importId.constData()), importId.size() * sizeof(QChar))); QByteArray coreImportFingerprint = deps.coreImport(importId).fingerprint; hash.addData(coreImportFingerprint); } - hash.addData("/", 1); + hash.addData("/"); QList imports = Utils::toList(allImports); std::sort(imports.begin(), imports.end()); for (const ImportKey &k : std::as_const(imports)) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 25a21fb7397..bc233ed188a 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -2681,22 +2681,26 @@ void StringListAspect::addToLayout(Layout &parent) } }; - connect(add, &QPushButton::clicked, this, [this, populate, editor] { - d->undoable.setSilently(d->undoable.get() << ""); - populate(); - const QTreeWidgetItem *root = editor->invisibleRootItem(); - QTreeWidgetItem *lastChild = root->child(root->childCount() - 1); - const QModelIndex index = editor->indexFromItem(lastChild, 0); - editor->edit(index); - }); + if (add) { + connect(add, &QPushButton::clicked, this, [this, populate, editor] { + d->undoable.setSilently(d->undoable.get() << ""); + populate(); + const QTreeWidgetItem *root = editor->invisibleRootItem(); + QTreeWidgetItem *lastChild = root->child(root->childCount() - 1); + const QModelIndex index = editor->indexFromItem(lastChild, 0); + editor->edit(index); + }); + } - connect(remove, &QPushButton::clicked, this, [this, editor, itemsToStringList] { - const QList selected = editor->selectedItems(); - QTC_ASSERT(selected.size() == 1, return); - editor->invisibleRootItem()->removeChild(selected.first()); - delete selected.first(); - d->undoable.set(undoStack(), itemsToStringList()); - }); + if (remove) { + connect(remove, &QPushButton::clicked, this, [this, editor, itemsToStringList] { + const QList selected = editor->selectedItems(); + QTC_ASSERT(selected.size() == 1, return); + editor->invisibleRootItem()->removeChild(selected.first()); + delete selected.first(); + d->undoable.set(undoStack(), itemsToStringList()); + }); + } connect( &d->undoable.m_signal, &UndoSignaller::changed, editor, [this, populate, itemsToStringList] { diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp index cd4fde81109..09e3a83520e 100644 --- a/src/libs/utils/layoutbuilder.cpp +++ b/src/libs/utils/layoutbuilder.cpp @@ -763,6 +763,31 @@ void Label::setText(const QString &text) access(this)->setText(text); } +void Label::setTextFormat(Qt::TextFormat format) +{ + access(this)->setTextFormat(format); +} + +void Label::setWordWrap(bool on) +{ + access(this)->setWordWrap(on); +} + +void Label::setTextInteractionFlags(Qt::TextInteractionFlags flags) +{ + access(this)->setTextInteractionFlags(flags); +} + +void Label::setOpenExternalLinks(bool on) +{ + access(this)->setOpenExternalLinks(on); +} + +void Label::onLinkHovered(const std::function &func, QObject *guard) +{ + QObject::connect(access(this), &QLabel::linkHovered, guard, func); +} + // Group Group::Group(std::initializer_list ps) diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h index 3a7eca26a57..07a6b9478ef 100644 --- a/src/libs/utils/layoutbuilder.h +++ b/src/libs/utils/layoutbuilder.h @@ -279,6 +279,11 @@ public: Label(const QString &text); void setText(const QString &); + void setTextFormat(Qt::TextFormat); + void setWordWrap(bool); + void setTextInteractionFlags(Qt::TextInteractionFlags); + void setOpenExternalLinks(bool); + void onLinkHovered(const std::function &, QObject *guard); }; class QTCREATOR_UTILS_EXPORT Group : public Widget @@ -446,6 +451,26 @@ class TitleId {}; auto title(auto p) { return IdAndArg{TitleId{}, p}; } void doit(auto x, TitleId, auto p) { x->setTitle(p); } +class TextFormatId {}; +auto textFormat(auto p) { return IdAndArg{TextFormatId{}, p}; } +void doit(auto x, TextFormatId, auto p) { x->setTextFormat(p); } + +class WordWrapId {}; +auto wordWrap(auto p) { return IdAndArg{WordWrapId{}, p}; } +void doit(auto x, WordWrapId, auto p) { x->setWordWrap(p); } + +class TextInteractionFlagId {}; +auto textInteractionFlags(auto p) { return IdAndArg{TextInteractionFlagId{}, p}; } +void doit(auto x, TextInteractionFlagId, auto p) { x->setTextInteractionFlags(p); } + +class OpenExternalLinksId {}; +auto openExternalLinks(auto p) { return IdAndArg{OpenExternalLinksId{}, p}; } +void doit(auto x, OpenExternalLinksId, auto p) { x->setOpenExternalLinks(p); } + +class OnLinkHoveredId {}; +auto onLinkHovered(auto p, QObject *guard) { return IdAndArg{OnLinkHoveredId{}, std::pair{p, guard}}; } +void doit(auto x, OnLinkHoveredId, auto p) { x->onLinkHovered(p.first, p.second); } + class GroupCheckerId {}; auto groupChecker(auto p) { return IdAndArg{GroupCheckerId{}, p}; } void doit(auto x, GroupCheckerId, auto p) { x->setGroupChecker(p); } diff --git a/src/libs/utils/outputformatter.cpp b/src/libs/utils/outputformatter.cpp index cf00b5ee3fa..d36662f4d34 100644 --- a/src/libs/utils/outputformatter.cpp +++ b/src/libs/utils/outputformatter.cpp @@ -58,7 +58,7 @@ Link OutputLineParser::parseLinkTarget(const QString &target) return {}; return Link(FilePath::fromString(parts.first()), parts.length() > 1 ? parts.at(1).toInt() : 0, - parts.length() > 2 ? parts.at(2).toInt() : 0); + parts.length() > 2 ? parts.at(2).toInt() - 1 : 0); } // The redirection mechanism is needed for broken build tools (e.g. xcodebuild) that get invoked @@ -141,26 +141,39 @@ FilePath OutputLineParser::absoluteFilePath(const FilePath &filePath) const return filePath; } -void OutputLineParser::addLinkSpecForAbsoluteFilePath(OutputLineParser::LinkSpecs &linkSpecs, - const FilePath &filePath, int lineNo, int pos, int len) +void OutputLineParser::addLinkSpecForAbsoluteFilePath( + OutputLineParser::LinkSpecs &linkSpecs, + const FilePath &filePath, + int lineNo, + int column, + int pos, + int len) { if (filePath.toFileInfo().isAbsolute()) - linkSpecs.append({pos, len, createLinkTarget(filePath, lineNo)}); + linkSpecs.append({pos, len, createLinkTarget(filePath, lineNo, column)}); } -void OutputLineParser::addLinkSpecForAbsoluteFilePath(OutputLineParser::LinkSpecs &linkSpecs, - const FilePath &filePath, int lineNo, const QRegularExpressionMatch &match, - int capIndex) +void OutputLineParser::addLinkSpecForAbsoluteFilePath( + OutputLineParser::LinkSpecs &linkSpecs, + const FilePath &filePath, + int lineNo, + int column, + const QRegularExpressionMatch &match, + int capIndex) { - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match.capturedStart(capIndex), - match.capturedLength(capIndex)); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, column, + match.capturedStart(capIndex), match.capturedLength(capIndex)); } -void OutputLineParser::addLinkSpecForAbsoluteFilePath(OutputLineParser::LinkSpecs &linkSpecs, - const FilePath &filePath, int lineNo, const QRegularExpressionMatch &match, - const QString &capName) +void OutputLineParser::addLinkSpecForAbsoluteFilePath( + OutputLineParser::LinkSpecs &linkSpecs, + const FilePath &filePath, + int lineNo, + int column, + const QRegularExpressionMatch &match, + const QString &capName) { - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match.capturedStart(capName), - match.capturedLength(capName)); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, column, + match.capturedStart(capName), match.capturedLength(capName)); } bool Utils::OutputLineParser::fileExists(const FilePath &fp) const diff --git a/src/libs/utils/outputformatter.h b/src/libs/utils/outputformatter.h index d26dc643271..da4dfe8a3a1 100644 --- a/src/libs/utils/outputformatter.h +++ b/src/libs/utils/outputformatter.h @@ -93,12 +93,13 @@ protected: Utils::FilePath absoluteFilePath(const Utils::FilePath &filePath) const; static QString createLinkTarget(const FilePath &filePath, int line, int column); static void addLinkSpecForAbsoluteFilePath(LinkSpecs &linkSpecs, const FilePath &filePath, - int lineNo, int pos, int len); + int lineNo, int column, int pos, int len); static void addLinkSpecForAbsoluteFilePath(LinkSpecs &linkSpecs, const FilePath &filePath, - int lineNo, const QRegularExpressionMatch &match, - int capIndex); + int lineNo, int column, + const QRegularExpressionMatch &match, int capIndex); static void addLinkSpecForAbsoluteFilePath(LinkSpecs &linkSpecs, const FilePath &filePath, - int lineNo, const QRegularExpressionMatch &match, + int lineNo, int column, + const QRegularExpressionMatch &match, const QString &capName); bool fileExists(const Utils::FilePath &fp) const; diff --git a/src/libs/utils/unarchiver.cpp b/src/libs/utils/unarchiver.cpp index 84365654253..d9092e4ca95 100644 --- a/src/libs/utils/unarchiver.cpp +++ b/src/libs/utils/unarchiver.cpp @@ -43,6 +43,7 @@ static const QList &sTools() { static QList tools; if (tools.isEmpty()) { + // clang-format off if (HostOsInfo::isWindowsHost()) { tools << Tool{{"powershell", "-command Expand-Archive -Force '%{src}' '%{dest}'", CommandLine::Raw}, {"application/zip"}, @@ -74,6 +75,10 @@ static const QList &sTools() tools << Tool{{"cmake", {"-E", "tar", "xvjf", "%{src}"}}, {"application/x-bzip-compressed-tar"}, additionalCMakeDirs}; + // Keep this at the end so its only used as last resort. Otherwise it might be used for + // .tar.gz files. + tools << Tool{{"gzip", {"-d", "%{src}", "-c"}}, {"application/gzip"}, {}}; + // clang-format on } return tools; } @@ -147,6 +152,45 @@ void Unarchiver::start() m_sourceAndCommand->m_sourceFile, m_destDir); m_destDir.ensureWritableDir(); + if (command.executable().fileName() == "gzip") { + std::shared_ptr outputFile = std::make_shared( + (m_destDir / m_gzipFileDestName).toFSPathString()); + + if (!outputFile->open(QIODevice::WriteOnly)) { + emit outputReceived(Tr::tr("Failed to open output file.")); + emit done(DoneResult::Error); + return; + } + + m_process.reset(new Process); + QObject::connect(m_process.get(), &Process::readyReadStandardOutput, this, [this, outputFile] { + const QByteArray data = m_process->readAllRawStandardOutput(); + if (outputFile->write(data) != data.size()) { + emit outputReceived(Tr::tr("Failed to write output file.")); + emit done(DoneResult::Error); + } + }); + QObject::connect(m_process.get(), &Process::readyReadStandardError, this, [this] { + emit outputReceived(m_process->readAllStandardError()); + }); + QObject::connect(m_process.get(), &Process::done, this, [outputFile, this] { + outputFile->close(); + const bool success = m_process->result() == ProcessResult::FinishedWithSuccess; + if (!success) { + outputFile->remove(); + emit outputReceived(Tr::tr("Command failed.")); + } + emit done(toDoneResult(success)); + }); + emit outputReceived( + Tr::tr("Running %1\nin \"%2\".\n\n", "Running in ") + .arg(command.toUserOutput(), m_destDir.toUserOutput())); + m_process->setCommand(command); + m_process->setWorkingDirectory(m_destDir); + m_process->start(); + return; + } + m_process.reset(new Process); m_process->setProcessChannelMode(QProcess::MergedChannels); QObject::connect(m_process.get(), &Process::readyReadStandardOutput, this, [this] { diff --git a/src/libs/utils/unarchiver.h b/src/libs/utils/unarchiver.h index 61818318bb7..23fcad07a81 100644 --- a/src/libs/utils/unarchiver.h +++ b/src/libs/utils/unarchiver.h @@ -32,7 +32,10 @@ public: void setSourceAndCommand(const SourceAndCommand &data) { m_sourceAndCommand = data; } void setDestDir(const FilePath &destDir) { m_destDir = destDir; } - + void setGZipFileDestName(const QString &gzipFileDestName) + { + m_gzipFileDestName = gzipFileDestName; + } void start(); signals: @@ -43,6 +46,7 @@ private: std::optional m_sourceAndCommand; FilePath m_destDir; std::unique_ptr m_process; + QString m_gzipFileDestName; }; class QTCREATOR_UTILS_EXPORT UnarchiverTaskAdapter : public Tasking::TaskAdapter diff --git a/src/plugins/android/javaparser.cpp b/src/plugins/android/javaparser.cpp index 72859bfdab3..65ddfba9ad6 100644 --- a/src/plugins/android/javaparser.cpp +++ b/src/plugins/android/javaparser.cpp @@ -62,7 +62,7 @@ OutputLineParser::Result JavaParser::handleLine(const QString &line, OutputForma absoluteFilePath(file), lineno); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, match, 2); + addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, task.column, match, 2); scheduleTask(task, 1); return {Status::Done, linkSpecs}; } diff --git a/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in b/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in index 5ee0e41c3fc..920b3ec31bb 100644 --- a/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in +++ b/src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in @@ -15,7 +15,7 @@ ], "Description" : "Visualize CPU and Memory consumption for running applications", "LongDescription" : [ - "Select an application to monitor its performance in real-time.", + "Select an application to monitor its performance in real-time." ], "Url" : "https://www.qt.io", ${IDE_PLUGIN_DEPENDENCIES} diff --git a/src/plugins/baremetal/iarewparser.cpp b/src/plugins/baremetal/iarewparser.cpp index 23a1d10a1db..286cb0e1686 100644 --- a/src/plugins/baremetal/iarewparser.cpp +++ b/src/plugins/baremetal/iarewparser.cpp @@ -117,8 +117,8 @@ OutputLineParser::Result IarParser::parseWarningOrErrorOrFatalErrorDetailsMessag m_expectSnippet = false; m_expectFilePath = false; LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, - FilePathIndex); + addLinkSpecForAbsoluteFilePath( + linkSpecs, m_lastTask.file, m_lastTask.line, m_lastTask.column, match, FilePathIndex); return {Status::InProgress, linkSpecs}; } diff --git a/src/plugins/baremetal/keilparser.cpp b/src/plugins/baremetal/keilparser.cpp index 4ae0c6aa648..64bf64e46fd 100644 --- a/src/plugins/baremetal/keilparser.cpp +++ b/src/plugins/baremetal/keilparser.cpp @@ -62,8 +62,8 @@ OutputLineParser::Result KeilParser::parseArmWarningOrErrorDetailsMessage(const const QString descr = match.captured(DescriptionIndex); newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno)); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, - FilePathIndex); + addLinkSpecForAbsoluteFilePath( + linkSpecs, m_lastTask.file, m_lastTask.line, m_lastTask.column, match, FilePathIndex); return {Status::InProgress, linkSpecs}; } @@ -98,8 +98,8 @@ OutputLineParser::Result KeilParser::parseMcs51WarningOrErrorDetailsMessage1(con match.captured(MessageTextIndex)); newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno)); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, - FilePathIndex); + addLinkSpecForAbsoluteFilePath( + linkSpecs, m_lastTask.file, m_lastTask.line, m_lastTask.column, match, FilePathIndex); return {Status::InProgress, linkSpecs}; } @@ -119,8 +119,8 @@ OutputLineParser::Result KeilParser::parseMcs51WarningOrErrorDetailsMessage2(con match.captured(MessageTextIndex)); newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno)); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, - FilePathIndex); + addLinkSpecForAbsoluteFilePath( + linkSpecs, m_lastTask.file, m_lastTask.line, m_lastTask.column, match, FilePathIndex); return {Status::InProgress, linkSpecs}; } diff --git a/src/plugins/baremetal/sdccparser.cpp b/src/plugins/baremetal/sdccparser.cpp index aa97173f85c..517f051390b 100644 --- a/src/plugins/baremetal/sdccparser.cpp +++ b/src/plugins/baremetal/sdccparser.cpp @@ -73,8 +73,8 @@ OutputLineParser::Result SdccParser::handleLine(const QString &line, OutputForma const QString descr = match.captured(MessageTextIndex); newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno)); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, - FilePathIndex); + addLinkSpecForAbsoluteFilePath( + linkSpecs, m_lastTask.file, m_lastTask.line, m_lastTask.column, match, FilePathIndex); return {Status::InProgress, linkSpecs}; } @@ -90,8 +90,8 @@ OutputLineParser::Result SdccParser::handleLine(const QString &line, OutputForma const QString descr = match.captured(MessageTextIndex); newTask(CompileTask(type, descr, absoluteFilePath(fileName), lineno)); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, match, - FilePathIndex); + addLinkSpecForAbsoluteFilePath( + linkSpecs, m_lastTask.file, m_lastTask.line, m_lastTask.column, match, FilePathIndex); return {Status::InProgress, linkSpecs}; } diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 32ee429c4d1..f3600352642 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -349,7 +349,7 @@ public: ClangdClient * const q; const CppEditor::ClangdSettings::Data settings; - ClangdFollowSymbol *followSymbol = nullptr; + QList followSymbolOps; ClangdSwitchDeclDef *switchDeclDef = nullptr; ClangdFindLocalReferences *findLocalRefs = nullptr; std::optional versionNumber; @@ -501,8 +501,8 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir, c ClangdClient::~ClangdClient() { - if (d->followSymbol) - d->followSymbol->clear(); + for (ClangdFollowSymbol * const followSymbol : std::as_const(d->followSymbolOps)) + followSymbol->clear(); delete d; } @@ -990,7 +990,7 @@ MessageId ClangdClient::requestSymbolInfo(const Utils::FilePath &filePath, const #ifdef WITH_TESTS ClangdFollowSymbol *ClangdClient::currentFollowSymbolOperation() { - return d->followSymbol; + return d->followSymbolOps.isEmpty() ? nullptr : d->followSymbolOps.first(); } #endif @@ -1005,8 +1005,20 @@ void ClangdClient::followSymbol(TextDocument *document, { QTC_ASSERT(documentOpen(document), openDocument(document)); - if (d->followSymbol) - d->followSymbol->cancel(); + const ClangdFollowSymbol::Origin origin + = CppEditor::CppCodeModelSettings::isInteractiveFollowSymbol() + ? ClangdFollowSymbol::Origin::User + : ClangdFollowSymbol::Origin::Code; + if (origin == ClangdFollowSymbol::Origin::User) { + for (auto it = d->followSymbolOps.begin(); it != d->followSymbolOps.end(); ) { + if ((*it)->isInteractive()) { + (*it)->cancel(); + it = d->followSymbolOps.erase(it); + } else { + ++it; + } + } + } const QTextCursor adjustedCursor = d->adjustedCursor(cursor, document); if (followTo == FollowTo::SymbolDef && !resolveTarget) { @@ -1020,14 +1032,13 @@ void ClangdClient::followSymbol(TextDocument *document, qCDebug(clangdLog) << "follow symbol requested" << document->filePath() << adjustedCursor.blockNumber() << adjustedCursor.positionInBlock(); - auto clangdFollowSymbol = new ClangdFollowSymbol(this, adjustedCursor, editorWidget, document, - callback, followTo, openInSplit); + auto clangdFollowSymbol = new ClangdFollowSymbol(this, origin, adjustedCursor, editorWidget, + document, callback, followTo, openInSplit); connect(clangdFollowSymbol, &ClangdFollowSymbol::done, this, [this, clangdFollowSymbol] { clangdFollowSymbol->deleteLater(); - if (clangdFollowSymbol == d->followSymbol) - d->followSymbol = nullptr; + d->followSymbolOps.removeOne(clangdFollowSymbol); }); - d->followSymbol = clangdFollowSymbol; + d->followSymbolOps << clangdFollowSymbol; } void ClangdClient::switchDeclDef(TextDocument *document, const QTextCursor &cursor, diff --git a/src/plugins/clangcodemodel/clangdfollowsymbol.cpp b/src/plugins/clangcodemodel/clangdfollowsymbol.cpp index 2bedda4d986..29fa15fe8bb 100644 --- a/src/plugins/clangcodemodel/clangdfollowsymbol.cpp +++ b/src/plugins/clangcodemodel/clangdfollowsymbol.cpp @@ -73,10 +73,10 @@ private: class ClangdFollowSymbol::Private { public: - Private(ClangdFollowSymbol *q, ClangdClient *client, const QTextCursor &cursor, + Private(ClangdFollowSymbol *q, ClangdClient *client, Origin origin, const QTextCursor &cursor, CppEditorWidget *editorWidget, const FilePath &filePath, const LinkHandler &callback, bool openInSplit) - : q(q), client(client), cursor(cursor), editorWidget(editorWidget), + : q(q), client(client), origin(origin), cursor(cursor), editorWidget(editorWidget), uri(client->hostPathToServerUri(filePath)), callback(callback), virtualFuncAssistProvider(q), docRevision(editorWidget ? editorWidget->textDocument()->document()->revision() : -1), @@ -94,6 +94,7 @@ public: ClangdFollowSymbol * const q; ClangdClient * const client; + const Origin origin; const QTextCursor cursor; const QPointer editorWidget; const DocumentUri uri; @@ -117,11 +118,11 @@ public: bool done = false; }; -ClangdFollowSymbol::ClangdFollowSymbol(ClangdClient *client, const QTextCursor &cursor, - CppEditorWidget *editorWidget, TextDocument *document, const LinkHandler &callback, - FollowTo followTo, bool openInSplit) +ClangdFollowSymbol::ClangdFollowSymbol(ClangdClient *client, Origin origin, + const QTextCursor &cursor, CppEditorWidget *editorWidget, TextDocument *document, + const LinkHandler &callback, FollowTo followTo, bool openInSplit) : QObject(client), - d(new Private(this, client, cursor, editorWidget, document->filePath(), callback, + d(new Private(this, client, origin, cursor, editorWidget, document->filePath(), callback, openInSplit)) { // Abort if the user does something else with the document in the meantime. @@ -193,6 +194,11 @@ void ClangdFollowSymbol::clear() d->pendingGotoDefRequests.clear(); } +bool ClangdFollowSymbol::isInteractive() const +{ + return d->origin == Origin::User; +} + void ClangdFollowSymbol::emitDone(const Link &link) { if (d->done) diff --git a/src/plugins/clangcodemodel/clangdfollowsymbol.h b/src/plugins/clangcodemodel/clangdfollowsymbol.h index 33cef520d88..539ae461bc2 100644 --- a/src/plugins/clangcodemodel/clangdfollowsymbol.h +++ b/src/plugins/clangcodemodel/clangdfollowsymbol.h @@ -23,7 +23,9 @@ class ClangdFollowSymbol : public QObject { Q_OBJECT public: - ClangdFollowSymbol(ClangdClient *client, const QTextCursor &cursor, + enum class Origin { User, Code }; + + ClangdFollowSymbol(ClangdClient *client, Origin origin, const QTextCursor &cursor, CppEditor::CppEditorWidget *editorWidget, TextEditor::TextDocument *document, const Utils::LinkHandler &callback, FollowTo followTo, bool openInSplit); @@ -31,6 +33,8 @@ public: void cancel(); void clear(); + bool isInteractive() const; + signals: void done(); diff --git a/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in b/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in index 010f6b8721f..72621cda105 100644 --- a/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in +++ b/src/plugins/cmakeprojectmanager/CMakeProjectManager.json.in @@ -15,7 +15,7 @@ "Category" : "Build Systems", "Description" : "Automate the configuration of build systems with CMake", "LongDescription" : [ - "CMake controls the software compilation process by using simple configuration files, called CMakeLists.txt files." + "CMake controls the software compilation process by using simple configuration files, called CMakeLists.txt files.", "You also need:", "- CMake", "Qt Online Installer installs a CMake version that you can use." diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.cpp b/src/plugins/cmakeprojectmanager/cmakeparser.cpp index 7da4e383911..c5c8c30d253 100644 --- a/src/plugins/cmakeprojectmanager/cmakeparser.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeparser.cpp @@ -93,8 +93,8 @@ OutputLineParser::Result CMakeParser::handleLine(const QString &line, OutputForm match.captured(2).toInt()); m_lines = 1; LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, - match, 1); + addLinkSpecForAbsoluteFilePath( + linkSpecs, m_lastTask.file, m_lastTask.line, m_lastTask.column, match, 1); m_errorOrWarningLine.file = m_lastTask.file; m_errorOrWarningLine.line = m_lastTask.line; @@ -107,8 +107,8 @@ OutputLineParser::Result CMakeParser::handleLine(const QString &line, OutputForm m_lastTask = BuildSystemTask(Task::Error, QString(), absoluteFilePath(FilePath::fromUserInput(match.captured(1)))); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, - match, 1); + addLinkSpecForAbsoluteFilePath( + linkSpecs, m_lastTask.file, m_lastTask.line, m_lastTask.column, match, 1); m_lines = 1; return {Status::InProgress, linkSpecs}; } @@ -121,8 +121,8 @@ OutputLineParser::Result CMakeParser::handleLine(const QString &line, OutputForm match.captured(3).toInt()); m_lines = 1; LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, - match, 1); + addLinkSpecForAbsoluteFilePath( + linkSpecs, m_lastTask.file, m_lastTask.line, m_lastTask.column, match, 1); m_errorOrWarningLine.file = m_lastTask.file; m_errorOrWarningLine.line = m_lastTask.line; @@ -174,8 +174,13 @@ OutputLineParser::Result CMakeParser::handleLine(const QString &line, OutputForm m_lastTask.line = match.captured(1).toInt(); m_expectTripleLineErrorData = LINE_DESCRIPTION; LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, m_lastTask.file, m_lastTask.line, 0, - match.capturedStart()); + addLinkSpecForAbsoluteFilePath( + linkSpecs, + m_lastTask.file, + m_lastTask.line, + m_lastTask.column, + 0, + match.capturedStart()); return {Status::InProgress, linkSpecs}; } case LINE_DESCRIPTION: diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 777bb0e46cb..59e893569e6 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -210,9 +210,11 @@ static CMakeBuildTarget toBuildTarget(const TargetDetails &t, const FilePath &sourceDirectory, const FilePath &buildDirectory, bool relativeLibs, - const QSet &artifacts) + const QSet &sharedLibraryArtifacts) { const FilePath currentBuildDir = buildDirectory.resolvePath(t.buildDir); + const QSet sharedLibraryArtifactsPaths + = transform(sharedLibraryArtifacts, &FilePath::parentDir); CMakeBuildTarget ct; ct.title = t.name; @@ -306,7 +308,6 @@ static CMakeBuildTarget toBuildTarget(const TargetDetails &t, if (f.role == "libraries") tmp = tmp.parentDir(); - std::optional dllName; if (buildDir.osType() == OsTypeWindows && (f.role == "libraries")) { const auto partAsFilePath = FilePath::fromUserInput(part); part = partAsFilePath.fileName(); @@ -314,24 +315,6 @@ static CMakeBuildTarget toBuildTarget(const TargetDetails &t, // Skip object libraries on Windows. This case can happen with static qml plugins if (part.endsWith(".obj") || part.endsWith(".o")) continue; - - // Only consider dlls, not static libraries - for (const QString &suffix : - {QString(".lib"), QString(".dll.a"), QString(".a")}) { - if (part.endsWith(suffix) && !dllName) - dllName = part.chopped(suffix.length()).append(".dll"); - } - - // MinGW has libQt6Core.a -> Qt6Core.dll - // but libFoo.dll.a was already handled above - const QString mingwPrefix("lib"); - const QString mingwSuffix("a"); - const QString completeSuffix = partAsFilePath.completeSuffix(); - if (part.startsWith(mingwPrefix) && completeSuffix == mingwSuffix) { - dllName = part.chopped(mingwSuffix.length() + 1/*the '.'*/) - .sliced(mingwPrefix.length()) - .append(".dll"); - } } if (!tmp.isEmpty() && tmp.isDir()) { @@ -345,18 +328,15 @@ static CMakeBuildTarget toBuildTarget(const TargetDetails &t, {"/lib", "/lib64", "/usr/lib", "/usr/lib64", "/usr/local/lib"})) librarySeachPaths.append(tmp); - if (buildDir.osType() == OsTypeWindows && dllName) { - const auto validPath = [&artifacts](const FilePath& path) { - return path.exists() || artifacts.contains(path); - }; - if (validPath(tmp.pathAppended(*dllName))) + if (buildDir.osType() == OsTypeWindows) { + if (sharedLibraryArtifactsPaths.contains(tmp)) librarySeachPaths.append(tmp); // Libraries often have their import libs in ../lib and the // actual dll files in ../bin on windows. Qt is one example of that. if (tmp.fileName() == "lib") { const FilePath path = tmp.parentDir().pathAppended("bin"); - if (path.isDir() && validPath(path.pathAppended(*dllName))) + if (path.isDir()) librarySeachPaths.append(path); } } @@ -375,17 +355,19 @@ static QList generateBuildTargets(const QFuture &cancelF const FilePath &buildDirectory, bool relativeLibs) { - QSet artifacts; + QSet sharedLibraryArtifacts; for (const TargetDetails &t : input.targetDetails) - for (const FilePath &p: t.artifacts) - artifacts.insert(buildDirectory.resolvePath(p)); + if (t.type == "MODULE_LIBRARY" || t.type == "SHARED_LIBRARY") + for (const FilePath &p : t.artifacts) + sharedLibraryArtifacts.insert(buildDirectory.resolvePath(p)); QList result; result.reserve(input.targetDetails.size()); for (const TargetDetails &t : input.targetDetails) { if (cancelFuture.isCanceled()) return {}; - result.append(toBuildTarget(t, sourceDirectory, buildDirectory, relativeLibs, artifacts)); + result.append( + toBuildTarget(t, sourceDirectory, buildDirectory, relativeLibs, sharedLibraryArtifacts)); } return result; } diff --git a/src/plugins/copilot/copilotsettings.cpp b/src/plugins/copilot/copilotsettings.cpp index 9ddfa4edfbb..aeac499c631 100644 --- a/src/plugins/copilot/copilotsettings.cpp +++ b/src/plugins/copilot/copilotsettings.cpp @@ -168,41 +168,38 @@ CopilotSettings::CopilotSettings() setLayouter([this] { using namespace Layouting; - auto warningLabel = new QLabel; - warningLabel->setWordWrap(true); - warningLabel->setTextInteractionFlags( - Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard | Qt::TextSelectableByMouse); - warningLabel->setText( - Tr::tr("Enabling %1 is subject to your agreement and abidance with your applicable " - "%1 terms. It is your responsibility to know and accept the requirements and " - "parameters of using tools like %1. This may include, but is not limited to, " - "ensuring you have the rights to allow %1 access to your code, as well as " - "understanding any implications of your use of %1 and suggestions produced " - "(like copyright, accuracy, etc.).") - .arg("Copilot")); - - auto authWidget = new AuthWidget(); - - auto helpLabel = new QLabel(); - helpLabel->setTextFormat(Qt::MarkdownText); - helpLabel->setWordWrap(true); - helpLabel->setTextInteractionFlags( - Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard | Qt::TextSelectableByMouse); - helpLabel->setOpenExternalLinks(true); - connect(helpLabel, &QLabel::linkHovered, [](const QString &link) { - QToolTip::showText(QCursor::pos(), link); - }); - // clang-format off - helpLabel->setText(Tr::tr( - "The Copilot plugin requires node.js and the Copilot neovim plugin. " - "If you install the neovim plugin as described in %1, " - "the plugin will find the agent.js file automatically.\n\n" - "Otherwise you need to specify the path to the %2 " - "file from the Copilot neovim plugin.", - "Markdown text for the copilot instruction label") - .arg("[README.md](https://github.com/github/copilot.vim)") - .arg("[agent.js](https://github.com/github/copilot.vim/tree/release/dist)")); + + Label warningLabel { + wordWrap(true), + textInteractionFlags( + Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard | Qt::TextSelectableByMouse), + text(Tr::tr("Enabling %1 is subject to your agreement and abidance with your applicable " + "%1 terms. It is your responsibility to know and accept the requirements and " + "parameters of using tools like %1. This may include, but is not limited to, " + "ensuring you have the rights to allow %1 access to your code, as well as " + "understanding any implications of your use of %1 and suggestions produced " + "(like copyright, accuracy, etc.).") + .arg("Copilot")), + }; + + Label helpLabel { + textFormat(Qt::MarkdownText), + wordWrap(true), + textInteractionFlags( + Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard | Qt::TextSelectableByMouse), + openExternalLinks(true), + onLinkHovered([](const QString &link) { QToolTip::showText(QCursor::pos(), link); }, this), + text(Tr::tr( + "The Copilot plugin requires node.js and the Copilot neovim plugin. " + "If you install the neovim plugin as described in %1, " + "the plugin will find the agent.js file automatically.\n\n" + "Otherwise you need to specify the path to the %2 " + "file from the Copilot neovim plugin.", + "Markdown text for the copilot instruction label") + .arg("[README.md](https://github.com/github/copilot.vim)") + .arg("[agent.js](https://github.com/github/copilot.vim/tree/release/dist)")) + }; return Column { Group { @@ -213,7 +210,7 @@ CopilotSettings::CopilotSettings() } }, Form { - authWidget, br, + new AuthWidget, br, enableCopilot, br, nodeJsPath, br, distPath, br, diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index dd99f474503..0777bd20422 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -251,6 +251,9 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) expander->registerVariable("HostOs:ExecutableSuffix", Tr::tr("The platform executable suffix."), [] { return QString(Utils::HostOsInfo::withExecutableSuffix("")); }); + expander->registerFileVariables("IDE:Executable", + Tr::tr("The path to the running %1 itself.").arg(QGuiApplication::applicationDisplayName()), + []() { return FilePath::fromUserInput(QCoreApplication::applicationFilePath()); }); expander->registerVariable("IDE:ResourcePath", Tr::tr("The directory where %1 finds its pre-installed resources.") .arg(QGuiApplication::applicationDisplayName()), diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 5c0a1a8574a..da47d44b6e0 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -301,7 +301,6 @@ public: WindowSupport *m_windowSupport = nullptr; EditorManager *m_editorManager = nullptr; ExternalToolManager *m_externalToolManager = nullptr; - MessageManager *m_messageManager = nullptr; ProgressManagerPrivate *m_progressManager = nullptr; JsExpander *m_jsExpander = nullptr; VcsManager *m_vcsManager = nullptr; @@ -1395,7 +1394,6 @@ void ICorePrivate::init() m_rightNavigationWidget = new NavigationWidget(m_toggleRightSideBarAction, Side::Right); m_rightPaneWidget = new RightPaneWidget(); - m_messageManager = new MessageManager; m_editorManager = new EditorManager(this); m_externalToolManager = new ExternalToolManager(); @@ -1454,8 +1452,7 @@ ICorePrivate::~ICorePrivate() delete m_externalToolManager; m_externalToolManager = nullptr; - delete m_messageManager; - m_messageManager = nullptr; + MessageManager::destroy(); delete m_shortcutSettings; m_shortcutSettings = nullptr; delete m_toolSettings; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index 0fa19f2b6e5..6a32b294a3d 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -237,98 +237,6 @@ private: QList> m_outputData; }; -// This instance of this object is created by LocatorMatcher tree. -// It starts a separate thread which collects and deduplicates the results reported -// by LocatorStorage instances. The ResultsCollector is started as a first task in -// LocatorMatcher and runs in parallel to all the filters started by LocatorMatcher. -// When all the results are reported (the expected number of reports is set with setFilterCount()), -// the ResultsCollector finishes. The intermediate results are reported with -// serialOutputDataReady() signal. -// The object of ResultsCollector is registered in Tasking namespace under the -// ResultsCollectorTask name. -class ResultsCollector : public QObject -{ - Q_OBJECT - -public: - ~ResultsCollector(); - void setFilterCount(int count); - void start(); - - bool isRunning() const { return m_watcher.get(); } - - std::shared_ptr deduplicator() const { return m_deduplicator; } - -signals: - void serialOutputDataReady(const LocatorFilterEntries &serialOutputData); - void done(); - -private: - int m_filterCount = 0; - std::unique_ptr> m_watcher; - std::shared_ptr m_deduplicator; -}; - -ResultsCollector::~ResultsCollector() -{ - if (!isRunning()) - return; - - m_deduplicator->cancel(); - if (Utils::futureSynchronizer()) { - Utils::futureSynchronizer()->addFuture(m_watcher->future()); - return; - } - m_watcher->future().waitForFinished(); -} - -void ResultsCollector::setFilterCount(int count) -{ - QTC_ASSERT(!isRunning(), return); - QTC_ASSERT(count >= 0, return); - - m_filterCount = count; -} - -void ResultsCollector::start() -{ - QTC_ASSERT(!m_watcher, return); - QTC_ASSERT(!isRunning(), return); - if (m_filterCount == 0) { - emit done(); - return; - } - - m_deduplicator.reset(new ResultsDeduplicator(m_filterCount)); - m_watcher.reset(new QFutureWatcher); - connect(m_watcher.get(), &QFutureWatcherBase::resultReadyAt, this, [this](int index) { - emit serialOutputDataReady(m_watcher->resultAt(index)); - }); - connect(m_watcher.get(), &QFutureWatcherBase::finished, this, [this] { - emit done(); - m_watcher.release()->deleteLater(); - m_deduplicator.reset(); - }); - - // TODO: When filterCount == 1, deliver results directly and finish? - auto deduplicate = [](QPromise &promise, - const std::shared_ptr &deduplicator) { - deduplicator->run(promise); - }; - m_watcher->setFuture(Utils::asyncRun(deduplicate, m_deduplicator)); -} - -class ResultsCollectorTaskAdapter : public TaskAdapter -{ -public: - ResultsCollectorTaskAdapter() { - connect(task(), &ResultsCollector::done, this, [this] { emit done(DoneResult::Success); }); - } - void start() final { task()->start(); } -}; - -using ResultsCollectorTask = CustomTask; - class LocatorStoragePrivate { public: @@ -425,23 +333,39 @@ void LocatorMatcher::start() QTC_ASSERT(!isRunning(), return); d->m_output = {}; - const Storage collectorStorage; + const int filterCount = d->m_tasks.size(); + if (filterCount <= 0) + return; + + struct ResultsCollector + { + ~ResultsCollector() { + if (m_deduplicator) + m_deduplicator->cancel(); + } + std::shared_ptr m_deduplicator; + }; + + const Storage collectorStorage; const LoopList iterator(d->m_tasks); - const auto onCollectorSetup = [this, filterCount = d->m_tasks.size(), collectorStorage]( - ResultsCollector &collector) { - *collectorStorage = &collector; - collector.setFilterCount(filterCount); - connect(&collector, &ResultsCollector::serialOutputDataReady, - this, [this](const LocatorFilterEntries &serialOutputData) { + const auto onCollectorSetup = [this, filterCount, collectorStorage]( + Async &async) { + const std::shared_ptr deduplicator(new ResultsDeduplicator(filterCount)); + collectorStorage->m_deduplicator = deduplicator; + Async *asyncPtr = &async; + connect(asyncPtr, &AsyncBase::resultReadyAt, this, [this, asyncPtr](int index) { + const LocatorFilterEntries serialOutputData = asyncPtr->resultAt(index); d->m_output += serialOutputData; emit serialOutputDataReady(serialOutputData); }); + // TODO: When filterCount == 1, deliver results directly and finish? + async.setConcurrentCallData(&ResultsDeduplicator::run, deduplicator); }; - const auto onCollectorDone = [collectorStorage] { *collectorStorage = nullptr; }; + const auto onCollectorDone = [collectorStorage] { collectorStorage->m_deduplicator->cancel(); }; const auto onTaskTreeSetup = [iterator, input = d->m_input, collectorStorage](TaskTree &taskTree) { - const std::shared_ptr deduplicator = (*collectorStorage)->deduplicator(); + const std::shared_ptr deduplicator = collectorStorage->m_deduplicator; const Storage storage = iterator->storage; const auto onSetup = [storage, input, index = iterator.iteration(), deduplicator] { *storage = std::make_shared(input, index, deduplicator); @@ -458,7 +382,7 @@ void LocatorMatcher::start() const Group root { parallel, collectorStorage, - ResultsCollectorTask(onCollectorSetup, onCollectorDone), + AsyncTask(onCollectorSetup, onCollectorDone), Group { parallelLimit(d->m_parallelLimit), iterator, @@ -1472,5 +1396,3 @@ LocatorMatcherTask LocatorFileCache::matcher() const } } // Core - -#include "ilocatorfilter.moc" diff --git a/src/plugins/coreplugin/messagemanager.cpp b/src/plugins/coreplugin/messagemanager.cpp index 464d3fce716..d8e723ecf2c 100644 --- a/src/plugins/coreplugin/messagemanager.cpp +++ b/src/plugins/coreplugin/messagemanager.cpp @@ -5,113 +5,88 @@ #include "messageoutputwindow.h" -#include #include #include -#include -#include + +#include /*! - \class Core::MessageManager + \namespace Core::MessageManager \inheaderfile coreplugin/messagemanager.h \ingroup mainclasses \inmodule QtCreator - \brief The MessageManager class is used to post messages in the + \brief The MessageManager namespace is used to post messages in the \uicontrol{General Messages} pane. */ -namespace Core { +namespace Core::MessageManager { -static MessageManager *m_instance = nullptr; -static Internal::MessageOutputWindow *m_messageOutputWindow = nullptr; +static std::unique_ptr s_messageOutputWindow; enum class Flag { Silent, Flash, Disrupt }; static void showOutputPane(Flag flags) { - QTC_ASSERT(m_messageOutputWindow, return); - + QTC_ASSERT(s_messageOutputWindow, return); switch (flags) { - case Core::Flag::Silent: + case Flag::Silent: break; - case Core::Flag::Flash: - m_messageOutputWindow->flash(); + case Flag::Flash: + s_messageOutputWindow->flash(); break; - case Core::Flag::Disrupt: - m_messageOutputWindow->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus); + case Flag::Disrupt: + s_messageOutputWindow->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus); break; } } static void doWrite(const QString &text, Flag flags) { - QTC_ASSERT(m_messageOutputWindow, return); - + QTC_ASSERT(s_messageOutputWindow, return); showOutputPane(flags); - m_messageOutputWindow->append(text + '\n'); + s_messageOutputWindow->append(text + '\n'); } -static void write(const QString &text, Flag flags) +static void writeImpl(const QString &text, Flag flags) { - QTC_ASSERT(m_instance, return); - if (QThread::currentThread() == m_instance->thread()) - doWrite(text, flags); - else - QMetaObject::invokeMethod(m_instance, [text, flags] { - doWrite(text, flags); - }, Qt::QueuedConnection); + QTC_ASSERT(s_messageOutputWindow, return); + QMetaObject::invokeMethod(s_messageOutputWindow.get(), [text, flags] { doWrite(text, flags); }); } /*! \internal */ -MessageManager::MessageManager() +void init() { - m_instance = this; - m_messageOutputWindow = nullptr; + s_messageOutputWindow.reset(new Internal::MessageOutputWindow); } /*! \internal */ -MessageManager::~MessageManager() +void destroy() { - if (m_messageOutputWindow) { - ExtensionSystem::PluginManager::removeObject(m_messageOutputWindow); - delete m_messageOutputWindow; - } - m_instance = nullptr; + s_messageOutputWindow.reset(); } /*! \internal */ -void MessageManager::init() +void setFont(const QFont &font) { - m_messageOutputWindow = new Internal::MessageOutputWindow; - ExtensionSystem::PluginManager::addObject(m_messageOutputWindow); + QTC_ASSERT(s_messageOutputWindow, return); + s_messageOutputWindow->setFont(font); } /*! \internal */ -void MessageManager::setFont(const QFont &font) +void setWheelZoomEnabled(bool enabled) { - QTC_ASSERT(m_messageOutputWindow, return); - - m_messageOutputWindow->setFont(font); -} - -/*! - \internal -*/ -void MessageManager::setWheelZoomEnabled(bool enabled) -{ - QTC_ASSERT(m_messageOutputWindow, return); - - m_messageOutputWindow->setWheelZoomEnabled(enabled); + QTC_ASSERT(s_messageOutputWindow, return); + s_messageOutputWindow->setWheelZoomEnabled(enabled); } /*! @@ -124,9 +99,9 @@ void MessageManager::setWheelZoomEnabled(bool enabled) \sa writeFlashing() \sa writeDisrupting() */ -void MessageManager::writeSilently(const QString &message) +void writeSilently(const QString &message) { - Core::write(message, Flag::Silent); + writeImpl(message, Flag::Silent); } /*! @@ -141,9 +116,9 @@ void MessageManager::writeSilently(const QString &message) \sa writeSilently() \sa writeDisrupting() */ -void MessageManager::writeFlashing(const QString &message) +void writeFlashing(const QString &message) { - Core::write(message, Flag::Flash); + writeImpl(message, Flag::Flash); } /*! @@ -156,15 +131,15 @@ void MessageManager::writeFlashing(const QString &message) \sa writeSilently() \sa writeFlashing() */ -void MessageManager::writeDisrupting(const QString &message) +void writeDisrupting(const QString &message) { - Core::write(message, Flag::Disrupt); + writeImpl(message, Flag::Disrupt); } /*! \overload writeSilently() */ -void MessageManager::writeSilently(const QStringList &messages) +void writeSilently(const QStringList &messages) { writeSilently(messages.join('\n')); } @@ -172,7 +147,7 @@ void MessageManager::writeSilently(const QStringList &messages) /*! \overload writeFlashing() */ -void MessageManager::writeFlashing(const QStringList &messages) +void writeFlashing(const QStringList &messages) { writeFlashing(messages.join('\n')); } @@ -180,9 +155,9 @@ void MessageManager::writeFlashing(const QStringList &messages) /*! \overload writeDisrupting() */ -void MessageManager::writeDisrupting(const QStringList &messages) +void writeDisrupting(const QStringList &messages) { writeDisrupting(messages.join('\n')); } -} // namespace Core +} // namespace Core::MessageManager diff --git a/src/plugins/coreplugin/messagemanager.h b/src/plugins/coreplugin/messagemanager.h index f28b7072305..87a4b6f6499 100644 --- a/src/plugins/coreplugin/messagemanager.h +++ b/src/plugins/coreplugin/messagemanager.h @@ -5,47 +5,26 @@ #include "core_global.h" -#include -#include +#include QT_BEGIN_NAMESPACE class QFont; QT_END_NAMESPACE -namespace Core { +namespace Core::MessageManager { -class ICore; +CORE_EXPORT void setFont(const QFont &font); +CORE_EXPORT void setWheelZoomEnabled(bool enabled); -namespace Internal { -class ICorePrivate; -class MainWindow; -} +CORE_EXPORT void writeSilently(const QString &message); +CORE_EXPORT void writeFlashing(const QString &message); +CORE_EXPORT void writeDisrupting(const QString &message); -class CORE_EXPORT MessageManager : public QObject -{ - Q_OBJECT +CORE_EXPORT void writeSilently(const QStringList &messages); +CORE_EXPORT void writeFlashing(const QStringList &messages); +CORE_EXPORT void writeDisrupting(const QStringList &messages); -public: - static void setFont(const QFont &font); - static void setWheelZoomEnabled(bool enabled); +void init(); +void destroy(); - static void writeSilently(const QString &message); - static void writeFlashing(const QString &message); - static void writeDisrupting(const QString &message); - - static void writeSilently(const QStringList &messages); - static void writeFlashing(const QStringList &messages); - static void writeDisrupting(const QStringList &messages); - -private: - MessageManager(); - ~MessageManager() override; - - static void init(); - - friend class ICore; - friend class Internal::ICorePrivate; - friend class Internal::MainWindow; -}; - -} // namespace Core +} // namespace Core::MessageManager diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 53c009d4c39..5dde29a49cf 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -83,6 +83,7 @@ bool operator==(const CppEditor::CppCodeModelSettings &s1, && s1.useBuiltinPreprocessor == s2.useBuiltinPreprocessor && s1.indexerFileSizeLimitInMb == s2.indexerFileSizeLimitInMb && s1.m_categorizeFindReferences == s2.m_categorizeFindReferences + && s1.interactiveFollowSymbol == s2.interactiveFollowSymbol && s1.ignoreFiles == s2.ignoreFiles && s1.ignorePattern == s2.ignorePattern; } @@ -204,6 +205,16 @@ void CppCodeModelSettings::setCategorizeFindReferences(bool categorize) globalInstance().m_categorizeFindReferences = categorize; } +bool CppCodeModelSettings::isInteractiveFollowSymbol() +{ + return globalInstance().interactiveFollowSymbol; +} + +void CppCodeModelSettings::setInteractiveFollowSymbol(bool interactive) +{ + globalInstance().interactiveFollowSymbol = interactive; +} + CppCodeModelProjectSettings::CppCodeModelProjectSettings(ProjectExplorer::Project *project) : m_project(project) { diff --git a/src/plugins/cppeditor/cppcodemodelsettings.h b/src/plugins/cppeditor/cppcodemodelsettings.h index 9bf2b6862db..9f2f3d1718d 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.h +++ b/src/plugins/cppeditor/cppcodemodelsettings.h @@ -55,6 +55,9 @@ public: static bool categorizeFindReferences(); static void setCategorizeFindReferences(bool categorize); + static bool isInteractiveFollowSymbol(); + static void setInteractiveFollowSymbol(bool interactive); + QString ignorePattern; PCHUsage pchUsage = PchUse_BuildSystem; int indexerFileSizeLimitInMb = 5; @@ -63,7 +66,10 @@ public: bool useBuiltinPreprocessor = true; bool ignoreFiles = false; bool enableIndexing = true; - bool m_categorizeFindReferences = false; // Ephemeral! + + // Ephemeral! + bool m_categorizeFindReferences = false; + bool interactiveFollowSymbol = true; private: CppCodeModelSettings(Utils::QtcSettings *s) { fromSettings(s); } @@ -76,6 +82,14 @@ private: namespace Internal { void setupCppCodeModelSettingsPage(); void setupCppCodeModelProjectSettingsPanel(); + +class NonInteractiveFollowSymbolMarker +{ +public: + NonInteractiveFollowSymbolMarker() { CppCodeModelSettings::setInteractiveFollowSymbol(false); } + ~NonInteractiveFollowSymbolMarker() { CppCodeModelSettings::setInteractiveFollowSymbol(true); } +}; + } // namespace Internal } // namespace CppEditor diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index d5d64597b92..609b35051c4 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -623,6 +623,7 @@ void CppEditorWidget::renameUsages(const QString &replacement, QTextCursor curso const CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this, textDocument()}; CppModelManager::globalRename(cursorInEditor, replacement); }; + NonInteractiveFollowSymbolMarker niMarker; CppModelManager::followSymbol(CursorInEditor{cursor, textDocument()->filePath(), this, diff --git a/src/plugins/cppeditor/quickfixes/cppcodegenerationquickfixes.cpp b/src/plugins/cppeditor/quickfixes/cppcodegenerationquickfixes.cpp index 2d486e18173..7adf62cb815 100644 --- a/src/plugins/cppeditor/quickfixes/cppcodegenerationquickfixes.cpp +++ b/src/plugins/cppeditor/quickfixes/cppcodegenerationquickfixes.cpp @@ -260,15 +260,14 @@ static void extractNames(const CppRefactoringFilePtr &file, class GetterSetterRefactoringHelper { public: - GetterSetterRefactoringHelper(CppQuickFixOperation *operation, - const FilePath &filePath, - Class *clazz) + GetterSetterRefactoringHelper(CppQuickFixOperation *operation, Class *clazz) : m_operation(operation) , m_changes(m_operation->snapshot()) , m_locator(m_changes) - , m_headerFile(m_changes.cppFile(filePath)) + , m_headerFile(operation->currentFile()) , m_sourceFile([&] { - FilePath cppFilePath = correspondingHeaderOrSource(filePath, &m_isHeaderHeaderFile); + FilePath cppFilePath = correspondingHeaderOrSource(m_headerFile->filePath(), + &m_isHeaderHeaderFile); if (!m_isHeaderHeaderFile || !cppFilePath.exists()) { // there is no "source" file return m_headerFile; @@ -1271,11 +1270,10 @@ private: const ClassSpecifierAST *m_classAST; InsertionPointLocator::AccessSpec m_accessSpec; GenerateConstructorRefactoringHelper(CppQuickFixOperation *operation, - const FilePath &filePath, Class *clazz, const ClassSpecifierAST *classAST, InsertionPointLocator::AccessSpec accessSpec) - : GetterSetterRefactoringHelper(operation, filePath, clazz) + : GetterSetterRefactoringHelper(operation, clazz) , m_classAST(classAST) , m_accessSpec(accessSpec) {} @@ -1416,7 +1414,6 @@ private: } }; GenerateConstructorRefactoringHelper helper(this, - currentFile()->filePath(), m_classAST->symbol, m_classAST, accessSpec); @@ -1509,7 +1506,7 @@ public: void perform() override { - GetterSetterRefactoringHelper helper(this, currentFile()->filePath(), m_data.clazz); + GetterSetterRefactoringHelper helper(this, m_data.clazz); helper.performGeneration(m_data, m_generateFlags); helper.applyChanges(); } @@ -1829,9 +1826,7 @@ private: } if (m_candidates.empty()) return; - GetterSetterRefactoringHelper helper(this, - currentFile()->filePath(), - m_candidates.front().data.clazz); + GetterSetterRefactoringHelper helper(this, m_candidates.front().data.clazz); for (MemberInfo &mi : m_candidates) { if (mi.requestedFlags != 0) { helper.performGeneration(mi.data, mi.requestedFlags); diff --git a/src/plugins/cppeditor/quickfixes/cppinsertvirtualmethods.cpp b/src/plugins/cppeditor/quickfixes/cppinsertvirtualmethods.cpp index 31193e5cec0..1a2ee5ab878 100644 --- a/src/plugins/cppeditor/quickfixes/cppinsertvirtualmethods.cpp +++ b/src/plugins/cppeditor/quickfixes/cppinsertvirtualmethods.cpp @@ -767,8 +767,7 @@ public: printer.showTemplateParameters = true; Utils::ChangeSet headerChangeSet; const CppRefactoringChanges refactoring(snapshot()); - const Utils::FilePath filePath = currentFile()->filePath(); - const CppRefactoringFilePtr headerFile = refactoring.cppFile(filePath); + const CppRefactoringFilePtr headerFile = currentFile(); const LookupContext targetContext(headerFile->cppDocument(), snapshot()); const Class *targetClass = m_classAST->symbol; diff --git a/src/plugins/cppeditor/quickfixes/createdeclarationfromuse.cpp b/src/plugins/cppeditor/quickfixes/createdeclarationfromuse.cpp index f7a760a99e7..a0e8ad21417 100644 --- a/src/plugins/cppeditor/quickfixes/createdeclarationfromuse.cpp +++ b/src/plugins/cppeditor/quickfixes/createdeclarationfromuse.cpp @@ -370,6 +370,7 @@ private: if (!link.hasValidTarget()) collectOperations(interface, result); }; + NonInteractiveFollowSymbolMarker niMarker; CppModelManager::followSymbol(cursorInEditor, followSymbolFallback, false, false, FollowSymbolMode::Exact, CppModelManager::Backend::Builtin); diff --git a/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp b/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp index 740c42909d1..693b2c4a1d8 100644 --- a/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp +++ b/src/plugins/cppeditor/quickfixes/insertfunctiondefinition.cpp @@ -155,8 +155,7 @@ public: // rewrite the function name if (nameIncludesOperatorName(decl->name())) { - CppRefactoringFilePtr file = refactoring.cppFile(op->filePath()); - const QString operatorNameText = file->textOf(declAST->core_declarator); + const QString operatorNameText = op->currentFile()->textOf(declAST->core_declarator); oo.includeWhiteSpaceInOperatorName = operatorNameText.contains(QLatin1Char(' ')); } const QString name = oo.prettyName(LookupContext::minimalName(decl, targetCoN, diff --git a/src/plugins/cppeditor/quickfixes/moveclasstoownfile.cpp b/src/plugins/cppeditor/quickfixes/moveclasstoownfile.cpp index e556f80300b..e8a6c9b33fe 100644 --- a/src/plugins/cppeditor/quickfixes/moveclasstoownfile.cpp +++ b/src/plugins/cppeditor/quickfixes/moveclasstoownfile.cpp @@ -294,6 +294,7 @@ private: // Force queued execution, as the built-in editor can run the callback synchronously. const auto followSymbol = [cursorInEditor, callback] { + NonInteractiveFollowSymbolMarker niMarker; CppModelManager::followSymbol( cursorInEditor, callback, true, false, FollowSymbolMode::Exact); }; diff --git a/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp b/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp index f6223629ae9..e6ec6a8b9f1 100644 --- a/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp +++ b/src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp @@ -86,10 +86,10 @@ public: }; MoveFuncDefRefactoringHelper(CppQuickFixOperation *operation, MoveType type, - const FilePath &fromFile, const FilePath &toFile) + const FilePath &toFile) : m_operation(operation), m_type(type), m_changes(m_operation->snapshot()) { - m_fromFile = m_changes.cppFile(fromFile); + m_fromFile = operation->currentFile(); m_toFile = (m_type == MoveOutside) ? m_fromFile : m_changes.cppFile(toFile); } @@ -159,19 +159,18 @@ public: , m_funcDef(funcDef) , m_type(type) , m_cppFilePath(cppFilePath) - , m_headerFilePath(funcDef->symbol->filePath()) { if (m_type == MoveFuncDefRefactoringHelper::MoveOutside) { setDescription(Tr::tr("Move Definition Outside Class")); } else { - const FilePath resolved = m_cppFilePath.relativePathFrom(m_headerFilePath.parentDir()); + const FilePath resolved = m_cppFilePath.relativePathFrom(filePath().parentDir()); setDescription(Tr::tr("Move Definition to %1").arg(resolved.displayName())); } } void perform() override { - MoveFuncDefRefactoringHelper helper(this, m_type, m_headerFilePath, m_cppFilePath); + MoveFuncDefRefactoringHelper helper(this, m_type, m_cppFilePath); helper.performMove(m_funcDef); helper.applyChanges(); } @@ -180,7 +179,6 @@ private: FunctionDefinitionAST *m_funcDef; MoveFuncDefRefactoringHelper::MoveType m_type; const FilePath m_cppFilePath; - const FilePath m_headerFilePath; }; class MoveAllFuncDefOutsideOp : public CppQuickFixOperation @@ -193,12 +191,11 @@ public: , m_type(type) , m_classDef(classDef) , m_cppFilePath(cppFileName) - , m_headerFilePath(classDef->symbol->filePath()) { if (m_type == MoveFuncDefRefactoringHelper::MoveOutside) { setDescription(Tr::tr("Definitions Outside Class")); } else { - const FilePath resolved = m_cppFilePath.relativePathFrom(m_headerFilePath.parentDir()); + const FilePath resolved = m_cppFilePath.relativePathFrom(filePath().parentDir()); setDescription(Tr::tr("Move All Function Definitions to %1") .arg(resolved.displayName())); } @@ -206,7 +203,7 @@ public: void perform() override { - MoveFuncDefRefactoringHelper helper(this, m_type, m_headerFilePath, m_cppFilePath); + MoveFuncDefRefactoringHelper helper(this, m_type, m_cppFilePath); for (DeclarationListAST *it = m_classDef->member_specifier_list; it; it = it->next) { if (FunctionDefinitionAST *funcAST = it->value->asFunctionDefinition()) { if (funcAST->symbol && !funcAST->symbol->isGenerated()) @@ -220,7 +217,6 @@ private: MoveFuncDefRefactoringHelper::MoveType m_type; ClassSpecifierAST *m_classDef; const FilePath m_cppFilePath; - const FilePath m_headerFilePath; }; class MoveFuncDefToDeclOp : public CppQuickFixOperation diff --git a/src/plugins/cppeditor/quickfixes/rewritecomment.cpp b/src/plugins/cppeditor/quickfixes/rewritecomment.cpp index 518705039bb..3ac7fede2c5 100644 --- a/src/plugins/cppeditor/quickfixes/rewritecomment.cpp +++ b/src/plugins/cppeditor/quickfixes/rewritecomment.cpp @@ -235,29 +235,34 @@ public: private: void perform() override { - const auto textDoc = const_cast(currentFile()->document()); - const int pos = currentFile()->cppDocument()->translationUnit()->getTokenPositionInDocument( + const CppRefactoringFilePtr file = currentFile(); + const auto textDoc = const_cast(file->document()); + const int pos = file->cppDocument()->translationUnit()->getTokenPositionInDocument( m_symbol->sourceLocation(), textDoc); QTextCursor cursor(textDoc); cursor.setPosition(pos); - const CursorInEditor cursorInEditor(cursor, currentFile()->filePath(), editor(), + const CursorInEditor cursorInEditor(cursor, file->filePath(), editor(), editor()->textDocument()); - const auto callback = [symbolLoc = m_symbol->toLink(), comments = m_commentTokens] + const auto callback = [symbolLoc = m_symbol->toLink(), comments = m_commentTokens, file] (const Link &link) { - moveComments(link, symbolLoc, comments); + moveComments(file, link, symbolLoc, comments); }; + NonInteractiveFollowSymbolMarker niMarker; + CppCodeModelSettings::setInteractiveFollowSymbol(false); CppModelManager::followSymbol(cursorInEditor, callback, true, false, FollowSymbolMode::Exact); } - static void moveComments(const Link &targetLoc, const Link &symbolLoc, - const QList &comments) + static void moveComments( + const CppRefactoringFilePtr &sourceFile, + const Link &targetLoc, + const Link &symbolLoc, + const QList &comments) { if (!targetLoc.hasValidTarget() || targetLoc.hasSameLocation(symbolLoc)) return; CppRefactoringChanges changes(CppModelManager::snapshot()); - const CppRefactoringFilePtr sourceFile = changes.cppFile(symbolLoc.targetFilePath); const CppRefactoringFilePtr targetFile = targetLoc.targetFilePath == symbolLoc.targetFilePath ? sourceFile diff --git a/src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.cpp b/src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.cpp index eddc4d6e5ba..8429e6762f0 100644 --- a/src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.cpp +++ b/src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.cpp @@ -41,6 +41,7 @@ public: setDescription( Tr::tr("Re-order Member Function Definitions According to Declaration Order")); m_state->decls = decls; + m_state->currentFile = currentFile(); } private: @@ -71,6 +72,7 @@ private: QList decls; QHash defLocations; + CppRefactoringFilePtr currentFile; int remainingFollowSymbolOps = 0; }; @@ -120,6 +122,7 @@ private: // Force queued execution, as the built-in editor can run the callback synchronously. const auto followSymbol = [cursorInEditor, callback] { + NonInteractiveFollowSymbolMarker niMarker; CppModelManager::followSymbol( cursorInEditor, callback, true, false, FollowSymbolMode::Exact); }; @@ -157,7 +160,9 @@ private: if (defLocsExpectedOrder == defLocsActualOrder) continue; - CppRefactoringFilePtr file = factory.cppFile(it.key()); + CppRefactoringFilePtr file = it.key() == state->currentFile->filePath() + ? state->currentFile + : factory.cppFile(it.key()); ChangeSet changes; for (int i = 0; i < defLocsActualOrder.size(); ++i) { const DefLocation &actualLoc = defLocsActualOrder[i]; diff --git a/src/plugins/designer/Designer.json.in b/src/plugins/designer/Designer.json.in index fb84ac1388b..966becb0d41 100644 --- a/src/plugins/designer/Designer.json.in +++ b/src/plugins/designer/Designer.json.in @@ -15,7 +15,7 @@ "Category" : "Qt Creator", "Description" : "Design Qt-widgets based UIs", "LongDescription" : [ - "Create widgets and forms that are integrated with Qt C++ code.", + "Create widgets and forms that are integrated with Qt C++ code." ], "Url" : "https://www.qt.io", ${DESIGNER_PLUGIN_ARGUMENTS} diff --git a/src/plugins/extensionmanager/extensionmanagerplugin.cpp b/src/plugins/extensionmanager/extensionmanagerplugin.cpp index d94d5aa7ac5..979a75ad291 100644 --- a/src/plugins/extensionmanager/extensionmanagerplugin.cpp +++ b/src/plugins/extensionmanager/extensionmanagerplugin.cpp @@ -26,7 +26,6 @@ #include #include -using namespace ExtensionSystem; using namespace Core; using namespace Utils; @@ -45,7 +44,7 @@ public: Theme::IconsBaseColor}}); const Icon FLAT_ACTIVE({{":/extensionmanager/images/mode_extensionmanager_mask.png", Theme::IconsModeWelcomeActiveColor}}); - setIcon(Utils::Icon::modeIcon(FLAT, FLAT, FLAT_ACTIVE)); + setIcon(Icon::modeIcon(FLAT, FLAT, FLAT_ACTIVE)); setPriority(72); using namespace Layouting; diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index 78acb32e28e..363b8cb90ee 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -280,7 +280,7 @@ void ExtensionManagerWidget::updateView(const QModelIndex ¤t) const LinksData linksData = current.data(RoleDescriptionLinks).value(); if (!linksData.isEmpty()) { QString linksHtml; - const QStringList links = Utils::transform(linksData, [](const LinksData::Type &link) { + const QStringList links = transform(linksData, [](const LinksData::Type &link) { const QString anchor = link.first.isEmpty() ? link.second : link.first; return QString::fromLatin1("%2 >") .arg(link.second).arg(anchor); @@ -293,7 +293,7 @@ void ExtensionManagerWidget::updateView(const QModelIndex ¤t) if (!imagesData.isEmpty()) { const QString examplesBoxCss = QString::fromLatin1("height: 168px; background-color: %1; ") - .arg(creatorTheme()->color(Theme::Token_Background_Default).name()); + .arg(creatorColor(Theme::Token_Background_Default).name()); description.append(QString(R"(
%2
@@ -362,8 +362,8 @@ void ExtensionManagerWidget::updateView(const QModelIndex ¤t) if (!tags.isEmpty()) { const QString tagTemplate = QString(R"( %2 - )").arg(creatorTheme()->color(Theme::Token_Stroke_Subtle).name()); - const QStringList tagsFmt = Utils::transform(tags, [&tagTemplate](const QString &tag) { + )").arg(creatorColor(Theme::Token_Stroke_Subtle).name()); + const QStringList tagsFmt = transform(tags, [&tagTemplate](const QString &tag) { return tagTemplate.arg(tag); }); description.append(QString(R"( @@ -397,8 +397,7 @@ void ExtensionManagerWidget::updateView(const QModelIndex ¤t) if (isPack) { const PluginsData plugins = current.data(RolePlugins).value(); - const QStringList extensions = Utils::transform(plugins, - &QPair::first); + const QStringList extensions = transform(plugins, &QPair::first); const QString extensionsFmt = extensions.join("
"); description.append(QString(R"(
%2
@@ -422,7 +421,7 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url) StorageStruct() { progressDialog.reset(new QProgressDialog(Tr::tr("Downloading Plugin..."), Tr::tr("Cancel"), 0, 0, - Core::ICore::dialogParent())); + ICore::dialogParent())); progressDialog->setWindowModality(Qt::ApplicationModal); progressDialog->setFixedSize(progressDialog->sizeHint()); progressDialog->setAutoClose(false); diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp index 81264c59bd7..b5d42ec4f95 100644 --- a/src/plugins/extensionmanager/extensionsbrowser.cpp +++ b/src/plugins/extensionmanager/extensionsbrowser.cpp @@ -198,7 +198,7 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) auto manageLabel = new QLabel(Tr::tr("Manage Extensions")); manageLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH1)); - d->searchBox = new Core::SearchBox; + d->searchBox = new SearchBox; d->searchBox->setFixedWidth(itemSize.width()); d->updateButton = new Button(Tr::tr("Install..."), Button::MediumPrimary); @@ -252,10 +252,8 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent) connect(d->updateButton, &QAbstractButton::pressed, this, []() { executePluginInstallWizard(); }); - connect(ExtensionSystem::PluginManager::instance(), - &ExtensionSystem::PluginManager::pluginsChanged, this, updateModel); - connect(ExtensionSystem::PluginManager::instance(), - &ExtensionSystem::PluginManager::initializationDone, + connect(PluginManager::instance(), &PluginManager::pluginsChanged, this, updateModel); + connect(PluginManager::instance(), &PluginManager::initializationDone, this, &ExtensionsBrowser::fetchExtensions); connect(d->searchBox, &QLineEdit::textChanged, d->filterProxyModel, &QSortFilterProxyModel::setFilterWildcard); diff --git a/src/plugins/extensionmanager/extensionsmodel.cpp b/src/plugins/extensionmanager/extensionsmodel.cpp index 2315164e11f..881125555df 100644 --- a/src/plugins/extensionmanager/extensionsmodel.cpp +++ b/src/plugins/extensionmanager/extensionsmodel.cpp @@ -3,9 +3,6 @@ #include "extensionsmodel.h" -#include "extensionsbrowser.h" - -#include "extensionmanagertr.h" #include "utils/algorithm.h" #include @@ -30,16 +27,16 @@ namespace ExtensionManager::Internal { Q_LOGGING_CATEGORY(modelLog, "qtc.extensionmanager.model", QtWarningMsg) -struct PluginDependency +struct Dependency { QString name; QString version; }; -using PluginDependencies = QList; +using Dependencies = QList; struct Plugin { - PluginDependencies dependencies; + Dependencies dependencies; QString copyright; QString name; QString packageUrl; @@ -74,10 +71,10 @@ static Plugin pluginFromJson(const QJsonObject &obj) const QJsonObject metaDataObj = obj.value("meta_data").toObject(); const QJsonArray dependenciesArray = metaDataObj.value("Dependencies").toArray(); - PluginDependencies dependencies; + Dependencies dependencies; for (const QJsonValueConstRef &dependencyVal : dependenciesArray) { const QJsonObject dependencyObj = dependencyVal.toObject(); - dependencies.append(PluginDependency{ + dependencies.append(Dependency{ .name = dependencyObj.value("Name").toString(), .version = dependencyObj.value("Version").toString(), }); @@ -189,19 +186,12 @@ static Extensions parseExtensionsRepoReply(const QByteArray &jsonData) return parsedExtensions; } -class ExtensionsModelPrivate : public QObject +class ExtensionsModelPrivate { public: - ExtensionsModelPrivate(ExtensionsModel *parent) - : q(parent) - { - } - void setExtensions(const Extensions &extensions); void removeLocalExtensions(); - ExtensionsModel *q; - Extensions allExtensions; // Original, complete extensions entries Extensions absentExtensions; // All packs + plugin extensions that are not (yet) installed }; @@ -224,7 +214,7 @@ void ExtensionsModelPrivate::removeLocalExtensions() ExtensionsModel::ExtensionsModel(QObject *parent) : QAbstractListModel(parent) - , d(new ExtensionsModelPrivate(this)) + , d(new ExtensionsModelPrivate) { } @@ -250,7 +240,7 @@ static QVariant dataFromPluginSpec(const PluginSpec *pluginSpec, int role) return pluginSpec->copyright(); case RoleDependencies: { QStringList dependencies = transform(pluginSpec->dependencies(), - &ExtensionSystem::PluginDependency::toString); + &PluginDependency::toString); dependencies.sort(); return dependencies; } @@ -301,7 +291,7 @@ static QStringList dependenciesFromExtension(const Extension &extension) { QStringList dependencies; for (const Plugin &plugin : extension.plugins) { - for (const PluginDependency &dependency : plugin.dependencies) { + for (const Dependency &dependency : plugin.dependencies) { const QString withVersion = QString::fromLatin1("%1 (%2)").arg(dependency.name) .arg(dependency.version); dependencies.append(withVersion); @@ -404,8 +394,7 @@ void ExtensionsModel::setExtensionsJson(const QByteArray &json) PluginSpec *ExtensionsModel::pluginSpecForName(const QString &pluginName) { - return Utils::findOrDefault(PluginManager::plugins(), - Utils::equal(&PluginSpec::name, pluginName)); + return findOrDefault(PluginManager::plugins(), equal(&PluginSpec::name, pluginName)); } } // ExtensionManager::Internal diff --git a/src/plugins/lua/CMakeLists.txt b/src/plugins/lua/CMakeLists.txt index cb7ccb17e34..c7a62e3a8b8 100644 --- a/src/plugins/lua/CMakeLists.txt +++ b/src/plugins/lua/CMakeLists.txt @@ -39,10 +39,15 @@ add_qtc_plugin(Lua meta/simpletypes.lua meta/utils.lua meta/widgets.lua - meta/wizard.lua # generateqtbindings.cpp # Use this if you need to generate some code. ) +qt_add_resources(Lua lua_images_rcc + PREFIX "/lua" + FILES + images/settingscategory_lua.png + images/settingscategory_lua@2x.png +) set_source_files_properties(luauibindings.cpp PROPERTY SKIP_AUTOMOC ON PROPERTY SKIP_AUTOGEN ON) @@ -66,7 +71,6 @@ set(META_FILES meta/simpletypes.lua meta/utils.lua meta/widgets.lua - meta/wizard.lua ) qtc_copy_to_builddir(copy_lua_meta_files diff --git a/src/plugins/lua/bindings/fetch.cpp b/src/plugins/lua/bindings/fetch.cpp index 35e3255943f..22d1bc64cbd 100644 --- a/src/plugins/lua/bindings/fetch.cpp +++ b/src/plugins/lua/bindings/fetch.cpp @@ -3,11 +3,22 @@ #include "../luaengine.h" #include "../luaqttypes.h" +#include "../luatr.h" +#include +#include + +#include +#include +#include #include +#include +#include +#include #include #include +#include #include #include #include @@ -37,35 +48,205 @@ static QString opToString(QNetworkAccessManager::Operation op) void addFetchModule() { - LuaEngine::registerProvider( - "Fetch", [](sol::state_view lua) -> sol::object { - const ScriptPluginSpec *pluginSpec = lua.get("PluginSpec"); + class Module : Utils::AspectContainer + { + Utils::StringListAspect pluginsAllowedToFetch{this}; + Utils::StringListAspect pluginsNotAllowedToFetch{this}; - sol::table async = lua.script("return require('async')", "_fetch_").get(); - sol::function wrap = async["wrap"]; + class LuaOptionsPage : public Core::IOptionsPage + { + public: + LuaOptionsPage(Module *module) + { + setId("BB.Lua.Fetch"); + setDisplayName(Tr::tr("Network access")); + setCategory("ZY.Lua"); + setDisplayCategory("Lua"); + setCategoryIconPath(":/lua/images/settingscategory_lua.png"); + setSettingsProvider( + [module] { return static_cast(module); }); + } + }; - sol::table fetch = lua.create_table(); + LuaOptionsPage settingsPage{this}; - auto networkReplyType = lua.new_usertype( - "QNetworkReply", - "error", - sol::property([](QNetworkReply *self) -> int { return self->error(); }), - "readAll", - [](QNetworkReply *r) { return r->readAll().toStdString(); }, - "__tostring", - [](QNetworkReply *r) { - return QString("QNetworkReply(%1 \"%2\") => %3") - .arg(opToString(r->operation())) - .arg(r->url().toString()) - .arg(r->error()); - }); + public: + Module() + { + setSettingsGroup("Lua.Fetch"); - fetch["fetch_cb"] = [guard = pluginSpec->connectionGuard.get()]( - const sol::table &options, - const sol::function &callback, - const sol::this_state &thisState) { - auto url = options.get("url"); + pluginsAllowedToFetch.setSettingsKey("pluginsAllowedToFetch"); + pluginsAllowedToFetch.setLabelText("Plugins allowed to fetch data from the internet"); + pluginsAllowedToFetch.setToolTip( + "List of plugins that are allowed to fetch data from the internet"); + pluginsAllowedToFetch.setUiAllowAdding(false); + pluginsAllowedToFetch.setUiAllowEditing(false); + pluginsNotAllowedToFetch.setSettingsKey("pluginsNotAllowedToFetch"); + pluginsNotAllowedToFetch.setLabelText( + "Plugins not allowed to fetch data from the internet"); + pluginsNotAllowedToFetch.setToolTip( + "List of plugins that are not allowed to fetch data from the internet"); + pluginsNotAllowedToFetch.setUiAllowAdding(false); + pluginsNotAllowedToFetch.setUiAllowEditing(false); + + setLayouter([this] { + using namespace Layouting; + // clang-format off + return Form { + pluginsAllowedToFetch, br, + pluginsNotAllowedToFetch, br, + }; + // clang-format on + }); + + readSettings(); + } + + ~Module() { writeSettings(); } + + enum class IsAllowed { Yes, No, NeedsToAsk }; + + IsAllowed isAllowedToFetch(const QString &pluginName) const + { + if (pluginsAllowedToFetch().contains(pluginName)) + return IsAllowed::Yes; + if (pluginsNotAllowedToFetch().contains(pluginName)) + return IsAllowed::No; + return IsAllowed::NeedsToAsk; + } + + void setAllowedToFetch(const QString &pluginName, IsAllowed allowed) + { + if (allowed == IsAllowed::Yes) + pluginsAllowedToFetch.appendValue(pluginName); + else if (allowed == IsAllowed::No) + pluginsNotAllowedToFetch.appendValue(pluginName); + + if (allowed == IsAllowed::Yes) + pluginsNotAllowedToFetch.removeValue(pluginName); + else if (allowed == IsAllowed::No) + pluginsAllowedToFetch.removeValue(pluginName); + } + }; + + std::shared_ptr module = std::make_shared(); + + LuaEngine::registerProvider("Fetch", [mod = std::move(module)](sol::state_view lua) -> sol::object { + const ScriptPluginSpec *pluginSpec = lua.get("PluginSpec"); + + sol::table async = lua.script("return require('async')", "_fetch_").get(); + sol::function wrap = async["wrap"]; + + sol::table fetch = lua.create_table(); + + auto networkReplyType = lua.new_usertype( + "QNetworkReply", + "error", + sol::property([](QNetworkReply *self) -> int { return self->error(); }), + "readAll", + [](QNetworkReply *r) { return r->readAll().toStdString(); }, + "__tostring", + [](QNetworkReply *r) { + return QString("QNetworkReply(%1 \"%2\") => %3") + .arg(opToString(r->operation())) + .arg(r->url().toString()) + .arg(r->error()); + }); + + auto checkPermission = [mod, + pluginName = pluginSpec->name, + guard = pluginSpec->connectionGuard.get()]( + QString url, + std::function fetch, + std::function notAllowed) { + auto isAllowed = mod->isAllowedToFetch(pluginName); + if (isAllowed == Module::IsAllowed::Yes) { + fetch(); + return; + } + + if (isAllowed == Module::IsAllowed::No) { + notAllowed(); + return; + } + + if (QApplication::activeModalWidget()) { + // We are already showing a modal dialog, + // so we have to use a QMessageBox instead of the info bar + auto msgBox = new QMessageBox( + QMessageBox::Question, + Tr::tr("Allow Internet access"), + Tr::tr("The plugin \"%1\" would like to fetch from the following url:\n%2") + .arg(pluginName) + .arg(url), + QMessageBox::Yes | QMessageBox::No, + Core::ICore::dialogParent()); + msgBox->setCheckBox(new QCheckBox(Tr::tr("Remember choice"))); + + QObject::connect( + msgBox, &QMessageBox::accepted, guard, [mod, fetch, pluginName, msgBox]() { + if (msgBox->checkBox()->isChecked()) + mod->setAllowedToFetch(pluginName, Module::IsAllowed::Yes); + fetch(); + }); + + QObject::connect( + msgBox, &QMessageBox::rejected, guard, [mod, notAllowed, pluginName, msgBox]() { + if (msgBox->checkBox()->isChecked()) + mod->setAllowedToFetch(pluginName, Module::IsAllowed::No); + notAllowed(); + }); + + msgBox->show(); + + return; + } + + Utils::InfoBarEntry entry{ + Utils::Id::fromString("Fetch" + pluginName), + Tr::tr("The plugin \"%1\" would like to fetch data from the internet. Do " + "you want to allow this?") + .arg(pluginName)}; + entry.setDetailsWidgetCreator([pluginName, url] { + const QString markdown = Tr::tr("The plugin \"**%1**\" would like to fetch " + "from the following url:\n\n") + .arg(pluginName) + + QString("* [%3](%3)").arg(url); + + QLabel *list = new QLabel(); + list->setTextFormat(Qt::TextFormat::MarkdownText); + list->setText(markdown); + list->setMargin(Utils::StyleHelper::SpacingTokens::ExPaddingGapS); + return list; + }); + entry.addCustomButton(Tr::tr("Always Allow"), [mod, pluginName, fetch]() { + mod->setAllowedToFetch(pluginName, Module::IsAllowed::Yes); + Core::ICore::infoBar()->removeInfo(Utils::Id::fromString("Fetch" + pluginName)); + fetch(); + }); + entry.addCustomButton(Tr::tr("Allow once"), [pluginName, fetch]() { + Core::ICore::infoBar()->removeInfo(Utils::Id::fromString("Fetch" + pluginName)); + fetch(); + }); + + entry.setCancelButtonInfo(Tr::tr("Deny"), [mod, notAllowed, pluginName]() { + Core::ICore::infoBar()->removeInfo(Utils::Id::fromString("Fetch" + pluginName)); + mod->setAllowedToFetch(pluginName, Module::IsAllowed::No); + notAllowed(); + }); + Core::ICore::infoBar()->addInfo(entry); + }; + + fetch["fetch_cb"] = [checkPermission, + pluginName = pluginSpec->name, + guard = pluginSpec->connectionGuard.get(), + mod]( + const sol::table &options, + const sol::function &callback, + const sol::this_state &thisState) { + auto url = options.get("url"); + auto actualFetch = [guard, url, options, callback, thisState]() { auto method = (options.get_or("method", "GET")).toLower(); auto headers = options.get_or("headers", {}); auto data = options.get_or("body", {}); @@ -129,10 +310,17 @@ void addFetchModule() } }; - fetch["fetch"] = wrap(fetch["fetch_cb"]); + checkPermission(url, actualFetch, [callback, pluginName]() { + callback(Tr::tr("Fetching is not allowed for the plugin \"%1\" (You can edit " + "permissions in Preferences => Lua)") + .arg(pluginName)); + }); + }; - return fetch; - }); + fetch["fetch"] = wrap(fetch["fetch_cb"]); + + return fetch; + }); } } // namespace Lua::Internal diff --git a/src/plugins/lua/bindings/install.cpp b/src/plugins/lua/bindings/install.cpp index 75fb3cadb14..a044ff2fb8d 100644 --- a/src/plugins/lua/bindings/install.cpp +++ b/src/plugins/lua/bindings/install.cpp @@ -17,8 +17,10 @@ #include #include +#include #include #include +#include #include #include @@ -159,6 +161,7 @@ static Group installRecipe( emitResult(sourceAndCommand.error()); return SetupResult::StopWithError; } + unarchiver.setGZipFileDestName(installOptionsIt->name); unarchiver.setSourceAndCommand(*sourceAndCommand); unarchiver.setDestDir(destination(appDataPath, *installOptionsIt)); return SetupResult::Continue; @@ -170,6 +173,12 @@ static Group installRecipe( if (result == DoneWith::Cancel) return DoneResult::Error; + const FilePath destDir = destination(appDataPath, *installOptionsIt); + const FilePath binary = destDir / installOptionsIt->name; + + if (binary.isFile()) + binary.setPermissions(QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther); + expected_str doc = getOrCreatePackageInfo(appDataPath); if (!doc) return emitResult(doc.error()); @@ -178,7 +187,7 @@ static Group installRecipe( QJsonObject installedPackage; installedPackage["version"] = installOptionsIt->version; installedPackage["name"] = installOptionsIt->name; - installedPackage["path"] = destination(appDataPath, *installOptionsIt).toFSPathString(); + installedPackage["path"] = destDir.toFSPathString(); obj[installOptionsIt->name] = installedPackage; expected_str res = savePackageInfo(appDataPath, QJsonDocument(obj)); @@ -301,41 +310,71 @@ void addInstallModule() installOptionsList.append({url, name, version}); } + auto install = [&state, pluginSpec, installOptionsList, callback]() { + auto tree = state.createTree(); + + auto progress = new TaskProgress(tree); + progress->setDisplayName(Tr::tr("Installing package(s) %1").arg("...")); + + tree->setRecipe( + installRecipe(pluginSpec->appDataPath, installOptionsList, callback)); + tree->start(); + }; + + auto denied = [callback]() { callback(false, "User denied installation"); }; + + if (QApplication::activeModalWidget()) { + auto msgBox = new QMessageBox( + QMessageBox::Question, + Tr::tr("Install package"), + msg, + QMessageBox::Yes | QMessageBox::No, + Core::ICore::dialogParent()); + + const QString details + = Tr::tr("The plugin \"%1\" would like to install the following " + "package(s):\n\n") + .arg(pluginSpec->name) + + Utils::transform(installOptionsList, [](const InstallOptions &options) { + return QString("* %1 - %2 (from: %3)") + .arg(options.name, options.version, options.url.toString()); + }).join("\n"); + + msgBox->setDetailedText(details); + + auto guard = pluginSpec->connectionGuard.get(); + QObject::connect(msgBox, &QMessageBox::accepted, guard, install); + QObject::connect(msgBox, &QMessageBox::rejected, guard, denied); + + msgBox->show(); + return; + } + const Utils::Id infoBarId = Utils::Id::fromString( "Install" + pluginSpec->name + QString::number(qHash(installOptionsList))); InfoBarEntry entry(infoBarId, msg, InfoBarEntry::GlobalSuppression::Enabled); - entry.addCustomButton( - Tr::tr("Install"), - [infoBarId, &state, pluginSpec, installOptionsList, callback]() { - auto tree = state.createTree(); + entry.addCustomButton(Tr::tr("Install"), [install, infoBarId]() { + install(); + Core::ICore::infoBar()->removeInfo(infoBarId); + }); - auto progress = new TaskProgress(tree); - progress->setDisplayName(Tr::tr("Installing package(s) %1").arg("...")); + entry.setCancelButtonInfo(denied); - tree->setRecipe( - installRecipe(pluginSpec->appDataPath, installOptionsList, callback)); - tree->start(); - - Core::ICore::infoBar()->removeInfo(infoBarId); - }); - entry.setCancelButtonInfo( - [callback]() { callback(false, "User denied installation"); }); - - entry.setDetailsWidgetCreator([pluginSpec, installOptionsList]() -> QWidget * { - const QString markdown - = Tr::tr("The plugin \"**%1**\" would like to install the following " - "package(s):\n\n") - .arg(pluginSpec->name) - + Utils::transform(installOptionsList, [](const InstallOptions &options) { - return QString("* %1 - %2 (from: [%3](%3))") - .arg(options.name, options.version, options.url.toString()); - }).join("\n"); + const QString details + = Tr::tr("The plugin \"**%1**\" would like to install the following " + "package(s):\n\n") + .arg(pluginSpec->name) + + Utils::transform(installOptionsList, [](const InstallOptions &options) { + return QString("* %1 - %2 (from: [%3](%3))") + .arg(options.name, options.version, options.url.toString()); + }).join("\n"); + entry.setDetailsWidgetCreator([details]() -> QWidget * { QLabel *list = new QLabel(); list->setTextFormat(Qt::TextFormat::MarkdownText); - list->setText(markdown); + list->setText(details); list->setMargin(StyleHelper::SpacingTokens::ExPaddingGapS); return list; }); diff --git a/src/plugins/lua/bindings/qtcprocess.cpp b/src/plugins/lua/bindings/qtcprocess.cpp index c1b4a4eccdd..ff2726a96ef 100644 --- a/src/plugins/lua/bindings/qtcprocess.cpp +++ b/src/plugins/lua/bindings/qtcprocess.cpp @@ -29,11 +29,22 @@ void addProcessModule() p->setEnvironment(Environment::systemEnvironment()); QObject::connect(p, &Process::done, guard, [p, cb]() { cb(p->exitCode()); }); + }; + + process["commandOutput_cb"] = + [guard + = pluginSpec->connectionGuard.get()](const QString &cmdline, const sol::function &cb) { + Process *p = new Process; + p->setCommand(CommandLine::fromUserInput((cmdline))); + p->setEnvironment(Environment::systemEnvironment()); + + QObject::connect(p, &Process::done, guard, [p, cb]() { cb(p->allOutput()); }); p->start(); }; process["runInTerminal"] = wrap(process["runInTerminal_cb"]); + process["commandOutput"] = wrap(process["commandOutput_cb"]); return process; }); diff --git a/src/plugins/lua/images/settingscategory_lua.png b/src/plugins/lua/images/settingscategory_lua.png new file mode 100644 index 00000000000..7f1b6808fea Binary files /dev/null and b/src/plugins/lua/images/settingscategory_lua.png differ diff --git a/src/plugins/lua/images/settingscategory_lua@2x.png b/src/plugins/lua/images/settingscategory_lua@2x.png new file mode 100644 index 00000000000..a70400124db Binary files /dev/null and b/src/plugins/lua/images/settingscategory_lua@2x.png differ diff --git a/src/plugins/lua/lua.qbs b/src/plugins/lua/lua.qbs index 5f00384139c..1b49d94f519 100644 --- a/src/plugins/lua/lua.qbs +++ b/src/plugins/lua/lua.qbs @@ -68,7 +68,6 @@ QtcPlugin { "simpletypes.lua", "utils.lua", "widgets.lua", - "wizard.lua", ] qbs.install: true qbs.installDir: qtc.ide_data_path + "/lua/meta/" diff --git a/src/plugins/lua/luaengine.cpp b/src/plugins/lua/luaengine.cpp index 505313da865..29ca17fad6e 100644 --- a/src/plugins/lua/luaengine.cpp +++ b/src/plugins/lua/luaengine.cpp @@ -4,6 +4,7 @@ #include "luaengine.h" #include "luapluginspec.h" +#include "luatr.h" #include #include @@ -172,14 +173,6 @@ expected_str LuaEngine::connectHooks( return {}; } -expected_str LuaEngine::connectHooks(sol::state_view lua, const sol::table &hookTable) -{ - if (!hookTable) - return {}; - - return instance().connectHooks(lua, hookTable, ""); -} - expected_str LuaEngine::loadPlugin(const Utils::FilePath &path) { auto contents = path.fileContents(); @@ -204,12 +197,16 @@ expected_str LuaEngine::loadPlugin(const Utils::FilePath &path) sol::table pluginInfo = result.get(); if (!pluginInfo.valid()) return make_unexpected(QString("Script did not return a table with plugin info")); - return LuaPluginSpec::create(path, std::move(lua), pluginInfo); + return LuaPluginSpec::create(path, pluginInfo); } -expected_str LuaEngine::prepareSetup( - sol::state_view &lua, const LuaPluginSpec &pluginSpec, sol::optional hookTable) +expected_str LuaEngine::prepareSetup( + sol::state_view lua, const LuaPluginSpec &pluginSpec) { + auto contents = pluginSpec.filePath().fileContents(); + if (!contents) + return make_unexpected(contents.error()); + // TODO: Only open libraries requested by the plugin lua.open_libraries( sol::lib::base, @@ -261,10 +258,29 @@ expected_str LuaEngine::prepareSetup( for (const auto &func : d->m_autoProviders) func(lua); - if (hookTable) - return LuaEngine::connectHooks(lua, *hookTable); + sol::protected_function_result result = lua.safe_script( + std::string_view(contents->data(), contents->size()), + sol::script_pass_on_error, + pluginSpec.filePath().fileName().toUtf8().constData()); - return {}; + auto pluginTable = result.get>(); + if (!pluginTable) + return make_unexpected(Tr::tr("Script did not return a table")); + + auto hookTable = pluginTable->get>("hooks"); + + if (hookTable) { + auto connectResult = connectHooks(lua, *hookTable, {}); + if (!connectResult) + return make_unexpected(connectResult.error()); + } + + auto setupFunction = pluginTable->get_or("setup", {}); + + if (!setupFunction) + return make_unexpected(Tr::tr("Plugin info table did not contain a setup function")); + + return setupFunction; } bool LuaEngine::isCoroutine(lua_State *state) diff --git a/src/plugins/lua/luaengine.h b/src/plugins/lua/luaengine.h index 688c728808e..f8fa085d6d0 100644 --- a/src/plugins/lua/luaengine.h +++ b/src/plugins/lua/luaengine.h @@ -55,15 +55,13 @@ public: static LuaEngine &instance(); Utils::expected_str loadPlugin(const Utils::FilePath &path); - Utils::expected_str prepareSetup( - sol::state_view &lua, const LuaPluginSpec &pluginSpec, sol::optional hookTable); + Utils::expected_str prepareSetup( + sol::state_view lua, const LuaPluginSpec &pluginSpec); static void registerProvider(const QString &packageName, const PackageProvider &provider); static void autoRegister(const std::function ®isterFunction); static void registerHook(QString name, const std::function &hookProvider); - static Utils::expected_str connectHooks(sol::state_view lua, const sol::table &hookTable); - static bool isCoroutine(lua_State *state); static sol::table toTable(const sol::state_view &lua, const QJsonValue &v); diff --git a/src/plugins/lua/luapluginspec.cpp b/src/plugins/lua/luapluginspec.cpp index 4c4ac66d4e0..c3fcd558a55 100644 --- a/src/plugins/lua/luapluginspec.cpp +++ b/src/plugins/lua/luapluginspec.cpp @@ -34,28 +34,19 @@ class LuaPluginSpecPrivate { public: FilePath pluginScriptPath; - - sol::state lua; - sol::table pluginTable; - - sol::function setupFunction; + bool printToOutputPane = false; + std::unique_ptr activeLuaState; }; LuaPluginSpec::LuaPluginSpec() : d(new LuaPluginSpecPrivate()) {} -expected_str LuaPluginSpec::create(const FilePath &filePath, - sol::state lua, - sol::table pluginTable) +expected_str LuaPluginSpec::create(const FilePath &filePath, sol::table pluginTable) { std::unique_ptr pluginSpec(new LuaPluginSpec()); - pluginSpec->d->lua = std::move(lua); - pluginSpec->d->pluginTable = pluginTable; - - pluginSpec->d->setupFunction = pluginTable.get_or("setup", {}); - if (!pluginSpec->d->setupFunction) + if (!pluginTable.get_or("setup", {})) return make_unexpected(QString("Plugin info table did not contain a setup function")); QJsonValue v = LuaEngine::toJson(pluginTable); @@ -75,6 +66,7 @@ expected_str LuaPluginSpec::create(const FilePath &filePath, pluginSpec->setLocation(filePath.parentDir()); pluginSpec->d->pluginScriptPath = filePath; + pluginSpec->d->printToOutputPane = pluginTable.get_or("printToOutputPane", false); return pluginSpec.release(); } @@ -94,16 +86,19 @@ bool LuaPluginSpec::loadLibrary() } bool LuaPluginSpec::initializePlugin() { - expected_str setupResult - = LuaEngine::instance() - .prepareSetup(d->lua, *this, d->pluginTable.get>("hooks")); + QTC_ASSERT(!d->activeLuaState, return false); + + std::unique_ptr activeLuaState = std::make_unique(); + + expected_str setupResult + = LuaEngine::instance().prepareSetup(*activeLuaState, *this); if (!setupResult) { setError(Lua::Tr::tr("Failed to prepare plugin setup: %1").arg(setupResult.error())); return false; } - auto result = d->setupFunction.call(); + auto result = setupResult->call(); if (result.get_type() == sol::type::boolean && result.get() == false) { setError(Lua::Tr::tr("Plugin setup function returned false")); @@ -117,6 +112,8 @@ bool LuaPluginSpec::initializePlugin() } } + d->activeLuaState = std::move(activeLuaState); + setState(PluginSpec::State::Initialized); return true; } @@ -133,14 +130,18 @@ bool LuaPluginSpec::delayedInitialize() } ExtensionSystem::IPlugin::ShutdownFlag LuaPluginSpec::stop() { + d->activeLuaState.reset(); return ExtensionSystem::IPlugin::ShutdownFlag::SynchronousShutdown; } -void LuaPluginSpec::kill() {} +void LuaPluginSpec::kill() +{ + d->activeLuaState.reset(); +} bool LuaPluginSpec::printToOutputPane() const { - return d->pluginTable.get_or("printToOutputPane", false); + return d->printToOutputPane; } } // namespace Lua diff --git a/src/plugins/lua/luapluginspec.h b/src/plugins/lua/luapluginspec.h index 2d72bb53907..7c2ab3318bd 100644 --- a/src/plugins/lua/luapluginspec.h +++ b/src/plugins/lua/luapluginspec.h @@ -39,9 +39,8 @@ class LuaPluginSpec : public ExtensionSystem::PluginSpec LuaPluginSpec(); public: - static Utils::expected_str create(const Utils::FilePath &filePath, - sol::state lua, - sol::table pluginTable); + static Utils::expected_str create( + const Utils::FilePath &filePath, sol::table pluginTable); ExtensionSystem::IPlugin *plugin() const override; diff --git a/src/plugins/lua/meta/process.lua b/src/plugins/lua/meta/process.lua index 05199907706..53b4f35b7d0 100644 --- a/src/plugins/lua/meta/process.lua +++ b/src/plugins/lua/meta/process.lua @@ -8,4 +8,10 @@ local process = {} ---@return number The exit code of the command function process.runInTerminal(cmd) end +---@async +---Runs a command and returns the output! +---@param cmd string The command to run +---@return string The output of the command +function process.commandOutput(cmd) end + return process diff --git a/src/plugins/lua/meta/wizard.lua b/src/plugins/lua/meta/wizard.lua deleted file mode 100644 index fb5b000d514..00000000000 --- a/src/plugins/lua/meta/wizard.lua +++ /dev/null @@ -1,61 +0,0 @@ ----@meta Wizard - ----@module "Layout" -local Layout = require("Layout") - ----@module "Core" -local Core = require("Core") - -local wizard = {} - ----@class (exact) WizardFactoryOptions ----@field id string ----@field displayName string ----@field description string ----@field category string ----@field displayCategory string ----@field icon? string ----@field iconText? string ----@field factory function A function returning a Wizard - ---- Registers a wizard factory. ----@param options WizardFactoryOptions -function wizard.registerFactory(options) end - ----@class Wizard -Wizard = {} - ----@class (exact) WizardPageOptions ----@field title string ----@field layout LayoutItem ----@field initializePage? function The function called before showing the page - ----Add a page to the wizard ----@param options WizardPageOptions -function Wizard:addPage(options) end - ----@class SummaryPage -Wizard.SummaryPage = {} - ----Set the files to be shown on the summary page ----@param generatedFiles Core.GeneratedFile[] -function Wizard.SummaryPage:setFiles(generatedFiles) end - ----@class SummaryPageOptions ----@field title? string ----@field initializePage? function The function called before showing the page - ----Add a summary page to the wizard ----@param options SummaryPageOptions ----@return SummaryPage -function Wizard:addSummaryPage(options) end - ----@class WizardOptions ----@field fileFactory function A function returning a GeneratedFile[] - ----Create a wizard ----@param options WizardOptions ----@return Wizard -function wizard.create(options) end - -return wizard diff --git a/src/plugins/luals/luals/init.lua b/src/plugins/luals/luals/init.lua index 04c238197ad..e7bc13629cc 100644 --- a/src/plugins/luals/luals/init.lua +++ b/src/plugins/luals/luals/init.lua @@ -7,6 +7,7 @@ local S = require('Settings') local Gui = require('Gui') local a = require('async') local fetch = require('Fetch').fetch +local Install = require('Install') Settings = {} @@ -34,17 +35,12 @@ end local function installOrUpdateServer() local data = a.wait(fetch({ - url = "https://api.github.com/repos/LuaLS/lua-language-server/releases?per_page=1", - convertToTable = true, - headers = { - Accept = "application/vnd.github.v3+json", - ["X-GitHub-Api-Version"] = "2022-11-28" - } + url = "https://qtccache.qt.io/LuaLanguageServer/LatestRelease", + convertToTable = true })) if type(data) == "table" and #data > 0 then local r = data[1] - Install = require('Install') local lspPkgInfo = Install.packageInfo("lua-language-server") if not lspPkgInfo or lspPkgInfo.version ~= r.tag_name then local osTr = { mac = "darwin", windows = "win32", linux = "linux" } @@ -83,7 +79,7 @@ local function installOrUpdateServer() binary = "bin/lua-language-server.exe" end - Settings.binary.defaultPath = lspPkgInfo.path:resolvePath(binary) + Settings.binary:setValue(lspPkgInfo.path:resolvePath(binary)) Settings:apply() return end @@ -138,31 +134,53 @@ local function layoutSettings() --- "using namespace Gui" local _ENV = using(Gui) - local installButton = {} - - if Settings.binary.expandedValue:isExecutableFile() == false then - installButton = { - "Language server not found:", - Row { - PushButton { - text = "Try to install lua language server", - onClicked = function() a.sync(installServer)() end, - }, - st - } - } - end local layout = Form { Settings.binary, br, Settings.developMode, br, Settings.showSource, br, Settings.showNode, br, - table.unpack(installButton) + Row { + PushButton { + text = "Update Lua Language Server", + onClicked = function() a.sync(installOrUpdateServer)() end, + }, + st + } } - return layout end +local function binaryFromPkg() + local lspPkgInfo = Install.packageInfo("lua-language-server") + if lspPkgInfo then + local binary = "bin/lua-language-server" + if Utils.HostOsInfo.isWindowsHost() then + binary = "bin/lua-language-server.exe" + end + local binaryPath = lspPkgInfo.path:resolvePath(binary) + if binaryPath:isExecutableFile() == true then + return binaryPath + end + end + + return nil +end + +local function findBinary() + local binary = binaryFromPkg() + if binary then + return binary + end + + -- Search for the binary in the PATH + local serverPath = Utils.FilePath.fromUserInput("lua-language-server") + local absolute = a.wait(serverPath:searchInPath()):resolveSymlinks() + if absolute:isExecutableFile() == true then + return absolute + end + return serverPath +end + local function setupAspect() ---@class Settings: AspectContainer Settings = S.AspectContainer.create({ @@ -176,14 +194,9 @@ local function setupAspect() labelText = "Binary:", toolTip = "The path to the lua-language-server binary.", expectedKind = S.Kind.ExistingCommand, - defaultPath = Utils.FilePath.fromUserInput("lua-language-server"), + defaultPath = findBinary(), }) - -- Search for the binary in the PATH - local serverPath = Settings.binary.defaultPath - local absolute = a.wait(serverPath:searchInPath()):resolveSymlinks() - if absolute:isExecutableFile() == true then - Settings.binary.defaultPath = absolute - end + Settings.developMode = S.BoolAspect.create({ settingsKey = "LuaCopilot.DevelopMode", displayName = "Enable Develop Mode", diff --git a/src/plugins/mercurial/mercurialsettings.cpp b/src/plugins/mercurial/mercurialsettings.cpp index 05c96672f90..79423ab7746 100644 --- a/src/plugins/mercurial/mercurialsettings.cpp +++ b/src/plugins/mercurial/mercurialsettings.cpp @@ -30,7 +30,7 @@ MercurialSettings::MercurialSettings() binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setDefaultValue(Constants::MERCURIALDEFAULT); binaryPath.setDisplayName(Tr::tr("Mercurial Command")); - binaryPath.setHistoryCompleter("Bazaar.Command.History"); + binaryPath.setHistoryCompleter("Mercurial.Command.History"); binaryPath.setLabelText(Tr::tr("Command:")); userName.setDisplayStyle(StringAspect::LineEditDisplay); diff --git a/src/plugins/mesonprojectmanager/mesonoutputparser.cpp b/src/plugins/mesonprojectmanager/mesonoutputparser.cpp index 9ba777f0753..241f05a9160 100644 --- a/src/plugins/mesonprojectmanager/mesonoutputparser.cpp +++ b/src/plugins/mesonprojectmanager/mesonoutputparser.cpp @@ -56,7 +56,7 @@ inline Utils::OutputLineParser::LinkSpecs MesonOutputParser::addTask( fileName, match.captured(lineNumberCapIndex).toInt()); addTask(task); - addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, match, 1); + addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, task.column, match, 1); #else Q_UNUSED(type); Q_UNUSED(line); diff --git a/src/plugins/nim/project/nimoutputtaskparser.cpp b/src/plugins/nim/project/nimoutputtaskparser.cpp index 31fc1e8e77a..1fde71d3c21 100644 --- a/src/plugins/nim/project/nimoutputtaskparser.cpp +++ b/src/plugins/nim/project/nimoutputtaskparser.cpp @@ -39,7 +39,7 @@ NimParser::Result NimParser::handleLine(const QString &lne, OutputFormat) const CompileTask t(type, message, absoluteFilePath(FilePath::fromUserInput(filename)), lineNumber); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, t.file, t.line, match, 1); + addLinkSpecForAbsoluteFilePath(linkSpecs, t.file, t.line, t.column, match, 1); scheduleTask(t, 1); return {Status::Done, linkSpecs}; } diff --git a/src/plugins/projectexplorer/clangparser.cpp b/src/plugins/projectexplorer/clangparser.cpp index 28679f0ed58..05bcc3e0aa2 100644 --- a/src/plugins/projectexplorer/clangparser.cpp +++ b/src/plugins/projectexplorer/clangparser.cpp @@ -65,7 +65,7 @@ OutputLineParser::Result ClangParser::handleLine(const QString &line, OutputForm const int lineNo = match.captured(3).toInt(); const int column = 0; LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 2); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, column, match, 2); createOrAmendTask(Task::Unknown, lne.trimmed(), lne, false, filePath, lineNo, column, linkSpecs); return {Status::InProgress, linkSpecs}; @@ -84,7 +84,7 @@ OutputLineParser::Result ClangParser::handleLine(const QString &line, OutputForm const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1))); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 1); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, column, match, 1); createOrAmendTask(taskType(match.captured(8)), match.captured(9), lne, false, filePath, lineNo, column, linkSpecs); return {Status::InProgress, linkSpecs}; @@ -235,7 +235,7 @@ void ProjectExplorerTest::testClangOutputParser_data() 68, 10, QVector() << formatRange(34, 0) - << formatRange(34, 28, "olpfile:///usr/include/c++/4.6/utility::68::-1") + << formatRange(34, 28, "olpfile:///usr/include/c++/4.6/utility::68::10") << formatRange(62, 93))) << QString(); @@ -255,7 +255,7 @@ void ProjectExplorerTest::testClangOutputParser_data() 567, 51, QVector() << formatRange(74, 0) - << formatRange(74, 64, "olpfile:///home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp::567::-1") + << formatRange(74, 64, "olpfile:///home/code/src/creator/src/plugins/coreplugin/manhattanstyle.cpp::567::51") << formatRange(138, 202))) << QString(); diff --git a/src/plugins/projectexplorer/customparser.cpp b/src/plugins/projectexplorer/customparser.cpp index e10595af78a..0e2a360af11 100644 --- a/src/plugins/projectexplorer/customparser.cpp +++ b/src/plugins/projectexplorer/customparser.cpp @@ -237,7 +237,7 @@ OutputLineParser::Result CustomParser::hasMatch( const int lineNumber = match.captured(expression.lineNumberCap()).toInt(); const QString message = match.captured(expression.messageCap()); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, fileName, lineNumber, match, + addLinkSpecForAbsoluteFilePath(linkSpecs, fileName, lineNumber, -1, match, expression.fileNameCap()); scheduleTask(CompileTask(taskType, message, fileName, lineNumber), 1); return {Status::Done, linkSpecs}; diff --git a/src/plugins/projectexplorer/gccparser.cpp b/src/plugins/projectexplorer/gccparser.cpp index 3e61df45dee..3a43e8ebe99 100644 --- a/src/plugins/projectexplorer/gccparser.cpp +++ b/src/plugins/projectexplorer/gccparser.cpp @@ -221,7 +221,7 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat const int lineNo = match.captured(2).toInt(); const int column = match.captured(3).toInt(); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, "file"); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, column, match, "file"); gccCreateOrAmendTask( Task::Unknown, lne.trimmed(), lne, false, filePath, lineNo, column, linkSpecs); return {Status::InProgress, linkSpecs}; @@ -234,7 +234,7 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(3))); LinkSpecs linkSpecs; if (!filePath.isEmpty()) - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, -1, match, 3); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, -1, -1, match, 3); gccCreateOrAmendTask(type, match.captured(2), lne, false, filePath, -1, 0, linkSpecs); return {Status::Done, linkSpecs}; } @@ -243,7 +243,12 @@ OutputLineParser::Result GccParser::handleLine(const QString &line, OutputFormat const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(data->rawFilePath)); LinkSpecs linkSpecs; addLinkSpecForAbsoluteFilePath( - linkSpecs, filePath, data->line, data->fileOffset, data->rawFilePath.size()); + linkSpecs, + filePath, + data->line, + data->column, + data->fileOffset, + data->rawFilePath.size()); gccCreateOrAmendTask( data->type, data->description, lne, false, filePath, data->line, data->column, linkSpecs); return {Status::InProgress, linkSpecs}; @@ -343,9 +348,9 @@ void ProjectExplorerTest::testGccOutputParsers_data() 9, 0, QVector() << formatRange(46, 0) - << formatRange(46, 29, "olpfile:///temp/test/untitled8/main.cpp::0::-1") + << formatRange(46, 29, "olpfile:///temp/test/untitled8/main.cpp::0::0") << formatRange(75, 39) - << formatRange(114, 29, "olpfile:///temp/test/untitled8/main.cpp::9::-1") + << formatRange(114, 29, "olpfile:///temp/test/untitled8/main.cpp::9::0") << formatRange(143, 56)) << CompileTask(Task::Error, "(Each undeclared identifier is reported only once for each function it appears in.)", @@ -514,9 +519,9 @@ void ProjectExplorerTest::testGccOutputParsers_data() 264, 0, QVector() << formatRange(45, 0) - << formatRange(45, 68, "olpfile:///home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp::0::-1") + << formatRange(45, 68, "olpfile:///home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp::0::0") << formatRange(113, 106) - << formatRange(219, 68, "olpfile:///home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp::264::-1") + << formatRange(219, 68, "olpfile:///home/code/src/creator/src/plugins/projectexplorer/gnumakeparser.cpp::264::0") << formatRange(287, 57)) << CompileTask(Task::Error, "expected ';' before ':' token", @@ -583,9 +588,9 @@ void ProjectExplorerTest::testGccOutputParsers_data() 194, 0, QVector() << formatRange(50, 0) - << formatRange(50, 67, "olpfile:///Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c::0::-1") + << formatRange(50, 67, "olpfile:///Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c::0::0") << formatRange(117, 216) - << formatRange(333, 67, "olpfile:///Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c::194::-1") + << formatRange(333, 67, "olpfile:///Qt/4.6.2-Symbian/s60sdk/epoc32/include/stdapis/stlport/stl/_tree.c::194::0") << formatRange(400, 64))) << QString(); @@ -822,9 +827,9 @@ void ProjectExplorerTest::testGccOutputParsers_data() 1134, 26, QVector() << formatRange(26, 22) - << formatRange(48, 39, "olpfile:///Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h::15::-1") + << formatRange(48, 39, "olpfile:///Symbian/SDK/EPOC32/INCLUDE/GCCE/GCCE.h::15::0") << formatRange(87, 46) - << formatRange(133, 50, "olpfile:///Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh::1134::-1") + << formatRange(133, 50, "olpfile:///Symbian/SDK/epoc32/include/variant/Symbian_OS.hrh::1134::26") << formatRange(183, 44))} << QString(); @@ -929,7 +934,7 @@ void ProjectExplorerTest::testGccOutputParsers_data() 14, 25, QVector() << formatRange(41, 22) - << formatRange(63, 67, "olpfile:///home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp::31::-1") + << formatRange(63, 67, "olpfile:///home/code/src/creator/src/libs/extensionsystem/pluginerrorview.cpp::31::0") << formatRange(130, 146))} << QString(); @@ -953,11 +958,11 @@ void ProjectExplorerTest::testGccOutputParsers_data() 597, 5, QVector() << formatRange(43, 22) - << formatRange(65, 31, "olpfile:///usr/include/qt4/QtCore/QString::1::-1") + << formatRange(65, 31, "olpfile:///usr/include/qt4/QtCore/QString::1::0") << formatRange(96, 40) - << formatRange(136, 33, "olpfile:///usr/include/qt4/QtCore/qstring.h::0::-1") + << formatRange(136, 33, "olpfile:///usr/include/qt4/QtCore/qstring.h::0::0") << formatRange(169, 28) - << formatRange(197, 33, "olpfile:///usr/include/qt4/QtCore/qstring.h::597::-1") + << formatRange(197, 33, "olpfile:///usr/include/qt4/QtCore/qstring.h::597::5") << formatRange(230, 99))} << QString(); @@ -1233,17 +1238,17 @@ void ProjectExplorerTest::testGccOutputParsers_data() 273, 25, QVector() << formatRange(140, 22) - << formatRange(162, 32, "olpfile:///usr/include/qt/QtCore/qlocale.h::43::-1") + << formatRange(162, 32, "olpfile:///usr/include/qt/QtCore/qlocale.h::43::0") << formatRange(194, 27) - << formatRange(221, 36, "olpfile:///usr/include/qt/QtCore/qtextstream.h::46::-1") + << formatRange(221, 36, "olpfile:///usr/include/qt/QtCore/qtextstream.h::46::0") << formatRange(257, 27) - << formatRange(284, 38, "olpfile:///qtc/src/shared/proparser/proitems.cpp::31::-1") + << formatRange(284, 38, "olpfile:///qtc/src/shared/proparser/proitems.cpp::31::0") << formatRange(322, 5) - << formatRange(327, 33, "olpfile:///usr/include/qt/QtCore/qvariant.h::0::-1") + << formatRange(327, 33, "olpfile:///usr/include/qt/QtCore/qvariant.h::0::0") << formatRange(360, 51) - << formatRange(411, 33, "olpfile:///usr/include/qt/QtCore/qvariant.h::273::-1") + << formatRange(411, 33, "olpfile:///usr/include/qt/QtCore/qvariant.h::273::25") << formatRange(444, 229) - << formatRange(673, 33, "olpfile:///usr/include/qt/QtCore/qvariant.h::399::-1") + << formatRange(673, 33, "olpfile:///usr/include/qt/QtCore/qvariant.h::399::16") << formatRange(706, 221)), compileTask(Task::Error, "no match for ‘operator+’ (operand types are ‘boxed_value’ and ‘boxed_value’)\n" @@ -1477,13 +1482,13 @@ void ProjectExplorerTest::testGccOutputParsers_data() FilePath::fromUserInput("/data/dev/creator/src/libs/utils/aspects.cpp"), 3454, 13, QVector{ formatRange(82, 22), - formatRange(104, 44, "olpfile:///data/dev/creator/src/libs/utils/aspects.cpp::12::-1"), + formatRange(104, 44, "olpfile:///data/dev/creator/src/libs/utils/aspects.cpp::12::0"), formatRange(148, 5), - formatRange(153, 48, "olpfile:///data/dev/creator/src/libs/utils/layoutbuilder.h::0::-1"), + formatRange(153, 48, "olpfile:///data/dev/creator/src/libs/utils/layoutbuilder.h::0::0"), formatRange(201, 177), - formatRange(378, 44, "olpfile:///data/dev/creator/src/libs/utils/aspects.cpp::3454::-1"), + formatRange(378, 44, "olpfile:///data/dev/creator/src/libs/utils/aspects.cpp::3454::13"), formatRange(422, 31), - formatRange(453, 48, "olpfile:///data/dev/creator/src/libs/utils/layoutbuilder.h::79::-1"), + formatRange(453, 48, "olpfile:///data/dev/creator/src/libs/utils/layoutbuilder.h::79::51"), formatRange(501, 228)})}) << QString(); } diff --git a/src/plugins/projectexplorer/gnumakeparser.cpp b/src/plugins/projectexplorer/gnumakeparser.cpp index d31ce499700..015d030d180 100644 --- a/src/plugins/projectexplorer/gnumakeparser.cpp +++ b/src/plugins/projectexplorer/gnumakeparser.cpp @@ -103,7 +103,7 @@ OutputLineParser::Result GnuMakeParser::handleLine(const QString &line, OutputFo if (!m_suppressIssues) { const FilePath file = absoluteFilePath(FilePath::fromUserInput(match.captured(1))); const int lineNo = match.captured(4).toInt(); - addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, match, 1); + addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, -1, match, 1); emitTask(BuildSystemTask(res.type, res.description, file, lineNo)); } return {Status::Done, linkSpecs}; diff --git a/src/plugins/projectexplorer/ldparser.cpp b/src/plugins/projectexplorer/ldparser.cpp index ea7521bd0e2..95bb4e84959 100644 --- a/src/plugins/projectexplorer/ldparser.cpp +++ b/src/plugins/projectexplorer/ldparser.cpp @@ -62,7 +62,7 @@ Utils::OutputLineParser::Result LdParser::handleLine(const QString &line, Utils: if (match.hasMatch()) { handle = true; filePath = absoluteFilePath(Utils::FilePath::fromString(match.captured("file"))); - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, 0, match, "file"); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, -1, -1, match, "file"); currentTask().setFile(filePath); } else { handle = !lne.isEmpty() && lne.at(0).isSpace(); @@ -135,7 +135,7 @@ Utils::OutputLineParser::Result LdParser::handleLine(const QString &line, Utils: } if (hasKeyword || filePath.fileName().endsWith(".o")) { LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineno, match, capIndex); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineno, -1, match, capIndex); createOrAmendTask(type, description, line, false, filePath, lineno, 0, linkSpecs); return {getStatus(), linkSpecs}; } diff --git a/src/plugins/projectexplorer/linuxiccparser.cpp b/src/plugins/projectexplorer/linuxiccparser.cpp index 734f8148658..6e625b240a5 100644 --- a/src/plugins/projectexplorer/linuxiccparser.cpp +++ b/src/plugins/projectexplorer/linuxiccparser.cpp @@ -59,7 +59,7 @@ OutputLineParser::Result LinuxIccParser::handleLine(const QString &line, OutputF const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(1))); const int lineNo = match.captured(2).toInt(); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 1); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, -1, match, 1); createOrAmendTask(type, match.captured(6).trimmed(), line, false, filePath, lineNo); m_expectFirstLine = false; return Status::InProgress; diff --git a/src/plugins/projectexplorer/lldparser.cpp b/src/plugins/projectexplorer/lldparser.cpp index 3bb4079b766..0bc36ff845e 100644 --- a/src/plugins/projectexplorer/lldparser.cpp +++ b/src/plugins/projectexplorer/lldparser.cpp @@ -46,7 +46,7 @@ Utils::OutputLineParser::Result LldParser::handleLine(const QString &line, Utils const auto file = absoluteFilePath(Utils::FilePath::fromUserInput( trimmedLine.mid(filePathOffset, filePathLen).trimmed())); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, filePathOffset, filePathLen); + addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, -1, filePathOffset, filePathLen); scheduleTask(CompileTask(Task::Unknown, trimmedLine.mid(4).trimmed(), file, lineNo), 1); return {Status::Done, linkSpecs}; diff --git a/src/plugins/projectexplorer/msvcparser.cpp b/src/plugins/projectexplorer/msvcparser.cpp index 0613a0b74e8..17710cb13c3 100644 --- a/src/plugins/projectexplorer/msvcparser.cpp +++ b/src/plugins/projectexplorer/msvcparser.cpp @@ -114,7 +114,7 @@ OutputLineParser::Result MsvcParser::handleLine(const QString &line, OutputForma const FilePath filePath = absoluteFilePath(FilePath::fromUserInput(match.captured(2))); const int lineNo = match.captured(3).toInt(); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, match, 2); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, lineNo, -1, match, 2); createOrAmendTask(Task::Unknown, description, line, false, filePath, lineNo, 0, linkSpecs); return {Status::InProgress, linkSpecs}; } @@ -146,7 +146,7 @@ MsvcParser::Result MsvcParser::processCompileLine(const QString &line) QPair position = parseFileName(match.captured(1)); const FilePath filePath = absoluteFilePath(position.first); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, position.second, match, 1); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, position.second, -1, match, 1); const QString &description = match.captured(3) + match.captured(4).trimmed(); createOrAmendTask( taskType(match.captured(2)), @@ -228,7 +228,7 @@ OutputLineParser::Result ClangClParser::handleLine(const QString &line, OutputFo const FilePath file = absoluteFilePath(position.first); const int lineNo = position.second; LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, match, 1); + addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineNo, -1, match, 1); createOrAmendTask( taskType(match.captured(2)), match.captured(3).trimmed(), line, false, file, lineNo); return {Status::InProgress, linkSpecs}; diff --git a/src/plugins/projectexplorer/sanitizerparser.cpp b/src/plugins/projectexplorer/sanitizerparser.cpp index 8da13d5d37b..546de844485 100644 --- a/src/plugins/projectexplorer/sanitizerparser.cpp +++ b/src/plugins/projectexplorer/sanitizerparser.cpp @@ -93,7 +93,8 @@ OutputLineParser::Result SanitizerParser::handleContinuation(const QString &line m_task.file = file; m_task.line = summaryMatch.captured("line").toInt(); m_task.column = summaryMatch.captured("column").toInt(); - addLinkSpecForAbsoluteFilePath(linkSpecs, file, m_task.line, summaryMatch, "file"); + addLinkSpecForAbsoluteFilePath( + linkSpecs, file, m_task.line, m_task.column, summaryMatch, "file"); addLinkSpecs(linkSpecs); } } else { @@ -107,7 +108,7 @@ OutputLineParser::Result SanitizerParser::handleContinuation(const QString &line const FilePath file = absoluteFilePath(FilePath::fromUserInput(fileMatch.captured("file"))); if (fileExists(file)) { addLinkSpecForAbsoluteFilePath(linkSpecs, file, fileMatch.captured("line").toInt(), - fileMatch, "file"); + fileMatch.captured("column").toInt(), fileMatch, "file"); addLinkSpecs(linkSpecs); } } diff --git a/src/plugins/projectexplorer/xcodebuildparser.cpp b/src/plugins/projectexplorer/xcodebuildparser.cpp index 8a2d3e2962a..2037614e043 100644 --- a/src/plugins/projectexplorer/xcodebuildparser.cpp +++ b/src/plugins/projectexplorer/xcodebuildparser.cpp @@ -57,7 +57,8 @@ OutputLineParser::Result XcodebuildParser::handleLine(const QString &line, Outpu absoluteFilePath(FilePath::fromString( lne.left(filePathEndPos)))); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, 0, filePathEndPos); + addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, task.column, 0, + filePathEndPos); scheduleTask(task, 1); return {Status::Done, linkSpecs}; } diff --git a/src/plugins/qmakeprojectmanager/qmakeparser.cpp b/src/plugins/qmakeprojectmanager/qmakeparser.cpp index 57051ba5a20..0b0bdc5af08 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparser.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparser.cpp @@ -46,7 +46,7 @@ OutputLineParser::Result QMakeParser::handleLine(const QString &line, OutputForm BuildSystemTask t(type, description, absoluteFilePath(FilePath::fromUserInput(fileName)), match.captured(2).toInt() /* line */); LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, t.file, t.line, fileNameOffset, + addLinkSpecForAbsoluteFilePath(linkSpecs, t.file, t.line, t.column, fileNameOffset, fileName.length()); scheduleTask(t, 1); return {Status::Done, linkSpecs}; diff --git a/src/plugins/qtsupport/qtparser.cpp b/src/plugins/qtsupport/qtparser.cpp index 387af762a3b..93fd16d90a5 100644 --- a/src/plugins/qtsupport/qtparser.cpp +++ b/src/plugins/qtsupport/qtparser.cpp @@ -45,7 +45,7 @@ Utils::OutputLineParser::Result QtParser::handleLine(const QString &line, Utils: LinkSpecs linkSpecs; const Utils::FilePath file = absoluteFilePath(Utils::FilePath::fromUserInput(match.captured("file"))); - addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineno, match, "file"); + addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineno, -1, match, "file"); CompileTask task(type, match.captured("description").trimmed(), file, lineno); task.column = match.captured("column").toInt(); scheduleTask(task, 1); @@ -62,7 +62,7 @@ Utils::OutputLineParser::Result QtParser::handleLine(const QString &line, Utils: message.prepend(": ").prepend(fileName); } else if (fileName.endsWith(".ui")) { filePath = absoluteFilePath(Utils::FilePath::fromUserInput(fileName)); - addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, -1, match, "file"); + addLinkSpecForAbsoluteFilePath(linkSpecs, filePath, -1, -1, match, "file"); } else { isUicMessage = false; } @@ -79,7 +79,7 @@ Utils::OutputLineParser::Result QtParser::handleLine(const QString &line, Utils: LinkSpecs linkSpecs; const Utils::FilePath file = absoluteFilePath(Utils::FilePath::fromUserInput(match.captured("file"))); - addLinkSpecForAbsoluteFilePath(linkSpecs, file, 0, match, "file"); + addLinkSpecForAbsoluteFilePath(linkSpecs, file, -1, -1, match, "file"); CompileTask task(type, match.captured("description"), file); scheduleTask(task, 1); return {Status::Done, linkSpecs}; @@ -95,7 +95,7 @@ Utils::OutputLineParser::Result QtParser::handleLine(const QString &line, Utils: if (!ok) lineno = -1; LinkSpecs linkSpecs; - addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineno, match, "file"); + addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineno, -1, match, "file"); CompileTask task(type, match.captured("description"), file, lineno, match.captured("column").toInt()); scheduleTask(task, 1); diff --git a/src/plugins/qtsupport/qttestparser.cpp b/src/plugins/qtsupport/qttestparser.cpp index 93030f20e68..a19929b7544 100644 --- a/src/plugins/qtsupport/qttestparser.cpp +++ b/src/plugins/qtsupport/qttestparser.cpp @@ -44,8 +44,8 @@ OutputLineParser::Result QtTestParser::handleLine(const QString &line, OutputFor m_currentTask.file = absoluteFilePath(FilePath::fromString( QDir::fromNativeSeparators(match.captured("file")))); m_currentTask.line = match.captured("line").toInt(); - addLinkSpecForAbsoluteFilePath(linkSpecs, m_currentTask.file, m_currentTask.line, match, - "file"); + addLinkSpecForAbsoluteFilePath( + linkSpecs, m_currentTask.file, m_currentTask.line, m_currentTask.column, match, "file"); emitCurrentTask(); return {Status::Done, linkSpecs}; } diff --git a/src/plugins/rustls/rustls/init.lua b/src/plugins/rustls/rustls/init.lua index c83d71ae5ff..474c368f3a9 100644 --- a/src/plugins/rustls/rustls/init.lua +++ b/src/plugins/rustls/rustls/init.lua @@ -8,6 +8,7 @@ local S = require('Settings') local Gui = require('Gui') local a = require('async') local fetch = require('Fetch').fetch +local Install = require('Install') Settings = {} @@ -39,7 +40,6 @@ local function installOrUpdateServer() if r.prerelease then r = data[2] end - Install = require('Install') local lspPkgInfo = Install.packageInfo("rust-analyzer") if not lspPkgInfo or lspPkgInfo.version ~= r.tag_name then local osTr = { mac = "apple-darwin", windows = "pc-windows-msvc", linux = "unknown-linux-gnu" } @@ -80,7 +80,7 @@ local function installOrUpdateServer() binary = "rust-analyzer.exe" end - Settings.binary.defaultPath = lspPkgInfo.path:resolvePath(binary) + Settings.binary:setValue(lspPkgInfo.path:resolvePath(binary)) Settings:apply() return end @@ -130,8 +130,8 @@ local function layoutSettings() Settings.binary, br, Row { PushButton { - text("Try to install Rust language server"), - onClicked(function() a.sync(installOrUpdateServer)() end), + text = "Try to install Rust language server", + onClicked = function() a.sync(installOrUpdateServer)() end, br, }, st @@ -141,6 +141,36 @@ local function layoutSettings() return layout end +local function binaryFromPkg() + local lspPkgInfo = Install.packageInfo("rust-analyzer") + if lspPkgInfo then + local binary = "rust-analyzer" + if Utils.HostOsInfo.isWindowsHost() then + binary = "rust-analyzer.exe" + end + local binaryPath = lspPkgInfo.path:resolvePath(binary) + if binaryPath:isExecutableFile() == true then + return binaryPath + end + end + + return nil +end + +local function findBinary() + local binary = binaryFromPkg() + if binary then + return binary + end + + -- Search for the binary in the PATH + local serverPath = Utils.FilePath.fromUserInput("rust-analyzer") + local absolute = a.wait(serverPath:searchInPath()):resolveSymlinks() + if absolute:isExecutableFile() == true then + return absolute + end + return serverPath +end local function setupAspect() ---@class Settings: AspectContainer Settings = S.AspectContainer.create({ @@ -154,14 +184,8 @@ local function setupAspect() labelText = "Binary:", toolTip = "The path to the rust analyzer binary.", expectedKind = S.Kind.ExistingCommand, - defaultPath = Utils.FilePath.fromUserInput("rust-analyzer"), + defaultPath = findBinary(), }) - -- Search for the binary in the PATH - local serverPath = Settings.binary.defaultPath - local absolute = a.wait(serverPath:searchInPath()):resolveSymlinks() - if absolute:isExecutableFile() == true then - Settings.binary.defaultPath = absolute - end return Settings end diff --git a/src/plugins/vcsbase/VcsBase.json.in b/src/plugins/vcsbase/VcsBase.json.in index 49933bc2aeb..a1717a9138a 100644 --- a/src/plugins/vcsbase/VcsBase.json.in +++ b/src/plugins/vcsbase/VcsBase.json.in @@ -16,7 +16,7 @@ "Description" : "Provides the technical basis for version control system (VCS) extensions", "LongDescription" : [ "You also need:", - "- An extension for a VCS tool, such as Git, and the tool + "- An extension for a VCS tool, such as Git, and the tool" ], "Url" : "https://www.qt.io", ${IDE_PLUGIN_DEPENDENCIES} diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 4385f84084f..8e5109eee5c 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1949,6 +1949,9 @@ void tst_Dumpers::dumper() } while (localsBeginPos != -1); actual.fromString(QString::fromLocal8Bit(contents)); context.nameSpace = actual["result"]["qtnamespace"].data(); + int runtime = actual["result"]["runtime"].data().toFloat() * 1000; + qCDebug(lcDumpers, "CaseInner: %5d", runtime); + m_totalInnerTime += runtime; actual = actual["result"]["data"]; }