forked from qt-creator/qt-creator
QbsProjectManager: Add a language client
... and use it to follow symbols that QmlJSEditor does not know about. For now, the only implemented case on the server side is getting to a product or module via a Depends item. More functionality will follow. Change-Id: I597c7ab10f4bf6962684ed26357dfc0eef3a6c15 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -2,7 +2,7 @@ add_qtc_plugin(QbsProjectManager
|
||||
DEPENDS Qt::Qml Qt::Widgets QmlJS
|
||||
DEFINES
|
||||
IDE_LIBRARY_BASENAME="${IDE_LIBRARY_BASE_PATH}"
|
||||
PLUGIN_DEPENDS Core ProjectExplorer CppEditor QtSupport QmlJSTools
|
||||
PLUGIN_DEPENDS Core CppEditor LanguageClient ProjectExplorer QmlJSTools QmlJSEditor QtSupport
|
||||
SOURCES
|
||||
customqbspropertiesdialog.cpp customqbspropertiesdialog.h
|
||||
defaultpropertyprovider.cpp defaultpropertyprovider.h
|
||||
@@ -10,8 +10,10 @@ add_qtc_plugin(QbsProjectManager
|
||||
qbsbuildconfiguration.cpp qbsbuildconfiguration.h
|
||||
qbsbuildstep.cpp qbsbuildstep.h
|
||||
qbscleanstep.cpp qbscleanstep.h
|
||||
qbseditor.cpp qbseditor.h
|
||||
qbsinstallstep.cpp qbsinstallstep.h
|
||||
qbskitaspect.cpp qbskitaspect.h
|
||||
qbslanguageclient.cpp qbslanguageclient.h
|
||||
qbsnodes.cpp qbsnodes.h
|
||||
qbsnodetreebuilder.cpp qbsnodetreebuilder.h
|
||||
qbspmlogging.cpp qbspmlogging.h
|
||||
|
||||
60
src/plugins/qbsprojectmanager/qbseditor.cpp
Normal file
60
src/plugins/qbsprojectmanager/qbseditor.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "qbseditor.h"
|
||||
|
||||
#include "qbslanguageclient.h"
|
||||
#include "qbsprojectmanagertr.h"
|
||||
|
||||
#include <languageclient/languageclientmanager.h>
|
||||
#include <utils/mimeconstants.h>
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
using namespace LanguageClient;
|
||||
using namespace QmlJSEditor;
|
||||
using namespace Utils;
|
||||
|
||||
namespace QbsProjectManager::Internal {
|
||||
|
||||
class QbsEditorWidget : public QmlJSEditorWidget
|
||||
{
|
||||
private:
|
||||
void findLinkAt(const QTextCursor &cursor,
|
||||
const LinkHandler &processLinkCallback,
|
||||
bool resolveTarget = true,
|
||||
bool inNextSplit = false) override;
|
||||
};
|
||||
|
||||
QbsEditorFactory::QbsEditorFactory() : QmlJSEditorFactory("QbsEditor.QbsEditor")
|
||||
{
|
||||
setDisplayName(Tr::tr("Qbs Editor"));
|
||||
setMimeTypes({Utils::Constants::QBS_MIMETYPE});
|
||||
setEditorWidgetCreator([] { return new QbsEditorWidget; });
|
||||
}
|
||||
|
||||
void QbsEditorWidget::findLinkAt(const QTextCursor &cursor, const LinkHandler &processLinkCallback,
|
||||
bool resolveTarget, bool inNextSplit)
|
||||
{
|
||||
const LinkHandler extendedCallback = [self = QPointer(this), cursor, processLinkCallback,
|
||||
resolveTarget](const Link &link) {
|
||||
if (link.hasValidTarget())
|
||||
return processLinkCallback(link);
|
||||
if (!self)
|
||||
return;
|
||||
const auto doc = self->textDocument();
|
||||
if (!doc)
|
||||
return;
|
||||
const QList<Client *> &candidates = LanguageClientManager::clientsSupportingDocument(doc);
|
||||
for (Client * const candidate : candidates) {
|
||||
const auto qbsClient = qobject_cast<QbsLanguageClient *>(candidate);
|
||||
if (!qbsClient || !qbsClient->isActive() || !qbsClient->documentOpen(doc))
|
||||
continue;
|
||||
qbsClient->findLinkAt(doc, cursor, processLinkCallback, resolveTarget,
|
||||
LinkTarget::SymbolDef);
|
||||
}
|
||||
};
|
||||
QmlJSEditorWidget::findLinkAt(cursor, extendedCallback, resolveTarget, inNextSplit);
|
||||
}
|
||||
|
||||
} // namespace QbsProjectManager::Internal
|
||||
16
src/plugins/qbsprojectmanager/qbseditor.h
Normal file
16
src/plugins/qbsprojectmanager/qbseditor.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <qmljseditor/qmljseditor.h>
|
||||
|
||||
namespace QbsProjectManager::Internal {
|
||||
|
||||
class QbsEditorFactory : public QmlJSEditor::QmlJSEditorFactory
|
||||
{
|
||||
public:
|
||||
QbsEditorFactory();
|
||||
};
|
||||
|
||||
} // namespace QbsProjectManager::Internal
|
||||
90
src/plugins/qbsprojectmanager/qbslanguageclient.cpp
Normal file
90
src/plugins/qbsprojectmanager/qbslanguageclient.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "qbslanguageclient.h"
|
||||
|
||||
#include "qbsproject.h"
|
||||
#include "qbssettings.h"
|
||||
|
||||
#include <coreplugin/editormanager/documentmodel.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <languageclient/languageclientinterface.h>
|
||||
#include <languageclient/languageclientsettings.h>
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <utils/filepath.h>
|
||||
#include <utils/mimeconstants.h>
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
using namespace Core;
|
||||
using namespace LanguageClient;
|
||||
using namespace TextEditor;
|
||||
using namespace Utils;
|
||||
|
||||
namespace QbsProjectManager::Internal {
|
||||
|
||||
class QbsLanguageClientInterface : public LocalSocketClientInterface
|
||||
{
|
||||
public:
|
||||
QbsLanguageClientInterface(const QString &serverPath)
|
||||
: LocalSocketClientInterface(serverPath),
|
||||
m_qbsExecutable(QbsSettings::qbsExecutableFilePath()) {}
|
||||
|
||||
private:
|
||||
Utils::FilePath serverDeviceTemplate() const override{ return m_qbsExecutable; };
|
||||
|
||||
const FilePath m_qbsExecutable;
|
||||
};
|
||||
|
||||
class QbsLanguageClient::Private
|
||||
{
|
||||
public:
|
||||
Private(QbsLanguageClient * q) : q(q) {}
|
||||
|
||||
void checkDocument(IDocument *document);
|
||||
|
||||
QbsLanguageClient * const q;
|
||||
QPointer<QbsBuildSystem> buildSystem;
|
||||
};
|
||||
|
||||
|
||||
QbsLanguageClient::QbsLanguageClient(const QString &serverPath, QbsBuildSystem *buildSystem)
|
||||
: Client(new QbsLanguageClientInterface(serverPath)), d(new Private(this))
|
||||
{
|
||||
d->buildSystem = buildSystem;
|
||||
setName(QString::fromLatin1("qbs@%1").arg(serverPath));
|
||||
setCurrentProject(buildSystem->project());
|
||||
LanguageFilter langFilter;
|
||||
langFilter.mimeTypes << Utils::Constants::QBS_MIMETYPE;
|
||||
setSupportedLanguage(langFilter);
|
||||
connect(EditorManager::instance(), &EditorManager::documentOpened,
|
||||
this, [this](IDocument *document) { d->checkDocument(document); });
|
||||
const QList<IDocument *> &allDocuments = DocumentModel::openedDocuments();
|
||||
for (IDocument * const document : allDocuments)
|
||||
d->checkDocument(document);
|
||||
start();
|
||||
}
|
||||
|
||||
QbsLanguageClient::~QbsLanguageClient() { delete d; }
|
||||
|
||||
bool QbsLanguageClient::isActive() const
|
||||
{
|
||||
if (!d->buildSystem)
|
||||
return false;
|
||||
if (!d->buildSystem->target()->activeBuildConfiguration())
|
||||
return false;
|
||||
if (d->buildSystem->target()->activeBuildConfiguration()->buildSystem() != d->buildSystem)
|
||||
return false;
|
||||
if (d->buildSystem->project()->activeTarget() != d->buildSystem->target())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void QbsLanguageClient::Private::checkDocument(IDocument *document)
|
||||
{
|
||||
if (const auto doc = qobject_cast<TextDocument *>(document))
|
||||
q->openDocument(doc);
|
||||
}
|
||||
|
||||
} // namespace QbsProjectManager::Internal
|
||||
25
src/plugins/qbsprojectmanager/qbslanguageclient.h
Normal file
25
src/plugins/qbsprojectmanager/qbslanguageclient.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <languageclient/client.h>
|
||||
|
||||
namespace QbsProjectManager::Internal {
|
||||
class QbsBuildSystem;
|
||||
|
||||
class QbsLanguageClient : public LanguageClient::Client
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QbsLanguageClient(const QString &serverPath, QbsBuildSystem *buildSystem);
|
||||
~QbsLanguageClient() override;
|
||||
|
||||
bool isActive() const;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
} // namespace QbsProjectManager::Internal
|
||||
@@ -11,11 +11,13 @@ QtcPlugin {
|
||||
Depends { name: "QmlJS" }
|
||||
Depends { name: "Utils" }
|
||||
|
||||
Depends { name: "ProjectExplorer" }
|
||||
Depends { name: "Core" }
|
||||
Depends { name: "CppEditor" }
|
||||
Depends { name: "QtSupport" }
|
||||
Depends { name: "LanguageClient" }
|
||||
Depends { name: "ProjectExplorer" }
|
||||
Depends { name: "QmlJSEditor" }
|
||||
Depends { name: "QmlJSTools" }
|
||||
Depends { name: "QtSupport" }
|
||||
|
||||
files: [
|
||||
"customqbspropertiesdialog.h",
|
||||
@@ -29,10 +31,14 @@ QtcPlugin {
|
||||
"qbsbuildstep.h",
|
||||
"qbscleanstep.cpp",
|
||||
"qbscleanstep.h",
|
||||
"qbseditor.cpp",
|
||||
"qbseditor.h",
|
||||
"qbsinstallstep.cpp",
|
||||
"qbsinstallstep.h",
|
||||
"qbskitaspect.cpp",
|
||||
"qbskitaspect.h",
|
||||
"qbslanguageclient.cpp",
|
||||
"qbslanguageclient.h",
|
||||
"qbsnodes.cpp",
|
||||
"qbsnodes.h",
|
||||
"qbsnodetreebuilder.cpp",
|
||||
@@ -48,7 +54,8 @@ QtcPlugin {
|
||||
"qbsprojectimporter.cpp",
|
||||
"qbsprojectimporter.h",
|
||||
"qbsprojectmanager.qrc",
|
||||
"qbsprojectmanager_global.h", "qbsprojectmanagertr.h",
|
||||
"qbsprojectmanager_global.h",
|
||||
"qbsprojectmanagertr.h",
|
||||
"qbsprojectmanagerconstants.h",
|
||||
"qbsprojectmanagerplugin.cpp",
|
||||
"qbsprojectmanagerplugin.h",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "qbsbuildconfiguration.h"
|
||||
#include "qbsbuildstep.h"
|
||||
#include "qbscleanstep.h"
|
||||
#include "qbseditor.h"
|
||||
#include "qbsinstallstep.h"
|
||||
#include "qbsnodes.h"
|
||||
#include "qbsprofilessettingspage.h"
|
||||
@@ -68,6 +69,7 @@ public:
|
||||
QbsInstallStepFactory installStepFactory;
|
||||
QbsSettingsPage settingsPage;
|
||||
QbsProfilesSettingsPage profilesSetttingsPage;
|
||||
QbsEditorFactory editorFactory;
|
||||
};
|
||||
|
||||
QbsProjectManagerPlugin::~QbsProjectManagerPlugin()
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
#include "qbssession.h"
|
||||
|
||||
#include "qbslanguageclient.h"
|
||||
#include "qbspmlogging.h"
|
||||
#include "qbsproject.h"
|
||||
#include "qbsprojectmanagerconstants.h"
|
||||
#include "qbsprojectmanagertr.h"
|
||||
#include "qbssettings.h"
|
||||
@@ -130,6 +132,7 @@ class QbsSession::Private
|
||||
{
|
||||
public:
|
||||
Process *qbsProcess = nullptr;
|
||||
QbsLanguageClient *languageClient = nullptr;
|
||||
PacketReader *packetReader = nullptr;
|
||||
QJsonObject currentRequest;
|
||||
QJsonObject projectData;
|
||||
@@ -140,7 +143,7 @@ public:
|
||||
State state = State::Inactive;
|
||||
};
|
||||
|
||||
QbsSession::QbsSession(QObject *parent) : QObject(parent), d(new Private)
|
||||
QbsSession::QbsSession(QbsBuildSystem *buildSystem) : QObject(buildSystem), d(new Private)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
@@ -449,6 +452,12 @@ void QbsSession::handlePacket(const QJsonObject &packet)
|
||||
setError(Error::VersionMismatch);
|
||||
return;
|
||||
}
|
||||
if (packet.value("api-level").toInt() > 4) {
|
||||
const QString lspSocket = packet.value("lsp-socket").toString();
|
||||
if (!lspSocket.isEmpty())
|
||||
d->languageClient = new QbsLanguageClient(lspSocket,
|
||||
static_cast<QbsBuildSystem *>(parent()));
|
||||
}
|
||||
d->state = State::Active;
|
||||
sendQueuedRequest();
|
||||
} else if (type == "project-resolved") {
|
||||
@@ -567,6 +576,7 @@ void QbsSession::setInactive()
|
||||
if (d->qbsProcess->state() == QProcess::Running)
|
||||
sendQuitPacket();
|
||||
d->qbsProcess = nullptr;
|
||||
d->languageClient = nullptr; // Owned by LanguageClientManager
|
||||
}
|
||||
|
||||
FileChangeResult QbsSession::updateFileList(const char *action, const QStringList &files,
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace ProjectExplorer { class Target; }
|
||||
|
||||
namespace QbsProjectManager {
|
||||
namespace Internal {
|
||||
class QbsBuildSystem;
|
||||
|
||||
class ErrorInfoItem
|
||||
{
|
||||
@@ -96,7 +97,7 @@ class QbsSession : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QbsSession(QObject *parent = nullptr);
|
||||
explicit QbsSession(QbsBuildSystem *buildSystem);
|
||||
~QbsSession() override;
|
||||
|
||||
enum class State { Initializing, Active, Inactive };
|
||||
|
||||
@@ -1134,7 +1134,6 @@ QmlJSEditorFactory::QmlJSEditorFactory(Utils::Id _id)
|
||||
using namespace Utils::Constants;
|
||||
addMimeType(QML_MIMETYPE);
|
||||
addMimeType(QMLPROJECT_MIMETYPE);
|
||||
addMimeType(QBS_MIMETYPE);
|
||||
addMimeType(QMLTYPES_MIMETYPE);
|
||||
addMimeType(JS_MIMETYPE);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user