7#include <QtLanguageServer/private/qlanguageserverspectypes_p.h>
8#include <QtCore/qthreadpool.h>
9#include <QtCore/private/qduplicatetracker_p.h>
10#include <QtCore/QRegularExpression>
11#include <QtQmlDom/private/qqmldomexternalitems_p.h>
12#include <QtQmlDom/private/qqmldomtop_p.h>
27 m_response = std::move(response);
29 if (!doc.textDocument)
32 std::optional<int> targetVersion;
35 targetVersion = doc.textDocument->version();
36 code = doc.textDocument->toPlainText();
38 m_minVersion = (targetVersion ? *targetVersion : 0);
46 protocol->registerCompletionItemResolveRequestHandler(
47 [](
const QByteArray &,
const CompletionItem &cParams,
48 LSPResponse<CompletionItem> &&response) { response.sendResponse(cParams); });
53 return u
"QmlCompletionSupport"_s;
57 const QLspSpecification::InitializeParams &,
58 QLspSpecification::InitializeResult &serverCapabilities)
60 QLspSpecification::CompletionOptions cOptions;
61 if (serverCapabilities.capabilities.completionProvider)
62 cOptions = *serverCapabilities.capabilities.completionProvider;
63 cOptions.resolveProvider =
false;
65 serverCapabilities.capabilities.completionProvider = cOptions;
72 req->sendCompletions(doc);
97 return QStringView(m_code).
mid(m_filterStart, m_pos - m_filterStart);
102 return QStringView(m_code).
mid(m_baseStart, m_filterStart - m_baseStart);
113 bool m_atLineStart = {};
117 : m_code(code), m_pos(
pos)
122 m_filterStart = m_pos;
123 while (m_filterStart != 0) {
124 QChar c = code.
at(m_filterStart - 1);
125 if (!
c.isLetterOrNumber() &&
c != u
'_')
131 m_baseStart = m_filterStart;
132 while (m_baseStart != 0) {
134 if (
c != u
'.' || m_baseStart == 1)
136 c = code.
at(m_baseStart - 2);
137 if (!
c.isLetterOrNumber() &&
c != u
'_')
140 while (m_baseStart != 0) {
142 if (!
c.isLetterOrNumber() &&
c != u
'_')
147 if (m_baseStart == baseEnd)
150 m_atLineStart =
true;
151 m_lineStart = m_baseStart;
152 while (m_lineStart != 0) {
154 if (
c == u
'\n' ||
c == u
'\r')
157 m_atLineStart =
false;
182 + ((!ctx.preLine().isEmpty() && ctx.preLine().last().isSpace()) ? 1 : 0);
183 if (effectiveLength < 2) {
185 comp.label =
"import";
186 comp.kind = int(CompletionItemKind::Keyword);
189 if (linePieces.
isEmpty() || linePieces.
first() != u
"import")
191 if (effectiveLength == 2) {
194 }
else if (effectiveLength == 3) {
195 if (linePieces.
last() != u
"as") {
199 comp.kind = int(CompletionItemKind::Keyword);
205 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<
DomEnvironment>()) {
206 switch (importCompletionType) {
211 for (
const QString &uri : envPtr->moduleIndexUris(env)) {
213 if (uri.startsWith(
base)) {
221 comp.label =
label.toUtf8();
222 comp.kind = int(CompletionItemKind::Module);
230 if (
ctx.base().isEmpty()) {
232 envPtr->moduleIndexMajorVersions(env, linePieces.
at(1).toString())) {
235 comp.kind = int(CompletionItemKind::Constant);
239 bool hasMajorVersion =
ctx.base().endsWith(u
'.');
242 majorV =
ctx.base().mid(0,
ctx.base().size() - 1).toInt(&hasMajorVersion);
243 if (!hasMajorVersion)
245 if (std::shared_ptr<ModuleIndex> mIndex =
246 envPtr->moduleIndexWithUri(env, linePieces.
at(1).toString(), majorV)) {
247 for (
int minorV : mIndex->minorVersions()) {
250 comp.kind = int(CompletionItemKind::Constant);
263 qCDebug(complLog) <<
"adding ids completions";
267 comp.label = k.toUtf8();
268 comp.kind = int(CompletionItemKind::Value);
278 qCDebug(complLog) <<
"binding completions";
279 containingObject.visitPrototypeChain(
281 qCDebug(complLog) <<
"prototypeChain" <<
it.internalKindStr() <<
it.canonicalPath();
284 auto methods = itPtr->methods();
287 if (
it.value().methodType == MethodInfo::MethodType::Signal) {
291 (u
"on"_s +
signal.at(0).toUpper() +
signal.mid(1)).toUtf8();
297 auto pDefs = itPtr->propertyDefs();
298 for (
auto it2 = pDefs.keyBegin(); it2 != pDefs.keyEnd(); ++it2) {
299 qCDebug(complLog) <<
"adding property" << *it2;
301 comp.label = it2->toUtf8();
302 comp.insertText = (*it2 + u
": "_s).toUtf8();
303 comp.kind = int(CompletionItemKind::Property);
309 VisitPrototypesOption::Normal);
322 auto addLocalSymbols = [&
res, typeCompletionType, completeMethodCalls, &symbols](
DomItem &
el) {
323 switch (typeCompletionType) {
327 switch (
el.internalKind()) {
328 case DomType::ImportScope: {
330 LocalSymbolsType::QmlTypes | LocalSymbolsType::Namespaces);
331 qCDebug(complLog) <<
"adding local symbols of:" <<
el.internalKindStr()
332 <<
el.canonicalPath() << localSymbols;
333 symbols[CompletionItemKind::Class] += localSymbols;
337 qCDebug(complLog) <<
"skipping local symbols for non type" <<
el.internalKindStr()
338 <<
el.canonicalPath();
344 auto localSymbols =
el.localSymbolNames(LocalSymbolsType::All);
346 auto methods = elPtr->methods();
349 localSymbols.remove(
it.key());
354 if (!pInfo.typeName.isEmpty())
355 param << pInfo.typeName;
356 if (!pInfo.name.isEmpty())
358 if (pInfo.defaultValue) {
359 param << u
"= " + pInfo.defaultValue->code();
361 parameters.append(
param.join(u
' '));
366 if (!
it->comments.regionComments.
isEmpty()) {
368 commentsStr +=
c.rawComment().toString().
trimmed() + u
'\n';
374 u
"%1%2(%3)"_s.
arg(commentsStr,
it.key(), parameters.join(u
", "))
376 comp.label = (
it.key() + u
"()").toUtf8();
377 comp.kind = int(CompletionItemKind::Function);
380 comp.detail =
"returns void";
382 comp.detail = (u
"returns "_s +
it->typeName).toUtf8();
386 comp.insertText = comp.label;
389 comp.insertText = (
it.key() + u
"(").toUtf8();
396 qCDebug(complLog) <<
"adding local symbols of:" <<
el.internalKindStr()
397 <<
el.canonicalPath() << localSymbols;
398 symbols[CompletionItemKind::Field] += localSymbols;
403 if (
ctx.base().isEmpty()) {
405 qCDebug(complLog) <<
"adding symbols reachable from:" <<
context.internalKindStr()
409 &visited, &visitedRefs);
414 auto addReachableSymbols = [&visited, &visitedRefs, &addLocalSymbols](
Path,
416 qCDebug(complLog) <<
"adding directly accessible symbols of" <<
it.internalKindStr()
417 <<
it.canonicalPath();
418 it.visitDirectAccessibleScopes(addLocalSymbols, VisitPrototypesOption::Normal,
428 for (
auto symbol = symbolKinds.value().constBegin();
429 symbol != symbolKinds.value().constEnd(); ++symbol) {
431 comp.label = symbol->toUtf8();
432 comp.kind = int(symbolKinds.key());
443 qCWarning(complLog) <<
"No valid document for completions for "
449 qCWarning(complLog) <<
"sendCompletions on older doc version";
451 qCWarning(complLog) <<
"using outdated valid doc, position might be incorrect";
455 if (std::shared_ptr<DomEnvironment> envPtr =
file.environment().ownerAs<
DomEnvironment>())
456 envPtr->clearReferenceCache();
462 -
ctx.filterChars().size());
463 if (itemsFound.size() > 1) {
465 for (
auto &
it : itemsFound)
466 paths.append(
it.domItem.canonicalPath().toString());
468 <<
" at the same depth:" <<
paths <<
"(using first)";
471 if (!itemsFound.isEmpty())
472 currentItem = itemsFound.first().domItem;
475 <<
"base:" <<
ctx.base() <<
"filter:" <<
ctx.filterChars()
483 if (!containingObject) {
486 if (
ctx.atLineStart()) {
487 if (
ctx.base().isEmpty()) {
490 comp.label =
"pragma";
491 comp.kind = int(CompletionItemKind::Keyword);
503 if (
ctx.atLineStart() && currentItem.
internalKind() != DomType::ScriptExpression
507 if (
ctx.base().isEmpty()) {
509 { u
"property", u
"readonly", u
"default", u
"signal", u
"function" })) {
511 comp.label =
s.toUtf8();
512 comp.kind = int(CompletionItemKind::Keyword);
static JNINativeMethod methods[]
Implements a server for the language server protocol.
qsizetype size() const noexcept
bool isEmpty() const noexcept
const_reference at(qsizetype i) const noexcept
const_iterator constBegin() const
const_iterator constEnd() const
Represents a consistent set of types organized in modules, it is the top level of the DOM.
DomItem qmlObject(GoTo option=GoTo::Strict, FilterUpOptions options=FilterUpOptions::ReturnOuter)
QString internalKindStr() const
DomItem component(GoTo option=GoTo::Strict)
InternalKind internalKind() const
DomItem fileObject(GoTo option=GoTo::Strict)
static qsizetype textOffsetFrom(const QString &code, int row, int character)
Convert a text position from (line, column) into an offset.
static QList< QQmlLSUtilsItemLocation > itemsFromTextLocation(QQmlJS::Dom::DomItem file, int line, int character)
Find the DomItem representing the object situated in file at given line and character/column.
\inmodule QtCore \reentrant
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
qsizetype size() const
Returns the number of characters in this string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString trimmed() const &
QByteArray toUtf8() const &
QString name() const override
void registerHandlers(QLanguageServer *server, QLanguageServerProtocol *protocol) override
void setupCapabilities(const QLspSpecification::InitializeParams &clientInfo, QLspSpecification::InitializeResult &) override
void process(RequestPointerArgument req) override
std::optional< int > docVersion
std::optional< int > validDocVersion
QQmlJS::Dom::DomItem validDoc
OpenDocumentSnapshot snapshotByUrl(const QByteArray &url)
QSet< QString >::iterator it
Path lookupSymbolPath(QString name)
void defaultErrorHandler(const ErrorMessage &error)
Calls the default error handler (by default errorToQDebug)
Combined button and popup list for selecting options.
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLsizei const GLuint * paths
GLuint GLsizei const GLchar * label
[43]
GLenum const GLint * param
static qreal component(const QPointF &point, unsigned int i)
static QList< CompletionItem > idsCompletions(DomItem component)
static QList< CompletionItem > reachableSymbols(DomItem &context, const CompletionContextStrings &ctx, TypeCompletionsType typeCompletionType, FunctionCompletion completeMethodCalls)
static QList< CompletionItem > importCompletions(DomItem &file, const CompletionContextStrings &ctx)
static QList< CompletionItem > bindingsCompletions(DomItem &containingObject)
static void split(QT_FT_Vector *b)
QStringView filterChars() const
QStringView preLine() const
CompletionContextStrings(QString code, qsizetype pos)
QString urlAndPos() const
void sendCompletions(QmlLsp::OpenDocumentSnapshot &)
QList< QLspSpecification::CompletionItem > completions(QmlLsp::OpenDocumentSnapshot &doc) const
decltype(auto) getRequestHandler()
QmlLsp::QQmlCodeModel * m_codeModel