5#ifndef QQMLBASEMODULE_P_H
6#define QQMLBASEMODULE_P_H
22#include <QtQmlDom/private/qqmldom_utils_p.h>
26#include <unordered_map>
28template<
typename ParametersT,
typename ResponseT>
33 using Parameters = ParametersT;
34 using Response = ResponseT;
41 Parameters m_parameters;
44 bool fillFrom(QmlLsp::OpenDocument doc,
const Parameters ¶ms, Response &&response);
48
49
50
51
52
54template<
typename Result,
typename ResponseCallback>
70 template<
typename... T>
74 "ResponseScopeGuard::setErrorFrom was passed a variant that never contains"
75 " an error message.");
84
85
86
87
88
89
90
91
92
104 std::visit(qOverloadedVisitor{ [
this](Result *result) { m_callback.sendResponse(*result); },
105 [
this](
const QQmlLSUtils::ErrorMessage &error) {
106 m_callback.sendErrorResponse(error.code,
107 error.message.toUtf8());
113template<
typename RequestType>
128 virtual void process(RequestPointerArgument toBeProcessed) = 0;
141template<
typename Parameters,
typename Response>
142bool BaseRequest<Parameters, Response>::fillFrom(QmlLsp::OpenDocument doc,
const Parameters ¶ms,
146 m_parameters = params;
147 m_response = std::move(response);
149 if (!doc.textDocument) {
150 qDebug() <<
"Cannot find document in qmlls's codemodel, did you open it before accessing "
156 QMutexLocker l(doc.textDocument->mutex());
157 m_minVersion = doc.textDocument->version().value_or(0);
162template <
typename RequestType>
166 QObject::connect(m_codeModelManager, &QmlLsp::QQmlCodeModelManager::updatedSnapshot,
this,
167 &QQmlBaseModule<RequestType>::updatedSnapshot);
170template<
typename RequestType>
173 QMutexLocker l(&m_pending_mutex);
177template<
typename RequestType>
187template<
typename RequestType>
191 auto req =
std::make_unique<RequestType>();
193 QQmlLSUtils::lspUriToQmlUrl(parameters.textDocument.uri));
195 if (!req->fillFrom(doc, parameters,
std::move(response))) {
196 req->m_response.sendErrorResponse(0,
"Received invalid request.", parameters);
199 const int minVersion = req->m_minVersion;
201 QMutexLocker l(&m_pending_mutex);
202 m_pending.insert({ QString::fromUtf8(req->m_parameters.textDocument.uri), std::move(req) });
205 if (doc.snapshot.docVersion && *doc.snapshot.docVersion >= minVersion)
206 updatedSnapshot(QQmlLSUtils::lspUriToQmlUrl(parameters.textDocument.uri));
209template<
typename RequestType>
213 std::vector<RequestPointer> toCompl;
215 QMutexLocker l(&m_pending_mutex);
216 for (
auto [it, end] = m_pending.equal_range(QString::fromUtf8(url)); it != end;) {
217 if (
auto &[key, value] = *it;
218 doc.docVersion && value->m_minVersion <= *doc.docVersion) {
219 toCompl.push_back(
std::move(value));
220 it = m_pending.erase(it);
226 for (
auto it = toCompl.rbegin(), end = toCompl.rend(); it != end; ++it) {
227 process(std::move(*it));
231template<
typename RequestType>
237 QQmlLSUtils::lspUriToQmlUrl(request->m_parameters.textDocument.uri));
239 if (!doc.snapshot.validDocVersion || doc.snapshot.validDocVersion != doc.snapshot.docVersion) {
240 return QQmlLSUtils::ErrorMessage{ 0,
241 u"Cannot proceed: current QML document is invalid! Fix"
242 u" all the errors in your QML code and try again."_s };
245 QQmlJS::Dom::DomItem file = doc.snapshot.validDoc.fileObject(QQmlJS::Dom::GoTo::MostLikely);
247 if (
auto envPtr = file.environment().ownerAs<QQmlJS::Dom::DomEnvironment>())
248 envPtr->clearReferenceCache();
250 return QQmlLSUtils::ErrorMessage{
252 u"Could not find file %1 in project."_s.arg(doc.snapshot.doc.toString()),
256 auto itemsFound = QQmlLSUtils::itemsFromTextLocation(file, request->m_parameters.position.line,
257 request->m_parameters.position.character);
259 if (itemsFound.isEmpty()) {
260 return QQmlLSUtils::ErrorMessage{
262 u"Could not find any items at given text location."_s,
Implements a server for the language server protocol.
QString name() const override
void registerHandlers(QLanguageServer *server, QLanguageServerProtocol *protocol) override
QQmlLSCompletion m_completionEngine
void setupCapabilities(const QLspSpecification::InitializeParams &clientInfo, QLspSpecification::InitializeResult &) override
void process(RequestPointerArgument req) override
static bool positionIsFollowedBySpaces(qsizetype position, const QString &code)
QQmlBaseModule< RequestType > BaseT
decltype(auto) getRequestHandler()
QmlLsp::QQmlCodeModelManager * m_codeModelManager
std::variant< QList< QQmlLSUtils::ItemLocation >, QQmlLSUtils::ErrorMessage > itemsForRequest(const RequestPointer &request)
void requestHandler(const RequestParameters ¶meters, RequestResponse &&response)
typename RequestType::Response RequestResponse
virtual void process(RequestPointerArgument toBeProcessed)=0
QQmlBaseModule(QmlLsp::QQmlCodeModelManager *codeModel)
typename RequestType::Parameters RequestParameters
std::unordered_multimap< QString, RequestPointer > m_pending
This class sends a result or an error when going out of scope.
bool setErrorFrom(const std::optional< QQmlLSUtils::ErrorMessage > &error)
ResponseCallback & m_callback
void setError(const QQmlLSUtils::ErrorMessage &error)
ResponseScopeGuard(Result &results, ResponseCallback &callback)
bool setErrorFrom(const std::variant< T... > &variant)