26 switch (highlightKind) {
91 switch (highlightKind) {
151
152
153
154
155
156
161 static QSet<QString> noConstructorObjects = { u"Math"_s, u"JSON"_s, u"Atomics"_s, u"Reflect"_s,
165 if (noConstructorObjects.contains(name))
168 if (item.directParent().internalKind() == DomType::ScriptNewMemberExpression) {
171 if (DomItem containingCallExpression = item.filterUp(
172 [](DomType k,
const DomItem &) {
return k == DomType::ScriptCallExpression; },
173 FilterUpOptions::ReturnOuter)) {
176 const auto callee = containingCallExpression.field(Fields::callee);
177 if (callee.internalKind() == DomType::ScriptBinaryExpression) {
178 const auto right = callee.field(Fields::right);
179 if (right.internalKind() == DomType::ScriptIdentifierExpression
180 && right.field(Fields::identifier).value().toString() == name) {
194 using namespace QLspSpecification;
195 using namespace Utils;
199 addModifier(SemanticTokenModifiers::Definition, &modifier);
202 addModifier(SemanticTokenModifiers::DefaultLibrary, &modifier);
205 addModifier(SemanticTokenModifiers::Static, &modifier);
208 addModifier(SemanticTokenModifiers::Static, &modifier);
211 addModifier(SemanticTokenModifiers::Static, &modifier);
214 addModifier(SemanticTokenModifiers::Abstract, &modifier);
217 addModifier(SemanticTokenModifiers::Readonly, &modifier);
224 QMultiMap<QString, QString> fieldFilterAdd{};
225 QMultiMap<QString, QString> fieldFilterRemove{
226 { QString(), Fields::propertyInfos.toString() },
227 { QString(), Fields::fileLocationsTree.toString() },
228 { QString(), Fields::importScope.toString() },
229 { QString(), Fields::defaultPropertyName.toString() },
230 { QString(), Fields::get.toString() },
232 return FieldFilter{ fieldFilterAdd, fieldFilterRemove };
237 QmlHighlightModifiers modifiers)
243 const std::optional<HighlightsRange> &range)
248 [
this](
const Path &path,
const DomItem &item,
bool b) {
249 return this->visitor(path, item, b);
251 VisitOption::Default | VisitOption::NoPath, emptyChildrenVisitor, emptyChildrenVisitor,
252 highlightingFilter());
257 if (m_range.has_value()) {
258 const auto fLocs = FileLocations::treeOf(item);
261 const auto regions = fLocs->info().regions;
262 if (!Utils::rangeOverlapsWithSourceLocation(regions[MainRegion],
266 switch (item.internalKind()) {
267 case DomType::Comment: {
268 highlightComment(item);
271 case DomType::Import: {
272 highlightImport(item);
275 case DomType::Binding: {
276 highlightBinding(item);
279 case DomType::Pragma: {
280 highlightPragma(item);
283 case DomType::EnumDecl: {
284 highlightEnumDecl(item);
287 case DomType::EnumItem: {
288 highlightEnumItem(item);
291 case DomType::QmlObject: {
292 highlightQmlObject(item);
295 case DomType::QmlComponent: {
296 highlightComponent(item);
299 case DomType::PropertyDefinition: {
300 highlightPropertyDefinition(item);
303 case DomType::MethodInfo: {
304 highlightMethod(item);
307 case DomType::ScriptLiteral: {
308 highlightScriptLiteral(item);
311 case DomType::ScriptCallExpression: {
312 highlightCallExpression(item);
315 case DomType::ScriptIdentifierExpression: {
316 highlightIdentifier(item);
320 if (item.ownerAs<ScriptExpression>())
321 highlightScriptExpressions(item);
324 Q_UNREACHABLE_RETURN(
false);
329 const auto comment = item.as<Comment>();
331 const auto locs = Utils::sourceLocationsFromMultiLineToken(
332 comment->info().comment(), comment->info().sourceLocation());
333 for (
const auto &loc : locs)
334 addHighlight(loc, QmlHighlightKind::Comment);
339 const auto fLocs = FileLocations::treeOf(item);
342 const auto regions = fLocs->info().regions;
343 const auto import = item.as<Import>();
345 addHighlight(regions[ImportTokenRegion], QmlHighlightKind::QmlKeyword);
346 if (import->uri.isModule())
347 addHighlight(regions[ImportUriRegion], QmlHighlightKind::QmlImportId);
349 addHighlight(regions[ImportUriRegion], QmlHighlightKind::String);
350 if (regions.contains(VersionRegion))
351 addHighlight(regions[VersionRegion], QmlHighlightKind::Number);
352 if (regions.contains(AsTokenRegion)) {
353 addHighlight(regions[AsTokenRegion], QmlHighlightKind::QmlKeyword);
354 addHighlight(regions[IdNameRegion], QmlHighlightKind::QmlNamespace);
360 const auto binding = item.as<Binding>();
362 const auto fLocs = FileLocations::treeOf(item);
364 qCDebug(semanticTokens) <<
"Can't find the locations for" << item.internalKind();
367 const auto regions = fLocs->info().regions;
369 if (binding->name().contains(
"."_L1))
372 if (binding->bindingType() != BindingType::Normal) {
373 addHighlight(regions[OnTokenRegion], QmlHighlightKind::QmlKeyword);
374 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlProperty);
378 return addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlProperty);
383 const auto fLocs = FileLocations::treeOf(item);
386 const auto regions = fLocs->info().regions;
387 addHighlight(regions[PragmaKeywordRegion], QmlHighlightKind::QmlKeyword);
388 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlPragmaName );
389 const auto pragma = item.as<Pragma>();
390 for (
auto i = 0; i < pragma->values.size(); ++i) {
391 DomItem value = item.field(Fields::values).index(i);
392 const auto valueRegions = FileLocations::treeOf(value)->info().regions;
393 addHighlight(valueRegions[PragmaValuesRegion], QmlHighlightKind::QmlPragmaValue);
400 const auto fLocs = FileLocations::treeOf(item);
403 const auto regions = fLocs->info().regions;
404 addHighlight(regions[EnumKeywordRegion], QmlHighlightKind::QmlKeyword);
405 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlEnumName);
410 const auto fLocs = FileLocations::treeOf(item);
413 const auto regions = fLocs->info().regions;
414 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlEnumMember);
415 if (regions.contains(EnumValueRegion))
416 addHighlight(regions[EnumValueRegion], QmlHighlightKind::Number);
421 const auto qmlObject = item.as<QmlObject>();
423 const auto fLocs = FileLocations::treeOf(item);
426 const auto regions = fLocs->info().regions;
428 if (!qmlObject->idStr().isEmpty()) {
429 addHighlight(regions[IdTokenRegion], QmlHighlightKind::QmlProperty);
430 addHighlight(regions[IdNameRegion], QmlHighlightKind::QmlLocalId);
433 if (qmlObject->name().contains(
"."_L1))
436 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlType);
441 const auto fLocs = FileLocations::treeOf(item);
444 const auto regions = fLocs->info().regions;
445 const auto componentKeywordIt = regions.constFind(ComponentKeywordRegion);
446 if (componentKeywordIt == regions.constEnd())
448 addHighlight(*componentKeywordIt, QmlHighlightKind::QmlKeyword);
449 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlType);
454 const auto propertyDef = item.as<PropertyDefinition>();
455 Q_ASSERT(propertyDef);
456 const auto fLocs = FileLocations::treeOf(item);
459 const auto regions = fLocs->info().regions;
461 if (propertyDef->isDefaultMember) {
463 addHighlight(regions[DefaultKeywordRegion], QmlHighlightKind::QmlKeyword);
465 if (propertyDef->isVirtual) {
467 addHighlight(regions[VirtualKeywordRegion], QmlHighlightKind::QmlKeyword);
469 if (propertyDef->isOverride) {
471 addHighlight(regions[OverrideKeywordRegion], QmlHighlightKind::QmlKeyword);
473 if (propertyDef->isFinal) {
475 addHighlight(regions[FinalKeywordRegion], QmlHighlightKind::QmlKeyword);
477 if (propertyDef->isRequired) {
479 addHighlight(regions[RequiredKeywordRegion], QmlHighlightKind::QmlKeyword);
481 if (propertyDef->isReadonly) {
483 addHighlight(regions[ReadonlyKeywordRegion], QmlHighlightKind::QmlKeyword);
485 addHighlight(regions[PropertyKeywordRegion], QmlHighlightKind::QmlKeyword);
486 if (propertyDef->isAlias())
487 addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlKeyword);
489 addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
491 addHighlight(regions[TypeModifierRegion], QmlHighlightKind::QmlTypeModifier);
492 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlProperty,
498 const auto method = item.as<MethodInfo>();
500 const auto fLocs = FileLocations::treeOf(item);
503 const auto regions = fLocs->info().regions;
504 switch (method->methodType) {
505 case MethodInfo::Signal: {
506 addHighlight(regions[SignalKeywordRegion], QmlHighlightKind::QmlKeyword);
507 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlMethod);
510 case MethodInfo::Method: {
511 addHighlight(regions[FunctionKeywordRegion], QmlHighlightKind::QmlKeyword);
512 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlMethod);
513 addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
520 for (
auto i = 0; i < method->parameters.size(); ++i) {
521 DomItem parameter = item.field(Fields::parameters).index(i);
522 const auto paramRegions = FileLocations::treeOf(parameter)->info().regions;
523 addHighlight(paramRegions[IdentifierRegion],
524 QmlHighlightKind::QmlMethodParameter);
525 addHighlight(paramRegions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
532 const auto literal = item.as<ScriptElements::Literal>();
534 const auto fLocs = FileLocations::treeOf(item);
537 const auto regions = fLocs->info().regions;
538 if (std::holds_alternative<QString>(literal->literalValue())) {
539 const auto file = item.containingFile().as<QmlFile>();
542 const auto &code = file->engine()->code();
543 const auto offset = regions[MainRegion].offset;
544 const auto length = regions[MainRegion].length;
545 const QStringView literalCode = QStringView{code}.mid(offset, length);
546 const auto &locs = Utils::sourceLocationsFromMultiLineToken(
547 literalCode, regions[MainRegion]);
548 for (
const auto &loc : locs)
549 addHighlight(loc, QmlHighlightKind::String);
550 }
else if (std::holds_alternative<
double>(literal->literalValue()))
551 addHighlight(regions[MainRegion], QmlHighlightKind::Number);
552 else if (std::holds_alternative<
bool>(literal->literalValue()))
553 addHighlight(regions[MainRegion], QmlHighlightKind::QmlKeyword);
554 else if (std::holds_alternative<std::nullptr_t>(literal->literalValue()))
555 addHighlight(regions[MainRegion], QmlHighlightKind::QmlKeyword);
557 qCWarning(semanticTokens) <<
"Invalid literal variant";
562 using namespace QLspSpecification;
563 const auto id = item.as<ScriptElements::IdentifierExpression>();
565 const auto loc = id->mainRegionLocation();
569 if (m_highlights.contains(loc.offset))
575 if (QQmlLSUtils::isFieldMemberAccess(item))
576 highlightFieldMemberAccess(item, loc);
578 highlightBySemanticAnalysis(item, loc);
583 const auto highlight = [
this](
const DomItem &item) {
584 if (item.internalKind() == DomType::ScriptIdentifierExpression) {
585 const auto id = item.as<ScriptElements::IdentifierExpression>();
587 const auto loc = id->mainRegionLocation();
588 addHighlight(loc, QmlHighlightKind::QmlMethod);
592 if (item.internalKind() == DomType::ScriptCallExpression) {
594 const auto callee = item.field(Fields::callee);
595 if (callee.internalKind() == DomType::ScriptIdentifierExpression) {
598 }
else if (callee.internalKind() == DomType::ScriptBinaryExpression) {
600 const auto right = callee.field(Fields::right);
601 if (right.internalKind() == DomType::ScriptIdentifierExpression)
609 QQmlJS::SourceLocation loc)
613 const auto name = item.field(Fields::identifier).value().toString();
614 if (!name.isEmpty() && name.at(0).category() == QChar::Letter_Uppercase) {
617 return highlightBySemanticAnalysis(item, loc);
620 const auto expression =
621 QQmlLSUtils::resolveExpressionType(item, QQmlLSUtils::ResolveOptions::ResolveOwnerType);
624 addHighlight(loc, QmlHighlightKind::Field);
628 if (expression->type == QQmlLSUtils::MethodIdentifier
629 || expression->type == QQmlLSUtils::LambdaMethodIdentifier) {
630 addHighlight(loc, QmlHighlightKind::QmlMethod);
633 return addHighlight(loc, QmlHighlightKind::Field);
637void HighlightingVisitor::highlightBySemanticAnalysis(
const DomItem &item, QQmlJS::SourceLocation loc)
639 const auto expression = QQmlLSUtils::resolveExpressionType(
640 item, QQmlLSUtils::ResolveOptions::ResolveOwnerType);
643 addHighlight(loc, QmlHighlightKind::Unknown);
646 switch (expression->type) {
647 case QQmlLSUtils::QmlComponentIdentifier:
648 addHighlight(loc, QmlHighlightKind::QmlType);
650 case QQmlLSUtils::JavaScriptIdentifier: {
653 if (
const auto scope = expression->semanticScope) {
654 if (
const auto jsIdentifier = scope->jsIdentifier(*expression->name)) {
655 if (jsIdentifier->kind == QQmlJSScope::JavaScriptIdentifier::Parameter)
657 if (jsIdentifier->isConst) {
660 addHighlight(loc, tokenType, modifier);
664 if (
const auto name = expression->name) {
665 if (
const auto highlightKind = resolveJsGlobalObjectKind(item, *name))
666 return addHighlight(loc, *highlightKind);
670 case QQmlLSUtils::PropertyIdentifier: {
671 if (
const auto scope = expression->semanticScope) {
673 if (scope == item.qmlObject().semanticScope()) {
675 }
else if (scope == item.rootQmlObject(GoTo::MostLikely).semanticScope()) {
680 const auto property = scope->property(expression->name.value());
682 if (!property.isWritable())
684 addHighlight(loc, tokenType, modifier);
688 case QQmlLSUtils::PropertyChangedSignalIdentifier:
689 addHighlight(loc, QmlHighlightKind::QmlSignal);
691 case QQmlLSUtils::PropertyChangedHandlerIdentifier:
692 addHighlight(loc, QmlHighlightKind::QmlSignalHandler);
694 case QQmlLSUtils::SignalIdentifier:
695 addHighlight(loc, QmlHighlightKind::QmlSignal);
697 case QQmlLSUtils::SignalHandlerIdentifier:
698 addHighlight(loc, QmlHighlightKind::QmlSignalHandler);
700 case QQmlLSUtils::MethodIdentifier:
701 addHighlight(loc, QmlHighlightKind::QmlMethod);
703 case QQmlLSUtils::QmlObjectIdIdentifier: {
704 if (!expression->semanticScope) {
707 addHighlight(loc, QmlHighlightKind::Unknown);
710 const auto qmlfile = item.fileObject().as<QmlFile>();
712 addHighlight(loc, QmlHighlightKind::Unknown);
715 const auto resolver = qmlfile->typeResolver();
717 addHighlight(loc, QmlHighlightKind::Unknown);
720 const auto &objects = resolver->objectsById();
721 if (expression->name.has_value()) {
722 const auto &name = expression->name.value();
723 const auto boundName =
724 objects.id(expression->semanticScope, item.qmlObject().semanticScope());
725 if (!boundName.isEmpty() && name == boundName) {
727 addHighlight(loc, QmlHighlightKind::QmlLocalId);
730 addHighlight(loc, QmlHighlightKind::QmlExternalId);
734 addHighlight(loc, QmlHighlightKind::QmlExternalId);
738 case QQmlLSUtils::SingletonIdentifier:
739 addHighlight(loc, QmlHighlightKind::QmlType);
741 case QQmlLSUtils::EnumeratorIdentifier:
742 addHighlight(loc, QmlHighlightKind::QmlEnumName);
744 case QQmlLSUtils::EnumeratorValueIdentifier:
745 addHighlight(loc, QmlHighlightKind::QmlEnumMember);
747 case QQmlLSUtils::AttachedTypeIdentifier:
748 case QQmlLSUtils::AttachedTypeIdentifierInBindingTarget:
749 addHighlight(loc, QmlHighlightKind::QmlType);
751 case QQmlLSUtils::GroupedPropertyIdentifier:
752 addHighlight(loc, QmlHighlightKind::QmlProperty);
754 case QQmlLSUtils::QualifiedModuleIdentifier:
755 addHighlight(loc, QmlHighlightKind::QmlNamespace);
758 qCWarning(semanticTokens)
759 << QString::fromLatin1(
"Semantic token for %1 has not been implemented yet")
760 .arg(
int(expression->type));
766 const auto fLocs = FileLocations::treeOf(item);
769 const auto regions = fLocs->info().regions;
770 switch (item.internalKind()) {
771 case DomType::ScriptLiteral:
772 highlightScriptLiteral(item);
774 case DomType::ScriptForStatement:
775 addHighlight(regions[ForKeywordRegion], QmlHighlightKind::QmlKeyword);
776 addHighlight(regions[TypeIdentifierRegion],
777 QmlHighlightKind::QmlKeyword);
780 case DomType::ScriptVariableDeclaration: {
781 addHighlight(regions[TypeIdentifierRegion],
782 QmlHighlightKind::QmlKeyword);
785 case DomType::ScriptReturnStatement:
786 addHighlight(regions[ReturnKeywordRegion], QmlHighlightKind::QmlKeyword);
788 case DomType::ScriptCaseClause:
789 addHighlight(regions[CaseKeywordRegion], QmlHighlightKind::QmlKeyword);
791 case DomType::ScriptDefaultClause:
792 addHighlight(regions[DefaultKeywordRegion], QmlHighlightKind::QmlKeyword);
794 case DomType::ScriptSwitchStatement:
795 addHighlight(regions[SwitchKeywordRegion], QmlHighlightKind::QmlKeyword);
797 case DomType::ScriptWhileStatement:
798 addHighlight(regions[WhileKeywordRegion], QmlHighlightKind::QmlKeyword);
800 case DomType::ScriptDoWhileStatement:
801 addHighlight(regions[DoKeywordRegion], QmlHighlightKind::QmlKeyword);
802 addHighlight(regions[WhileKeywordRegion], QmlHighlightKind::QmlKeyword);
804 case DomType::ScriptTryCatchStatement:
805 addHighlight(regions[TryKeywordRegion], QmlHighlightKind::QmlKeyword);
806 addHighlight(regions[CatchKeywordRegion], QmlHighlightKind::QmlKeyword);
807 addHighlight(regions[FinallyKeywordRegion], QmlHighlightKind::QmlKeyword);
809 case DomType::ScriptForEachStatement:
810 addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlKeyword);
811 addHighlight(regions[ForKeywordRegion], QmlHighlightKind::QmlKeyword);
812 addHighlight(regions[InOfTokenRegion], QmlHighlightKind::QmlKeyword);
814 case DomType::ScriptThrowStatement:
815 addHighlight(regions[ThrowKeywordRegion], QmlHighlightKind::QmlKeyword);
817 case DomType::ScriptBreakStatement:
818 addHighlight(regions[BreakKeywordRegion], QmlHighlightKind::QmlKeyword);
820 case DomType::ScriptContinueStatement:
821 addHighlight(regions[ContinueKeywordRegion], QmlHighlightKind::QmlKeyword);
823 case DomType::ScriptIfStatement:
824 addHighlight(regions[IfKeywordRegion], QmlHighlightKind::QmlKeyword);
825 addHighlight(regions[ElseKeywordRegion], QmlHighlightKind::QmlKeyword);
827 case DomType::ScriptLabelledStatement:
828 addHighlight(regions[IdentifierRegion], QmlHighlightKind::JsLabel);
830 case DomType::ScriptConditionalExpression:
831 addHighlight(regions[QuestionMarkTokenRegion], QmlHighlightKind::Operator);
832 addHighlight(regions[ColonTokenRegion], QmlHighlightKind::Operator);
834 case DomType::ScriptUnaryExpression:
835 case DomType::ScriptPostExpression:
836 addHighlight(regions[OperatorTokenRegion], QmlHighlightKind::Operator);
838 case DomType::ScriptType:
839 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlType);
840 addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
842 case DomType::ScriptFunctionExpression: {
843 addHighlight(regions[FunctionKeywordRegion], QmlHighlightKind::QmlKeyword);
844 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlMethod);
847 case DomType::ScriptYieldExpression:
848 addHighlight(regions[YieldKeywordRegion], QmlHighlightKind::QmlKeyword);
850 case DomType::ScriptThisExpression:
851 addHighlight(regions[ThisKeywordRegion], QmlHighlightKind::QmlKeyword);
853 case DomType::ScriptSuperLiteral:
854 addHighlight(regions[SuperKeywordRegion], QmlHighlightKind::QmlKeyword);
856 case DomType::ScriptNewMemberExpression:
857 case DomType::ScriptNewExpression:
858 addHighlight(regions[NewKeywordRegion], QmlHighlightKind::QmlKeyword);
860 case DomType::ScriptTemplateExpressionPart:
861 addHighlight(regions[DollarLeftBraceTokenRegion], QmlHighlightKind::Operator);
862 visitor(Path(), item.field(Fields::expression),
false);
863 addHighlight(regions[RightBraceRegion], QmlHighlightKind::Operator);
865 case DomType::ScriptTemplateLiteral:
866 addHighlight(regions[LeftBacktickTokenRegion], QmlHighlightKind::String);
867 addHighlight(regions[RightBacktickTokenRegion], QmlHighlightKind::String);
869 case DomType::ScriptTemplateStringPart: {
871 QString code = item.field(Fields::value).value().toString();
872 const auto &locs = Utils::sourceLocationsFromMultiLineToken(
873 code, regions[MainRegion]);
874 for (
const auto &loc : locs)
875 addHighlight(loc, QmlHighlightKind::String);
879 qCDebug(semanticTokens) <<
"Script Expressions with kind" << item.internalKind()
880 <<
"not implemented";
885 QmlHighlightModifiers modifierKind)
887 return Utils::addHighlight(m_highlights, loc, highlightKind, modifierKind);
891
892
893
894
895
896
897
898
901 const QQmlJS::SourceLocation &locationInDocument)
903 auto lineBreakLength = qsizetype(std::char_traits<
char>::length(
"\n"));
904 const auto lineLengths = [&lineBreakLength](QStringView literal) {
905 std::vector<qsizetype> lineLengths;
906 qsizetype startIndex = 0;
907 qsizetype pos = literal.indexOf(u'\n');
914 if (pos - 1 > 0 && literal[pos - 1] == u'\r') {
916 lineBreakLength = qsizetype(std::char_traits<
char>::length(
"\r\n"));
920 lineLengths.push_back(pos - startIndex);
922 startIndex = pos + lineBreakLength;
923 pos = literal.indexOf(
'\n'_L1, startIndex);
926 if (startIndex < literal.length()) {
927 lineLengths.push_back(literal.length() - startIndex);
932 QList<QQmlJS::SourceLocation> result;
935 QQmlJS::SourceLocation lineLoc = locationInDocument;
936 for (
const auto lineLength : lineLengths(stringLiteral)) {
937 lineLoc.length = lineLength;
938 result.push_back(lineLoc);
941 lineLoc.offset += lineLoc.length + lineBreakLength;
943 lineLoc.startColumn = 1;
951 constexpr auto tokenEncodingLength = 5;
952 result.reserve(tokenEncodingLength * highlights.size());
956 const auto m_mapToProtocol = mode == HighlightingMode::Default
957 ? mapToProtocolDefault
958 : mapToProtocolForQtCreator;
959 std::for_each(highlights.constBegin(), highlights.constEnd(), [&](
const auto &token) {
960 int length = token.loc.length;
961 int line = token.loc.startLine - 1;
962 int col = token.loc.startColumn - 1;
963 Q_ASSERT(line >= prevLine);
964 if (line != prevLine)
966 result.emplace_back(line - prevLine);
967 result.emplace_back(col - prevColumn);
968 result.emplace_back(length);
969 result.emplace_back(m_mapToProtocol(token.kind));
970 result.emplace_back(fromQmlModifierKindToLspTokenType(token.modifiers));
979
980
981
982
983
984
985
986
987
992 *baseModifier |= (1 <<
int(modifier));
996
997
998
1002 int startOffsetItem =
int(loc.offset);
1003 int endOffsetItem = startOffsetItem +
int(loc.length);
1008
1009
1010
1013 int length = resultID.length();
1014 for (
int i = length - 1; i >= 0; --i) {
1015 if (resultID[i] ==
'9') {
1018 resultID[i] = resultID[i] + 1;
1022 resultID.prepend(
'1');
1026
1027
1028
1029
1030
1034 const auto [oldStart, newStart] =
1035 std::mismatch(oldData.cbegin(), oldData.cend(), newData.cbegin(), newData.cend());
1039 const auto [r1, r2] = std::mismatch(oldData.crbegin(), std::make_reverse_iterator(oldStart),
1040 newData.crbegin(), std::make_reverse_iterator(newStart));
1041 const auto oldEnd = r1.base();
1042 const auto newEnd = r2.base();
1045 if (oldStart == oldEnd && newStart == newEnd)
1048 SemanticTokensEdit edit;
1049 edit.start =
int(std::distance(newData.cbegin(), newStart));
1050 edit.deleteCount =
int(std::distance(oldStart, oldEnd));
1052 if (newStart >= newData.cbegin() && newEnd <= newData.cend() && newStart < newEnd)
1053 edit.data.emplace(newStart, newEnd);
1055 return { std::move(edit) };
1059 const QQmlJS::SourceLocation &loc,
1061 QmlHighlightModifiers modifierKind)
1063 if (!loc.isValid() || loc.length == 0) {
1064 qCDebug(semanticTokens)
1065 <<
"Invalid locations: Cannot add highlight to token";
1068 if (!out.contains(loc.offset))
1069 out.insert(loc.offset,
HighlightToken(loc, highlightKind, modifierKind));
1073 const std::optional<HighlightsRange> &range)
1075 using namespace QQmlJS::Dom;
1077 return highlightDomElements.highlights();
1081 const QString &lastValidCode,
const QString ¤tCode)
1085 const QList<Diff> diffs = differ.diff(lastValidCode, currentCode);
1086 HighlightsContainer shifts = cachedHighlights;
1087 applyDiffs(shifts, diffs);
1093 auto [row, col] = QQmlJS::SourceLocation::rowAndColumnFrom(text, text.size());
1094 return { row - 1, col - 1 };
1099 auto [newLines, lastLineLength] = newlineCountAndLastLineLength(text);
1101 cursor.startLine += newLines;
1102 cursor.startColumn = lastLineLength + 1;
1104 cursor.startColumn += text.size();
1106 cursor.offset += text.size();
1115 return t.end() < offset;
1120 return t.begin() > offset;
1124 const QQmlJS::SourceLocation &cursor)
1126 return token.begin() < cursor.begin() && token.end() >= cursor.begin();
1130 const QQmlJS::SourceLocation &cursor)
1132 return token.begin() >= cursor.begin() && token.begin() <= cursor.end();
1136 int newlines,
int lastLen,
int diffLen)
1138 if (t.startLine == cursor.startLine) {
1140 t.startColumn = lastLen + t.startColumn - cursor.startColumn + 1;
1142 t.startColumn += lastLen;
1145 t.startLine += newlines;
1146 t.offset += diffLen;
1150 const QQmlJS::SourceLocation &cursor)
1152 auto begin = diff.text.cbegin();
1153 auto end = diff.text.cend();
1155 auto ptr = std::find_if(begin, end, [](QChar c) {
return c.isSpace(); });
1158 t.length = cursor.begin() - t.begin() + std::distance(begin, ptr);
1160 t.length += diff.text.size();
1165 const QQmlJS::SourceLocation &cursor,
int newlines,
1168 const int diffLen = diff.text.size();
1169 t.offset = cursor.begin();
1170 t.length += diffLen;
1171 t.startLine = cursor.startLine;
1172 t.startColumn = cursor.startColumn;
1175 auto rbegin = diff.text.rbegin();
1176 auto rend = diff.text.rend();
1177 auto ptr = std::find_if(rbegin, rend, [](QChar c) {
return c.isSpace(); });
1180 std::ptrdiff_t omitted = std::distance(ptr, rend);
1181 t.offset += omitted;
1182 t.length -= omitted;
1183 t.startColumn += omitted;
1188 t.startLine += newlines;
1189 t.startColumn = lastLen - std::distance(ptr.base(), diff.text.end()) + 1;
1196 const auto [newlines, lastLen] = newlineCountAndLastLineLength(diff.text);
1197 const auto diffLen = diff.text.size();
1198 cursor.length = quint32(diffLen);
1200 HighlightsContainer shifted;
1202 for (
auto item : highlights) {
1203 auto &token = item.loc;
1204 if (tokenBeforeOffset(token, cursor.begin())) {
1205 shifted.insert(token.offset, item);
1209 if (tokenAfterOffset(token, cursor.begin())) {
1210 shiftTokenAfterInsert(token, cursor, newlines, lastLen, diffLen);
1211 shifted.insert(token.offset, item);
1216 if (insertionInsideToken(token, cursor)) {
1217 expandTokenForMiddleInsert(token, diff, cursor);
1218 }
else if (insertionTouchesTokenLeft(token, cursor)) {
1219 expandTokenForLeftOverlap(token, diff, cursor, newlines, lastLen);
1222 shifted.insert(token.offset, item);
1225 highlights.swap(shifted);
1228 updateCursorPositionByDiff(diff.text, cursor);
1236 return t.begin() < delStart && t.end() > delEnd;
1241 return t.begin() < delStart && t.end() <= delEnd;
1246 return t.begin() >= delStart && t.end() > delEnd;
1253 const QQmlJS::SourceLocation &cursor,
int diffLen)
1255 t.offset -= diffLen;
1258 if (t.startLine == cursor.startLine + newlines) {
1260 t.startColumn = cursor.startColumn + (t.startColumn - lastLen) - 1;
1262 t.startColumn -= lastLen;
1267 t.startLine -= newlines;
1274 int newlines, quint32 delStartLine, quint32 delStartColumn)
1276 const quint32 deletedLen = delEnd - delStart;
1278 if (spansAcrossDeletion(t, delStart, delEnd)) {
1280 t.length -= deletedLen;
1284 if (leftFragmentRemains(t, delStart, delEnd)) {
1286 t.length = delStart - t.begin();
1290 if (rightFragmentRemains(t, delStart, delEnd)) {
1292 quint32 overlap = delEnd - t.begin();
1293 t.offset = delStart;
1294 t.length -= overlap;
1296 t.startColumn = delStartColumn;
1298 t.startLine = delStartLine;
1310 const auto [newlines, lastLen] = newlineCountAndLastLineLength(diff.text);
1311 const int diffLen = diff.text.size();
1313 cursor.length = diffLen;
1315 const quint32 delStart = cursor.offset;
1316 const quint32 delEnd = cursor.offset + diffLen;
1318 HighlightsContainer shifts;
1320 for (
auto item : highlights) {
1321 auto &token = item.loc;
1326 if (tokenBeforeOffset(token, delStart)) {
1327 shifts.insert(token.offset, item);
1334 if (tokenAfterOffset(token, delEnd)) {
1335 shiftTokenAfterDelete(token, newlines, lastLen, cursor, diffLen);
1336 shifts.insert(token.offset, item);
1343 applyDeletionOverlap(token, delStart, delEnd, newlines, cursor.startLine,
1344 cursor.startColumn);
1346 if (token.length == 0)
1349 shifts.insert(token.offset, item);
1352 highlights.swap(shifts);
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381void Utils::
applyDiffs(HighlightsContainer &highlights,
const QList<QQmlLSUtils::Diff> &diffs)
1384 if (highlights.isEmpty())
1387 QQmlJS::SourceLocation cursor;
1390 cursor.startLine = 1;
1391 cursor.startColumn = 1;
1393 for (
const Diff &diff : diffs) {
1394 switch (diff.command) {
1397 updateCursorPositionByDiff(diff.text, cursor);
1399 case Diff::Insert: {
1400 updateHighlightsOnInsert(highlights, cursor, diff);
1403 case Diff::Delete: {
1404 updateHighlightsOnDelete(highlights, cursor, diff);