25 switch (highlightKind) {
90 switch (highlightKind) {
150
151
152
153
154
155
160 static QSet<QString> noConstructorObjects = { u"Math"_s, u"JSON"_s, u"Atomics"_s, u"Reflect"_s,
164 if (noConstructorObjects.contains(name))
167 if (item.directParent().internalKind() == DomType::ScriptNewMemberExpression) {
170 if (DomItem containingCallExpression = item.filterUp(
171 [](DomType k,
const DomItem &) {
return k == DomType::ScriptCallExpression; },
172 FilterUpOptions::ReturnOuter)) {
175 const auto callee = containingCallExpression.field(Fields::callee);
176 if (callee.internalKind() == DomType::ScriptBinaryExpression) {
177 const auto right = callee.field(Fields::right);
178 if (right.internalKind() == DomType::ScriptIdentifierExpression
179 && right.field(Fields::identifier).value().toString() == name) {
193 using namespace QLspSpecification;
194 using namespace Utils;
198 addModifier(SemanticTokenModifiers::Definition, &modifier);
201 addModifier(SemanticTokenModifiers::DefaultLibrary, &modifier);
204 addModifier(SemanticTokenModifiers::Static, &modifier);
207 addModifier(SemanticTokenModifiers::Static, &modifier);
210 addModifier(SemanticTokenModifiers::Static, &modifier);
213 addModifier(SemanticTokenModifiers::Abstract, &modifier);
216 addModifier(SemanticTokenModifiers::Readonly, &modifier);
223 QMultiMap<QString, QString> fieldFilterAdd{};
224 QMultiMap<QString, QString> fieldFilterRemove{
225 { QString(), Fields::propertyInfos.toString() },
226 { QString(), Fields::fileLocationsTree.toString() },
227 { QString(), Fields::importScope.toString() },
228 { QString(), Fields::defaultPropertyName.toString() },
229 { QString(), Fields::get.toString() },
231 return FieldFilter{ fieldFilterAdd, fieldFilterRemove };
236 QmlHighlightModifiers modifiers)
242 const std::optional<HighlightsRange> &range)
247 [
this](
const Path &path,
const DomItem &item,
bool b) {
248 return this->visitor(path, item, b);
250 VisitOption::Default | VisitOption::NoPath, emptyChildrenVisitor, emptyChildrenVisitor,
251 highlightingFilter());
256 if (m_range.has_value()) {
257 const auto fLocs = FileLocations::treeOf(item);
260 const auto regions = fLocs->info().regions;
261 if (!Utils::rangeOverlapsWithSourceLocation(regions[MainRegion],
265 switch (item.internalKind()) {
266 case DomType::Comment: {
267 highlightComment(item);
270 case DomType::Import: {
271 highlightImport(item);
274 case DomType::Binding: {
275 highlightBinding(item);
278 case DomType::Pragma: {
279 highlightPragma(item);
282 case DomType::EnumDecl: {
283 highlightEnumDecl(item);
286 case DomType::EnumItem: {
287 highlightEnumItem(item);
290 case DomType::QmlObject: {
291 highlightQmlObject(item);
294 case DomType::QmlComponent: {
295 highlightComponent(item);
298 case DomType::PropertyDefinition: {
299 highlightPropertyDefinition(item);
302 case DomType::MethodInfo: {
303 highlightMethod(item);
306 case DomType::ScriptLiteral: {
307 highlightScriptLiteral(item);
310 case DomType::ScriptCallExpression: {
311 highlightCallExpression(item);
314 case DomType::ScriptIdentifierExpression: {
315 highlightIdentifier(item);
319 if (item.ownerAs<ScriptExpression>())
320 highlightScriptExpressions(item);
323 Q_UNREACHABLE_RETURN(
false);
328 const auto comment = item.as<Comment>();
330 const auto locs = Utils::sourceLocationsFromMultiLineToken(
331 comment->info().comment(), comment->info().sourceLocation());
332 for (
const auto &loc : locs)
333 addHighlight(loc, QmlHighlightKind::Comment);
338 const auto fLocs = FileLocations::treeOf(item);
341 const auto regions = fLocs->info().regions;
342 const auto import = item.as<Import>();
344 addHighlight(regions[ImportTokenRegion], QmlHighlightKind::QmlKeyword);
345 if (import->uri.isModule())
346 addHighlight(regions[ImportUriRegion], QmlHighlightKind::QmlImportId);
348 addHighlight(regions[ImportUriRegion], QmlHighlightKind::String);
349 if (regions.contains(VersionRegion))
350 addHighlight(regions[VersionRegion], QmlHighlightKind::Number);
351 if (regions.contains(AsTokenRegion)) {
352 addHighlight(regions[AsTokenRegion], QmlHighlightKind::QmlKeyword);
353 addHighlight(regions[IdNameRegion], QmlHighlightKind::QmlNamespace);
359 const auto binding = item.as<Binding>();
361 const auto fLocs = FileLocations::treeOf(item);
363 qCDebug(semanticTokens) <<
"Can't find the locations for" << item.internalKind();
366 const auto regions = fLocs->info().regions;
368 if (binding->name().contains(
"."_L1))
371 if (binding->bindingType() != BindingType::Normal) {
372 addHighlight(regions[OnTokenRegion], QmlHighlightKind::QmlKeyword);
373 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlProperty);
377 return addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlProperty);
382 const auto fLocs = FileLocations::treeOf(item);
385 const auto regions = fLocs->info().regions;
386 addHighlight(regions[PragmaKeywordRegion], QmlHighlightKind::QmlKeyword);
387 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlPragmaName );
388 const auto pragma = item.as<Pragma>();
389 for (
auto i = 0; i < pragma->values.size(); ++i) {
390 DomItem value = item.field(Fields::values).index(i);
391 const auto valueRegions = FileLocations::treeOf(value)->info().regions;
392 addHighlight(valueRegions[PragmaValuesRegion], QmlHighlightKind::QmlPragmaValue);
399 const auto fLocs = FileLocations::treeOf(item);
402 const auto regions = fLocs->info().regions;
403 addHighlight(regions[EnumKeywordRegion], QmlHighlightKind::QmlKeyword);
404 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlEnumName);
409 const auto fLocs = FileLocations::treeOf(item);
412 const auto regions = fLocs->info().regions;
413 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlEnumMember);
414 if (regions.contains(EnumValueRegion))
415 addHighlight(regions[EnumValueRegion], QmlHighlightKind::Number);
420 const auto qmlObject = item.as<QmlObject>();
422 const auto fLocs = FileLocations::treeOf(item);
425 const auto regions = fLocs->info().regions;
427 if (!qmlObject->idStr().isEmpty()) {
428 addHighlight(regions[IdTokenRegion], QmlHighlightKind::QmlProperty);
429 addHighlight(regions[IdNameRegion], QmlHighlightKind::QmlLocalId);
432 if (qmlObject->name().contains(
"."_L1))
435 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlType);
440 const auto fLocs = FileLocations::treeOf(item);
443 const auto regions = fLocs->info().regions;
444 const auto componentKeywordIt = regions.constFind(ComponentKeywordRegion);
445 if (componentKeywordIt == regions.constEnd())
447 addHighlight(*componentKeywordIt, QmlHighlightKind::QmlKeyword);
448 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlType);
453 const auto propertyDef = item.as<PropertyDefinition>();
454 Q_ASSERT(propertyDef);
455 const auto fLocs = FileLocations::treeOf(item);
458 const auto regions = fLocs->info().regions;
460 if (propertyDef->isDefaultMember) {
462 addHighlight(regions[DefaultKeywordRegion], QmlHighlightKind::QmlKeyword);
464 if (propertyDef->isVirtual) {
466 addHighlight(regions[VirtualKeywordRegion], QmlHighlightKind::QmlKeyword);
468 if (propertyDef->isOverride) {
470 addHighlight(regions[OverrideKeywordRegion], QmlHighlightKind::QmlKeyword);
472 if (propertyDef->isFinal) {
474 addHighlight(regions[FinalKeywordRegion], QmlHighlightKind::QmlKeyword);
476 if (propertyDef->isRequired) {
478 addHighlight(regions[RequiredKeywordRegion], QmlHighlightKind::QmlKeyword);
480 if (propertyDef->isReadonly) {
482 addHighlight(regions[ReadonlyKeywordRegion], QmlHighlightKind::QmlKeyword);
484 addHighlight(regions[PropertyKeywordRegion], QmlHighlightKind::QmlKeyword);
485 if (propertyDef->isAlias())
486 addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlKeyword);
488 addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
490 addHighlight(regions[TypeModifierRegion], QmlHighlightKind::QmlTypeModifier);
491 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlProperty,
497 const auto method = item.as<MethodInfo>();
499 const auto fLocs = FileLocations::treeOf(item);
502 const auto regions = fLocs->info().regions;
503 switch (method->methodType) {
504 case MethodInfo::Signal: {
505 addHighlight(regions[SignalKeywordRegion], QmlHighlightKind::QmlKeyword);
506 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlMethod);
509 case MethodInfo::Method: {
510 addHighlight(regions[FunctionKeywordRegion], QmlHighlightKind::QmlKeyword);
511 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlMethod);
512 addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
519 for (
auto i = 0; i < method->parameters.size(); ++i) {
520 DomItem parameter = item.field(Fields::parameters).index(i);
521 const auto paramRegions = FileLocations::treeOf(parameter)->info().regions;
522 addHighlight(paramRegions[IdentifierRegion],
523 QmlHighlightKind::QmlMethodParameter);
524 addHighlight(paramRegions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
531 const auto literal = item.as<ScriptElements::Literal>();
533 const auto fLocs = FileLocations::treeOf(item);
536 const auto regions = fLocs->info().regions;
537 if (std::holds_alternative<QString>(literal->literalValue())) {
538 const auto file = item.containingFile().as<QmlFile>();
541 const auto &code = file->engine()->code();
542 const auto offset = regions[MainRegion].offset;
543 const auto length = regions[MainRegion].length;
544 const QStringView literalCode = QStringView{code}.mid(offset, length);
545 const auto &locs = Utils::sourceLocationsFromMultiLineToken(
546 literalCode, regions[MainRegion]);
547 for (
const auto &loc : locs)
548 addHighlight(loc, QmlHighlightKind::String);
549 }
else if (std::holds_alternative<
double>(literal->literalValue()))
550 addHighlight(regions[MainRegion], QmlHighlightKind::Number);
551 else if (std::holds_alternative<
bool>(literal->literalValue()))
552 addHighlight(regions[MainRegion], QmlHighlightKind::QmlKeyword);
553 else if (std::holds_alternative<std::nullptr_t>(literal->literalValue()))
554 addHighlight(regions[MainRegion], QmlHighlightKind::QmlKeyword);
556 qCWarning(semanticTokens) <<
"Invalid literal variant";
561 using namespace QLspSpecification;
562 const auto id = item.as<ScriptElements::IdentifierExpression>();
564 const auto loc = id->mainRegionLocation();
568 if (m_highlights.contains(loc.offset))
574 if (QQmlLSUtils::isFieldMemberAccess(item))
575 highlightFieldMemberAccess(item, loc);
577 highlightBySemanticAnalysis(item, loc);
582 const auto highlight = [
this](
const DomItem &item) {
583 if (item.internalKind() == DomType::ScriptIdentifierExpression) {
584 const auto id = item.as<ScriptElements::IdentifierExpression>();
586 const auto loc = id->mainRegionLocation();
587 addHighlight(loc, QmlHighlightKind::QmlMethod);
591 if (item.internalKind() == DomType::ScriptCallExpression) {
593 const auto callee = item.field(Fields::callee);
594 if (callee.internalKind() == DomType::ScriptIdentifierExpression) {
597 }
else if (callee.internalKind() == DomType::ScriptBinaryExpression) {
599 const auto right = callee.field(Fields::right);
600 if (right.internalKind() == DomType::ScriptIdentifierExpression)
608 QQmlJS::SourceLocation loc)
612 const auto name = item.field(Fields::identifier).value().toString();
613 if (!name.isEmpty() && name.at(0).category() == QChar::Letter_Uppercase) {
616 return highlightBySemanticAnalysis(item, loc);
619 const auto expression =
620 QQmlLSUtils::resolveExpressionType(item, QQmlLSUtils::ResolveOptions::ResolveOwnerType);
623 addHighlight(loc, QmlHighlightKind::Field);
627 if (expression->type == QQmlLSUtils::MethodIdentifier
628 || expression->type == QQmlLSUtils::LambdaMethodIdentifier) {
629 addHighlight(loc, QmlHighlightKind::QmlMethod);
632 return addHighlight(loc, QmlHighlightKind::Field);
636void HighlightingVisitor::highlightBySemanticAnalysis(
const DomItem &item, QQmlJS::SourceLocation loc)
638 const auto expression = QQmlLSUtils::resolveExpressionType(
639 item, QQmlLSUtils::ResolveOptions::ResolveOwnerType);
642 addHighlight(loc, QmlHighlightKind::Unknown);
645 switch (expression->type) {
646 case QQmlLSUtils::QmlComponentIdentifier:
647 addHighlight(loc, QmlHighlightKind::QmlType);
649 case QQmlLSUtils::JavaScriptIdentifier: {
652 if (
const auto scope = expression->semanticScope) {
653 if (
const auto jsIdentifier = scope->jsIdentifier(*expression->name)) {
654 if (jsIdentifier->kind == QQmlJSScope::JavaScriptIdentifier::Parameter)
656 if (jsIdentifier->isConst) {
659 addHighlight(loc, tokenType, modifier);
663 if (
const auto name = expression->name) {
664 if (
const auto highlightKind = resolveJsGlobalObjectKind(item, *name))
665 return addHighlight(loc, *highlightKind);
669 case QQmlLSUtils::PropertyIdentifier: {
670 if (
const auto scope = expression->semanticScope) {
672 if (scope == item.qmlObject().semanticScope()) {
674 }
else if (scope == item.rootQmlObject(GoTo::MostLikely).semanticScope()) {
679 const auto property = scope->property(expression->name.value());
681 if (!property.isWritable())
683 addHighlight(loc, tokenType, modifier);
687 case QQmlLSUtils::PropertyChangedSignalIdentifier:
688 addHighlight(loc, QmlHighlightKind::QmlSignal);
690 case QQmlLSUtils::PropertyChangedHandlerIdentifier:
691 addHighlight(loc, QmlHighlightKind::QmlSignalHandler);
693 case QQmlLSUtils::SignalIdentifier:
694 addHighlight(loc, QmlHighlightKind::QmlSignal);
696 case QQmlLSUtils::SignalHandlerIdentifier:
697 addHighlight(loc, QmlHighlightKind::QmlSignalHandler);
699 case QQmlLSUtils::MethodIdentifier:
700 addHighlight(loc, QmlHighlightKind::QmlMethod);
702 case QQmlLSUtils::QmlObjectIdIdentifier: {
703 if (!expression->semanticScope) {
706 addHighlight(loc, QmlHighlightKind::Unknown);
709 const auto qmlfile = item.fileObject().as<QmlFile>();
711 addHighlight(loc, QmlHighlightKind::Unknown);
714 const auto resolver = qmlfile->typeResolver();
716 addHighlight(loc, QmlHighlightKind::Unknown);
719 const auto &objects = resolver->objectsById();
720 if (expression->name.has_value()) {
721 const auto &name = expression->name.value();
722 const auto boundName =
723 objects.id(expression->semanticScope, item.qmlObject().semanticScope());
724 if (!boundName.isEmpty() && name == boundName) {
726 addHighlight(loc, QmlHighlightKind::QmlLocalId);
729 addHighlight(loc, QmlHighlightKind::QmlExternalId);
733 addHighlight(loc, QmlHighlightKind::QmlExternalId);
737 case QQmlLSUtils::SingletonIdentifier:
738 addHighlight(loc, QmlHighlightKind::QmlType);
740 case QQmlLSUtils::EnumeratorIdentifier:
741 addHighlight(loc, QmlHighlightKind::QmlEnumName);
743 case QQmlLSUtils::EnumeratorValueIdentifier:
744 addHighlight(loc, QmlHighlightKind::QmlEnumMember);
746 case QQmlLSUtils::AttachedTypeIdentifier:
747 case QQmlLSUtils::AttachedTypeIdentifierInBindingTarget:
748 addHighlight(loc, QmlHighlightKind::QmlType);
750 case QQmlLSUtils::GroupedPropertyIdentifier:
751 addHighlight(loc, QmlHighlightKind::QmlProperty);
753 case QQmlLSUtils::QualifiedModuleIdentifier:
754 addHighlight(loc, QmlHighlightKind::QmlNamespace);
757 qCWarning(semanticTokens)
758 << QString::fromLatin1(
"Semantic token for %1 has not been implemented yet")
759 .arg(
int(expression->type));
765 const auto fLocs = FileLocations::treeOf(item);
768 const auto regions = fLocs->info().regions;
769 switch (item.internalKind()) {
770 case DomType::ScriptLiteral:
771 highlightScriptLiteral(item);
773 case DomType::ScriptForStatement:
774 addHighlight(regions[ForKeywordRegion], QmlHighlightKind::QmlKeyword);
775 addHighlight(regions[TypeIdentifierRegion],
776 QmlHighlightKind::QmlKeyword);
779 case DomType::ScriptVariableDeclaration: {
780 addHighlight(regions[TypeIdentifierRegion],
781 QmlHighlightKind::QmlKeyword);
784 case DomType::ScriptReturnStatement:
785 addHighlight(regions[ReturnKeywordRegion], QmlHighlightKind::QmlKeyword);
787 case DomType::ScriptCaseClause:
788 addHighlight(regions[CaseKeywordRegion], QmlHighlightKind::QmlKeyword);
790 case DomType::ScriptDefaultClause:
791 addHighlight(regions[DefaultKeywordRegion], QmlHighlightKind::QmlKeyword);
793 case DomType::ScriptSwitchStatement:
794 addHighlight(regions[SwitchKeywordRegion], QmlHighlightKind::QmlKeyword);
796 case DomType::ScriptWhileStatement:
797 addHighlight(regions[WhileKeywordRegion], QmlHighlightKind::QmlKeyword);
799 case DomType::ScriptDoWhileStatement:
800 addHighlight(regions[DoKeywordRegion], QmlHighlightKind::QmlKeyword);
801 addHighlight(regions[WhileKeywordRegion], QmlHighlightKind::QmlKeyword);
803 case DomType::ScriptTryCatchStatement:
804 addHighlight(regions[TryKeywordRegion], QmlHighlightKind::QmlKeyword);
805 addHighlight(regions[CatchKeywordRegion], QmlHighlightKind::QmlKeyword);
806 addHighlight(regions[FinallyKeywordRegion], QmlHighlightKind::QmlKeyword);
808 case DomType::ScriptForEachStatement:
809 addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlKeyword);
810 addHighlight(regions[ForKeywordRegion], QmlHighlightKind::QmlKeyword);
811 addHighlight(regions[InOfTokenRegion], QmlHighlightKind::QmlKeyword);
813 case DomType::ScriptThrowStatement:
814 addHighlight(regions[ThrowKeywordRegion], QmlHighlightKind::QmlKeyword);
816 case DomType::ScriptBreakStatement:
817 addHighlight(regions[BreakKeywordRegion], QmlHighlightKind::QmlKeyword);
819 case DomType::ScriptContinueStatement:
820 addHighlight(regions[ContinueKeywordRegion], QmlHighlightKind::QmlKeyword);
822 case DomType::ScriptIfStatement:
823 addHighlight(regions[IfKeywordRegion], QmlHighlightKind::QmlKeyword);
824 addHighlight(regions[ElseKeywordRegion], QmlHighlightKind::QmlKeyword);
826 case DomType::ScriptLabelledStatement:
827 addHighlight(regions[IdentifierRegion], QmlHighlightKind::JsLabel);
829 case DomType::ScriptConditionalExpression:
830 addHighlight(regions[QuestionMarkTokenRegion], QmlHighlightKind::Operator);
831 addHighlight(regions[ColonTokenRegion], QmlHighlightKind::Operator);
833 case DomType::ScriptUnaryExpression:
834 case DomType::ScriptPostExpression:
835 addHighlight(regions[OperatorTokenRegion], QmlHighlightKind::Operator);
837 case DomType::ScriptType:
838 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlType);
839 addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
841 case DomType::ScriptFunctionExpression: {
842 addHighlight(regions[FunctionKeywordRegion], QmlHighlightKind::QmlKeyword);
843 addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlMethod);
846 case DomType::ScriptYieldExpression:
847 addHighlight(regions[YieldKeywordRegion], QmlHighlightKind::QmlKeyword);
849 case DomType::ScriptThisExpression:
850 addHighlight(regions[ThisKeywordRegion], QmlHighlightKind::QmlKeyword);
852 case DomType::ScriptSuperLiteral:
853 addHighlight(regions[SuperKeywordRegion], QmlHighlightKind::QmlKeyword);
855 case DomType::ScriptNewMemberExpression:
856 case DomType::ScriptNewExpression:
857 addHighlight(regions[NewKeywordRegion], QmlHighlightKind::QmlKeyword);
859 case DomType::ScriptTemplateExpressionPart:
860 addHighlight(regions[DollarLeftBraceTokenRegion], QmlHighlightKind::Operator);
861 visitor(Path(), item.field(Fields::expression),
false);
862 addHighlight(regions[RightBraceRegion], QmlHighlightKind::Operator);
864 case DomType::ScriptTemplateLiteral:
865 addHighlight(regions[LeftBacktickTokenRegion], QmlHighlightKind::String);
866 addHighlight(regions[RightBacktickTokenRegion], QmlHighlightKind::String);
868 case DomType::ScriptTemplateStringPart: {
870 QString code = item.field(Fields::value).value().toString();
871 const auto &locs = Utils::sourceLocationsFromMultiLineToken(
872 code, regions[MainRegion]);
873 for (
const auto &loc : locs)
874 addHighlight(loc, QmlHighlightKind::String);
878 qCDebug(semanticTokens) <<
"Script Expressions with kind" << item.internalKind()
879 <<
"not implemented";
884 QmlHighlightModifiers modifierKind)
886 return Utils::addHighlight(m_highlights, loc, highlightKind, modifierKind);
890
891
892
893
894
895
896
897
900 const QQmlJS::SourceLocation &locationInDocument)
902 auto lineBreakLength = qsizetype(std::char_traits<
char>::length(
"\n"));
903 const auto lineLengths = [&lineBreakLength](QStringView literal) {
904 std::vector<qsizetype> lineLengths;
905 qsizetype startIndex = 0;
906 qsizetype pos = literal.indexOf(u'\n');
913 if (pos - 1 > 0 && literal[pos - 1] == u'\r') {
915 lineBreakLength = qsizetype(std::char_traits<
char>::length(
"\r\n"));
919 lineLengths.push_back(pos - startIndex);
921 startIndex = pos + lineBreakLength;
922 pos = literal.indexOf(
'\n'_L1, startIndex);
925 if (startIndex < literal.length()) {
926 lineLengths.push_back(literal.length() - startIndex);
931 QList<QQmlJS::SourceLocation> result;
934 QQmlJS::SourceLocation lineLoc = locationInDocument;
935 for (
const auto lineLength : lineLengths(stringLiteral)) {
936 lineLoc.length = lineLength;
937 result.push_back(lineLoc);
940 lineLoc.offset += lineLoc.length + lineBreakLength;
942 lineLoc.startColumn = 1;
948 HighlightingMode mode)
950 QList<
unsigned> result;
951 constexpr auto tokenEncodingLength = 5;
952 result.reserve(tokenEncodingLength * highlights.size());
954 unsigned prevLine = 0;
955 unsigned prevColumn = 0;
956 const auto m_mapToProtocol = mode == HighlightingMode::Default
957 ? mapToProtocolDefault
958 : mapToProtocolForQtCreator;
959 std::for_each(highlights.constBegin(), highlights.constEnd(), [&](
const auto &token) {
960 unsigned length = token.loc.length;
961 unsigned line = token.loc.startLine - 1u;
962 unsigned col = token.loc.startColumn - 1u;
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
1032 const QList<
unsigned> &newData)
1035 const auto [oldStart, newStart] =
1036 std::mismatch(oldData.cbegin(), oldData.cend(), newData.cbegin(), newData.cend());
1040 const auto [r1, r2] = std::mismatch(oldData.crbegin(), std::make_reverse_iterator(oldStart),
1041 newData.crbegin(), std::make_reverse_iterator(newStart));
1042 const auto oldEnd = r1.base();
1043 const auto newEnd = r2.base();
1046 if (oldStart == oldEnd && newStart == newEnd)
1049 SemanticTokensEdit edit;
1050 edit.start =
int(std::distance(newData.cbegin(), newStart));
1051 edit.deleteCount =
int(std::distance(oldStart, oldEnd));
1053 if (newStart >= newData.cbegin() && newEnd <= newData.cend() && newStart < newEnd)
1054 edit.data.emplace(newStart, newEnd);
1056 return { std::move(edit) };
1060 const QQmlJS::SourceLocation &loc,
1062 QmlHighlightModifiers modifierKind)
1064 if (!loc.isValid() || loc.length == 0) {
1065 qCDebug(semanticTokens)
1066 <<
"Invalid locations: Cannot add highlight to token";
1069 if (!out.contains(loc.offset))
1070 out.insert(loc.offset,
HighlightToken(loc, highlightKind, modifierKind));
1074 const std::optional<HighlightsRange> &range)
1076 using namespace QQmlJS::Dom;
1078 return highlightDomElements.highlights();
1082 const QString &lastValidCode,
const QString ¤tCode)
1086 const QList<Diff> diffs = differ.diff(lastValidCode, currentCode);
1087 HighlightsContainer shifts = cachedHighlights;
1088 applyDiffs(shifts, diffs);
1094 auto [row, col] = QQmlJS::SourceLocation::rowAndColumnFrom(text, text.size());
1095 return { row - 1, col - 1 };
1100 auto [newLines, lastLineLength] = newlineCountAndLastLineLength(text);
1102 cursor.startLine += newLines;
1103 cursor.startColumn = lastLineLength + 1;
1105 cursor.startColumn += text.size();
1107 cursor.offset += text.size();
1116 return t.end() < offset;
1121 return t.begin() > offset;
1125 const QQmlJS::SourceLocation &cursor)
1127 return token.begin() < cursor.begin() && token.end() >= cursor.begin();
1131 const QQmlJS::SourceLocation &cursor)
1133 return token.begin() >= cursor.begin() && token.begin() <= cursor.end();
1137 int newlines,
int lastLen,
int diffLen)
1139 if (t.startLine == cursor.startLine) {
1141 t.startColumn = lastLen + t.startColumn - cursor.startColumn + 1;
1143 t.startColumn += lastLen;
1146 t.startLine += newlines;
1147 t.offset += diffLen;
1151 const QQmlJS::SourceLocation &cursor)
1153 auto begin = diff.text.cbegin();
1154 auto end = diff.text.cend();
1156 auto ptr = std::find_if(begin, end, [](QChar c) {
return c.isSpace(); });
1159 t.length = cursor.begin() - t.begin() + std::distance(begin, ptr);
1161 t.length += diff.text.size();
1166 const QQmlJS::SourceLocation &cursor,
int newlines,
1169 const int diffLen = diff.text.size();
1170 t.offset = cursor.begin();
1171 t.length += diffLen;
1172 t.startLine = cursor.startLine;
1173 t.startColumn = cursor.startColumn;
1176 auto rbegin = diff.text.rbegin();
1177 auto rend = diff.text.rend();
1178 auto ptr = std::find_if(rbegin, rend, [](QChar c) {
return c.isSpace(); });
1181 std::ptrdiff_t omitted = std::distance(ptr, rend);
1182 t.offset += omitted;
1183 t.length -= omitted;
1184 t.startColumn += omitted;
1189 t.startLine += newlines;
1190 t.startColumn = lastLen - std::distance(ptr.base(), diff.text.end()) + 1;
1197 const auto [newlines, lastLen] = newlineCountAndLastLineLength(diff.text);
1198 const auto diffLen = diff.text.size();
1199 cursor.length = quint32(diffLen);
1201 HighlightsContainer shifted;
1203 for (
auto item : highlights) {
1204 auto &token = item.loc;
1205 if (tokenBeforeOffset(token, cursor.begin())) {
1206 shifted.insert(token.offset, item);
1210 if (tokenAfterOffset(token, cursor.begin())) {
1211 shiftTokenAfterInsert(token, cursor, newlines, lastLen, diffLen);
1212 shifted.insert(token.offset, item);
1217 if (insertionInsideToken(token, cursor)) {
1218 expandTokenForMiddleInsert(token, diff, cursor);
1219 }
else if (insertionTouchesTokenLeft(token, cursor)) {
1220 expandTokenForLeftOverlap(token, diff, cursor, newlines, lastLen);
1223 shifted.insert(token.offset, item);
1226 highlights.swap(shifted);
1229 updateCursorPositionByDiff(diff.text, cursor);
1237 return t.begin() < delStart && t.end() > delEnd;
1242 return t.begin() < delStart && t.end() <= delEnd;
1247 return t.begin() >= delStart && t.end() > delEnd;
1254 const QQmlJS::SourceLocation &cursor,
int diffLen)
1256 t.offset -= diffLen;
1259 if (t.startLine == cursor.startLine + newlines) {
1261 t.startColumn = cursor.startColumn + (t.startColumn - lastLen) - 1;
1263 t.startColumn -= lastLen;
1268 t.startLine -= newlines;
1275 int newlines, quint32 delStartLine, quint32 delStartColumn)
1277 const quint32 deletedLen = delEnd - delStart;
1279 if (spansAcrossDeletion(t, delStart, delEnd)) {
1281 t.length -= deletedLen;
1285 if (leftFragmentRemains(t, delStart, delEnd)) {
1287 t.length = delStart - t.begin();
1291 if (rightFragmentRemains(t, delStart, delEnd)) {
1293 quint32 overlap = delEnd - t.begin();
1294 t.offset = delStart;
1295 t.length -= overlap;
1297 t.startColumn = delStartColumn;
1299 t.startLine = delStartLine;
1311 const auto [newlines, lastLen] = newlineCountAndLastLineLength(diff.text);
1312 const int diffLen = diff.text.size();
1314 cursor.length = diffLen;
1316 const quint32 delStart = cursor.offset;
1317 const quint32 delEnd = cursor.offset + diffLen;
1319 HighlightsContainer shifts;
1321 for (
auto item : highlights) {
1322 auto &token = item.loc;
1327 if (tokenBeforeOffset(token, delStart)) {
1328 shifts.insert(token.offset, item);
1335 if (tokenAfterOffset(token, delEnd)) {
1336 shiftTokenAfterDelete(token, newlines, lastLen, cursor, diffLen);
1337 shifts.insert(token.offset, item);
1344 applyDeletionOverlap(token, delStart, delEnd, newlines, cursor.startLine,
1345 cursor.startColumn);
1347 if (token.length == 0)
1350 shifts.insert(token.offset, item);
1353 highlights.swap(shifts);
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382void Utils::
applyDiffs(HighlightsContainer &highlights,
const QList<QQmlLSUtils::Diff> &diffs)
1385 if (highlights.isEmpty())
1388 QQmlJS::SourceLocation cursor;
1391 cursor.startLine = 1;
1392 cursor.startColumn = 1;
1394 for (
const Diff &diff : diffs) {
1395 switch (diff.command) {
1398 updateCursorPositionByDiff(diff.text, cursor);
1400 case Diff::Insert: {
1401 updateHighlightsOnInsert(highlights, cursor, diff);
1404 case Diff::Delete: {
1405 updateHighlightsOnDelete(highlights, cursor, diff);