forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/6.0'
Change-Id: Ic6f91a71dd7d540eb9b6c27ba5ef9931583566b5
This commit is contained in:
6
.github/workflows/build_cmake.yml
vendored
6
.github/workflows/build_cmake.yml
vendored
@@ -4,7 +4,7 @@ on: [push, pull_request]
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
QT_VERSION: 5.15.2
|
QT_VERSION: 5.15.2
|
||||||
CLANG_VERSION: 120
|
CLANG_VERSION: 130
|
||||||
ELFUTILS_VERSION: 0.175
|
ELFUTILS_VERSION: 0.175
|
||||||
CMAKE_VERSION: 3.21.1
|
CMAKE_VERSION: 3.21.1
|
||||||
NINJA_VERSION: 1.10.2
|
NINJA_VERSION: 1.10.2
|
||||||
@@ -286,9 +286,9 @@ jobs:
|
|||||||
set(libclang "libclang-release_${clang_version}-based-windows-vs2019_32.7z")
|
set(libclang "libclang-release_${clang_version}-based-windows-vs2019_32.7z")
|
||||||
endif()
|
endif()
|
||||||
elseif ("${{ runner.os }}" STREQUAL "Linux")
|
elseif ("${{ runner.os }}" STREQUAL "Linux")
|
||||||
set(libclang "libclang-release_${clang_version}-based-linux-Ubuntu18.04-gcc9.3-x86_64.7z")
|
set(libclang "libclang-release_${clang_version}-based-linux-Ubuntu20.04-gcc9.3-x86_64.7z")
|
||||||
elseif ("${{ runner.os }}" STREQUAL "macOS")
|
elseif ("${{ runner.os }}" STREQUAL "macOS")
|
||||||
set(libclang "libclang-release_${clang_version}-based-mac.7z")
|
set(libclang "libclang-release_${clang_version}-based-macos-universal.7z")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(libclang_url "https://\${qt_mirror}/development_releases/prebuilt/libclang/${libclang}")
|
set(libclang_url "https://\${qt_mirror}/development_releases/prebuilt/libclang/${libclang}")
|
||||||
|
@@ -57,7 +57,8 @@ else()
|
|||||||
find_package(Qt6 CONFIG ${__arguments} ${Qt5_FIND_COMPONENTS})
|
find_package(Qt6 CONFIG ${__arguments} ${Qt5_FIND_COMPONENTS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
foreach(comp IN LISTS Qt5_FIND_COMPONENTS)
|
set(__additional_imported_components ATSPI2_nolink) # Work around QTBUG-97023
|
||||||
|
foreach(comp IN LISTS Qt5_FIND_COMPONENTS __additional_imported_components)
|
||||||
if(TARGET Qt6::${comp})
|
if(TARGET Qt6::${comp})
|
||||||
if (NOT TARGET Qt5::${comp})
|
if (NOT TARGET Qt5::${comp})
|
||||||
set_property(TARGET Qt6::${comp} PROPERTY IMPORTED_GLOBAL TRUE)
|
set_property(TARGET Qt6::${comp} PROPERTY IMPORTED_GLOBAL TRUE)
|
||||||
|
@@ -7,7 +7,7 @@ instructions:
|
|||||||
variableValue: "RelWithDebInfo"
|
variableValue: "RelWithDebInfo"
|
||||||
- type: EnvironmentVariable
|
- type: EnvironmentVariable
|
||||||
variableName: QTC_QT_BASE_URL
|
variableName: QTC_QT_BASE_URL
|
||||||
variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.2/6.2.0-rc-released/"
|
variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.2/6.2.0-final-released/"
|
||||||
- type: EnvironmentVariable
|
- type: EnvironmentVariable
|
||||||
variableName: QTC_QT_MODULES
|
variableName: QTC_QT_MODULES
|
||||||
variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquickcontrols2 qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations"
|
variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquickcontrols2 qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations"
|
||||||
|
@@ -1075,6 +1075,20 @@ SecondColumnLayout {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: ceMode
|
||||||
|
function onActivated() {
|
||||||
|
spinBox.readValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: modelNodeBackend
|
||||||
|
function onSelectionChanged() {
|
||||||
|
spinBox.readValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GradientPropertySpinBox {
|
GradientPropertySpinBox {
|
||||||
id: spinBox
|
id: spinBox
|
||||||
implicitWidth: StudioTheme.Values.controlGap
|
implicitWidth: StudioTheme.Values.controlGap
|
||||||
|
@@ -45,6 +45,10 @@ Item {
|
|||||||
|
|
||||||
onFocusChanged: restoreCursor()
|
onFocusChanged: restoreCursor()
|
||||||
|
|
||||||
|
function readValue() {
|
||||||
|
spinBox.realValue = gradientLine.model.readGradientProperty(wrapper.propertyName)
|
||||||
|
}
|
||||||
|
|
||||||
StudioControls.RealSpinBox {
|
StudioControls.RealSpinBox {
|
||||||
id: spinBox
|
id: spinBox
|
||||||
|
|
||||||
@@ -56,9 +60,7 @@ Item {
|
|||||||
realStepSize: 1
|
realStepSize: 1
|
||||||
decimals: 0
|
decimals: 0
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: wrapper.readValue()
|
||||||
spinBox.realValue = gradientLine.model.readGradientProperty(wrapper.propertyName)
|
|
||||||
}
|
|
||||||
onCompressedRealValueModified: {
|
onCompressedRealValueModified: {
|
||||||
gradientLine.model.setGradientProperty(wrapper.propertyName, spinBox.realValue)
|
gradientLine.model.setGradientProperty(wrapper.propertyName, spinBox.realValue)
|
||||||
}
|
}
|
||||||
|
@@ -494,6 +494,11 @@ int main(int argc, char **argv)
|
|||||||
QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
|
QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Utils::HostOsInfo::isRunningUnderRosetta()) {
|
||||||
|
// work around QTBUG-97085: QRegularExpression jitting is not reentrant under Rosetta
|
||||||
|
qputenv("QT_ENABLE_REGEXP_JIT", "0");
|
||||||
|
}
|
||||||
|
|
||||||
Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX");
|
Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX");
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
|
@@ -1747,7 +1747,7 @@ bool Check::visit(CallExpression *ast)
|
|||||||
static const QStringList colorFunctions = {"lighter", "darker", "rgba", "tint", "hsla", "hsva"};
|
static const QStringList colorFunctions = {"lighter", "darker", "rgba", "tint", "hsla", "hsva"};
|
||||||
|
|
||||||
static const QStringList qtFunction = {"point", "rect", "size", "vector2d", "vector3d", "vector4d", "quaternion" "matrix4x4", "formatDate",
|
static const QStringList qtFunction = {"point", "rect", "size", "vector2d", "vector3d", "vector4d", "quaternion" "matrix4x4", "formatDate",
|
||||||
"formatDateTime", "formatTime"};
|
"formatDateTime", "formatTime", "resolvedUrl"};
|
||||||
|
|
||||||
const bool whiteListedFunction = translationFunctions.contains(name) || whiteListedFunctions.contains(name) || colorFunctions.contains(name) || qtFunction.contains(name);
|
const bool whiteListedFunction = translationFunctions.contains(name) || whiteListedFunctions.contains(name) || colorFunctions.contains(name) || qtFunction.contains(name);
|
||||||
|
|
||||||
|
@@ -136,7 +136,9 @@ void Environment::setupEnglishOutput()
|
|||||||
set("LANGUAGE", "en_US:en");
|
set("LANGUAGE", "en_US:en");
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath Environment::searchInDirectory(const QStringList &execs, const FilePath &directory,
|
static FilePath searchInDirectory(const Environment &env,
|
||||||
|
const QStringList &execs,
|
||||||
|
const FilePath &directory,
|
||||||
QSet<FilePath> &alreadyChecked)
|
QSet<FilePath> &alreadyChecked)
|
||||||
{
|
{
|
||||||
const int checkedCount = alreadyChecked.count();
|
const int checkedCount = alreadyChecked.count();
|
||||||
@@ -199,17 +201,19 @@ QString Environment::expandedValueForKey(const QString &key) const
|
|||||||
return expandVariables(value(key));
|
return expandVariables(value(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath Environment::searchInPath(const QString &executable,
|
static FilePath searchInDirectoriesHelper(const Environment &env,
|
||||||
const FilePaths &additionalDirs,
|
const QString &executable,
|
||||||
const PathFilter &func) const
|
const FilePaths &dirs,
|
||||||
|
const Environment::PathFilter &func,
|
||||||
|
bool usePath)
|
||||||
{
|
{
|
||||||
if (executable.isEmpty())
|
if (executable.isEmpty())
|
||||||
return FilePath();
|
return FilePath();
|
||||||
|
|
||||||
const QString exec = QDir::cleanPath(expandVariables(executable));
|
const QString exec = QDir::cleanPath(env.expandVariables(executable));
|
||||||
const QFileInfo fi(exec);
|
const QFileInfo fi(exec);
|
||||||
|
|
||||||
const QStringList execs = appendExeExtensions(exec);
|
const QStringList execs = env.appendExeExtensions(exec);
|
||||||
|
|
||||||
if (fi.isAbsolute()) {
|
if (fi.isAbsolute()) {
|
||||||
for (const QString &path : execs) {
|
for (const QString &path : execs) {
|
||||||
@@ -221,23 +225,38 @@ FilePath Environment::searchInPath(const QString &executable,
|
|||||||
}
|
}
|
||||||
|
|
||||||
QSet<FilePath> alreadyChecked;
|
QSet<FilePath> alreadyChecked;
|
||||||
for (const FilePath &dir : additionalDirs) {
|
for (const FilePath &dir : dirs) {
|
||||||
FilePath tmp = searchInDirectory(execs, dir, alreadyChecked);
|
FilePath tmp = searchInDirectory(env, execs, dir, alreadyChecked);
|
||||||
if (!tmp.isEmpty() && (!func || func(tmp)))
|
if (!tmp.isEmpty() && (!func || func(tmp)))
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (usePath) {
|
||||||
if (executable.contains('/'))
|
if (executable.contains('/'))
|
||||||
return FilePath();
|
return FilePath();
|
||||||
|
|
||||||
for (const FilePath &p : path()) {
|
for (const FilePath &p : env.path()) {
|
||||||
FilePath tmp = searchInDirectory(execs, p, alreadyChecked);
|
FilePath tmp = searchInDirectory(env, execs, p, alreadyChecked);
|
||||||
if (!tmp.isEmpty() && (!func || func(tmp)))
|
if (!tmp.isEmpty() && (!func || func(tmp)))
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return FilePath();
|
return FilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FilePath Environment::searchInDirectories(const QString &executable,
|
||||||
|
const FilePaths &dirs) const
|
||||||
|
{
|
||||||
|
return searchInDirectoriesHelper(*this, executable, dirs, {}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath Environment::searchInPath(const QString &executable,
|
||||||
|
const FilePaths &additionalDirs,
|
||||||
|
const PathFilter &func) const
|
||||||
|
{
|
||||||
|
return searchInDirectoriesHelper(*this, executable, additionalDirs, func, true);
|
||||||
|
}
|
||||||
|
|
||||||
FilePaths Environment::findAllInPath(const QString &executable,
|
FilePaths Environment::findAllInPath(const QString &executable,
|
||||||
const FilePaths &additionalDirs,
|
const FilePaths &additionalDirs,
|
||||||
const Environment::PathFilter &func) const
|
const Environment::PathFilter &func) const
|
||||||
@@ -262,14 +281,14 @@ FilePaths Environment::findAllInPath(const QString &executable,
|
|||||||
QSet<FilePath> result;
|
QSet<FilePath> result;
|
||||||
QSet<FilePath> alreadyChecked;
|
QSet<FilePath> alreadyChecked;
|
||||||
for (const FilePath &dir : additionalDirs) {
|
for (const FilePath &dir : additionalDirs) {
|
||||||
FilePath tmp = searchInDirectory(execs, dir, alreadyChecked);
|
FilePath tmp = searchInDirectory(*this, execs, dir, alreadyChecked);
|
||||||
if (!tmp.isEmpty() && (!func || func(tmp)))
|
if (!tmp.isEmpty() && (!func || func(tmp)))
|
||||||
result << tmp;
|
result << tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!executable.contains('/')) {
|
if (!executable.contains('/')) {
|
||||||
for (const FilePath &p : path()) {
|
for (const FilePath &p : path()) {
|
||||||
FilePath tmp = searchInDirectory(execs, p, alreadyChecked);
|
FilePath tmp = searchInDirectory(*this, execs, p, alreadyChecked);
|
||||||
if (!tmp.isEmpty() && (!func || func(tmp)))
|
if (!tmp.isEmpty() && (!func || func(tmp)))
|
||||||
result << tmp;
|
result << tmp;
|
||||||
}
|
}
|
||||||
|
@@ -63,6 +63,8 @@ public:
|
|||||||
FilePath searchInPath(const QString &executable,
|
FilePath searchInPath(const QString &executable,
|
||||||
const FilePaths &additionalDirs = FilePaths(),
|
const FilePaths &additionalDirs = FilePaths(),
|
||||||
const PathFilter &func = PathFilter()) const;
|
const PathFilter &func = PathFilter()) const;
|
||||||
|
FilePath searchInDirectories(const QString &executable,
|
||||||
|
const FilePaths &dirs) const;
|
||||||
FilePaths findAllInPath(const QString &executable,
|
FilePaths findAllInPath(const QString &executable,
|
||||||
const FilePaths &additionalDirs = FilePaths(),
|
const FilePaths &additionalDirs = FilePaths(),
|
||||||
const PathFilter &func = PathFilter()) const;
|
const PathFilter &func = PathFilter()) const;
|
||||||
@@ -80,10 +82,6 @@ public:
|
|||||||
|
|
||||||
static void modifySystemEnvironment(const EnvironmentItems &list); // use with care!!!
|
static void modifySystemEnvironment(const EnvironmentItems &list); // use with care!!!
|
||||||
static void setSystemEnvironment(const Environment &environment); // don't use at all!!!
|
static void setSystemEnvironment(const Environment &environment); // don't use at all!!!
|
||||||
|
|
||||||
private:
|
|
||||||
static FilePath searchInDirectory(const QStringList &execs, const FilePath &directory,
|
|
||||||
QSet<FilePath> &alreadyChecked);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT EnvironmentChange final
|
class QTCREATOR_UTILS_EXPORT EnvironmentChange final
|
||||||
|
@@ -1208,7 +1208,7 @@ FilePath FilePath::searchInDirectories(const FilePaths &dirs) const
|
|||||||
QTC_ASSERT(s_deviceHooks.searchInPath, return {});
|
QTC_ASSERT(s_deviceHooks.searchInPath, return {});
|
||||||
return s_deviceHooks.searchInPath(*this, dirs);
|
return s_deviceHooks.searchInPath(*this, dirs);
|
||||||
}
|
}
|
||||||
return Environment::systemEnvironment().searchInPath(path(), dirs);
|
return Environment::systemEnvironment().searchInDirectories(path(), dirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath FilePath::searchInPath(const QList<FilePath> &additionalDirs) const
|
FilePath FilePath::searchInPath(const QList<FilePath> &additionalDirs) const
|
||||||
|
@@ -69,8 +69,8 @@ public:
|
|||||||
|
|
||||||
void updateDeviceFromUi() final {}
|
void updateDeviceFromUi() final {}
|
||||||
static QString dialogTitle();
|
static QString dialogTitle();
|
||||||
static bool criticalDialog(const QString &error);
|
static bool criticalDialog(const QString &error, QWidget *parent = nullptr);
|
||||||
static bool questionDialog(const QString &question);
|
static bool questionDialog(const QString &question, QWidget *parent = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
|
AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
|
||||||
@@ -114,10 +114,10 @@ QString AndroidDeviceWidget::dialogTitle()
|
|||||||
return tr("Android Device Manager");
|
return tr("Android Device Manager");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidDeviceWidget::criticalDialog(const QString &error)
|
bool AndroidDeviceWidget::criticalDialog(const QString &error, QWidget *parent)
|
||||||
{
|
{
|
||||||
qCDebug(androidDeviceLog) << error;
|
qCDebug(androidDeviceLog) << error;
|
||||||
QMessageBox box(Core::ICore::dialogParent());
|
QMessageBox box(parent ? parent : Core::ICore::dialogParent());
|
||||||
box.QDialog::setWindowTitle(dialogTitle());
|
box.QDialog::setWindowTitle(dialogTitle());
|
||||||
box.setText(error);
|
box.setText(error);
|
||||||
box.setIcon(QMessageBox::Critical);
|
box.setIcon(QMessageBox::Critical);
|
||||||
@@ -125,9 +125,9 @@ bool AndroidDeviceWidget::criticalDialog(const QString &error)
|
|||||||
return box.exec();
|
return box.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidDeviceWidget::questionDialog(const QString &question)
|
bool AndroidDeviceWidget::questionDialog(const QString &question, QWidget *parent)
|
||||||
{
|
{
|
||||||
QMessageBox box(Core::ICore::dialogParent());
|
QMessageBox box(parent ? parent : Core::ICore::dialogParent());
|
||||||
box.QDialog::setWindowTitle(dialogTitle());
|
box.QDialog::setWindowTitle(dialogTitle());
|
||||||
box.setText(question);
|
box.setText(question);
|
||||||
box.setIcon(QMessageBox::Question);
|
box.setIcon(QMessageBox::Question);
|
||||||
@@ -155,19 +155,56 @@ AndroidDevice::AndroidDevice()
|
|||||||
AndroidDeviceManager::instance()->updateDevicesListOnce();
|
AndroidDeviceManager::instance()->updateDevicesListOnce();
|
||||||
}});
|
}});
|
||||||
|
|
||||||
addDeviceAction({tr("Start AVD"), [](const IDevice::Ptr &device, QWidget *parent) {
|
addEmulatorActionsIfNotFound();
|
||||||
if (device->machineType() == IDevice::Emulator)
|
}
|
||||||
AndroidDeviceManager::instance()->startAvd(device);
|
|
||||||
}});
|
|
||||||
|
|
||||||
addDeviceAction({tr("Erase AVD"), [](const IDevice::Ptr &device, QWidget *parent) {
|
void AndroidDevice::addEmulatorActionsIfNotFound()
|
||||||
if (device->machineType() == IDevice::Emulator)
|
{
|
||||||
AndroidDeviceManager::instance()->eraseAvd(device);
|
static const QString startAvdAction = tr("Start AVD");
|
||||||
}});
|
static const QString eraseAvdAction = tr("Erase AVD");
|
||||||
|
static const QString avdArgumentsAction = tr("AVD Arguments");
|
||||||
|
|
||||||
addDeviceAction({tr("AVD Arguments"), [](const IDevice::Ptr &device, QWidget *parent) {
|
bool hasStartAction = false;
|
||||||
AndroidDeviceManager::instance()->setEmulatorArguments();
|
bool hasEraseAction = false;
|
||||||
|
bool hasAvdArgumentsAction = false;
|
||||||
|
|
||||||
|
for (const DeviceAction &item : deviceActions()) {
|
||||||
|
if (item.display == startAvdAction)
|
||||||
|
hasStartAction = true;
|
||||||
|
else if (item.display == eraseAvdAction)
|
||||||
|
hasEraseAction = true;
|
||||||
|
else if (item.display == avdArgumentsAction)
|
||||||
|
hasAvdArgumentsAction = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (machineType() == Emulator) {
|
||||||
|
if (!hasStartAction) {
|
||||||
|
addDeviceAction({startAvdAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
|
AndroidDeviceManager::instance()->startAvd(device, parent);
|
||||||
}});
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasEraseAction) {
|
||||||
|
addDeviceAction({eraseAvdAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
|
AndroidDeviceManager::instance()->eraseAvd(device, parent);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasAvdArgumentsAction) {
|
||||||
|
addDeviceAction({avdArgumentsAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
|
Q_UNUSED(device)
|
||||||
|
AndroidDeviceManager::instance()->setEmulatorArguments(parent);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidDevice::fromMap(const QVariantMap &map)
|
||||||
|
{
|
||||||
|
IDevice::fromMap(map);
|
||||||
|
// Add Actions for Emulator is not added already.
|
||||||
|
// This is needed because actions for Emulators and physical devices are not the same.
|
||||||
|
addEmulatorActionsIfNotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
IDevice::Ptr AndroidDevice::create()
|
IDevice::Ptr AndroidDevice::create()
|
||||||
@@ -407,8 +444,9 @@ void AndroidDeviceManager::updateDevicesListOnce()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device)
|
void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(device.data());
|
const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(device.data());
|
||||||
const QString name = androidDev->avdName();
|
const QString name = androidDev->avdName();
|
||||||
qCDebug(androidDeviceLog, "Starting Android AVD id \"%s\".", qPrintable(name));
|
qCDebug(androidDeviceLog, "Starting Android AVD id \"%s\".", qPrintable(name));
|
||||||
@@ -422,7 +460,7 @@ void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device)
|
void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device, QWidget *parent)
|
||||||
{
|
{
|
||||||
if (device.isNull())
|
if (device.isNull())
|
||||||
return;
|
return;
|
||||||
@@ -432,7 +470,7 @@ void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device)
|
|||||||
|
|
||||||
const QString name = static_cast<const AndroidDevice *>(device.data())->avdName();
|
const QString name = static_cast<const AndroidDevice *>(device.data())->avdName();
|
||||||
const QString question = tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name);
|
const QString question = tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name);
|
||||||
if (!AndroidDeviceWidget::questionDialog(question))
|
if (!AndroidDeviceWidget::questionDialog(question, parent))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qCDebug(androidDeviceLog) << QString("Erasing Android AVD \"%1\" from the system.").arg(name);
|
qCDebug(androidDeviceLog) << QString("Erasing Android AVD \"%1\" from the system.").arg(name);
|
||||||
@@ -460,12 +498,12 @@ void AndroidDeviceManager::handleAvdRemoved()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidDeviceManager::setEmulatorArguments()
|
void AndroidDeviceManager::setEmulatorArguments(QWidget *parent)
|
||||||
{
|
{
|
||||||
const QString helpUrl =
|
const QString helpUrl =
|
||||||
"https://developer.android.com/studio/run/emulator-commandline#startup-options";
|
"https://developer.android.com/studio/run/emulator-commandline#startup-options";
|
||||||
|
|
||||||
QInputDialog dialog(Core::ICore::dialogParent());
|
QInputDialog dialog(parent ? parent : Core::ICore::dialogParent());
|
||||||
dialog.setWindowTitle(tr("Emulator Command-line Startup Options"));
|
dialog.setWindowTitle(tr("Emulator Command-line Startup Options"));
|
||||||
dialog.setLabelText(tr("Emulator command-line startup options "
|
dialog.setLabelText(tr("Emulator command-line startup options "
|
||||||
"(<a href=\"%1\">Help Web Page</a>):").arg(helpUrl));
|
"(<a href=\"%1\">Help Web Page</a>):").arg(helpUrl));
|
||||||
|
@@ -46,6 +46,8 @@ class AndroidDevice final : public ProjectExplorer::IDevice
|
|||||||
public:
|
public:
|
||||||
AndroidDevice();
|
AndroidDevice();
|
||||||
|
|
||||||
|
void fromMap(const QVariantMap &map) override;
|
||||||
|
|
||||||
static IDevice::Ptr create();
|
static IDevice::Ptr create();
|
||||||
static AndroidDeviceInfo androidDeviceInfoFromIDevice(const IDevice *dev);
|
static AndroidDeviceInfo androidDeviceInfoFromIDevice(const IDevice *dev);
|
||||||
static void setAndroidDeviceInfoExtras(IDevice *dev, const AndroidDeviceInfo &info);
|
static void setAndroidDeviceInfoExtras(IDevice *dev, const AndroidDeviceInfo &info);
|
||||||
@@ -74,6 +76,7 @@ public:
|
|||||||
AndroidConfig::OpenGl openGlStatus() const;
|
AndroidConfig::OpenGl openGlStatus() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void addEmulatorActionsIfNotFound();
|
||||||
ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override;
|
ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override;
|
||||||
ProjectExplorer::IDeviceWidget *createWidget() override;
|
ProjectExplorer::IDeviceWidget *createWidget() override;
|
||||||
bool canAutoDetectPorts() const override;
|
bool canAutoDetectPorts() const override;
|
||||||
@@ -99,10 +102,10 @@ public:
|
|||||||
void updateDevicesList();
|
void updateDevicesList();
|
||||||
void updateDevicesListOnce();
|
void updateDevicesListOnce();
|
||||||
|
|
||||||
void startAvd(const ProjectExplorer::IDevice::Ptr &device);
|
void startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr);
|
||||||
void eraseAvd(const ProjectExplorer::IDevice::Ptr &device);
|
void eraseAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr);
|
||||||
|
|
||||||
void setEmulatorArguments();
|
void setEmulatorArguments(QWidget *parent = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AndroidDeviceManager(QObject *parent = nullptr);
|
AndroidDeviceManager(QObject *parent = nullptr);
|
||||||
|
@@ -59,10 +59,12 @@ public:
|
|||||||
PackageFilterModel(AndroidSdkModel* sdkModel);
|
PackageFilterModel(AndroidSdkModel* sdkModel);
|
||||||
|
|
||||||
void setAcceptedPackageState(AndroidSdkPackage::PackageState state);
|
void setAcceptedPackageState(AndroidSdkPackage::PackageState state);
|
||||||
|
void setAcceptedSearchPackage(const QString &text);
|
||||||
bool filterAcceptsRow(int source_row, const QModelIndex &sourceParent) const override;
|
bool filterAcceptsRow(int source_row, const QModelIndex &sourceParent) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AndroidSdkPackage::PackageState m_packageState = AndroidSdkPackage::AnyValidState;
|
AndroidSdkPackage::PackageState m_packageState = AndroidSdkPackage::AnyValidState;
|
||||||
|
QString m_searchText;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config,
|
AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config,
|
||||||
@@ -129,6 +131,15 @@ AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_ui->searchField->setPlaceholderText("Filter");
|
||||||
|
connect(m_ui->searchField, &QLineEdit::textChanged, [this, proxyModel](const QString &text) {
|
||||||
|
const bool isExpanded = m_ui->expandCheck->isChecked();
|
||||||
|
proxyModel->setAcceptedSearchPackage(text);
|
||||||
|
m_sdkModel->resetSelection();
|
||||||
|
// It is more convenient to expand the view with the results
|
||||||
|
m_ui->expandCheck->setChecked(!text.isEmpty());
|
||||||
|
});
|
||||||
|
|
||||||
connect(m_ui->applySelectionButton, &QPushButton::clicked,
|
connect(m_ui->applySelectionButton, &QPushButton::clicked,
|
||||||
this, &AndroidSdkManagerWidget::onApplyButton);
|
this, &AndroidSdkManagerWidget::onApplyButton);
|
||||||
connect(m_ui->cancelButton, &QPushButton::clicked, this,
|
connect(m_ui->cancelButton, &QPushButton::clicked, this,
|
||||||
@@ -469,6 +480,12 @@ void PackageFilterModel::setAcceptedPackageState(AndroidSdkPackage::PackageState
|
|||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PackageFilterModel::setAcceptedSearchPackage(const QString &name)
|
||||||
|
{
|
||||||
|
m_searchText = name;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||||
{
|
{
|
||||||
QModelIndex srcIndex = sourceModel()->index(sourceRow, 0, sourceParent);
|
QModelIndex srcIndex = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||||
@@ -479,19 +496,24 @@ bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour
|
|||||||
return (AndroidSdkPackage::PackageState)i.data(AndroidSdkModel::PackageStateRole).toInt();
|
return (AndroidSdkPackage::PackageState)i.data(AndroidSdkModel::PackageStateRole).toInt();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto packageFound = [this](const QModelIndex& i) {
|
||||||
|
return i.data(AndroidSdkModel::packageNameColumn).toString()
|
||||||
|
.contains(m_searchText, Qt::CaseInsensitive);
|
||||||
|
};
|
||||||
|
|
||||||
bool showTopLevel = false;
|
bool showTopLevel = false;
|
||||||
if (!sourceParent.isValid()) {
|
if (!sourceParent.isValid()) {
|
||||||
// Top Level items
|
// Top Level items
|
||||||
for (int row = 0; row < sourceModel()->rowCount(srcIndex); ++row) {
|
for (int row = 0; row < sourceModel()->rowCount(srcIndex); ++row) {
|
||||||
QModelIndex childIndex = sourceModel()->index(row, 0, srcIndex);
|
QModelIndex childIndex = sourceModel()->index(row, 0, srcIndex);
|
||||||
if (m_packageState & packageState(childIndex)) {
|
if ((m_packageState & packageState(childIndex) && packageFound(childIndex))) {
|
||||||
showTopLevel = true;
|
showTopLevel = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return showTopLevel || (packageState(srcIndex) & m_packageState);
|
return showTopLevel || (packageState(srcIndex) & m_packageState) && packageFound(srcIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionsDialog::OptionsDialog(AndroidSdkManager *sdkManager, const QStringList &args,
|
OptionsDialog::OptionsDialog(AndroidSdkManager *sdkManager, const QStringList &args,
|
||||||
|
@@ -51,27 +51,7 @@
|
|||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>4</number>
|
<number>4</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="2" column="0" colspan="4">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="expandCheck">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Expand All</string>
|
|
||||||
</property>
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QTreeView" name="packagesView">
|
<widget class="QTreeView" name="packagesView">
|
||||||
<property name="indentation">
|
<property name="indentation">
|
||||||
<number>20</number>
|
<number>20</number>
|
||||||
@@ -81,7 +61,7 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="2" column="4">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="updateInstalledButton">
|
<widget class="QPushButton" name="updateInstalledButton">
|
||||||
@@ -149,6 +129,16 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="Utils::FancyLineEdit" name="searchField"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QCheckBox" name="expandCheck">
|
||||||
|
<property name="text">
|
||||||
|
<string>Expand All</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="outputStack">
|
<widget class="QWidget" name="outputStack">
|
||||||
@@ -234,6 +224,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>Utils::FancyLineEdit</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header location="global">utils/fancylineedit.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>packagesView</tabstop>
|
<tabstop>packagesView</tabstop>
|
||||||
<tabstop>showAllRadio</tabstop>
|
<tabstop>showAllRadio</tabstop>
|
||||||
|
@@ -36,7 +36,7 @@ add_qtc_plugin(ClangCodeModel
|
|||||||
clangfixitoperationsextractor.cpp clangfixitoperationsextractor.h
|
clangfixitoperationsextractor.cpp clangfixitoperationsextractor.h
|
||||||
clangfollowsymbol.cpp clangfollowsymbol.h
|
clangfollowsymbol.cpp clangfollowsymbol.h
|
||||||
clangfunctionhintmodel.cpp clangfunctionhintmodel.h
|
clangfunctionhintmodel.cpp clangfunctionhintmodel.h
|
||||||
clanggloballocatorfilters.cpp clanggloballocatorfilters.h
|
clangdlocatorfilters.cpp clangdlocatorfilters.h
|
||||||
clanghighlightingresultreporter.cpp clanghighlightingresultreporter.h
|
clanghighlightingresultreporter.cpp clanghighlightingresultreporter.h
|
||||||
clanghoverhandler.cpp clanghoverhandler.h
|
clanghoverhandler.cpp clanghoverhandler.h
|
||||||
clangisdiagnosticrelatedtolocation.h
|
clangisdiagnosticrelatedtolocation.h
|
||||||
|
@@ -43,7 +43,7 @@ SOURCES += \
|
|||||||
clangoverviewmodel.cpp \
|
clangoverviewmodel.cpp \
|
||||||
clangdclient.cpp \
|
clangdclient.cpp \
|
||||||
clangdquickfixfactory.cpp \
|
clangdquickfixfactory.cpp \
|
||||||
clanggloballocatorfilters.cpp \
|
clangdlocatorfilters.cpp \
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
clangactivationsequencecontextprocessor.h \
|
clangactivationsequencecontextprocessor.h \
|
||||||
@@ -85,7 +85,7 @@ HEADERS += \
|
|||||||
clangoverviewmodel.h \
|
clangoverviewmodel.h \
|
||||||
clangdclient.h \
|
clangdclient.h \
|
||||||
clangdquickfixfactory.h \
|
clangdquickfixfactory.h \
|
||||||
clanggloballocatorfilters.h \
|
clangdlocatorfilters.h \
|
||||||
|
|
||||||
FORMS += clangprojectsettingswidget.ui
|
FORMS += clangprojectsettingswidget.ui
|
||||||
|
|
||||||
|
@@ -64,6 +64,8 @@ QtcPlugin {
|
|||||||
"clangdiagnosticmanager.h",
|
"clangdiagnosticmanager.h",
|
||||||
"clangdiagnostictooltipwidget.cpp",
|
"clangdiagnostictooltipwidget.cpp",
|
||||||
"clangdiagnostictooltipwidget.h",
|
"clangdiagnostictooltipwidget.h",
|
||||||
|
"clangdlocatorfilters.cpp",
|
||||||
|
"clangdlocatorfilters.h",
|
||||||
"clangdquickfixfactory.cpp",
|
"clangdquickfixfactory.cpp",
|
||||||
"clangdquickfixfactory.h",
|
"clangdquickfixfactory.h",
|
||||||
"clangeditordocumentparser.cpp",
|
"clangeditordocumentparser.cpp",
|
||||||
@@ -78,8 +80,6 @@ QtcPlugin {
|
|||||||
"clangfollowsymbol.h",
|
"clangfollowsymbol.h",
|
||||||
"clangfunctionhintmodel.cpp",
|
"clangfunctionhintmodel.cpp",
|
||||||
"clangfunctionhintmodel.h",
|
"clangfunctionhintmodel.h",
|
||||||
"clanggloballocatorfilters.cpp",
|
|
||||||
"clanggloballocatorfilters.h",
|
|
||||||
"clanghighlightingresultreporter.cpp",
|
"clanghighlightingresultreporter.cpp",
|
||||||
"clanghighlightingresultreporter.h",
|
"clanghighlightingresultreporter.h",
|
||||||
"clanghoverhandler.cpp",
|
"clanghoverhandler.cpp",
|
||||||
|
@@ -978,31 +978,7 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
|
|||||||
};
|
};
|
||||||
const auto hideDiagsHandler = []{ ClangDiagnosticManager::clearTaskHubIssues(); };
|
const auto hideDiagsHandler = []{ ClangDiagnosticManager::clearTaskHubIssues(); };
|
||||||
setDiagnosticsHandlers(textMarkCreator, hideDiagsHandler);
|
setDiagnosticsHandlers(textMarkCreator, hideDiagsHandler);
|
||||||
|
setSymbolStringifier(displayNameFromDocumentSymbol);
|
||||||
static const auto symbolStringifier = [](SymbolKind kind, const QString &name,
|
|
||||||
const QString &detail) -> QString
|
|
||||||
{
|
|
||||||
switch (kind) {
|
|
||||||
case LanguageServerProtocol::SymbolKind::Constructor:
|
|
||||||
return name + detail;
|
|
||||||
case LanguageServerProtocol::SymbolKind::Method:
|
|
||||||
case LanguageServerProtocol::SymbolKind::Function: {
|
|
||||||
const int parenOffset = detail.indexOf(" (");
|
|
||||||
if (parenOffset == -1)
|
|
||||||
return name;
|
|
||||||
return name + detail.mid(parenOffset + 1) + " -> " + detail.mid(0, parenOffset);
|
|
||||||
}
|
|
||||||
case LanguageServerProtocol::SymbolKind::Variable:
|
|
||||||
case LanguageServerProtocol::SymbolKind::Field:
|
|
||||||
case LanguageServerProtocol::SymbolKind::Constant:
|
|
||||||
if (detail.isEmpty())
|
|
||||||
return name;
|
|
||||||
return name + " -> " + detail;
|
|
||||||
default:
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
setSymbolStringifier(symbolStringifier);
|
|
||||||
setSemanticTokensHandler([this](TextDocument *doc, const QList<ExpandedSemanticToken> &tokens) {
|
setSemanticTokensHandler([this](TextDocument *doc, const QList<ExpandedSemanticToken> &tokens) {
|
||||||
d->handleSemanticTokens(doc, tokens);
|
d->handleSemanticTokens(doc, tokens);
|
||||||
});
|
});
|
||||||
@@ -1236,6 +1212,30 @@ bool ClangdClient::testingEnabled() const
|
|||||||
return d->isTesting;
|
return d->isTesting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ClangdClient::displayNameFromDocumentSymbol(SymbolKind kind, const QString &name,
|
||||||
|
const QString &detail)
|
||||||
|
{
|
||||||
|
switch (kind) {
|
||||||
|
case SymbolKind::Constructor:
|
||||||
|
return name + detail;
|
||||||
|
case SymbolKind::Method:
|
||||||
|
case LanguageServerProtocol::SymbolKind::Function: {
|
||||||
|
const int parenOffset = detail.indexOf(" (");
|
||||||
|
if (parenOffset == -1)
|
||||||
|
return name;
|
||||||
|
return name + detail.mid(parenOffset + 1) + " -> " + detail.mid(0, parenOffset);
|
||||||
|
}
|
||||||
|
case SymbolKind::Variable:
|
||||||
|
case SymbolKind::Field:
|
||||||
|
case SymbolKind::Constant:
|
||||||
|
if (detail.isEmpty())
|
||||||
|
return name;
|
||||||
|
return name + " -> " + detail;
|
||||||
|
default:
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Location> &locations)
|
void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Location> &locations)
|
||||||
{
|
{
|
||||||
const auto refData = runningFindUsages.find(key);
|
const auto refData = runningFindUsages.find(key);
|
||||||
|
@@ -79,6 +79,9 @@ public:
|
|||||||
void enableTesting();
|
void enableTesting();
|
||||||
bool testingEnabled() const;
|
bool testingEnabled() const;
|
||||||
|
|
||||||
|
static QString displayNameFromDocumentSymbol(LanguageServerProtocol::SymbolKind kind,
|
||||||
|
const QString &name, const QString &detail);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void indexingFinished();
|
void indexingFinished();
|
||||||
void foundReferences(const QList<Core::SearchResultItem> &items);
|
void foundReferences(const QList<Core::SearchResultItem> &items);
|
||||||
|
@@ -23,15 +23,17 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "clanggloballocatorfilters.h"
|
#include "clangdlocatorfilters.h"
|
||||||
|
|
||||||
#include "clangdclient.h"
|
#include "clangdclient.h"
|
||||||
#include "clangmodelmanagersupport.h"
|
#include "clangmodelmanagersupport.h"
|
||||||
|
#include "clangcurrentdocumentfilter.h"
|
||||||
|
|
||||||
#include <cppeditor/cppeditorconstants.h>
|
#include <cppeditor/cppeditorconstants.h>
|
||||||
#include <cppeditor/cpplocatorfilter.h>
|
#include <cppeditor/cpplocatorfilter.h>
|
||||||
#include <cppeditor/cppmodelmanager.h>
|
#include <cppeditor/cppmodelmanager.h>
|
||||||
#include <cppeditor/indexitem.h>
|
#include <cppeditor/indexitem.h>
|
||||||
|
#include <languageclient/languageclientutils.h>
|
||||||
#include <languageclient/locatorfilter.h>
|
#include <languageclient/locatorfilter.h>
|
||||||
#include <projectexplorer/session.h>
|
#include <projectexplorer/session.h>
|
||||||
#include <utils/link.h>
|
#include <utils/link.h>
|
||||||
@@ -39,6 +41,8 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
using namespace LanguageServerProtocol;
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -222,5 +226,104 @@ ClangFunctionsFilter::ClangFunctionsFilter()
|
|||||||
setDefaultIncludedByDefault(false);
|
setDefaultIncludedByDefault(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CppCurrentDocumentFilter : public ClangCurrentDocumentFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CppCurrentDocumentFilter()
|
||||||
|
{
|
||||||
|
setId({});
|
||||||
|
setDisplayName({});
|
||||||
|
setDefaultShortcutString({});
|
||||||
|
setEnabled(false);
|
||||||
|
setHidden(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class LspCurrentDocumentFilter : public LanguageClient::DocumentLocatorFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LspCurrentDocumentFilter()
|
||||||
|
{
|
||||||
|
setId({});
|
||||||
|
setDisplayName({});
|
||||||
|
setDefaultShortcutString({});
|
||||||
|
setEnabled(false);
|
||||||
|
setHidden(true);
|
||||||
|
forceUse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Core::LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info,
|
||||||
|
const Core::LocatorFilterEntry &parent) override
|
||||||
|
{
|
||||||
|
Core::LocatorFilterEntry entry;
|
||||||
|
entry.filter = this;
|
||||||
|
entry.displayName = ClangdClient::displayNameFromDocumentSymbol(
|
||||||
|
static_cast<SymbolKind>(info.kind()), info.name(),
|
||||||
|
info.detail().value_or(QString()));
|
||||||
|
const Position &pos = info.range().start();
|
||||||
|
entry.internalData = QVariant::fromValue(Utils::LineColumn(pos.line(), pos.character()));
|
||||||
|
entry.extraInfo = parent.extraInfo;
|
||||||
|
if (!entry.extraInfo.isEmpty())
|
||||||
|
entry.extraInfo.append("::");
|
||||||
|
entry.extraInfo.append(parent.displayName);
|
||||||
|
|
||||||
|
// TODO: Can we extend clangd to send visibility information?
|
||||||
|
entry.displayIcon = LanguageClient::symbolIcon(info.kind());
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClangdCurrentDocumentFilter::Private
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CppCurrentDocumentFilter cppFilter;
|
||||||
|
LspCurrentDocumentFilter lspFilter;
|
||||||
|
Core::ILocatorFilter *activeFilter = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() : d(new Private)
|
||||||
|
{
|
||||||
|
setId(CppEditor::Constants::CURRENT_DOCUMENT_FILTER_ID);
|
||||||
|
setDisplayName(CppEditor::Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME);
|
||||||
|
setDefaultShortcutString(".");
|
||||||
|
setPriority(High);
|
||||||
|
setDefaultIncludedByDefault(false);
|
||||||
|
setEnabled(false);
|
||||||
|
connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
|
||||||
|
this, [this](const Core::IEditor *editor) { setEnabled(editor); });
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangdCurrentDocumentFilter::~ClangdCurrentDocumentFilter() { delete d; }
|
||||||
|
|
||||||
|
void ClangdCurrentDocumentFilter::prepareSearch(const QString &entry)
|
||||||
|
{
|
||||||
|
const auto doc = TextEditor::TextDocument::currentTextDocument();
|
||||||
|
QTC_ASSERT(doc, return);
|
||||||
|
if (const ClangdClient * const client = ClangModelManagerSupport::instance()
|
||||||
|
->clientForFile(doc->filePath()); client && client->reachable()) {
|
||||||
|
d->activeFilter = &d->lspFilter;
|
||||||
|
} else {
|
||||||
|
d->activeFilter = &d->cppFilter;
|
||||||
|
}
|
||||||
|
d->activeFilter->prepareSearch(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Core::LocatorFilterEntry> ClangdCurrentDocumentFilter::matchesFor(
|
||||||
|
QFutureInterface<Core::LocatorFilterEntry> &future, const QString &entry)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(d->activeFilter, return {});
|
||||||
|
return d->activeFilter->matchesFor(future, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangdCurrentDocumentFilter::accept(Core::LocatorFilterEntry selection, QString *newText,
|
||||||
|
int *selectionStart, int *selectionLength) const
|
||||||
|
{
|
||||||
|
QTC_ASSERT(d->activeFilter, return);
|
||||||
|
d->activeFilter->accept(selection, newText, selectionStart, selectionLength);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
@@ -60,5 +60,22 @@ public:
|
|||||||
ClangFunctionsFilter();
|
ClangFunctionsFilter();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ClangdCurrentDocumentFilter : public Core::ILocatorFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClangdCurrentDocumentFilter();
|
||||||
|
~ClangdCurrentDocumentFilter() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void prepareSearch(const QString &entry) override;
|
||||||
|
QList<Core::LocatorFilterEntry> matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future,
|
||||||
|
const QString &entry) override;
|
||||||
|
void accept(Core::LocatorFilterEntry selection, QString *newText,
|
||||||
|
int *selectionStart, int *selectionLength) const override;
|
||||||
|
|
||||||
|
class Private;
|
||||||
|
Private * const d;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
@@ -26,12 +26,11 @@
|
|||||||
#include "clangmodelmanagersupport.h"
|
#include "clangmodelmanagersupport.h"
|
||||||
|
|
||||||
#include "clangconstants.h"
|
#include "clangconstants.h"
|
||||||
#include "clangcurrentdocumentfilter.h"
|
|
||||||
#include "clangdclient.h"
|
#include "clangdclient.h"
|
||||||
#include "clangdquickfixfactory.h"
|
#include "clangdquickfixfactory.h"
|
||||||
#include "clangeditordocumentprocessor.h"
|
#include "clangeditordocumentprocessor.h"
|
||||||
#include "clangfollowsymbol.h"
|
#include "clangfollowsymbol.h"
|
||||||
#include "clanggloballocatorfilters.h"
|
#include "clangdlocatorfilters.h"
|
||||||
#include "clanghoverhandler.h"
|
#include "clanghoverhandler.h"
|
||||||
#include "clangoverviewmodel.h"
|
#include "clangoverviewmodel.h"
|
||||||
#include "clangprojectsettings.h"
|
#include "clangprojectsettings.h"
|
||||||
@@ -113,8 +112,7 @@ ClangModelManagerSupport::ClangModelManagerSupport()
|
|||||||
m_instance = this;
|
m_instance = this;
|
||||||
|
|
||||||
watchForExternalChanges();
|
watchForExternalChanges();
|
||||||
CppEditor::CppModelManager::instance()->setCurrentDocumentFilter(
|
cppModelManager()->setCurrentDocumentFilter(std::make_unique<ClangdCurrentDocumentFilter>());
|
||||||
std::make_unique<ClangCurrentDocumentFilter>());
|
|
||||||
cppModelManager()->setLocatorFilter(std::make_unique<ClangGlobalSymbolFilter>());
|
cppModelManager()->setLocatorFilter(std::make_unique<ClangGlobalSymbolFilter>());
|
||||||
cppModelManager()->setClassesFilter(std::make_unique<ClangClassesFilter>());
|
cppModelManager()->setClassesFilter(std::make_unique<ClangClassesFilter>());
|
||||||
cppModelManager()->setFunctionsFilter(std::make_unique<ClangFunctionsFilter>());
|
cppModelManager()->setFunctionsFilter(std::make_unique<ClangFunctionsFilter>());
|
||||||
|
@@ -393,6 +393,7 @@ void ClangdTestFollowSymbol::test()
|
|||||||
timer.stop();
|
timer.stop();
|
||||||
|
|
||||||
QCOMPARE(actualLink.targetFilePath, filePath(targetFile));
|
QCOMPARE(actualLink.targetFilePath, filePath(targetFile));
|
||||||
|
if (client()->versionNumber() < QVersionNumber(14))
|
||||||
QEXPECT_FAIL("union member ref", "https://github.com/clangd/clangd/issues/877", Abort);
|
QEXPECT_FAIL("union member ref", "https://github.com/clangd/clangd/issues/877", Abort);
|
||||||
QCOMPARE(actualLink.targetLine, targetLine);
|
QCOMPARE(actualLink.targetLine, targetLine);
|
||||||
QCOMPARE(actualLink.targetColumn + 1, targetColumn);
|
QCOMPARE(actualLink.targetColumn + 1, targetColumn);
|
||||||
|
@@ -340,9 +340,12 @@ static FileInfos sortedFileInfos(const QVector<CppEditor::ProjectPart::ConstPtr>
|
|||||||
if (file.path == CppEditor::CppModelManager::configurationFileName())
|
if (file.path == CppEditor::CppModelManager::configurationFileName())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (file.active && CppEditor::ProjectFile::isSource(file.kind)) {
|
if (file.active
|
||||||
|
&& (CppEditor::ProjectFile::isSource(file.kind)
|
||||||
|
|| CppEditor::ProjectFile::isHeader(file.kind))) {
|
||||||
|
ProjectFile::Kind sourceKind = CppEditor::ProjectFile::sourceKind(file.kind);
|
||||||
fileInfos.emplace_back(Utils::FilePath::fromString(file.path),
|
fileInfos.emplace_back(Utils::FilePath::fromString(file.path),
|
||||||
file.kind,
|
sourceKind,
|
||||||
projectPart);
|
projectPart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -160,11 +160,12 @@ static FileInfo getFileInfo(const FilePath &file, Project *project)
|
|||||||
if (!projectFile.active)
|
if (!projectFile.active)
|
||||||
continue;
|
continue;
|
||||||
// found the best candidate, early return
|
// found the best candidate, early return
|
||||||
|
ProjectFile::Kind sourceKind = ProjectFile::sourceKind(projectFile.kind);
|
||||||
if (projectPart->buildTargetType != BuildTargetType::Unknown)
|
if (projectPart->buildTargetType != BuildTargetType::Unknown)
|
||||||
return FileInfo(projectFilePath, projectFile.kind, projectPart);
|
return FileInfo(projectFilePath, sourceKind, projectPart);
|
||||||
// found something but keep looking for better candidates
|
// found something but keep looking for better candidates
|
||||||
if (candidate.projectPart.isNull())
|
if (candidate.projectPart.isNull())
|
||||||
candidate = FileInfo(projectFilePath, projectFile.kind, projectPart);
|
candidate = FileInfo(projectFilePath, sourceKind, projectPart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -213,7 +213,7 @@ void CMakeToolSettingsAccessor::saveCMakeTools(const QList<CMakeTool *> &cmakeTo
|
|||||||
for (const CMakeTool *item : cmakeTools) {
|
for (const CMakeTool *item : cmakeTools) {
|
||||||
Utils::FilePath fi = item->cmakeExecutable();
|
Utils::FilePath fi = item->cmakeExecutable();
|
||||||
|
|
||||||
if (fi.isExecutableFile()) {
|
if (fi.needsDevice() || fi.isExecutableFile()) { // be graceful for device related stuff
|
||||||
QVariantMap tmp = item->toMap();
|
QVariantMap tmp = item->toMap();
|
||||||
if (tmp.isEmpty())
|
if (tmp.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
|
@@ -87,6 +87,37 @@ bool ProjectFile::isAmbiguousHeader(const QString &filePath)
|
|||||||
return filePath.endsWith(".h");
|
return filePath.endsWith(".h");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProjectFile::Kind ProjectFile::sourceForHeaderKind(ProjectFile::Kind kind)
|
||||||
|
{
|
||||||
|
ProjectFile::Kind sourceKind;
|
||||||
|
switch (kind) {
|
||||||
|
case ProjectFile::CHeader:
|
||||||
|
sourceKind = ProjectFile::CSource;
|
||||||
|
break;
|
||||||
|
case ProjectFile::ObjCHeader:
|
||||||
|
sourceKind = ProjectFile::ObjCSource;
|
||||||
|
break;
|
||||||
|
case ProjectFile::ObjCXXHeader:
|
||||||
|
sourceKind = ProjectFile::ObjCXXSource;
|
||||||
|
break;
|
||||||
|
case ProjectFile::Unsupported: // no file extension, e.g. stl headers
|
||||||
|
case ProjectFile::AmbiguousHeader:
|
||||||
|
case ProjectFile::CXXHeader:
|
||||||
|
default:
|
||||||
|
sourceKind = ProjectFile::CXXSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectFile::Kind ProjectFile::sourceKind(Kind kind)
|
||||||
|
{
|
||||||
|
ProjectFile::Kind sourceKind = kind;
|
||||||
|
if (ProjectFile::isHeader(kind))
|
||||||
|
sourceKind = ProjectFile::sourceForHeaderKind(kind);
|
||||||
|
return sourceKind;
|
||||||
|
}
|
||||||
|
|
||||||
bool ProjectFile::isHeader(ProjectFile::Kind kind)
|
bool ProjectFile::isHeader(ProjectFile::Kind kind)
|
||||||
{
|
{
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
|
@@ -53,6 +53,9 @@ public:
|
|||||||
static Kind classifyByMimeType(const QString &mt);
|
static Kind classifyByMimeType(const QString &mt);
|
||||||
static Kind classify(const QString &filePath);
|
static Kind classify(const QString &filePath);
|
||||||
|
|
||||||
|
static Kind sourceForHeaderKind(Kind kind);
|
||||||
|
static Kind sourceKind(Kind kind);
|
||||||
|
|
||||||
static bool isSource(Kind kind);
|
static bool isSource(Kind kind);
|
||||||
static bool isHeader(Kind kind);
|
static bool isHeader(Kind kind);
|
||||||
static bool isC(Kind kind);
|
static bool isC(Kind kind);
|
||||||
|
@@ -61,6 +61,6 @@ updateCodeActionRefactoringMarker(Client *client,
|
|||||||
const LanguageServerProtocol::CodeAction &action,
|
const LanguageServerProtocol::CodeAction &action,
|
||||||
const LanguageServerProtocol::DocumentUri &uri);
|
const LanguageServerProtocol::DocumentUri &uri);
|
||||||
void updateEditorToolBar(Core::IEditor *editor);
|
void updateEditorToolBar(Core::IEditor *editor);
|
||||||
const QIcon symbolIcon(int type);
|
const QIcon LANGUAGECLIENT_EXPORT symbolIcon(int type);
|
||||||
|
|
||||||
} // namespace LanguageClient
|
} // namespace LanguageClient
|
||||||
|
@@ -63,8 +63,8 @@ void DocumentLocatorFilter::updateCurrentClient()
|
|||||||
|
|
||||||
TextEditor::TextDocument *document = TextEditor::TextDocument::currentTextDocument();
|
TextEditor::TextDocument *document = TextEditor::TextDocument::currentTextDocument();
|
||||||
if (Client *client = LanguageClientManager::clientForDocument(document);
|
if (Client *client = LanguageClientManager::clientForDocument(document);
|
||||||
client && client->locatorsEnabled()) {
|
client && (client->locatorsEnabled() || m_forced)) {
|
||||||
setEnabled(true);
|
setEnabled(!m_forced);
|
||||||
if (m_symbolCache != client->documentSymbolCache()) {
|
if (m_symbolCache != client->documentSymbolCache()) {
|
||||||
disconnect(m_updateSymbolsConnection);
|
disconnect(m_updateSymbolsConnection);
|
||||||
m_symbolCache = client->documentSymbolCache();
|
m_symbolCache = client->documentSymbolCache();
|
||||||
@@ -98,7 +98,7 @@ void DocumentLocatorFilter::resetSymbols()
|
|||||||
m_currentSymbols.reset();
|
m_currentSymbols.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info,
|
static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info,
|
||||||
Core::ILocatorFilter *filter)
|
Core::ILocatorFilter *filter)
|
||||||
{
|
{
|
||||||
Core::LocatorFilterEntry entry;
|
Core::LocatorFilterEntry entry;
|
||||||
@@ -109,13 +109,31 @@ Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info,
|
|||||||
entry.displayIcon = symbolIcon(info.kind());
|
entry.displayIcon = symbolIcon(info.kind());
|
||||||
entry.internalData = QVariant::fromValue(info.location().toLink());
|
entry.internalData = QVariant::fromValue(info.location().toLink());
|
||||||
return entry;
|
return entry;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info,
|
Core::LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const SymbolInformation &info)
|
||||||
Core::ILocatorFilter *filter)
|
|
||||||
{
|
{
|
||||||
|
return LanguageClient::generateLocatorEntry(info, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateLocatorEntries(
|
||||||
|
const SymbolInformation &info, const QRegularExpression ®exp,
|
||||||
|
const Core::LocatorFilterEntry &parent)
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
if (regexp.match(info.name()).hasMatch())
|
||||||
|
return {generateLocatorEntry(info)};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(
|
||||||
|
const DocumentSymbol &info,
|
||||||
|
const Core::LocatorFilterEntry &parent)
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
Core::LocatorFilterEntry entry;
|
Core::LocatorFilterEntry entry;
|
||||||
entry.filter = filter;
|
entry.filter = this;
|
||||||
entry.displayName = info.name();
|
entry.displayName = info.name();
|
||||||
if (Utils::optional<QString> detail = info.detail())
|
if (Utils::optional<QString> detail = info.detail())
|
||||||
entry.extraInfo = detail.value_or(QString());
|
entry.extraInfo = detail.value_or(QString());
|
||||||
@@ -125,6 +143,23 @@ Core::LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info,
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateLocatorEntries(
|
||||||
|
const DocumentSymbol &info, const QRegularExpression ®exp,
|
||||||
|
const Core::LocatorFilterEntry &parent)
|
||||||
|
{
|
||||||
|
QList<Core::LocatorFilterEntry> entries;
|
||||||
|
const QList<DocumentSymbol> children = info.children().value_or(QList<DocumentSymbol>());
|
||||||
|
const bool hasMatch = regexp.match(info.name()).hasMatch();
|
||||||
|
Core::LocatorFilterEntry entry;
|
||||||
|
if (hasMatch || !children.isEmpty())
|
||||||
|
entry = generateLocatorEntry(info, parent);
|
||||||
|
if (hasMatch)
|
||||||
|
entries << entry;
|
||||||
|
for (const DocumentSymbol &child : children)
|
||||||
|
entries << generateLocatorEntries(child, regexp, entry);
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateEntries(const QList<T> &list,
|
QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateEntries(const QList<T> &list,
|
||||||
const QString &filter)
|
const QString &filter)
|
||||||
@@ -138,11 +173,8 @@ QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateEntries(const QLi
|
|||||||
if (!regexp.isValid())
|
if (!regexp.isValid())
|
||||||
return entries;
|
return entries;
|
||||||
|
|
||||||
for (const T &item : list) {
|
for (const T &item : list)
|
||||||
QRegularExpressionMatch match = regexp.match(item.name());
|
entries << generateLocatorEntries(item, regexp, {});
|
||||||
if (match.hasMatch())
|
|
||||||
entries << generateLocatorEntry(item, this);
|
|
||||||
}
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
#include "languageclient_global.h"
|
||||||
|
|
||||||
#include <coreplugin/locator/ilocatorfilter.h>
|
#include <coreplugin/locator/ilocatorfilter.h>
|
||||||
#include <languageserverprotocol/lsptypes.h>
|
#include <languageserverprotocol/lsptypes.h>
|
||||||
@@ -38,7 +39,7 @@ namespace Core { class IEditor; }
|
|||||||
|
|
||||||
namespace LanguageClient {
|
namespace LanguageClient {
|
||||||
|
|
||||||
class DocumentLocatorFilter : public Core::ILocatorFilter
|
class LANGUAGECLIENT_EXPORT DocumentLocatorFilter : public Core::ILocatorFilter
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@@ -57,6 +58,8 @@ signals:
|
|||||||
void symbolsUpToDate(QPrivateSignal);
|
void symbolsUpToDate(QPrivateSignal);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void forceUse() { m_forced = true; }
|
||||||
|
|
||||||
QPointer<DocumentSymbolCache> m_symbolCache;
|
QPointer<DocumentSymbolCache> m_symbolCache;
|
||||||
LanguageServerProtocol::DocumentUri m_currentUri;
|
LanguageServerProtocol::DocumentUri m_currentUri;
|
||||||
|
|
||||||
@@ -67,11 +70,25 @@ private:
|
|||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
QList<Core::LocatorFilterEntry> generateEntries(const QList<T> &list, const QString &filter);
|
QList<Core::LocatorFilterEntry> generateEntries(const QList<T> &list, const QString &filter);
|
||||||
|
QList<Core::LocatorFilterEntry> generateLocatorEntries(
|
||||||
|
const LanguageServerProtocol::SymbolInformation &info,
|
||||||
|
const QRegularExpression ®exp,
|
||||||
|
const Core::LocatorFilterEntry &parent);
|
||||||
|
QList<Core::LocatorFilterEntry> generateLocatorEntries(
|
||||||
|
const LanguageServerProtocol::DocumentSymbol &info,
|
||||||
|
const QRegularExpression ®exp,
|
||||||
|
const Core::LocatorFilterEntry &parent);
|
||||||
|
virtual Core::LocatorFilterEntry generateLocatorEntry(
|
||||||
|
const LanguageServerProtocol::DocumentSymbol &info,
|
||||||
|
const Core::LocatorFilterEntry &parent);
|
||||||
|
virtual Core::LocatorFilterEntry generateLocatorEntry(
|
||||||
|
const LanguageServerProtocol::SymbolInformation &info);
|
||||||
|
|
||||||
QMutex m_mutex;
|
QMutex m_mutex;
|
||||||
QMetaObject::Connection m_updateSymbolsConnection;
|
QMetaObject::Connection m_updateSymbolsConnection;
|
||||||
QMetaObject::Connection m_resetSymbolsConnection;
|
QMetaObject::Connection m_resetSymbolsConnection;
|
||||||
Utils::optional<LanguageServerProtocol::DocumentSymbolsResult> m_currentSymbols;
|
Utils::optional<LanguageServerProtocol::DocumentSymbolsResult> m_currentSymbols;
|
||||||
|
bool m_forced = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LANGUAGECLIENT_EXPORT WorkspaceLocatorFilter : public Core::ILocatorFilter
|
class LANGUAGECLIENT_EXPORT WorkspaceLocatorFilter : public Core::ILocatorFilter
|
||||||
|
@@ -3313,7 +3313,7 @@ void ProjectExplorerPluginPrivate::openRecentProject(const QString &fileName)
|
|||||||
{
|
{
|
||||||
if (!fileName.isEmpty()) {
|
if (!fileName.isEmpty()) {
|
||||||
ProjectExplorerPlugin::OpenProjectResult result
|
ProjectExplorerPlugin::OpenProjectResult result
|
||||||
= ProjectExplorerPlugin::openProject(FilePath::fromString(fileName));
|
= ProjectExplorerPlugin::openProject(FilePath::fromUserInput(fileName));
|
||||||
if (!result)
|
if (!result)
|
||||||
ProjectExplorerPlugin::showOpenProjectError(result);
|
ProjectExplorerPlugin::showOpenProjectError(result);
|
||||||
}
|
}
|
||||||
|
@@ -448,7 +448,7 @@ void RewriterView::auxiliaryDataChanged(const ModelNode &node, const PropertyNam
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (node.isRootNode()) {
|
if (node.isRootNode()) {
|
||||||
if (name == "width" || name == "height" || name == "autoSize")
|
if (name == "width" || name == "height" || name == "autoSize" || name == "formeditorColor")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -49,9 +49,9 @@ ProFileCache::ProFileCache()
|
|||||||
|
|
||||||
ProFileCache::~ProFileCache()
|
ProFileCache::~ProFileCache()
|
||||||
{
|
{
|
||||||
foreach (const Entry &ent, parsed_files)
|
for (const auto &keyValuePair : parsed_files)
|
||||||
if (ent.pro)
|
if (keyValuePair.second.pro)
|
||||||
ent.pro->deref();
|
keyValuePair.second.pro->deref();
|
||||||
QMakeVfs::deref();
|
QMakeVfs::deref();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,20 +72,37 @@ void ProFileCache::discardFile(int id)
|
|||||||
#endif
|
#endif
|
||||||
auto it = parsed_files.find(id);
|
auto it = parsed_files.find(id);
|
||||||
if (it != parsed_files.end()) {
|
if (it != parsed_files.end()) {
|
||||||
|
Entry &entry = it->second;
|
||||||
#ifdef PROPARSER_THREAD_SAFE
|
#ifdef PROPARSER_THREAD_SAFE
|
||||||
if (it->locker) {
|
Entry::Locker *locker = entry.locker;
|
||||||
if (!it->locker->done) {
|
if (locker) { // Either it's still being prepared or it's already done but someone
|
||||||
++it->locker->waiters;
|
// else started waiting for it when it wasn't ready yet
|
||||||
it->locker->cond.wait(&mutex);
|
// and is still waiting.
|
||||||
if (!--it->locker->waiters) {
|
if (!locker->done) {
|
||||||
delete it->locker;
|
++locker->waiters;
|
||||||
it->locker = 0;
|
locker->cond.wait(&mutex); // Mutex is unlocked and relocked,
|
||||||
|
// everything may happen in this time window
|
||||||
|
it = parsed_files.find(id); // In meantime the iterator could have
|
||||||
|
// been invalidated, search for it again
|
||||||
|
Q_ASSERT(it != parsed_files.end()); // This would mean that some other
|
||||||
|
// waiter removed our entry, but only
|
||||||
|
// the last waiter should do it
|
||||||
|
if (!--locker->waiters) {
|
||||||
|
delete locker;
|
||||||
|
} else {
|
||||||
|
// There are still other waiters. Do nothing now.
|
||||||
|
locker->removeOnLastWaiter = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (locker->waiters) {
|
||||||
|
// It's done but some waiters are still awaiting to be woken.
|
||||||
|
locker->removeOnLastWaiter = true; // Mark it for other waiters
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (it->pro)
|
if (entry.pro)
|
||||||
it->pro->deref();
|
entry.pro->deref();
|
||||||
parsed_files.erase(it);
|
parsed_files.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,26 +112,53 @@ void ProFileCache::discardFiles(const QString &prefix, QMakeVfs *vfs)
|
|||||||
#ifdef PROPARSER_THREAD_SAFE
|
#ifdef PROPARSER_THREAD_SAFE
|
||||||
QMutexLocker lck(&mutex);
|
QMutexLocker lck(&mutex);
|
||||||
#endif
|
#endif
|
||||||
auto it = parsed_files.begin(), end = parsed_files.end();
|
auto it = parsed_files.begin();
|
||||||
while (it != end) {
|
while (it != parsed_files.end()) {
|
||||||
|
const int id = it->first;
|
||||||
// Note: this is empty for virtual files from other VFSes.
|
// Note: this is empty for virtual files from other VFSes.
|
||||||
QString fn = vfs->fileNameForId(it.key());
|
const QString fn = vfs->fileNameForId(id);
|
||||||
if (fn.startsWith(prefix)) {
|
if (fn.startsWith(prefix)) {
|
||||||
|
bool continueFromScratch = false;
|
||||||
|
Entry &entry = it->second;
|
||||||
#ifdef PROPARSER_THREAD_SAFE
|
#ifdef PROPARSER_THREAD_SAFE
|
||||||
if (it->locker) {
|
Entry::Locker *locker = entry.locker;
|
||||||
if (!it->locker->done) {
|
if (locker) { // Either it's still being prepared or it's already done but someone
|
||||||
++it->locker->waiters;
|
// else started waiting for it when it wasn't ready yet
|
||||||
it->locker->cond.wait(&mutex);
|
// and is still waiting.
|
||||||
if (!--it->locker->waiters) {
|
if (!locker->done) { // It's still being prepared.
|
||||||
delete it->locker;
|
++locker->waiters;
|
||||||
it->locker = 0;
|
locker->cond.wait(&mutex); // Mutex is unlocked and relocked,
|
||||||
|
// everything may happen in this time window
|
||||||
|
it = parsed_files.find(id); // In meantime the iterator could have
|
||||||
|
// been invalidated, search for it again
|
||||||
|
Q_ASSERT(it != parsed_files.end()); // This would mean that some other
|
||||||
|
// waiter removed our entry, but only
|
||||||
|
// the last waiter should do it
|
||||||
|
if (!--locker->waiters) {
|
||||||
|
delete locker; // No more waiters, remove locker and entry
|
||||||
|
continueFromScratch = true;
|
||||||
|
} else {
|
||||||
|
// There are still other waiters. Do nothing now
|
||||||
|
locker->removeOnLastWaiter = true;
|
||||||
|
it = parsed_files.begin(); // Start from scratch, as new matching
|
||||||
|
// entries could have appeared.
|
||||||
|
// If we hit it again, we will skip it
|
||||||
|
// as the locker is already marked as done
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
} else if (locker->waiters) {
|
||||||
|
// It's done but some waiters are still awaiting to be woken.
|
||||||
|
locker->removeOnLastWaiter = true; // Mark it for other waiters
|
||||||
|
++it; // We skip it for now, other waiter will do the job
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (it->pro)
|
if (entry.pro)
|
||||||
it->pro->deref();
|
entry.pro->deref();
|
||||||
it = parsed_files.erase(it);
|
it = parsed_files.erase(it);
|
||||||
|
if (continueFromScratch)
|
||||||
|
it = parsed_files.begin();
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
@@ -187,20 +231,44 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
|
|||||||
if ((flags & ParseUseCache) && m_cache) {
|
if ((flags & ParseUseCache) && m_cache) {
|
||||||
ProFileCache::Entry *ent;
|
ProFileCache::Entry *ent;
|
||||||
#ifdef PROPARSER_THREAD_SAFE
|
#ifdef PROPARSER_THREAD_SAFE
|
||||||
QMutexLocker locker(&m_cache->mutex);
|
QMutexLocker lck(&m_cache->mutex);
|
||||||
#endif
|
#endif
|
||||||
auto it = m_cache->parsed_files.find(id);
|
auto it = m_cache->parsed_files.find(id);
|
||||||
if (it != m_cache->parsed_files.end()) {
|
if (it != m_cache->parsed_files.end()) {
|
||||||
ent = &*it;
|
ent = &it->second;
|
||||||
#ifdef PROPARSER_THREAD_SAFE
|
#ifdef PROPARSER_THREAD_SAFE
|
||||||
if (ent->locker && !ent->locker->done) {
|
ProFileCache::Entry::Locker *locker = ent->locker;
|
||||||
++ent->locker->waiters;
|
if (locker) { // Either it's still being prepared or it's already done but someone
|
||||||
|
// else started waiting for it when it wasn't ready yet
|
||||||
|
// and is still waiting.
|
||||||
|
if (!locker->done) { // It's still being prepared.
|
||||||
|
++locker->waiters;
|
||||||
QThreadPool::globalInstance()->releaseThread();
|
QThreadPool::globalInstance()->releaseThread();
|
||||||
ent->locker->cond.wait(locker.mutex());
|
locker->cond.wait(lck.mutex()); // Mutex is unlocked and relocked,
|
||||||
|
// everything may happen in this time window
|
||||||
QThreadPool::globalInstance()->reserveThread();
|
QThreadPool::globalInstance()->reserveThread();
|
||||||
if (!--ent->locker->waiters) {
|
|
||||||
delete ent->locker;
|
it = m_cache->parsed_files.find(id); // In meantime the iterator could have
|
||||||
|
// been invalidated, search for it again
|
||||||
|
Q_ASSERT(it != m_cache->parsed_files.end()); // This would mean that some other
|
||||||
|
// waiter removed our entry, but only
|
||||||
|
// the last waiter should do it
|
||||||
|
const bool remove = locker->removeOnLastWaiter; // Some waiter marked this
|
||||||
|
// entry for removal.
|
||||||
|
if (!--locker->waiters) { // If we were the last waiter
|
||||||
|
delete locker; // we do it now
|
||||||
ent->locker = 0;
|
ent->locker = 0;
|
||||||
|
if (remove) {
|
||||||
|
if (ent->pro)
|
||||||
|
ent->pro->deref();
|
||||||
|
m_cache->parsed_files.erase(it);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (remove)
|
||||||
|
return nullptr;
|
||||||
|
} else if (locker->removeOnLastWaiter) {
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -210,7 +278,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
|
|||||||
ent = &m_cache->parsed_files[id];
|
ent = &m_cache->parsed_files[id];
|
||||||
#ifdef PROPARSER_THREAD_SAFE
|
#ifdef PROPARSER_THREAD_SAFE
|
||||||
ent->locker = new ProFileCache::Entry::Locker;
|
ent->locker = new ProFileCache::Entry::Locker;
|
||||||
locker.unlock();
|
lck.unlock(); // We unlock the mutex and open a time window
|
||||||
#endif
|
#endif
|
||||||
QString contents;
|
QString contents;
|
||||||
if (readFile(id, flags, &contents)) {
|
if (readFile(id, flags, &contents)) {
|
||||||
@@ -222,11 +290,17 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
|
|||||||
}
|
}
|
||||||
ent->pro = pro;
|
ent->pro = pro;
|
||||||
#ifdef PROPARSER_THREAD_SAFE
|
#ifdef PROPARSER_THREAD_SAFE
|
||||||
locker.relock();
|
lck.relock(); // We relock it back and close the window. Someone could have added a new
|
||||||
if (ent->locker->waiters) {
|
// entry to the parsed_files list (or removed one). However, no one
|
||||||
ent->locker->done = true;
|
// was awoken for our id in this time window.
|
||||||
|
it = m_cache->parsed_files.find(id); // In meantime the iterator could have
|
||||||
|
// been invalidated, search for it again
|
||||||
|
Q_ASSERT(it != m_cache->parsed_files.end()); // This would mean that our reference
|
||||||
|
// is also invalid
|
||||||
|
if (ent->locker->waiters) { // Someone runs getter or wants to remove it
|
||||||
|
ent->locker->done = true; // The structure is ready
|
||||||
ent->locker->cond.wakeAll();
|
ent->locker->cond.wakeAll();
|
||||||
} else {
|
} else { // No one was interested, remove locker as everything is ready now
|
||||||
delete ent->locker;
|
delete ent->locker;
|
||||||
ent->locker = 0;
|
ent->locker = 0;
|
||||||
}
|
}
|
||||||
|
@@ -29,13 +29,14 @@
|
|||||||
#include "qmakevfs.h"
|
#include "qmakevfs.h"
|
||||||
#include "proitems.h"
|
#include "proitems.h"
|
||||||
|
|
||||||
#include <qhash.h>
|
|
||||||
#include <qstack.h>
|
#include <qstack.h>
|
||||||
#ifdef PROPARSER_THREAD_SAFE
|
#ifdef PROPARSER_THREAD_SAFE
|
||||||
# include <qmutex.h>
|
# include <qmutex.h>
|
||||||
# include <qwaitcondition.h>
|
# include <qwaitcondition.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QMAKE_EXPORT QMakeParserHandler
|
class QMAKE_EXPORT QMakeParserHandler
|
||||||
{
|
{
|
||||||
@@ -208,16 +209,16 @@ private:
|
|||||||
ProFile *pro;
|
ProFile *pro;
|
||||||
#ifdef PROPARSER_THREAD_SAFE
|
#ifdef PROPARSER_THREAD_SAFE
|
||||||
struct Locker {
|
struct Locker {
|
||||||
Locker() : waiters(0), done(false) {}
|
|
||||||
QWaitCondition cond;
|
QWaitCondition cond;
|
||||||
int waiters;
|
int waiters = 0;
|
||||||
bool done;
|
bool done = false;
|
||||||
|
bool removeOnLastWaiter = false;
|
||||||
};
|
};
|
||||||
Locker *locker;
|
Locker *locker;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
QHash<int, Entry> parsed_files;
|
std::unordered_map<int, Entry> parsed_files;
|
||||||
#ifdef PROPARSER_THREAD_SAFE
|
#ifdef PROPARSER_THREAD_SAFE
|
||||||
QMutex mutex;
|
QMutex mutex;
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user