Merge remote-tracking branch 'origin/11.0' into qds/dev

Change-Id: I23063e42621b272bd4b04a06746955e6b5768b49
This commit is contained in:
Tim Jenssen
2023-08-15 14:31:59 +02:00
76 changed files with 966 additions and 424 deletions

View File

@@ -278,26 +278,16 @@ static Utils::QtcSettings *createUserSettings()
static void setHighDpiEnvironmentVariable()
{
if (Utils::HostOsInfo::isMacHost())
if (Utils::HostOsInfo::isMacHost() || qEnvironmentVariableIsSet("QT_SCALE_FACTOR_ROUNDING_POLICY"))
return;
std::unique_ptr<QSettings> settings(createUserSettings());
const bool defaultValue = Utils::HostOsInfo::isWindowsHost();
const bool enableHighDpiScaling = settings->value("Core/EnableHighDpiScaling", defaultValue).toBool();
static const char ENV_VAR_QT_DEVICE_PIXEL_RATIO[] = "QT_DEVICE_PIXEL_RATIO";
if (enableHighDpiScaling
&& !qEnvironmentVariableIsSet(ENV_VAR_QT_DEVICE_PIXEL_RATIO) // legacy in 5.6, but still functional
&& !qEnvironmentVariableIsSet("QT_AUTO_SCREEN_SCALE_FACTOR")
&& !qEnvironmentVariableIsSet("QT_SCALE_FACTOR")
&& !qEnvironmentVariableIsSet("QT_SCREEN_SCALE_FACTORS")) {
return;
}
if (!qEnvironmentVariableIsSet("QT_SCALE_FACTOR_ROUNDING_POLICY"))
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
Qt::HighDpiScaleFactorRoundingPolicy::Floor);
const auto policy = enableHighDpiScaling ? Qt::HighDpiScaleFactorRoundingPolicy::PassThrough
: Qt::HighDpiScaleFactorRoundingPolicy::Floor;
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(policy);
}
void setPixmapCacheLimit()

View File

@@ -54,6 +54,10 @@ bool UnixPtyProcess::startProcess(const QString &shellPath,
int rc = 0;
m_shellProcess.m_handleMaster = ::posix_openpt(O_RDWR | O_NOCTTY);
int flags = fcntl(m_shellProcess.m_handleMaster, F_GETFL, 0);
fcntl(m_shellProcess.m_handleMaster, F_SETFL, flags | O_NONBLOCK);
if (m_shellProcess.m_handleMaster <= 0) {
m_lastError = QString("UnixPty Error: unable to open master -> %1").arg(QLatin1String(strerror(errno)));
kill();
@@ -308,10 +312,7 @@ QByteArray UnixPtyProcess::readAll()
qint64 UnixPtyProcess::write(const QByteArray &byteArray)
{
int result = ::write(m_shellProcess.m_handleMaster, byteArray.constData(), byteArray.size());
Q_UNUSED(result)
return byteArray.size();
return ::write(m_shellProcess.m_handleMaster, byteArray.constData(), byteArray.size());
}
bool UnixPtyProcess::isAvailable()

View File

@@ -204,7 +204,27 @@ FilePath FilePath::currentWorkingPath()
bool FilePath::isRootPath() const
{
// FIXME: Make host-independent
if (needsDevice()) {
QStringView path = pathView();
if (osType() != OsTypeWindows)
return path == QLatin1String("/");
// Remote windows paths look like this: "/c:/", so we remove the leading '/'
if (path.startsWith('/'))
path = path.mid(1);
if (path.length() > 3)
return false;
if (!startsWithDriveLetter())
return false;
if (path.length() == 3 && path[2] != QLatin1Char('/'))
return false;
return true;
}
return *this == FilePath::fromString(QDir::rootPath());
}
@@ -1269,7 +1289,16 @@ FilePath FilePath::fromSettings(const QVariant &variant)
const QUrl url = variant.toUrl();
return FilePath::fromParts(url.scheme(), url.host(), url.path());
}
return FilePath::fromUserInput(variant.toString());
// The installer sometimes fails and adds "docker:/..." instead of "docker://...
// So we fix these paths here in those cases.
QString data = variant.toString();
if (data.length() > 8 && data.startsWith("docker:/") && data[8] != '/') {
qWarning() << "Broken path in settings:" << data << ", applying workaround.";
data.insert(8, '/');
}
return FilePath::fromUserInput(data);
}
QVariant FilePath::toSettings() const
@@ -1337,15 +1366,15 @@ bool FilePath::contains(const QString &s) const
/*!
\brief Checks whether the FilePath starts with a drive letter.
Defaults to \c false if it is a non-Windows host or represents a path on device
Returns whether FilePath starts with a drive letter
*/
bool FilePath::startsWithDriveLetter() const
{
const QStringView p = pathView();
return !needsDevice() && p.size() >= 2 && isWindowsDriveLetter(p[0]) && p.at(1) == ':';
QStringView p = pathView();
if (needsDevice() && !p.isEmpty())
p = p.mid(1);
return p.size() >= 2 && isWindowsDriveLetter(p[0]) && p.at(1) == ':';
}
/*!

View File

@@ -722,8 +722,7 @@ bool FileUtils::copyRecursively(
bool FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath)
{
QTC_ASSERT(srcFilePath.exists(), return false);
QTC_ASSERT(srcFilePath.scheme() == tgtFilePath.scheme(), return false);
QTC_ASSERT(srcFilePath.host() == tgtFilePath.host(), return false);
QTC_ASSERT(srcFilePath.isSameDevice(tgtFilePath), return false);
if (tgtFilePath.exists()) {
const QDateTime srcModified = srcFilePath.lastModified();

View File

@@ -1204,7 +1204,7 @@ FilePath Process::workingDirectory() const
void Process::setWorkingDirectory(const FilePath &dir)
{
if (dir.needsDevice() && d->m_setup.m_commandLine.executable().needsDevice()) {
QTC_CHECK(dir.host() == d->m_setup.m_commandLine.executable().host());
QTC_CHECK(dir.isSameDevice(d->m_setup.m_commandLine.executable()));
}
d->m_setup.m_workingDirectory = dir;
}
@@ -1564,9 +1564,11 @@ qint64 Process::writeRaw(const QByteArray &input)
QTC_ASSERT(state() == QProcess::Running, return -1);
QTC_ASSERT(QThread::currentThread() == thread(), return -1);
qint64 result = -1;
QMetaObject::invokeMethod(d->m_process.get(), [this, input] {
d->m_process->write(input);
}, d->connectionType(), &result);
QMetaObject::invokeMethod(
d->m_process.get(),
[this, input] { return d->m_process->write(input); },
d->connectionType(),
&result);
return result;
}

View File

@@ -59,9 +59,6 @@ ClangFormatSettings::ClangFormatSettings()
fallbackStyle.addOption("WebKit");
fallbackStyle.setDefaultValue("Default");
predefinedStyle.setSettingsKey("predefinedStyle");
predefinedStyle.setDefaultValue("LLVM");
customStyle.setSettingsKey("customStyle");
documentationFilePath = Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME)
@@ -254,7 +251,8 @@ public:
connect(styleButtonGroup, &QButtonGroup::buttonClicked, this, updateEnabled);
connect(&s.predefinedStyle, &SelectionAspect::volatileValueChanged, this, updateEnabled);
setOnApply([settings, configurations] {
setOnApply([settings, configurations, customizedStyleButton] {
settings->usePredefinedStyle.setValue(!customizedStyleButton->isChecked());
settings->customStyle.setValue(configurations->currentConfiguration());
settings->save();
});

View File

@@ -161,7 +161,9 @@ clang::format::FormatStyle qtcStyle()
style.SpaceAfterTemplateKeyword = false;
style.SpaceBeforeAssignmentOperators = true;
style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
#if LLVM_VERSION_MAJOR < 17
style.SpaceInEmptyParentheses = false;
#endif
style.SpacesBeforeTrailingComments = 1;
#if LLVM_VERSION_MAJOR >= 13
style.SpacesInAngles = FormatStyle::SIAS_Never;
@@ -169,8 +171,12 @@ clang::format::FormatStyle qtcStyle()
style.SpacesInAngles = false;
#endif
style.SpacesInContainerLiterals = false;
#if LLVM_VERSION_MAJOR >= 17
style.SpacesInParens = FormatStyle::SIPO_Never;
#else
style.SpacesInCStyleCastParentheses = false;
style.SpacesInParentheses = false;
#endif
style.SpacesInSquareBrackets = false;
addQtcStatementMacros(style);
style.Standard = FormatStyle::LS_Cpp11;

View File

@@ -14,6 +14,8 @@
#include <android/androidconstants.h>
#include <baremetal/baremetalconstants.h>
#include <ios/iosconstants.h>
#include <webassembly/webassemblyconstants.h>
@@ -188,6 +190,8 @@ static bool supportsStageForInstallation(const Kit *kit)
return runDevice->id() != buildDevice->id()
&& runDevice->type() != Android::Constants::ANDROID_DEVICE_TYPE
&& runDevice->type() != Ios::Constants::IOS_DEVICE_TYPE
&& runDevice->type() != Ios::Constants::IOS_SIMULATOR_TYPE
&& runDevice->type() != BareMetal::Constants::BareMetalOsType
&& runDevice->type() != WebAssembly::Constants::WEBASSEMBLY_DEVICE_TYPE;
}

View File

@@ -654,9 +654,31 @@ FilePaths CMakeBuildSystem::filesGeneratedFrom(const FilePath &sourceFile) const
FilePath generatedFilePath = buildConfiguration()->buildDirectory().resolvePath(relativePath);
if (sourceFile.suffix() == "ui") {
generatedFilePath = generatedFilePath
.pathAppended("ui_" + sourceFile.completeBaseName() + ".h");
return {generatedFilePath};
const QString generatedFileName = "ui_" + sourceFile.completeBaseName() + ".h";
auto targetNode = this->project()->nodeForFilePath(sourceFile);
while (!dynamic_cast<const CMakeTargetNode *>(targetNode))
targetNode = targetNode->parentFolderNode();
FilePaths generatedFilePaths;
if (targetNode) {
const QString autogenSignature = targetNode->buildKey() + "_autogen/include";
// If AUTOUIC reports the generated header file name, use that path
generatedFilePaths = this->project()->files(
[autogenSignature, generatedFileName](const Node *n) {
const FilePath filePath = n->filePath();
if (!filePath.contains(autogenSignature))
return false;
return Project::GeneratedFiles(n) && filePath.endsWith(generatedFileName);
});
}
if (generatedFilePaths.empty())
generatedFilePaths = {generatedFilePath.pathAppended(generatedFileName)};
return generatedFilePaths;
}
if (sourceFile.suffix() == "scxml") {
generatedFilePath = generatedFilePath.pathAppended(sourceFile.completeBaseName());

View File

@@ -79,7 +79,7 @@ void CMakeProcess::run(const BuildDirParameters &parameters, const QStringList &
}
if (buildDirectory.needsDevice()) {
if (cmake->cmakeExecutable().host() != buildDirectory.host()) {
if (!cmake->cmakeExecutable().isSameDevice(buildDirectory)) {
const QString msg = ::CMakeProjectManager::Tr::tr(
"CMake executable \"%1\" and build directory \"%2\" must be on the same device.")
.arg(cmake->cmakeExecutable().toUserOutput(), buildDirectory.toUserOutput());

View File

@@ -61,6 +61,12 @@ CMakeSpecificSettings::CMakeSpecificSettings()
// never save this to the settings:
ninjaPath.setToSettingsTransformation(
[](const QVariant &) { return QVariant::fromValue(QString()); });
ninjaPath.setFromSettingsTransformation([](const QVariant &from) {
// Sometimes the installer appends the same ninja path to the qtcreator.ini file
const QString path = from.canConvert<QStringList>() ? from.toStringList().last()
: from.toString();
return FilePath::fromUserInput(path).toVariant();
});
packageManagerAutoSetup.setSettingsKey("PackageManagerAutoSetup");
packageManagerAutoSetup.setDefaultValue(true);

View File

@@ -486,6 +486,26 @@ static std::vector<FileApiDetails::FragmentInfo> extractFragments(const QJsonObj
});
}
static void addIncludeInfo(std::vector<IncludeInfo> *includes,
const QJsonObject &compileGroups,
const QString &section)
{
const std::vector<IncludeInfo> add
= transform<std::vector>(compileGroups.value(section).toArray(), [](const QJsonValue &v) {
const QJsonObject i = v.toObject();
const QString path = i.value("path").toString();
const bool isSystem = i.value("isSystem").toBool();
const ProjectExplorer::HeaderPath hp(path,
isSystem
? ProjectExplorer::HeaderPathType::System
: ProjectExplorer::HeaderPathType::User);
return IncludeInfo{ProjectExplorer::RawProjectPart::frameworkDetectionHeuristic(hp),
i.value("backtrace").toInt(-1)};
});
std::copy(add.cbegin(), add.cend(), std::back_inserter(*includes));
}
static TargetDetails extractTargetDetails(const QJsonObject &root, QString &errorMessage)
{
TargetDetails t;
@@ -581,6 +601,10 @@ static TargetDetails extractTargetDetails(const QJsonObject &root, QString &erro
const QJsonArray compileGroups = root.value("compileGroups").toArray();
t.compileGroups = transform<std::vector>(compileGroups, [](const QJsonValue &v) {
const QJsonObject o = v.toObject();
std::vector<IncludeInfo> includes;
addIncludeInfo(&includes, o, "includes");
// new in CMake 3.27+:
addIncludeInfo(&includes, o, "frameworks");
return CompileInfo{
transform<std::vector>(o.value("sourceIndexes").toArray(),
[](const QJsonValue &v) { return v.toInt(-1); }),
@@ -590,21 +614,7 @@ static TargetDetails extractTargetDetails(const QJsonObject &root, QString &erro
const QJsonObject o = v.toObject();
return o.value("fragment").toString();
}),
transform<std::vector>(
o.value("includes").toArray(),
[](const QJsonValue &v) {
const QJsonObject i = v.toObject();
const QString path = i.value("path").toString();
const bool isSystem = i.value("isSystem").toBool();
const ProjectExplorer::HeaderPath
hp(path,
isSystem ? ProjectExplorer::HeaderPathType::System
: ProjectExplorer::HeaderPathType::User);
return IncludeInfo{
ProjectExplorer::RawProjectPart::frameworkDetectionHeuristic(hp),
i.value("backtrace").toInt(-1)};
}),
includes,
transform<std::vector>(o.value("defines").toArray(),
[](const QJsonValue &v) {
const QJsonObject d = v.toObject();

View File

@@ -95,14 +95,19 @@ void AuthWidget::updateClient(const Utils::FilePath &nodeJs, const Utils::FilePa
m_client = nullptr;
setState(Tr::tr("Sign In"), false);
m_button->setEnabled(false);
if (!nodeJs.isExecutableFile() || !agent.exists()) {
if (!nodeJs.isExecutableFile() || !agent.exists())
return;
}
setState(Tr::tr("Sign In"), true);
m_client = new CopilotClient(nodeJs, agent);
connect(m_client, &Client::initialized, this, &AuthWidget::checkStatus);
connect(m_client, &QObject::destroyed, this, [destroyedClient = m_client, this]() {
if (destroyedClient != m_client)
return;
m_client = nullptr;
m_progressIndicator->hide();
});
}
void AuthWidget::signIn()

View File

@@ -49,6 +49,36 @@ CommandsFile::CommandsFile(const FilePath &filename)
}
// XML attributes cannot contain these characters, and
// QXmlStreamWriter just bails out with an error.
// QKeySequence::toString() should probably not result in these
// characters, but it currently does, see QTCREATORBUG-29431
static bool containsInvalidCharacters(const QString &s)
{
const auto end = s.constEnd();
for (auto it = s.constBegin(); it != end; ++it) {
// from QXmlStreamWriterPrivate::writeEscaped
if (*it == u'\v' || *it == u'\f' || *it <= u'\x1F' || *it >= u'\uFFFE') {
return true;
}
}
return false;
}
static QString toAttribute(const QString &s)
{
if (containsInvalidCharacters(s))
return "0x" + QString::fromUtf8(s.toUtf8().toHex());
return s;
}
static QString fromAttribute(const QStringView &s)
{
if (s.startsWith(QLatin1String("0x")))
return QString::fromUtf8(QByteArray::fromHex(s.sliced(2).toUtf8()));
return s.toString();
}
/*!
\internal
*/
@@ -77,7 +107,7 @@ QMap<QString, QList<QKeySequence>> CommandsFile::importCommands() const
QTC_ASSERT(!currentId.isEmpty(), continue);
const QXmlStreamAttributes attributes = r.attributes();
if (attributes.hasAttribute(ctx.valueAttribute)) {
const QString keyString = attributes.value(ctx.valueAttribute).toString();
const QString keyString = fromAttribute(attributes.value(ctx.valueAttribute));
QList<QKeySequence> keys = result.value(currentId);
result.insert(currentId, keys << QKeySequence(keyString));
}
@@ -94,7 +124,6 @@ QMap<QString, QList<QKeySequence>> CommandsFile::importCommands() const
/*!
\internal
*/
bool CommandsFile::exportCommands(const QList<ShortcutItem *> &items)
{
FileSaver saver(m_filePath, QIODevice::Text);
@@ -119,7 +148,7 @@ bool CommandsFile::exportCommands(const QList<ShortcutItem *> &items)
w.writeAttribute(ctx.idAttribute, id.toString());
for (const QKeySequence &k : item->m_keys) {
w.writeEmptyElement(ctx.keyElement);
w.writeAttribute(ctx.valueAttribute, k.toString());
w.writeAttribute(ctx.valueAttribute, toAttribute(k.toString()));
}
w.writeEndElement(); // Shortcut
}
@@ -127,7 +156,8 @@ bool CommandsFile::exportCommands(const QList<ShortcutItem *> &items)
w.writeEndElement();
w.writeEndDocument();
saver.setResult(&w);
if (!saver.setResult(&w))
qWarning() << saver.errorString();
}
return saver.finalize();
}

View File

@@ -343,10 +343,10 @@ IDocument::OpenResult IDocument::open(QString *errorString, const Utils::FilePat
*/
bool IDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave)
{
emit aboutToSave(filePath, autoSave);
emit aboutToSave(filePath.isEmpty() ? this->filePath() : filePath, autoSave);
const bool success = saveImpl(errorString, filePath, autoSave);
if (success)
emit saved(filePath, autoSave);
emit saved(filePath.isEmpty() ? this->filePath() : filePath, autoSave);
return success;
}

View File

@@ -64,6 +64,13 @@ static QString defineDirectiveToDefineOption(const Macro &macro)
return QString::fromUtf8(option);
}
static QStringList cpuBlacklist()
{
QStringList blacklist = qtcEnvironmentVariable("QTC_CLANGD_CPU_BLACKLIST")
.split(':', Qt::SkipEmptyParts);
return blacklist << "cortex-a72.cortex-a53"; // See QTCREATORBUG-29304
}
QStringList XclangArgs(const QStringList &args)
{
QStringList options;
@@ -270,6 +277,7 @@ void CompilerOptionsBuilder::addPicIfCompilerFlagsContainsIt()
void CompilerOptionsBuilder::addCompilerFlags()
{
add(m_compilerFlags.flags);
removeUnsupportedCpuFlags();
}
void CompilerOptionsBuilder::addMsvcExceptions()
@@ -375,6 +383,17 @@ void CompilerOptionsBuilder::addIncludeFile(const QString &file)
}
}
void CompilerOptionsBuilder::removeUnsupportedCpuFlags()
{
const QStringList blacklist = cpuBlacklist();
for (auto it = m_options.begin(); it != m_options.end();) {
if (it->startsWith("-mcpu=") && blacklist.contains(it->mid(6)))
it = m_options.erase(it);
else
++it;
}
}
void CompilerOptionsBuilder::addIncludedFiles(const QStringList &files)
{
for (const QString &file : files) {

View File

@@ -87,6 +87,7 @@ private:
QStringList wrappedMingwHeadersIncludePath() const;
QByteArray msvcVersion() const;
void addIncludeFile(const QString &file);
void removeUnsupportedCpuFlags();
private:
const ProjectPart &m_projectPart;

View File

@@ -124,6 +124,9 @@ bool CppRefactoringFile::isCursorOn(unsigned tokenIndex) const
bool CppRefactoringFile::isCursorOn(const AST *ast) const
{
if (!ast)
return false;
QTextCursor tc = cursor();
int cursorBegin = tc.selectionStart();

View File

@@ -749,7 +749,7 @@ bool DebuggerRunTool::fixupParameters()
}
}
if (!debuggerSettings()->autoEnrichParameters.value()) {
if (debuggerSettings()->autoEnrichParameters.value()) {
const FilePath sysroot = rp.sysRoot;
if (rp.debugInfoLocation.isEmpty())
rp.debugInfoLocation = sysroot / "/usr/lib/debug";

View File

@@ -161,7 +161,10 @@ AttachCoreDialog::~AttachCoreDialog()
int AttachCoreDialog::exec()
{
connect(d->symbolFileName, &PathChooser::textChanged, this, &AttachCoreDialog::changed);
connect(d->symbolFileName, &PathChooser::validChanged, this, &AttachCoreDialog::changed);
connect(d->coreFileName, &PathChooser::validChanged, this, [this] {
coreFileChanged(d->coreFileName->rawFilePath());
});
connect(d->coreFileName, &PathChooser::textChanged, this, [this] {
coreFileChanged(d->coreFileName->rawFilePath());
});

View File

@@ -247,8 +247,10 @@ class RevertDialog : public QDialog
{
public:
RevertDialog(const QString &title, QWidget *parent = nullptr);
QString revision() const { return m_revisionLineEdit->text(); }
QLineEdit *m_revisionLineEdit;
private:
QLineEdit *m_revisionLineEdit = nullptr;
};
FossilPlugin::~FossilPlugin()
@@ -429,15 +431,11 @@ void FossilPluginPrivate::revertCurrentFile()
const VcsBase::VcsBasePluginState state = currentState();
QTC_ASSERT(state.hasFile(), return);
QDialog dialog(Core::ICore::dialogParent());
auto revisionLineEdit = new QLineEdit;
if (dialog.exec() != QDialog::Accepted)
return;
m_client.revertFile(state.currentFileTopLevel(),
state.relativeCurrentFile(),
revisionLineEdit->text());
RevertDialog dialog(Tr::tr("Revert"), Core::ICore::dialogParent());
if (dialog.exec() == QDialog::Accepted) {
m_client.revertFile(state.currentFileTopLevel(), state.relativeCurrentFile(),
dialog.revision());
}
}
void FossilPluginPrivate::statusCurrentFile()
@@ -512,7 +510,7 @@ void FossilPluginPrivate::revertAll()
RevertDialog dialog(Tr::tr("Revert"), Core::ICore::dialogParent());
if (dialog.exec() == QDialog::Accepted)
m_client.revertAll(state.topLevel(), dialog.m_revisionLineEdit->text());
m_client.revertAll(state.topLevel(), dialog.revision());
}
void FossilPluginPrivate::statusMulti()
@@ -628,7 +626,7 @@ void FossilPluginPrivate::update()
RevertDialog dialog(Tr::tr("Update"), Core::ICore::dialogParent());
if (dialog.exec() == QDialog::Accepted)
m_client.update(state.topLevel(), dialog.m_revisionLineEdit->text());
m_client.update(state.topLevel(), dialog.revision());
}
void FossilPluginPrivate::configureRepository()

View File

@@ -421,9 +421,10 @@ public:
QVector<ParameterAction *> m_projectActions;
QVector<QAction *> m_repositoryActions;
ParameterAction *m_applyCurrentFilePatchAction = nullptr;
Gerrit::Internal::GerritPlugin m_gerritPlugin;
GitClient m_gitClient;
Gerrit::Internal::GerritPlugin m_gerritPlugin;
QPointer<StashDialog> m_stashDialog;
BranchViewFactory m_branchViewFactory;
QPointer<RemoteDialog> m_remoteDialog;

View File

@@ -61,7 +61,8 @@ public:
};
CommandBuilderAspect::CommandBuilderAspect(BuildStep *step)
: d(new CommandBuilderAspectPrivate(step))
: BaseAspect(step)
, d(new CommandBuilderAspectPrivate(step))
{
}

View File

@@ -287,8 +287,13 @@ public:
void setProposal(IAssistProposal *proposal, const QString &prefix)
{
if (!proposal)
if (!proposal) {
// Close the proposal if we have no running processor otherwise ignore the empty
// proposal and wait for the processor to finish
if (!m_processor || !m_processor->running())
closeProposal();
return;
}
if (proposal->id() != TextEditor::Constants::GENERIC_PROPOSAL_ID) {
// We received something else than a generic proposal so we cannot update the model
closeProposal();
@@ -305,13 +310,14 @@ public:
GenericProposalWidget::updateProposal(std::move(interface));
return;
}
auto processor = m_provider->createProcessor(interface.get());
QTC_ASSERT(processor, return);
m_processor = m_provider->createProcessor(interface.get());
QTC_ASSERT(m_processor, return);
const QString prefix = interface->textAt(m_basePosition,
interface->position() - m_basePosition);
processor->setAsyncCompletionAvailableHandler([this, processor, prefix](IAssistProposal *proposal) {
m_processor->setAsyncCompletionAvailableHandler([this, processor = m_processor, prefix](
IAssistProposal *proposal) {
QTC_ASSERT(processor == m_processor, return);
if (!processor->running()) {
// do not delete this processor directly since this function is called from within the processor
@@ -324,11 +330,11 @@ public:
setProposal(proposal, prefix);
});
setProposal(processor->start(std::move(interface)), prefix);
if (processor->running())
m_processor = processor;
else
delete processor;
setProposal(m_processor->start(std::move(interface)), prefix);
if (!m_processor->running()) {
delete m_processor;
m_processor = nullptr;
}
}
private:

View File

@@ -10,6 +10,7 @@
#include <coreplugin/icore.h>
#include <debugger/debuggeritem.h>
#include <debugger/debuggeritemmanager.h>
#include <projectexplorer/devicesupport/devicemanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/toolchainmanager.h>
@@ -447,7 +448,8 @@ static ToolChain *iarToolChain(const FilePath &path, Id language)
== BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID;
});
if (iarFactory) {
Toolchains detected = iarFactory->autoDetect(ToolchainDetector({}, {}, {}));
Toolchains detected = iarFactory->autoDetect(
{{}, DeviceManager::defaultDesktopDevice(), {}});
if (detected.isEmpty())
detected = iarFactory->detectForImport({path, language});
for (auto tc : detected) {

View File

@@ -107,10 +107,10 @@ static FilePath filePathValue(const FilePath &value, const QStringList &candidat
{
if (!value.isEmpty())
return value;
const FilePaths additionalSearchPaths = sshSettings->searchPathRetriever();
Environment env = Environment::systemEnvironment();
env.prependToPath(sshSettings->searchPathRetriever());
for (const QString &candidate : candidateFileNames) {
const FilePath filePath = Environment::systemEnvironment()
.searchInPath(candidate, additionalSearchPaths);
const FilePath filePath = env.searchInPath(candidate);
if (!filePath.isEmpty())
return filePath;
}

View File

@@ -1377,6 +1377,17 @@ void BuildDeviceKitAspect::devicesChanged()
// --------------------------------------------------------------------------
// EnvironmentKitAspect:
// --------------------------------------------------------------------------
static EnvironmentItem forceMSVCEnglishItem()
{
static EnvironmentItem item("VSLANG", "1033");
return item;
}
static bool enforcesMSVCEnglish(const EnvironmentItems &changes)
{
return changes.contains(forceMSVCEnglishItem());
}
namespace Internal {
class EnvironmentKitAspectWidget final : public KitAspectWidget
{
@@ -1411,7 +1422,7 @@ private:
void refresh() override
{
const EnvironmentItems changes = currentEnvironment();
const EnvironmentItems changes = envWithoutMSVCEnglishEnforcement();
const QString shortSummary = EnvironmentItem::toStringList(changes).join("; ");
m_summaryLabel->setText(shortSummary.isEmpty() ? Tr::tr("No changes to apply.") : shortSummary);
}
@@ -1423,32 +1434,29 @@ private:
VariableChooser::addSupportForChildWidgets(w, expander);
};
auto changes = EnvironmentDialog::getEnvironmentItems(m_summaryLabel,
currentEnvironment(),
envWithoutMSVCEnglishEnforcement(),
QString(),
polisher);
if (!changes)
return;
if (HostOsInfo::isWindowsHost()) {
const EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
if (m_vslangCheckbox->isChecked() && changes->indexOf(forceMSVCEnglishItem) < 0)
changes->append(forceMSVCEnglishItem);
// re-add what envWithoutMSVCEnglishEnforcement removed
// or update vslang checkbox if user added it manually
if (m_vslangCheckbox->isChecked() && !enforcesMSVCEnglish(*changes))
changes->append(forceMSVCEnglishItem());
else if (enforcesMSVCEnglish(*changes))
m_vslangCheckbox->setChecked(true);
}
EnvironmentKitAspect::setEnvironmentChanges(m_kit, *changes);
}
EnvironmentItems currentEnvironment() const
EnvironmentItems envWithoutMSVCEnglishEnforcement() const
{
EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(m_kit);
if (HostOsInfo::isWindowsHost()) {
const EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
if (changes.indexOf(forceMSVCEnglishItem) >= 0) {
m_vslangCheckbox->setCheckState(Qt::Checked);
changes.removeAll(forceMSVCEnglishItem);
}
}
if (HostOsInfo::isWindowsHost())
changes.removeAll(forceMSVCEnglishItem());
return sorted(std::move(changes), [](const EnvironmentItem &lhs, const EnvironmentItem &rhs)
{ return QString::localeAwareCompare(lhs.name, rhs.name) < 0; });
@@ -1461,13 +1469,14 @@ private:
m_vslangCheckbox->setToolTip(Tr::tr("Either switches MSVC to English or keeps the language and "
"just forces UTF-8 output (may vary depending on the used MSVC "
"compiler)."));
connect(m_vslangCheckbox, &QCheckBox::toggled, this, [this](bool checked) {
if (enforcesMSVCEnglish(EnvironmentKitAspect::environmentChanges(m_kit)))
m_vslangCheckbox->setChecked(true);
connect(m_vslangCheckbox, &QCheckBox::clicked, this, [this](bool checked) {
EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(m_kit);
const EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
if (!checked && changes.indexOf(forceMSVCEnglishItem) >= 0)
changes.removeAll(forceMSVCEnglishItem);
if (checked && changes.indexOf(forceMSVCEnglishItem) < 0)
changes.append(forceMSVCEnglishItem);
if (!checked && changes.indexOf(forceMSVCEnglishItem()) >= 0)
changes.removeAll(forceMSVCEnglishItem());
if (checked && changes.indexOf(forceMSVCEnglishItem()) < 0)
changes.append(forceMSVCEnglishItem());
EnvironmentKitAspect::setEnvironmentChanges(m_kit, changes);
});
}

View File

@@ -117,8 +117,12 @@ public:
bool filterIncludesErrors() const { return m_includeErrors; }
void setFilterIncludesErrors(bool b) { m_includeErrors = b; invalidateFilter(); }
QList<Utils::Id> filteredCategories() const { return m_categoryIds; }
void setFilteredCategories(const QList<Utils::Id> &categoryIds) { m_categoryIds = categoryIds; invalidateFilter(); }
QSet<Utils::Id> filteredCategories() const { return m_categoryIds; }
void setFilteredCategories(const QSet<Utils::Id> &categoryIds)
{
m_categoryIds = categoryIds;
invalidateFilter();
}
Task task(const QModelIndex &index) const { return taskModel()->task(mapToSource(index)); }
Tasks tasks(const QModelIndexList &indexes) const;
@@ -144,7 +148,7 @@ private:
bool m_filterStringIsRegexp = false;
bool m_filterIsInverted = false;
Qt::CaseSensitivity m_filterCaseSensitivity = Qt::CaseInsensitive;
QList<Utils::Id> m_categoryIds;
QSet<Utils::Id> m_categoryIds;
QString m_filterText;
QRegularExpression m_filterRegexp;
};

View File

@@ -327,19 +327,20 @@ void TaskWindow::setCategoryVisibility(Id categoryId, bool visible)
if (!categoryId.isValid())
return;
QList<Id> categories = d->m_filter->filteredCategories();
QSet<Id> categories = d->m_filter->filteredCategories();
if (visible)
categories.removeOne(categoryId);
categories.remove(categoryId);
else
categories.append(categoryId);
categories.insert(categoryId);
d->m_filter->setFilteredCategories(categories);
}
void TaskWindow::saveSettings()
{
QStringList categories = Utils::transform(d->m_filter->filteredCategories(), &Id::toString);
const QStringList categories = Utils::toList(
Utils::transform(d->m_filter->filteredCategories(), &Id::toString));
SessionManager::setValue(QLatin1String(SESSION_FILTER_CATEGORIES), categories);
SessionManager::setValue(QLatin1String(SESSION_FILTER_WARNINGS), d->m_filter->filterIncludesWarnings());
}
@@ -348,7 +349,8 @@ void TaskWindow::loadSettings()
{
QVariant value = SessionManager::value(QLatin1String(SESSION_FILTER_CATEGORIES));
if (value.isValid()) {
QList<Id> categories = Utils::transform(value.toStringList(), &Id::fromString);
const QSet<Id> categories = Utils::toSet(
Utils::transform(value.toStringList(), &Id::fromString));
d->m_filter->setFilteredCategories(categories);
}
value = SessionManager::value(QLatin1String(SESSION_FILTER_WARNINGS));
@@ -369,8 +371,8 @@ void TaskWindow::addCategory(Id categoryId, const QString &displayName, bool vis
{
d->m_model->addCategory(categoryId, displayName, priority);
if (!visible) {
QList<Id> filters = d->m_filter->filteredCategories();
filters += categoryId;
QSet<Id> filters = d->m_filter->filteredCategories();
filters.insert(categoryId);
d->m_filter->setFilteredCategories(filters);
}
}
@@ -469,7 +471,7 @@ void TaskWindow::updateCategoriesMenu()
d->m_categoriesMenu->clear();
const QList<Id> filteredCategories = d->m_filter->filteredCategories();
const QSet<Id> filteredCategories = d->m_filter->filteredCategories();
QMap<QString, Id> nameToIds;
const QList<Id> ids = d->m_model->categoryIds();

View File

@@ -3,10 +3,11 @@
#include "toolchainoptionspage.h"
#include "toolchain.h"
#include "abi.h"
#include "devicesupport/devicemanager.h"
#include "projectexplorerconstants.h"
#include "projectexplorertr.h"
#include "toolchain.h"
#include "toolchainconfigwidget.h"
#include "toolchainmanager.h"
@@ -404,7 +405,7 @@ void ToolChainOptionsWidget::redetectToolchains()
QSet<ToolChain *> toDelete;
ToolChainManager::resetBadToolchains();
for (ToolChainFactory *f : ToolChainFactory::allToolChainFactories()) {
const ToolchainDetector detector(knownTcs, {}, {}); // FIXME: Pass device and search paths
const ToolchainDetector detector(knownTcs, DeviceManager::defaultDesktopDevice(), {}); // FIXME: Pass search paths
for (ToolChain * const tc : f->autoDetect(detector)) {
if (knownTcs.contains(tc) || toDelete.contains(tc))
continue;

View File

@@ -512,7 +512,9 @@ QWidget *QMakeStep::createConfigWidget()
connect(abisListWidget, &QListWidget::itemChanged, this, [this] {
if (m_ignoreChanges.isLocked())
return;
handleAbiWidgetChange();
updateAbiWidgets();
if (QmakeBuildConfiguration *bc = qmakeBuildConfiguration())
BuildManager::buildLists({bc->cleanSteps()});
});
connect(widget, &QObject::destroyed, this, [this] {
@@ -704,7 +706,7 @@ void QMakeStep::updateAbiWidgets()
item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
item->setCheckState(selectedAbis.contains(param) ? Qt::Checked : Qt::Unchecked);
}
handleAbiWidgetChange();
abisChanged();
}
}
@@ -713,13 +715,6 @@ void QMakeStep::updateEffectiveQMakeCall()
m_effectiveCall->setValue(effectiveQMakeCall());
}
void QMakeStep::handleAbiWidgetChange()
{
abisChanged();
if (QmakeBuildConfiguration *bc = qmakeBuildConfiguration())
BuildManager::buildLists({bc->cleanSteps()});
}
void QMakeStep::recompileMessageBoxFinished(int button)
{
if (button == QMessageBox::Yes) {

View File

@@ -155,7 +155,6 @@ private:
void updateAbiWidgets();
void updateEffectiveQMakeCall();
void handleAbiWidgetChange();
Utils::CommandLine m_qmakeCommand;
Utils::CommandLine m_makeCommand;

View File

@@ -1675,8 +1675,8 @@ void DesignerActionManager::createDefaultDesignerActions()
setFlowStartDisplayName,
{},
flowCategory,
2,
{},
2,
&setFlowStartItem,
&isFlowItem,
&flowOptionVisible));

View File

@@ -29,8 +29,11 @@ FileTransferMethod defaultTransferMethod(Kit *kit)
return FileTransferMethod::Rsync;
}
if (runDevice && runDevice->extraData(Constants::SupportsSftp).toBool())
return FileTransferMethod::Sftp;
if (runDevice) {
const QVariant sftpInfo = runDevice->extraData(Constants::SupportsSftp);
if (!sftpInfo.isValid() || sftpInfo.toBool())
return FileTransferMethod::Sftp;
}
return FileTransferMethod::GenericCopy;
}

View File

@@ -18,7 +18,7 @@ EventItem::EventItem(const QPointF &pos, BaseItem *parent)
{
m_eventNameItem = new TextItem(this);
m_eventNameItem->setParentItem(this);
QFont serifFont("Times", 13, QFont::Normal);
QFont serifFont("Times", 10, QFont::Normal);
m_eventNameItem->setFont(serifFont);
QString color = editorInfo("fontColor");
@@ -49,7 +49,7 @@ OnEntryExitItem::OnEntryExitItem(BaseItem *parent)
{
m_eventNameItem = new TextItem(this);
m_eventNameItem->setParentItem(this);
QFont serifFont("Times", 13, QFont::Normal);
QFont serifFont("Times", 10, QFont::Normal);
m_eventNameItem->setFont(serifFont);
m_eventNameItem->setDefaultTextColor(Qt::black);
m_eventNameItem->setTextInteractionFlags(Qt::NoTextInteraction);

View File

@@ -232,6 +232,9 @@ void StateItem::transitionsChanged()
}
m_transitionRect = rectInternalTransitions;
positionOnEntryItems();
positionOnExitItems();
updateBoundingRect();
}
@@ -437,8 +440,7 @@ void StateItem::updatePolygon()
f.setPixelSize(m_titleRect.height() * 0.65);
m_stateNameItem->setFont(f);
if (m_onEntryItem)
m_onEntryItem->setPos(m_titleRect.x(), m_titleRect.bottom());
positionOnEntryItems();
positionOnExitItems();
updateTextPositions();
@@ -552,7 +554,7 @@ void StateItem::addChild(ScxmlTag *child)
item->setTag(child);
item->finalizeCreation();
item->updateAttributes();
m_onEntryItem->setPos(m_titleRect.x(), m_titleRect.bottom());
positionOnEntryItems();
} else if (child->tagName() == "onexit") {
OnEntryExitItem *item = new OnEntryExitItem(this);
m_onExitItem = item;
@@ -566,8 +568,18 @@ void StateItem::addChild(ScxmlTag *child)
void StateItem::positionOnExitItems()
{
int offset = m_onEntryItem ? m_onEntryItem->boundingRect().height() : 0;
if (m_onExitItem)
m_onExitItem->setPos(m_titleRect.x(), m_titleRect.bottom() + offset);
if (m_onExitItem) {
auto x = m_transitionRect.isValid() ? m_transitionRect.right() : m_titleRect.x();
m_onExitItem->setPos(x, m_titleRect.bottom() + offset);
}
}
void StateItem::positionOnEntryItems()
{
if (m_onEntryItem) {
auto x = m_transitionRect.isValid() ? m_transitionRect.right() : m_titleRect.x();
m_onEntryItem->setPos(x, m_titleRect.bottom());
}
}
QString StateItem::itemId() const

View File

@@ -75,6 +75,7 @@ private:
void checkParentBoundingRect();
void checkWarningItems();
void positionOnExitItems();
void positionOnEntryItems();
TextItem *m_stateNameItem;
StateWarningItem *m_stateWarningItem = nullptr;

View File

@@ -11,6 +11,7 @@
#include <vterm.h>
#include <QLoggingCategory>
#include <QTimer>
namespace Terminal::Internal {
@@ -21,6 +22,8 @@ QColor toQColor(const VTermColor &c)
return QColor(qRgb(c.rgb.red, c.rgb.green, c.rgb.blue));
};
constexpr int batchFlushSize = 256;
struct TerminalSurfacePrivate
{
TerminalSurfacePrivate(TerminalSurface *surface,
@@ -33,13 +36,64 @@ struct TerminalSurfacePrivate
, q(surface)
{}
void flush()
{
if (m_writeBuffer.isEmpty())
return;
QByteArray data = m_writeBuffer.left(batchFlushSize);
qint64 result = m_writeToPty(data);
if (result != data.size()) {
// Not all data was written, remove the unwritten data from the array
data.resize(qMax(0, result));
}
// Remove the written data from the buffer
if (data.size() > 0)
m_writeBuffer = m_writeBuffer.mid(data.size());
if (!m_writeBuffer.isEmpty())
m_delayWriteTimer.start();
}
void init()
{
m_delayWriteTimer.setInterval(1);
m_delayWriteTimer.setSingleShot(true);
QObject::connect(&m_delayWriteTimer, &QTimer::timeout, &m_delayWriteTimer, [this] {
flush();
});
vterm_set_utf8(m_vterm.get(), true);
static auto writeToPty = [](const char *s, size_t len, void *user) {
auto p = static_cast<TerminalSurfacePrivate *>(user);
emit p->q->writeToPty(QByteArray(s, static_cast<int>(len)));
QByteArray d(s, len);
// If its just a couple of chars, or we already have data in the writeBuffer,
// add the new data to the write buffer and start the delay timer
if (d.size() < batchFlushSize || !p->m_writeBuffer.isEmpty()) {
p->m_writeBuffer.append(d);
p->m_delayWriteTimer.start();
return;
}
// Try to write the data ...
qint64 result = p->m_writeToPty(d);
if (result != d.size()) {
// if writing failed, append the data to the writeBuffer and start the delay timer
// Check if partial data may have already been written ...
if (result <= 0)
p->m_writeBuffer.append(d);
else
p->m_writeBuffer.append(d.mid(result));
p->m_delayWriteTimer.start();
}
};
vterm_output_set_callback(m_vterm.get(), writeToPty, this);
@@ -313,6 +367,10 @@ struct TerminalSurfacePrivate
ShellIntegration *m_shellIntegration{nullptr};
TerminalSurface *q;
QTimer m_delayWriteTimer;
QByteArray m_writeBuffer;
TerminalSurface::WriteToPty m_writeToPty;
};
TerminalSurface::TerminalSurface(QSize initialGridSize, ShellIntegration *shellIntegration)
@@ -385,7 +443,7 @@ void TerminalSurface::clearAll()
vterm_input_write(d->m_vterm.get(), data.constData(), data.size());
// Send Ctrl+L which will clear the screen
emit writeToPty(QByteArray("\f"));
d->m_writeToPty(QByteArray("\f"));
}
void TerminalSurface::resize(QSize newSize)
@@ -419,8 +477,14 @@ void TerminalSurface::pasteFromClipboard(const QString &clipboardText)
return;
vterm_keyboard_start_paste(d->m_vterm.get());
for (unsigned int ch : clipboardText.toUcs4())
for (unsigned int ch : clipboardText.toUcs4()) {
// Workaround for weird nano behavior to correctly paste newlines
// see: http://savannah.gnu.org/bugs/?49176
// and: https://github.com/kovidgoyal/kitty/issues/994
if (ch == '\n')
ch = '\r';
vterm_keyboard_unichar(d->m_vterm.get(), ch, VTERM_MOD_NONE);
}
vterm_keyboard_end_paste(d->m_vterm.get());
if (!d->m_altscreen) {
@@ -487,6 +551,11 @@ ShellIntegration *TerminalSurface::shellIntegration() const
return d->m_shellIntegration;
}
void TerminalSurface::setWriteToPty(WriteToPty writeToPty)
{
d->m_writeToPty = writeToPty;
}
CellIterator TerminalSurface::begin() const
{
auto res = CellIterator(this, {0, 0});

View File

@@ -95,8 +95,9 @@ public:
ShellIntegration *shellIntegration() const;
using WriteToPty = std::function<qint64(const QByteArray &)>;
void setWriteToPty(WriteToPty writeToPty);
signals:
void writeToPty(const QByteArray &data);
void invalidated(QRect grid);
void fullSizeChanged(QSize newSize);
void cursorChanged(Cursor oldCursor, Cursor newCursor);

View File

@@ -327,10 +327,12 @@ void TerminalWidget::closeTerminal()
deleteLater();
}
void TerminalWidget::writeToPty(const QByteArray &data)
qint64 TerminalWidget::writeToPty(const QByteArray &data)
{
if (m_process && m_process->isRunning())
m_process->writeRaw(data);
return m_process->writeRaw(data);
return data.size();
}
void TerminalWidget::setupSurface()
@@ -351,10 +353,8 @@ void TerminalWidget::setupSurface()
}
});
connect(m_surface.get(),
&Internal::TerminalSurface::writeToPty,
this,
&TerminalWidget::writeToPty);
m_surface->setWriteToPty([this](const QByteArray &data) { return writeToPty(data); });
connect(m_surface.get(), &Internal::TerminalSurface::fullSizeChanged, this, [this] {
updateScrollBars();
});

View File

@@ -129,7 +129,7 @@ protected:
void setupColors();
void setupActions();
void writeToPty(const QByteArray &data);
qint64 writeToPty(const QByteArray &data);
int paintCell(QPainter &p,
const QRectF &cellRect,

View File

@@ -837,7 +837,7 @@ bool TextDocument::reload(QString *errorString, const FilePath &realFilePath)
auto documentLayout =
qobject_cast<TextDocumentLayout*>(d->m_document.documentLayout());
if (documentLayout)
documentLayout->documentAboutToReload(); // removes text marks non-permanently
documentLayout->documentAboutToReload(this); // removes text marks non-permanently
bool success = openImpl(errorString, filePath(), realFilePath, /*reload =*/true)
== OpenResult::Success;

View File

@@ -4,9 +4,16 @@
#include "textdocumentlayout.h"
#include "fontsettings.h"
#include "textdocument.h"
#include "texteditorplugin.h"
#include "texteditorsettings.h"
#include <utils/qtcassert.h>
#include <utils/temporarydirectory.h>
#include <QDebug>
#ifdef WITH_TESTS
#include <QTest>
#endif
namespace TextEditor {
@@ -667,11 +674,15 @@ TextMarks TextDocumentLayout::documentClosing()
return marks;
}
void TextDocumentLayout::documentAboutToReload()
void TextDocumentLayout::documentAboutToReload(TextDocument *baseTextDocument)
{
m_reloadMarks = documentClosing();
for (TextMark *mark : std::as_const(m_reloadMarks))
mark->setDeleteCallback([this, mark] { m_reloadMarks.removeOne(mark); });
for (TextMark *mark : std::as_const(m_reloadMarks)) {
mark->setDeleteCallback([this, mark, baseTextDocument] {
baseTextDocument->removeMarkFromMarksCache(mark);
m_reloadMarks.removeOne(mark);
});
}
}
void TextDocumentLayout::documentReloaded(TextDocument *baseTextDocument)
@@ -860,4 +871,23 @@ TextSuggestion::TextSuggestion()
TextSuggestion::~TextSuggestion() = default;
#ifdef WITH_TESTS
void Internal::TextEditorPlugin::testDeletingMarkOnReload()
{
auto doc = new TextDocument();
doc->setFilePath(Utils::TemporaryDirectory::masterDirectoryFilePath() / "TestMarkDoc.txt");
doc->setPlainText("asd");
auto documentLayout = qobject_cast<TextDocumentLayout *>(doc->document()->documentLayout());
QVERIFY(documentLayout);
auto mark = new TextMark(doc, 1, TextMarkCategory{"testMark","testMark"});
QVERIFY(doc->marks().contains(mark));
documentLayout->documentAboutToReload(doc); // removes text marks non-permanently
delete mark;
documentLayout->documentReloaded(doc); // re-adds text marks
QVERIFY(!doc->marks().contains(mark));
}
#endif
} // namespace TextEditor

View File

@@ -246,7 +246,7 @@ public:
QRectF blockBoundingRect(const QTextBlock &block) const override;
TextMarks documentClosing();
void documentAboutToReload();
void documentAboutToReload(TextDocument *baseTextDocument);
void documentReloaded(TextDocument *baseextDocument);
void updateMarksLineNumber();
void updateMarksBlock(const QTextBlock &block);

View File

@@ -40,6 +40,8 @@ private slots:
void testFormatting_data();
void testFormatting();
void testDeletingMarkOnReload();
#endif
};

View File

@@ -24,6 +24,7 @@
#ifdef Q_OS_LINUX
#include <sys/ptrace.h>
#include <sys/wait.h>
#endif
#include <iostream>
@@ -221,7 +222,23 @@ void onInferiorStarted()
if (!debugMode)
sendPid(inferiorId);
#else
qCInfo(log) << "Detaching ...";
ptrace(PTRACE_DETACH, inferiorId, 0, SIGSTOP);
// Wait until the process actually finished detaching
int status = 0;
waitpid(inferiorId, &status, WUNTRACED);
if (log().isInfoEnabled()) {
if (WIFEXITED(status))
qCInfo(log) << "inferior exited, status=" << WEXITSTATUS(status);
else if (WIFSIGNALED(status))
qCInfo(log) << "inferior killed by signal" << WTERMSIG(status);
else if (WIFSTOPPED(status))
qCInfo(log) << "inferior stopped by signal" << WSTOPSIG(status);
else if (WIFCONTINUED(status))
qCInfo(log) << "inferior continued";
}
sendPid(inferiorId);
#endif
}

View File

@@ -252,6 +252,15 @@ void AddQtOperation::unittest()
QCOMPARE(version1.value(QLatin1String(QMAKE)).toString(), QLatin1String("/tmp/test/qmake2"));
QVERIFY(version1.contains(QLatin1String("extraData")));
QCOMPARE(version1.value(QLatin1String("extraData")).toString(), QLatin1String("extraValue"));
// Docker paths
qtData.m_id = "testId3";
qtData.m_qmake = "docker://image///path/to//some/qmake";
map = qtData.addQt(map);
QVariantMap version2 = map.value(QLatin1String("QtVersion.2")).toMap();
QVERIFY(version2.contains(QLatin1String(QMAKE)));
QCOMPARE(version2.value(QLatin1String(QMAKE)).toString(), QLatin1String("docker://image/path/to/some/qmake"));
}
#endif
@@ -279,7 +288,7 @@ QVariantMap AddQtData::addQt(const QVariantMap &map) const
const QString qt = QString::fromLatin1(PREFIX) + QString::number(versionCount);
// Sanitize qmake path:
QString saneQmake = QDir::cleanPath(m_qmake);
const QString saneQmake = cleanPath(m_qmake);
// insert data:
KeyValuePairList data;

View File

@@ -84,7 +84,7 @@ bool Operation::save(const QVariantMap &map, const QString &file) const
return false;
}
QString dirName = QDir::cleanPath(path + "/..");
QString dirName = cleanPath(path + "/..");
QDir dir(dirName);
if (!dir.exists() && !dir.mkpath(QLatin1String("."))) {
std::cerr << "Error: Could not create directory " << qPrintable(dirName)
@@ -108,3 +108,12 @@ bool Operation::save(const QVariantMap &map, const QString &file) const
}
return true;
}
QString cleanPath(const QString &orig)
{
// QDir::cleanPath() destroys "//", one of which might be needed.
const int pos = orig.indexOf("://");
if (pos == -1)
return QDir::cleanPath(orig);
return orig.left(pos) + "://" + QDir::cleanPath(orig.mid(pos + 3));
}

View File

@@ -22,6 +22,8 @@ using KeyValuePairList = QList<KeyValuePair>;
QVariant valueFromString(const QString &v);
QString cleanPath(const QString &orig);
class Operation
{
public:

View File

@@ -3,6 +3,8 @@
#include "sdkpersistentsettings.h"
#include "operation.h" // for cleanPath()
#include <QCoreApplication>
#include <QDataStream>
#include <QDateTime>
@@ -826,7 +828,7 @@ void SdkPersistentSettingsWriter::setContents(const QVariantMap &data)
bool SdkPersistentSettingsWriter::write(const QVariantMap &data, QString *errorString) const
{
const QString parentDir = QDir::cleanPath(m_fileName + "/..");
const QString parentDir = cleanPath(m_fileName + "/..");
const QFileInfo fi(parentDir);
if (!(fi.exists() && fi.isDir() && fi.isWritable())) {