Merge remote-tracking branch 'origin/master' into 4.15
Change-Id: Ia313b9a8bf82940e496b7456801faf552fe4b022
8
dist/changes-4.15.0.md
vendored
@@ -33,9 +33,11 @@ Editing
|
||||
|
||||
### C++
|
||||
|
||||
* Added options for generation of getters and setters (QTCREATORBUG-1532)
|
||||
* Added `Create Constructor` refactoring operation
|
||||
* Added filtering of `Find Usages` based on access type (QTCREATORBUG-19373)
|
||||
* Added `Create Getter and Setter Member Functions` refactoring action
|
||||
(QTCREATORBUG-1532)
|
||||
* Added `Generate Constructor` refactoring action
|
||||
* Added filtering of `Find References to Symbol Under Cursor` based on access
|
||||
type (QTCREATORBUG-19373)
|
||||
* Added `Open in Editor` and `Open Type Hierarchy` to context menu on items in
|
||||
type hierarchy
|
||||
* Added highlighting of previous class when navigating in type hierarchy
|
||||
|
After Width: | Height: | Size: 7.3 KiB |
BIN
doc/qtcreator/images/qtcreator-refactoring-constructor.png
Normal file
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 8.5 KiB |
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Creator documentation.
|
||||
@@ -51,6 +51,8 @@
|
||||
\uicontrol {C++} > \uicontrol {Find References to Symbol Under Cursor} or
|
||||
press \key {Ctrl+Shift+U}.
|
||||
|
||||
\image qtcreator-find-references-to-symbol-under-cursor.png "Search results for finding references to symbols"
|
||||
|
||||
\note You can also select \uicontrol Edit > \uicontrol {Find/Replace} >
|
||||
\uicontrol {Advanced Find} > \uicontrol {C++ Symbols} to search for
|
||||
classes, functions, enums, and declarations either from files listed as
|
||||
@@ -100,6 +102,10 @@
|
||||
\li To expand and collapse the list of all instances, click the
|
||||
\inlineimage qtcreator-expand.png
|
||||
(\uicontrol {Expand All}) button.
|
||||
\li To filter the search results for the usage of symbols according to
|
||||
access type, such as read, write, or declaration, click the
|
||||
\inlineimage filtericon.png
|
||||
(\uicontrol {Filter Tree}) button and select the access type.
|
||||
\li To clear the search results, click the
|
||||
\inlineimage clean_pane_small.png
|
||||
(\uicontrol Clear) button.
|
||||
@@ -184,7 +190,8 @@
|
||||
\section1 Creating Functions
|
||||
|
||||
You can apply refactoring actions to implement member functions, insert
|
||||
virtual functions of base classes, and greate getter and setter functions.
|
||||
virtual functions of base classes, create getter and setter functions,
|
||||
and generate constructors.
|
||||
|
||||
\section2 Implementing Member Functions
|
||||
|
||||
@@ -217,6 +224,16 @@
|
||||
for member variables or only a getter or setter.
|
||||
|
||||
\image qtcreator-refactoring-getters-and-setters.png "Getters and Setters dialog"
|
||||
|
||||
\section2 Generating Constructors
|
||||
|
||||
You can apply the \uicontrol {Generate Constructor} refactoring action to
|
||||
create a public, protected, or private constructor for a class. Select the
|
||||
class members to initialize in the constructor. Drag and drop the parameters
|
||||
to specify their order in the constructor.
|
||||
|
||||
\image qtcreator-refactoring-constructor.png "Constructor dialog"
|
||||
|
||||
\endif
|
||||
|
||||
\section1 Summary of Refactoring Actions
|
||||
@@ -668,6 +685,10 @@
|
||||
\li Creates either both getter and setter member functions for
|
||||
member variables or only a getter or setter.
|
||||
\li Member variable in class definition
|
||||
\row
|
||||
\li Generate Constructor
|
||||
\li Creates a constructor for a class.
|
||||
\li Class definition
|
||||
\row
|
||||
\li Move Function Definition
|
||||
\li Moves a function definition to the implementation file, outside
|
||||
|
@@ -139,7 +139,10 @@ ScrollView {
|
||||
bottomPadding: 0
|
||||
expanded: importExpanded
|
||||
expandOnClick: false
|
||||
onToggleExpand: importExpanded = !importExpanded
|
||||
onToggleExpand: {
|
||||
if (categoryModel.rowCount() > 0)
|
||||
importExpanded = !importExpanded
|
||||
}
|
||||
onShowContextMenu: {
|
||||
importToRemove = importUsed ? "" : importUrl
|
||||
contextMenu.popup()
|
||||
|
@@ -989,6 +989,21 @@ protected:
|
||||
out("const ");
|
||||
}
|
||||
}
|
||||
switch (ast->type) {
|
||||
case PatternElement::Literal:
|
||||
case PatternElement::Method:
|
||||
case PatternElement::Binding:
|
||||
break;
|
||||
case PatternElement::Getter:
|
||||
out("get ");
|
||||
break;
|
||||
case PatternElement::Setter:
|
||||
out("set ");
|
||||
break;
|
||||
case PatternElement::SpreadElement:
|
||||
out("...");
|
||||
break;
|
||||
}
|
||||
out(ast->identifierToken);
|
||||
if (ast->initializer) {
|
||||
if (ast->isVariableDeclaration())
|
||||
@@ -1312,6 +1327,8 @@ protected:
|
||||
bool visit(ArgumentList *ast) override
|
||||
{
|
||||
for (ArgumentList *it = ast; it; it = it->next) {
|
||||
if (it->isSpreadElement)
|
||||
out("...");
|
||||
accept(it->expression);
|
||||
if (it->next) {
|
||||
out(", ", it->commaToken);
|
||||
|
@@ -403,7 +403,7 @@ AndroidDeviceInfoList AvdManagerOutputParser::listVirtualDevices(const AndroidCo
|
||||
avdList = parseAvdList(output);
|
||||
} while (output.contains(avdManufacturerError));
|
||||
|
||||
for (const QString &avdPathStr : avdErrorPaths)
|
||||
for (const QString &avdPathStr : qAsConst(avdErrorPaths))
|
||||
AvdConfigEditManufacturerTag(avdPathStr, true);
|
||||
|
||||
return avdList;
|
||||
|
@@ -1494,7 +1494,7 @@ FilePath AndroidConfig::getJdkPath()
|
||||
#endif // Q_OS_WIN
|
||||
}
|
||||
|
||||
for (const QString &version : allVersions) {
|
||||
for (const QString &version : qAsConst(allVersions)) {
|
||||
settings->beginGroup(version);
|
||||
jdkHome = FilePath::fromUserInput(settings->value("JavaHome").toString());
|
||||
settings->endGroup();
|
||||
|
@@ -538,7 +538,7 @@ void AndroidRunnerWorker::asyncStartHelper()
|
||||
forceStop();
|
||||
asyncStartLogcat();
|
||||
|
||||
for (const QString &entry : m_beforeStartAdbCommands)
|
||||
for (const QString &entry : qAsConst(m_beforeStartAdbCommands))
|
||||
runAdb(entry.split(' ', Qt::SkipEmptyParts));
|
||||
|
||||
QStringList args({"shell", "am", "start"});
|
||||
@@ -825,7 +825,7 @@ void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
|
||||
m_debugServerProcess.reset();
|
||||
|
||||
// Run adb commands after application quit.
|
||||
for (const QString &entry: m_afterFinishAdbCommands)
|
||||
for (const QString &entry: qAsConst(m_afterFinishAdbCommands))
|
||||
runAdb(entry.split(' ', Qt::SkipEmptyParts));
|
||||
} else {
|
||||
// In debugging cases this will be funneled to the engine to actually start
|
||||
|
@@ -566,7 +566,7 @@ void SdkManagerOutputParser::compilePackageAssociations()
|
||||
deleteAlreadyInstalled(images);
|
||||
|
||||
// Associate the system images with sdk platforms.
|
||||
for (AndroidSdkPackage *image : images) {
|
||||
for (AndroidSdkPackage *image : qAsConst(images)) {
|
||||
int imageApi = m_systemImages[image];
|
||||
auto itr = std::find_if(m_packages.begin(), m_packages.end(),
|
||||
[imageApi](const AndroidSdkPackage *p) {
|
||||
@@ -1151,7 +1151,7 @@ void AndroidSdkManagerPrivate::parseCommonArguments(QFutureInterface<QString> &f
|
||||
|
||||
void AndroidSdkManagerPrivate::clearPackages()
|
||||
{
|
||||
for (AndroidSdkPackage *p : m_allPackages)
|
||||
for (AndroidSdkPackage *p : qAsConst(m_allPackages))
|
||||
delete p;
|
||||
m_allPackages.clear();
|
||||
}
|
||||
|
@@ -298,7 +298,7 @@ void AndroidSdkModel::selectMissingEssentials()
|
||||
}
|
||||
|
||||
// Select SDK platform
|
||||
for (const SdkPlatform *platform : m_sdkPlatforms) {
|
||||
for (const SdkPlatform *platform : qAsConst(m_sdkPlatforms)) {
|
||||
if (!platform->installedLocation().isEmpty()) {
|
||||
pendingPkgs.removeOne(platform->sdkStylePath());
|
||||
} else if (pendingPkgs.contains(platform->sdkStylePath()) &&
|
||||
|
@@ -154,7 +154,7 @@ SdkPlatform::SdkPlatform(QVersionNumber version, QString sdkStylePathStr, int ap
|
||||
|
||||
SdkPlatform::~SdkPlatform()
|
||||
{
|
||||
for (SystemImage *image : m_systemImages)
|
||||
for (SystemImage *image : qAsConst(m_systemImages))
|
||||
delete image;
|
||||
m_systemImages.clear();
|
||||
}
|
||||
|
@@ -177,7 +177,7 @@ void AvdDialog::updateDeviceDefinitionComboBox()
|
||||
m_avdDialog.deviceDefinitionTypeComboBox->currentText());
|
||||
|
||||
m_avdDialog.deviceDefinitionComboBox->clear();
|
||||
for (const DeviceDefinitionStruct &item : m_deviceDefinitionsList) {
|
||||
for (const DeviceDefinitionStruct &item : qAsConst(m_deviceDefinitionsList)) {
|
||||
if (item.deviceType == curDeviceType)
|
||||
m_avdDialog.deviceDefinitionComboBox->addItem(item.name_id);
|
||||
}
|
||||
@@ -231,7 +231,7 @@ void AvdDialog::updateApiLevelComboBox()
|
||||
});
|
||||
|
||||
m_avdDialog.targetApiComboBox->clear();
|
||||
for (SystemImage *image : filteredList) {
|
||||
for (SystemImage *image : qAsConst(filteredList)) {
|
||||
QString imageString = "android-" % QString::number(image->apiLevel());
|
||||
const QStringList imageSplits = image->sdkStylePath().split(';');
|
||||
if (imageSplits.size() == 4)
|
||||
|
@@ -25,12 +25,21 @@
|
||||
|
||||
#include "javalanguageserver.h"
|
||||
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidconstants.h"
|
||||
#include "androidmanager.h"
|
||||
|
||||
#include <languageclient/client.h>
|
||||
#include <languageclient/languageclientinterface.h>
|
||||
#include <languageclient/languageclientutils.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectnodes.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
#include <utils/environment.h>
|
||||
#include <utils/pathchooser.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
#include <utils/variablechooser.h>
|
||||
|
||||
#include <QGridLayout>
|
||||
@@ -39,7 +48,6 @@
|
||||
using namespace Utils;
|
||||
|
||||
constexpr char languageServerKey[] = "languageServer";
|
||||
constexpr char workspaceKey[] = "workspace";
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
@@ -67,7 +75,6 @@ JLSSettingsWidget::JLSSettingsWidget(const JLSSettings *settings, QWidget *paren
|
||||
, m_name(new QLineEdit(settings->m_name, this))
|
||||
, m_java(new PathChooser(this))
|
||||
, m_ls(new PathChooser(this))
|
||||
, m_workspace(new PathChooser(this))
|
||||
{
|
||||
int row = 0;
|
||||
auto *mainLayout = new QGridLayout;
|
||||
@@ -88,11 +95,6 @@ JLSSettingsWidget::JLSSettingsWidget(const JLSSettings *settings, QWidget *paren
|
||||
m_ls->setPath(QDir::toNativeSeparators(settings->m_languageServer));
|
||||
mainLayout->addWidget(m_ls, row, 1);
|
||||
|
||||
mainLayout->addWidget(new QLabel(tr("Workspace:")), ++row, 0);
|
||||
m_workspace->setExpectedKind(Utils::PathChooser::Directory);
|
||||
m_workspace->setPath(QDir::toNativeSeparators(settings->m_workspace));
|
||||
mainLayout->addWidget(m_workspace, row, 1);
|
||||
|
||||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
@@ -117,9 +119,6 @@ bool JLSSettings::applyFromSettingsWidget(QWidget *widget)
|
||||
changed |= m_languageServer != jlswidget->languageServer();
|
||||
m_languageServer = jlswidget->languageServer();
|
||||
|
||||
changed |= m_workspace != jlswidget->workspace();
|
||||
m_workspace = jlswidget->workspace();
|
||||
|
||||
changed |= m_executable != jlswidget->java();
|
||||
m_executable = jlswidget->java();
|
||||
|
||||
@@ -130,8 +129,7 @@ bool JLSSettings::applyFromSettingsWidget(QWidget *widget)
|
||||
"-noverify "
|
||||
"-Xmx1G "
|
||||
"-jar \"%1\" "
|
||||
"-configuration \"%2\" "
|
||||
"-data \"%3\"";
|
||||
"-configuration \"%2\"";
|
||||
|
||||
QFileInfo languageServerFileInfo(m_languageServer);
|
||||
QDir configDir = languageServerFileInfo.absoluteDir();
|
||||
@@ -145,7 +143,7 @@ bool JLSSettings::applyFromSettingsWidget(QWidget *widget)
|
||||
configDir.cd("config_mac");
|
||||
}
|
||||
if (configDir.exists()) {
|
||||
arguments = arguments.arg(m_languageServer, configDir.absolutePath(), m_workspace);
|
||||
arguments = arguments.arg(m_languageServer, configDir.absolutePath());
|
||||
changed |= m_arguments != arguments;
|
||||
m_arguments = arguments;
|
||||
}
|
||||
@@ -159,14 +157,13 @@ QWidget *JLSSettings::createSettingsWidget(QWidget *parent) const
|
||||
|
||||
bool JLSSettings::isValid() const
|
||||
{
|
||||
return StdIOSettings::isValid() && !m_languageServer.isEmpty() && !m_workspace.isEmpty();
|
||||
return StdIOSettings::isValid() && !m_languageServer.isEmpty();
|
||||
}
|
||||
|
||||
QVariantMap JLSSettings::toMap() const
|
||||
{
|
||||
QVariantMap map = StdIOSettings::toMap();
|
||||
map.insert(languageServerKey, m_languageServer);
|
||||
map.insert(workspaceKey, m_workspace);
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -174,7 +171,6 @@ void JLSSettings::fromMap(const QVariantMap &map)
|
||||
{
|
||||
StdIOSettings::fromMap(map);
|
||||
m_languageServer = map[languageServerKey].toString();
|
||||
m_workspace = map[workspaceKey].toString();
|
||||
}
|
||||
|
||||
LanguageClient::BaseSettings *JLSSettings::copy() const
|
||||
@@ -182,12 +178,39 @@ LanguageClient::BaseSettings *JLSSettings::copy() const
|
||||
return new JLSSettings(*this);
|
||||
}
|
||||
|
||||
class JLSInterface : public LanguageClient::StdIOClientInterface
|
||||
{
|
||||
public:
|
||||
JLSInterface() = default;
|
||||
|
||||
QString workspaceDir() const { return m_workspaceDir.path(); }
|
||||
|
||||
private:
|
||||
TemporaryDirectory m_workspaceDir = TemporaryDirectory("QtCreator-jls-XXXXXX");
|
||||
};
|
||||
|
||||
LanguageClient::BaseClientInterface *JLSSettings::createInterface() const
|
||||
{
|
||||
auto interface = new JLSInterface();
|
||||
interface->setExecutable(m_executable);
|
||||
QString arguments = this->arguments();
|
||||
arguments += QString(" -data \"%1\"").arg(interface->workspaceDir());
|
||||
interface->setArguments(arguments);
|
||||
return interface;
|
||||
}
|
||||
|
||||
class JLSClient : public LanguageClient::Client
|
||||
{
|
||||
public:
|
||||
using Client::Client;
|
||||
|
||||
void executeCommand(const LanguageServerProtocol::Command &command) override;
|
||||
void setCurrentProject(ProjectExplorer::Project *project) override;
|
||||
void updateProjectFiles();
|
||||
void updateTarget(ProjectExplorer::Target *target);
|
||||
|
||||
private:
|
||||
ProjectExplorer::Target *m_currentTarget = nullptr;
|
||||
};
|
||||
|
||||
void JLSClient::executeCommand(const LanguageServerProtocol::Command &command)
|
||||
@@ -206,6 +229,127 @@ void JLSClient::executeCommand(const LanguageServerProtocol::Command &command)
|
||||
}
|
||||
}
|
||||
|
||||
void JLSClient::setCurrentProject(ProjectExplorer::Project *project)
|
||||
{
|
||||
Client::setCurrentProject(project);
|
||||
QTC_ASSERT(project, return);
|
||||
updateTarget(project->activeTarget());
|
||||
updateProjectFiles();
|
||||
connect(project, &ProjectExplorer::Project::activeTargetChanged,
|
||||
this, &JLSClient::updateTarget);
|
||||
}
|
||||
|
||||
static void generateProjectFile(const FilePath &projectDir,
|
||||
const QString &qtSrc,
|
||||
const QString &projectName)
|
||||
{
|
||||
const FilePath projectFilePath = projectDir.pathAppended(".project");
|
||||
QFile projectFile(projectFilePath.toString());
|
||||
if (projectFile.open(QFile::Truncate | QFile::WriteOnly)) {
|
||||
QXmlStreamWriter writer(&projectFile);
|
||||
writer.setAutoFormatting(true);
|
||||
writer.writeStartDocument();
|
||||
writer.writeComment("Autogenerated by Qt Creator. "
|
||||
"Changes to this file will not be taken into account.");
|
||||
writer.writeStartElement("projectDescription");
|
||||
writer.writeTextElement("name", projectName);
|
||||
writer.writeStartElement("natures");
|
||||
writer.writeTextElement("nature", "org.eclipse.jdt.core.javanature");
|
||||
writer.writeEndElement(); // natures
|
||||
writer.writeStartElement("linkedResources");
|
||||
writer.writeStartElement("link");
|
||||
writer.writeTextElement("name", "qtSrc");
|
||||
writer.writeTextElement("type", "2");
|
||||
writer.writeTextElement("location", qtSrc);
|
||||
writer.writeEndElement(); // link
|
||||
writer.writeEndElement(); // linkedResources
|
||||
writer.writeEndElement(); // projectDescription
|
||||
writer.writeEndDocument();
|
||||
projectFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
static void generateClassPathFile(const FilePath &projectDir,
|
||||
const QString &sourceDir,
|
||||
const QStringList &libs)
|
||||
{
|
||||
const FilePath classPathFilePath = projectDir.pathAppended(".classpath");
|
||||
QFile classPathFile(classPathFilePath.toString());
|
||||
if (classPathFile.open(QFile::Truncate | QFile::WriteOnly)) {
|
||||
QXmlStreamWriter writer(&classPathFile);
|
||||
writer.setAutoFormatting(true);
|
||||
writer.writeStartDocument();
|
||||
writer.writeComment("Autogenerated by Qt Creator. "
|
||||
"Changes to this file will not be taken into account.");
|
||||
writer.writeStartElement("classpath");
|
||||
writer.writeEmptyElement("classpathentry");
|
||||
writer.writeAttribute("kind", "src");
|
||||
writer.writeAttribute("path", sourceDir);
|
||||
writer.writeEmptyElement("classpathentry");
|
||||
writer.writeAttribute("kind", "src");
|
||||
writer.writeAttribute("path", "qtSrc");
|
||||
for (const QString &lib : libs) {
|
||||
writer.writeEmptyElement("classpathentry");
|
||||
writer.writeAttribute("kind", "lib");
|
||||
writer.writeAttribute("path", lib);
|
||||
}
|
||||
writer.writeEndElement(); // classpath
|
||||
writer.writeEndDocument();
|
||||
classPathFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void JLSClient::updateProjectFiles()
|
||||
{
|
||||
using namespace ProjectExplorer;
|
||||
if (!m_currentTarget)
|
||||
return;
|
||||
if (Target *target = m_currentTarget) {
|
||||
Kit *kit = m_currentTarget->kit();
|
||||
if (DeviceTypeKitAspect::deviceTypeId(kit) != Android::Constants::ANDROID_DEVICE_TYPE)
|
||||
return;
|
||||
if (ProjectNode *node = project()->findNodeForBuildKey(target->activeBuildKey())) {
|
||||
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit);
|
||||
if (!version)
|
||||
return;
|
||||
const QString qtSrc = version->prefix().toString() + "/src/android/java/src";
|
||||
const FilePath &projectDir = project()->rootProjectDirectory();
|
||||
if (!projectDir.exists())
|
||||
return;
|
||||
const FilePath packageSourceDir = FilePath::fromVariant(
|
||||
node->data(Constants::AndroidPackageSourceDir));
|
||||
FilePath sourceDir = packageSourceDir.pathAppended("src");
|
||||
if (!sourceDir.exists())
|
||||
return;
|
||||
sourceDir = sourceDir.relativeChildPath(projectDir);
|
||||
const FilePath &sdkLocation = AndroidConfigurations::currentConfig().sdkLocation();
|
||||
const QString &targetSDK = AndroidManager::buildTargetSDK(m_currentTarget);
|
||||
const QString androidJar = QString("%1/platforms/%2/android.jar")
|
||||
.arg(sdkLocation.toString(), targetSDK);
|
||||
QStringList libs(androidJar);
|
||||
QDir libDir(packageSourceDir.pathAppended("libs").toString());
|
||||
libs << Utils::transform(libDir.entryInfoList({"*.jar"}, QDir::Files),
|
||||
&QFileInfo::absoluteFilePath);
|
||||
generateProjectFile(projectDir, qtSrc, project()->displayName());
|
||||
generateClassPathFile(projectDir, sourceDir.toString(), libs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JLSClient::updateTarget(ProjectExplorer::Target *target)
|
||||
{
|
||||
if (m_currentTarget) {
|
||||
disconnect(m_currentTarget, &ProjectExplorer::Target::parsingFinished,
|
||||
this, &JLSClient::updateProjectFiles);
|
||||
}
|
||||
m_currentTarget = target;
|
||||
if (m_currentTarget) {
|
||||
connect(m_currentTarget, &ProjectExplorer::Target::parsingFinished,
|
||||
this, &JLSClient::updateProjectFiles);
|
||||
}
|
||||
updateProjectFiles();
|
||||
}
|
||||
|
||||
LanguageClient::Client *JLSSettings::createClient(LanguageClient::BaseClientInterface *interface) const
|
||||
{
|
||||
return new JLSClient(interface);
|
||||
|
@@ -42,9 +42,9 @@ public:
|
||||
void fromMap(const QVariantMap &map) final;
|
||||
LanguageClient::BaseSettings *copy() const final;
|
||||
LanguageClient::Client *createClient(LanguageClient::BaseClientInterface *interface) const final;
|
||||
LanguageClient::BaseClientInterface *createInterface() const override;
|
||||
|
||||
QString m_languageServer;
|
||||
QString m_workspace;
|
||||
|
||||
private:
|
||||
JLSSettings(const JLSSettings &other) = default;
|
||||
|
@@ -128,7 +128,7 @@ void ClangToolsUnitTests::testProject()
|
||||
QVERIFY(waitForFinishedTool.wait(m_timeout));
|
||||
|
||||
// Check for errors
|
||||
const QString errorText = waitForFinishedTool.takeFirst().first().toString();
|
||||
const QString errorText = waitForFinishedTool.takeFirst().constFirst().toString();
|
||||
const bool finishedSuccessfully = errorText.isEmpty();
|
||||
if (!finishedSuccessfully)
|
||||
qWarning("Error: %s", qPrintable(errorText));
|
||||
|
@@ -245,7 +245,7 @@ static FilePath qmakeFromCMakeCache(const CMakeConfig &config)
|
||||
if (!qmakeLocationTxt.open(QIODevice::ReadOnly)) {
|
||||
return FilePath();
|
||||
}
|
||||
FilePath qmakeLocation = FilePath::fromUtf8(qmakeLocationTxt.readLine().data());
|
||||
FilePath qmakeLocation = FilePath::fromUtf8(qmakeLocationTxt.readLine().constData());
|
||||
qCDebug(cmInputLog) << "qmake location: " << qmakeLocation.toUserOutput();
|
||||
|
||||
return qmakeLocation;
|
||||
|
@@ -100,6 +100,13 @@ Client::Client(BaseClientInterface *clientInterface)
|
||||
&Client::rehighlight);
|
||||
}
|
||||
|
||||
QString Client::name() const
|
||||
{
|
||||
if (m_project && !m_project->displayName().isEmpty())
|
||||
return tr("%1 for %2").arg(m_displayName, m_project->displayName());
|
||||
return m_displayName;
|
||||
}
|
||||
|
||||
static void updateEditorToolBar(QList<TextEditor::TextDocument *> documents)
|
||||
{
|
||||
for (TextEditor::TextDocument *document : documents) {
|
||||
@@ -790,16 +797,7 @@ void Client::projectOpened(ProjectExplorer::Project *project)
|
||||
|
||||
void Client::projectClosed(ProjectExplorer::Project *project)
|
||||
{
|
||||
if (project == m_project) {
|
||||
if (m_state == Initialized) {
|
||||
shutdown();
|
||||
} else {
|
||||
m_state = Shutdown; // otherwise the manager would try to restart this server
|
||||
emit finished();
|
||||
}
|
||||
}
|
||||
if (!sendWorkspceFolderChanges())
|
||||
return;
|
||||
if (sendWorkspceFolderChanges()) {
|
||||
WorkspaceFoldersChangeEvent event;
|
||||
event.setRemoved({WorkSpaceFolder(DocumentUri::fromFilePath(project->projectDirectory()),
|
||||
project->displayName())});
|
||||
@@ -808,6 +806,16 @@ void Client::projectClosed(ProjectExplorer::Project *project)
|
||||
DidChangeWorkspaceFoldersNotification change(params);
|
||||
sendContent(change);
|
||||
}
|
||||
if (project == m_project) {
|
||||
if (m_state == Initialized) {
|
||||
shutdown();
|
||||
} else {
|
||||
m_state = Shutdown; // otherwise the manager would try to restart this server
|
||||
emit finished();
|
||||
}
|
||||
m_project = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::setSupportedLanguage(const LanguageFilter &filter)
|
||||
{
|
||||
@@ -1260,6 +1268,8 @@ void Client::shutDownCallback(const ShutdownRequest::Response &shutdownResponse)
|
||||
|
||||
bool Client::sendWorkspceFolderChanges() const
|
||||
{
|
||||
if (!reachable())
|
||||
return false;
|
||||
if (m_dynamicCapabilities.isRegistered(
|
||||
DidChangeWorkspaceFoldersNotification::methodName).value_or(false)) {
|
||||
return true;
|
||||
|
@@ -87,7 +87,7 @@ public:
|
||||
// basic properties
|
||||
Utils::Id id() const { return m_id; }
|
||||
void setName(const QString &name) { m_displayName = name; }
|
||||
QString name() const { return m_displayName; }
|
||||
QString name() const;
|
||||
void sendContent(const LanguageServerProtocol::IContent &content);
|
||||
void cancelRequest(const LanguageServerProtocol::MessageId &id);
|
||||
|
||||
@@ -134,10 +134,10 @@ public:
|
||||
bool documentUpdatePostponed(const Utils::FilePath &fileName) const;
|
||||
|
||||
// workspace control
|
||||
void setCurrentProject(ProjectExplorer::Project *project);
|
||||
virtual void setCurrentProject(ProjectExplorer::Project *project);
|
||||
const ProjectExplorer::Project *project() const;
|
||||
void projectOpened(ProjectExplorer::Project *project);
|
||||
void projectClosed(ProjectExplorer::Project *project);
|
||||
virtual void projectOpened(ProjectExplorer::Project *project);
|
||||
virtual void projectClosed(ProjectExplorer::Project *project);
|
||||
|
||||
// commands
|
||||
void requestCodeActions(const LanguageServerProtocol::DocumentUri &uri,
|
||||
|
@@ -89,9 +89,7 @@ void BaseClientInterface::parseData(const QByteArray &data)
|
||||
}
|
||||
}
|
||||
|
||||
StdIOClientInterface::StdIOClientInterface(const QString &executable, const QString &arguments)
|
||||
: m_executable(executable)
|
||||
, m_arguments(arguments)
|
||||
StdIOClientInterface::StdIOClientInterface()
|
||||
{
|
||||
connect(&m_process, &QProcess::readyReadStandardError,
|
||||
this, &StdIOClientInterface::readError);
|
||||
@@ -99,9 +97,6 @@ StdIOClientInterface::StdIOClientInterface(const QString &executable, const QStr
|
||||
this, &StdIOClientInterface::readOutput);
|
||||
connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
this, &StdIOClientInterface::onProcessFinished);
|
||||
|
||||
m_process.setArguments(Utils::QtcProcess::splitArgs(m_arguments));
|
||||
m_process.setProgram(m_executable);
|
||||
}
|
||||
|
||||
StdIOClientInterface::~StdIOClientInterface()
|
||||
@@ -109,11 +104,6 @@ StdIOClientInterface::~StdIOClientInterface()
|
||||
Utils::SynchronousProcess::stopProcess(m_process);
|
||||
}
|
||||
|
||||
bool StdIOClientInterface::needsRestart(const StdIOSettings *settings) const
|
||||
{
|
||||
return m_executable != settings->m_executable || m_arguments != settings->arguments();
|
||||
}
|
||||
|
||||
bool StdIOClientInterface::start()
|
||||
{
|
||||
m_process.start();
|
||||
@@ -124,6 +114,16 @@ bool StdIOClientInterface::start()
|
||||
return true;
|
||||
}
|
||||
|
||||
void StdIOClientInterface::setExecutable(const QString &executable)
|
||||
{
|
||||
m_process.setProgram(executable);
|
||||
}
|
||||
|
||||
void StdIOClientInterface::setArguments(const QString &arguments)
|
||||
{
|
||||
m_process.setArguments(Utils::QtcProcess::splitArgs(arguments));
|
||||
}
|
||||
|
||||
void StdIOClientInterface::setWorkingDirectory(const QString &workingDirectory)
|
||||
{
|
||||
m_process.setWorkingDirectory(workingDirectory);
|
||||
|
@@ -25,6 +25,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "languageclient_global.h"
|
||||
|
||||
#include <languageserverprotocol/basemessage.h>
|
||||
|
||||
#include <QBuffer>
|
||||
@@ -34,13 +36,13 @@ namespace LanguageClient {
|
||||
|
||||
class StdIOSettings;
|
||||
|
||||
class BaseClientInterface : public QObject
|
||||
class LANGUAGECLIENT_EXPORT BaseClientInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BaseClientInterface();
|
||||
|
||||
virtual ~BaseClientInterface();
|
||||
~BaseClientInterface() override;
|
||||
|
||||
void sendMessage(const LanguageServerProtocol::BaseMessage &message);
|
||||
virtual bool start() { return true; }
|
||||
@@ -61,23 +63,23 @@ private:
|
||||
LanguageServerProtocol::BaseMessage m_currentMessage;
|
||||
};
|
||||
|
||||
class StdIOClientInterface : public BaseClientInterface
|
||||
class LANGUAGECLIENT_EXPORT StdIOClientInterface : public BaseClientInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
StdIOClientInterface(const QString &executable, const QString &arguments);
|
||||
StdIOClientInterface();
|
||||
~StdIOClientInterface() override;
|
||||
|
||||
StdIOClientInterface() = delete;
|
||||
StdIOClientInterface(const StdIOClientInterface &) = delete;
|
||||
StdIOClientInterface(StdIOClientInterface &&) = delete;
|
||||
StdIOClientInterface &operator=(const StdIOClientInterface &) = delete;
|
||||
StdIOClientInterface &operator=(StdIOClientInterface &&) = delete;
|
||||
|
||||
bool needsRestart(const StdIOSettings *settings) const;
|
||||
|
||||
bool start() override;
|
||||
|
||||
// These functions only have an effect if they are called before start
|
||||
void setExecutable(const QString &executable);
|
||||
void setArguments(const QString &arguments);
|
||||
void setWorkingDirectory(const QString &workingDirectory);
|
||||
|
||||
protected:
|
||||
@@ -88,9 +90,6 @@ private:
|
||||
void readError();
|
||||
void readOutput();
|
||||
void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
const QString m_executable;
|
||||
const QString m_arguments;
|
||||
};
|
||||
|
||||
} // namespace LanguageClient
|
||||
|
@@ -472,13 +472,17 @@ void LanguageClientManager::documentOpened(Core::IDocument *document)
|
||||
continue;
|
||||
|
||||
// check whether we already have a client running for this project
|
||||
if (Utils::findOrDefault(clients,
|
||||
[project](const QPointer<Client> &client) {
|
||||
return client->project() == project;
|
||||
})) {
|
||||
continue;
|
||||
Client *clientForProject = Utils::findOrDefault(clients,
|
||||
[project](Client *client) {
|
||||
return client->project()
|
||||
== project;
|
||||
});
|
||||
if (!clientForProject) {
|
||||
clientForProject = startClient(setting, project);
|
||||
clients << clientForProject;
|
||||
}
|
||||
clients << startClient(setting, project);
|
||||
QTC_ASSERT(clientForProject, continue);
|
||||
openDocumentWithClient(textDocument, clientForProject);
|
||||
}
|
||||
} else if (setting->m_startBehavior == BaseSettings::RequiresFile && clients.isEmpty()) {
|
||||
clients << startClient(setting);
|
||||
|
@@ -722,7 +722,10 @@ Utils::CommandLine StdIOSettings::command() const
|
||||
|
||||
BaseClientInterface *StdIOSettings::createInterface() const
|
||||
{
|
||||
return new StdIOClientInterface(m_executable, arguments());
|
||||
auto interface = new StdIOClientInterface;
|
||||
interface->setExecutable(m_executable);
|
||||
interface->setArguments(arguments());
|
||||
return interface;
|
||||
}
|
||||
|
||||
class JsonTreeItemDelegate : public QStyledItemDelegate
|
||||
|
@@ -62,7 +62,7 @@ void OutputParserTester::testParsing(const QString &lines,
|
||||
{
|
||||
const auto terminator = new TestTerminator(this);
|
||||
if (!lineParsers().isEmpty())
|
||||
terminator->setRedirectionDetector(lineParsers().last());
|
||||
terminator->setRedirectionDetector(lineParsers().constLast());
|
||||
addLineParser(terminator);
|
||||
reset();
|
||||
|
||||
@@ -113,7 +113,7 @@ TestTerminator::TestTerminator(OutputParserTester *t) :
|
||||
m_tester(t)
|
||||
{
|
||||
if (!t->lineParsers().isEmpty()) {
|
||||
for (const Utils::FilePath &searchDir : t->lineParsers().first()->searchDirectories())
|
||||
for (const Utils::FilePath &searchDir : t->lineParsers().constFirst()->searchDirectories())
|
||||
addSearchDir(searchDir);
|
||||
}
|
||||
}
|
||||
|
@@ -96,6 +96,18 @@ QHash<int, QByteArray> ItemLibraryCategoriesModel::roleNames() const
|
||||
return m_roleNames;
|
||||
}
|
||||
|
||||
void ItemLibraryCategoriesModel::expandCategories(bool expand)
|
||||
{
|
||||
int i = 0;
|
||||
for (const auto &category : std::as_const(m_categoryList)) {
|
||||
if (category->categoryExpanded() != expand) {
|
||||
category->setExpanded(expand);
|
||||
emit dataChanged(index(i), index(i), {m_roleNames.key("categoryExpanded")});
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void ItemLibraryCategoriesModel::addCategory(ItemLibraryCategory *category)
|
||||
{
|
||||
m_categoryList.append(category);
|
||||
|
@@ -48,6 +48,7 @@ public:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
void addCategory(ItemLibraryCategory *category);
|
||||
void expandCategories(bool expand = true);
|
||||
|
||||
const QList<QPointer<ItemLibraryCategory>> &categorySections() const;
|
||||
|
||||
|
@@ -78,6 +78,10 @@ bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool *
|
||||
hasVisibleItems = true;
|
||||
}
|
||||
|
||||
// expand category if it has an item matching search criteria
|
||||
if (hasVisibleItems && !categoryExpanded())
|
||||
setExpanded(true);
|
||||
|
||||
return hasVisibleItems;
|
||||
}
|
||||
|
||||
|
@@ -80,25 +80,28 @@ QObject *ItemLibraryImport::categoryModel()
|
||||
return &m_categoryModel;
|
||||
}
|
||||
|
||||
void ItemLibraryImport::expandCategories(bool expand)
|
||||
{
|
||||
m_categoryModel.expandCategories(expand);
|
||||
}
|
||||
|
||||
bool ItemLibraryImport::updateCategoryVisibility(const QString &searchText, bool *changed)
|
||||
{
|
||||
bool hasVisibleItems = false;
|
||||
|
||||
bool hasVisibleCategories = false;
|
||||
*changed = false;
|
||||
|
||||
for (const auto &category : m_categoryModel.categorySections()) {
|
||||
bool categoryChanged = false;
|
||||
hasVisibleItems = category->updateItemVisibility(searchText, &categoryChanged);
|
||||
bool hasVisibleItems = category->updateItemVisibility(searchText, &categoryChanged);
|
||||
categoryChanged |= category->setVisible(hasVisibleItems);
|
||||
|
||||
*changed |= categoryChanged;
|
||||
*changed |= hasVisibleItems;
|
||||
|
||||
if (hasVisibleItems)
|
||||
hasVisibleCategories = true;
|
||||
}
|
||||
|
||||
if (*changed)
|
||||
m_categoryModel.resetModel();
|
||||
|
||||
return hasVisibleItems;
|
||||
return hasVisibleCategories;
|
||||
}
|
||||
|
||||
Import ItemLibraryImport::importEntry() const
|
||||
|
@@ -63,6 +63,7 @@ public:
|
||||
void setImportUsed(bool importUsed);
|
||||
void sortCategorySections();
|
||||
void setImportExpanded(bool expanded = true);
|
||||
void expandCategories(bool expand = true);
|
||||
|
||||
static QString userComponentsTitle();
|
||||
|
||||
|
@@ -61,34 +61,28 @@ bool ItemLibraryModel::loadExpandedState(const QString §ionName)
|
||||
|
||||
void ItemLibraryModel::expandAll()
|
||||
{
|
||||
bool changed = false;
|
||||
int i = 0;
|
||||
for (const QPointer<ItemLibraryImport> &import : std::as_const(m_importList)) {
|
||||
if (import->hasCategories() && !import->importExpanded()) {
|
||||
changed = true;
|
||||
if (!import->importExpanded()) {
|
||||
import->setImportExpanded();
|
||||
emit dataChanged(index(i), index(i), {m_roleNames.key("importExpanded")});
|
||||
saveExpandedState(true, import->importUrl());
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
import->expandCategories(true);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void ItemLibraryModel::collapseAll()
|
||||
{
|
||||
bool changed = false;
|
||||
int i = 0;
|
||||
for (const QPointer<ItemLibraryImport> &import : std::as_const(m_importList)) {
|
||||
if (import->hasCategories() && import->importExpanded()) {
|
||||
changed = true;
|
||||
import->setImportExpanded(false);
|
||||
emit dataChanged(index(i), index(i), {m_roleNames.key("importExpanded")});
|
||||
saveExpandedState(false, import->importUrl());
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,9 +323,18 @@ void ItemLibraryModel::updateVisibility(bool *changed)
|
||||
{
|
||||
for (ItemLibraryImport *import : std::as_const(m_importList)) {
|
||||
bool categoryChanged = false;
|
||||
import->updateCategoryVisibility(m_searchText, &categoryChanged);
|
||||
bool hasVisibleItems = import->updateCategoryVisibility(m_searchText, &categoryChanged);
|
||||
|
||||
*changed |= categoryChanged;
|
||||
|
||||
// expand import if it has an item matching search criteria
|
||||
if (hasVisibleItems && !import->importExpanded())
|
||||
import->setImportExpanded();
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -275,6 +275,7 @@ void ItemLibraryWidget::handleAddImport(int index)
|
||||
m_model->changeImports({import}, {});
|
||||
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
|
||||
m_stackedWidget->setCurrentIndex(0); // switch to the Components view after import is added
|
||||
updateSearch();
|
||||
}
|
||||
|
||||
void ItemLibraryWidget::delayedUpdateModel()
|
||||
|
@@ -134,7 +134,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void storeIcon(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QIcon &icon)
|
||||
void storeIcon(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QIcon &icon) override
|
||||
{
|
||||
try {
|
||||
Sqlite::ImmediateTransaction transaction{database};
|
||||
|
@@ -337,7 +337,9 @@ void SubComponentManager::registerQmlFile(const QFileInfo &fileInfo, const QStri
|
||||
ItemLibraryEntry itemLibraryEntry;
|
||||
itemLibraryEntry.setType(componentName.toUtf8());
|
||||
itemLibraryEntry.setName(baseComponentName);
|
||||
#ifndef QMLDESIGNER_TEST
|
||||
itemLibraryEntry.setCategory(ItemLibraryImport::userComponentsTitle());
|
||||
#endif
|
||||
itemLibraryEntry.setCustomComponentSource(fileInfo.absoluteFilePath());
|
||||
if (!qualifier.isEmpty()) {
|
||||
itemLibraryEntry.setRequiredImport(fixedQualifier);
|
||||
|
@@ -12,6 +12,17 @@ function foo(a, b) {
|
||||
|
||||
var foo = function (a, b) {}
|
||||
|
||||
function spread() {
|
||||
iterableObj = [1, 2]
|
||||
obj = {
|
||||
"a": 42
|
||||
}
|
||||
foo(...iterableObj)
|
||||
let arr = [...iterableObj, '4', 'five', 6]
|
||||
foo(-1, ...args, 2, ...[3])
|
||||
console.log(Math.max(...[1, 2, 3, 4]))
|
||||
}
|
||||
|
||||
const func1 = x => x * 2
|
||||
const func2 = x => {
|
||||
return x * 7
|
||||
|