26 m_parameters = params;
27 m_response = std::move(response);
29 if (!doc.textDocument)
32 std::optional<
int> targetVersion;
34 QMutexLocker l(doc.textDocument->mutex());
35 targetVersion = doc.textDocument->version();
36 code = doc.textDocument->toPlainText();
38 m_minVersion = (targetVersion ? *targetVersion : 0);
62 const QLspSpecification::InitializeParams &,
63 QLspSpecification::InitializeResult &serverCapabilities)
65 QLspSpecification::CompletionOptions cOptions;
66 if (serverCapabilities.capabilities.completionProvider)
67 cOptions = *serverCapabilities.capabilities.completionProvider;
68 cOptions.resolveProvider =
false;
69 cOptions.triggerCharacters = QList<QByteArray>({ QByteArray(
".") });
70 serverCapabilities.capabilities.completionProvider = cOptions;
94 if (position >= code.size())
98 std::find_if(
std::next(code.cbegin(), position), code.cend(),
99 [](
const QChar &c) {
return c == u'\n' || c == u'\r' || !c.isSpace(); });
101 return newline == code.cend() || newline->isSpace();
115DomItem CompletionRequest::patchInvalidFileForParser(
const DomItem &file, qsizetype position)
const
118 if (position > 0 && code[position - 1] == u'.' && positionIsFollowedBySpaces(position, code)) {
119 qCWarning(QQmlLSCompletionLog)
120 <<
"Patching invalid document: adding a semicolon after '.' for "
121 << QString::fromUtf8(m_parameters.textDocument.uri);
123 const QString patchedCode =
124 code.first(position).append(u"_dummyIdentifier;").append(code.sliced(position));
129 DomItem newCurrent = file.environment().makeCopy(DomItem::CopyOption::EnvConnected).item();
132 auto newCurrentPtr = newCurrent.ownerAs<DomEnvironment>();
133 newCurrentPtr->loadFile(
134 FileToLoad::fromMemory(newCurrentPtr, file.canonicalFilePath(), patchedCode),
135 [&result](Path,
const DomItem &,
const DomItem &newValue) {
136 result = newValue.fileObject();
138 newCurrentPtr->loadPendingDependencies();
142 qCWarning(QQmlLSCompletionLog) <<
"No valid document for completions for "
143 << QString::fromUtf8(m_parameters.textDocument.uri);
149 const QQmlLSCompletion &completionEngine)
const
151 QList<CompletionItem> res;
154 const qsizetype pos = QQmlLSUtils::textOffsetFrom(code, m_parameters.position.line,
155 m_parameters.position.character);
157 const bool useValidDoc =
158 doc.validDoc && doc.validDocVersion && *doc.validDocVersion >= m_minVersion;
160 const DomItem file = useValidDoc
161 ? doc.validDoc.fileObject(QQmlJS::Dom::GoTo::MostLikely)
162 : patchInvalidFileForParser(doc.doc.fileObject(QQmlJS::Dom::GoTo::MostLikely), pos);
165 if (std::shared_ptr<DomEnvironment> envPtr = file.environment().ownerAs<DomEnvironment>())
166 envPtr->clearReferenceCache();
169 CompletionContextStrings ctx(code, pos);
170 auto itemsFound = QQmlLSUtils::itemsFromTextLocation(file, m_parameters.position.line,
171 m_parameters.position.character
172 - ctx.filterChars().size());
173 if (itemsFound.isEmpty()) {
174 qCDebug(QQmlLSCompletionLog) <<
"No items found for completions at" << urlAndPos();
178 if (itemsFound.size() > 1) {
180 for (
auto &it : itemsFound)
181 paths.append(it.domItem.canonicalPath().toString());
182 qCWarning(QQmlLSCompletionLog) <<
"Multiple elements of " << urlAndPos()
183 <<
" at the same depth:" << paths <<
"(using first)";
185 const DomItem currentItem = itemsFound.first().domItem;
186 qCDebug(QQmlLSCompletionLog) <<
"Completion at " << urlAndPos() <<
" "
187 << m_parameters.position.line <<
":"
188 << m_parameters.position.character <<
"offset:" << pos
189 <<
"base:" << ctx.base() <<
"filter:" << ctx.filterChars()
190 <<
"lastVersion:" << (doc.docVersion ? (*doc.docVersion) : -1)
192 << (doc.validDocVersion ? (*doc.validDocVersion) : -1) <<
"in"
193 << currentItem.internalKindStr() << currentItem.canonicalPath();
194 auto result = completionEngine.completions(currentItem, ctx);