File indexing completed on 2024-05-12 04:38:06
0001 /* 0002 SPDX-FileCopyrightText: 2007-2010 David Nolden <david.nolden.kdevelop@art-master.de> 0003 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org> 0004 SPDX-FileCopyrightText: 2009 Milian Wolff <mail@milianw.de> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "codehighlighting.h" 0010 0011 #include "../../interfaces/icore.h" 0012 #include "../../interfaces/ilanguagecontroller.h" 0013 #include "../../interfaces/icompletionsettings.h" 0014 #include "../../util/foregroundlock.h" 0015 #include <debug.h> 0016 0017 #include "../duchain/declaration.h" 0018 #include "../duchain/types/functiontype.h" 0019 #include "../duchain/types/enumeratortype.h" 0020 #include "../duchain/types/typealiastype.h" 0021 #include "../duchain/types/enumerationtype.h" 0022 #include "../duchain/types/structuretype.h" 0023 #include "../duchain/functiondefinition.h" 0024 #include "../duchain/use.h" 0025 0026 #include "colorcache.h" 0027 #include "configurablecolors.h" 0028 #include <duchain/parsingenvironment.h> 0029 #include <backgroundparser/backgroundparser.h> 0030 #include <backgroundparser/urlparselock.h> 0031 0032 #include <KTextEditor/Document> 0033 #include <KTextEditor/MovingInterface> 0034 0035 using namespace KTextEditor; 0036 0037 static const float highlightingZDepth = -500; 0038 0039 #define ifDebug(x) 0040 0041 namespace KDevelop { 0042 ///@todo Don't highlighting everything, only what is visible on-demand 0043 0044 CodeHighlighting::CodeHighlighting(QObject* parent) 0045 : QObject(parent) 0046 , m_localColorization(true) 0047 , m_globalColorization(true) 0048 { 0049 qRegisterMetaType<KDevelop::IndexedString>("KDevelop::IndexedString"); 0050 0051 adaptToColorChanges(); 0052 0053 connect(ColorCache::self(), &ColorCache::colorsGotChanged, 0054 this, &CodeHighlighting::adaptToColorChanges); 0055 } 0056 0057 CodeHighlighting::~CodeHighlighting() 0058 { 0059 qDeleteAll(m_highlights); 0060 } 0061 0062 void CodeHighlighting::adaptToColorChanges() 0063 { 0064 QMutexLocker lock(&m_dataMutex); 0065 // disable local highlighting if the ratio is set to 0 0066 m_localColorization = ICore::self()->languageController()->completionSettings()->localColorizationLevel() > 0; 0067 // disable global highlighting if the ratio is set to 0 0068 m_globalColorization = ICore::self()->languageController()->completionSettings()->globalColorizationLevel() > 0; 0069 0070 m_declarationAttributes.clear(); 0071 m_definitionAttributes.clear(); 0072 m_depthAttributes.clear(); 0073 m_referenceAttributes.clear(); 0074 } 0075 0076 KTextEditor::Attribute::Ptr CodeHighlighting::attributeForType(CodeHighlightingType type, 0077 CodeHighlightingContext context, 0078 const QColor& color) const 0079 { 0080 QMutexLocker lock(&m_dataMutex); 0081 KTextEditor::Attribute::Ptr a; 0082 switch (context) { 0083 case CodeHighlightingContext::Definition: 0084 a = m_definitionAttributes[type]; 0085 break; 0086 0087 case CodeHighlightingContext::Declaration: 0088 a = m_declarationAttributes[type]; 0089 break; 0090 0091 case CodeHighlightingContext::Reference: 0092 a = m_referenceAttributes[type]; 0093 break; 0094 } 0095 0096 if (!a || color.isValid()) { 0097 a = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute(*ColorCache::self()->defaultColors()->attribute( 0098 type))); 0099 0100 if (context == CodeHighlightingContext::Definition || context == CodeHighlightingContext::Declaration) { 0101 if (ICore::self()->languageController()->completionSettings()->boldDeclarations()) { 0102 a->setFontBold(); 0103 } 0104 } 0105 0106 if (color.isValid()) { 0107 a->setForeground(color); 0108 // a->setBackground(QColor(mix(0xffffff-color, backgroundColor(), 255-backgroundTinting))); 0109 } else { 0110 switch (context) { 0111 case CodeHighlightingContext::Definition: 0112 m_definitionAttributes.insert(type, a); 0113 break; 0114 case CodeHighlightingContext::Declaration: 0115 m_declarationAttributes.insert(type, a); 0116 break; 0117 case CodeHighlightingContext::Reference: 0118 m_referenceAttributes.insert(type, a); 0119 break; 0120 } 0121 } 0122 } 0123 0124 return a; 0125 } 0126 0127 ColorMap emptyColorMap() 0128 { 0129 ColorMap ret(ColorCache::self()->validColorCount() + 1, nullptr); 0130 return ret; 0131 } 0132 0133 CodeHighlightingInstance* CodeHighlighting::createInstance() const 0134 { 0135 return new CodeHighlightingInstance(this); 0136 } 0137 0138 bool CodeHighlighting::hasHighlighting(IndexedString url) const 0139 { 0140 DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url); 0141 if (tracker) { 0142 QMutexLocker lock(&m_dataMutex); 0143 const auto highlightingIt = m_highlights.constFind(tracker); 0144 return highlightingIt != m_highlights.constEnd() && !(*highlightingIt)->m_highlightedRanges.isEmpty(); 0145 } 0146 return false; 0147 } 0148 0149 void CodeHighlighting::highlightDUChain(ReferencedTopDUContext context) 0150 { 0151 ENSURE_CHAIN_NOT_LOCKED 0152 0153 IndexedString url; 0154 0155 { 0156 DUChainReadLocker lock; 0157 if (!context) 0158 return; 0159 0160 url = context->url(); 0161 } 0162 0163 // This prevents the background-parser from updating the top-context while we're working with it 0164 UrlParseLock urlLock(context->url()); 0165 0166 DUChainReadLocker lock; 0167 0168 qint64 revision = context->parsingEnvironmentFile()->modificationRevision().revision; 0169 0170 qCDebug(LANGUAGE) << "highlighting du chain" << url.toUrl(); 0171 0172 if (!m_localColorization && !m_globalColorization) { 0173 qCDebug(LANGUAGE) << "highlighting disabled"; 0174 QMetaObject::invokeMethod(this, "clearHighlightingForDocument", Qt::QueuedConnection, 0175 Q_ARG(KDevelop::IndexedString, url)); 0176 return; 0177 } 0178 0179 CodeHighlightingInstance* instance = createInstance(); 0180 0181 lock.unlock(); 0182 0183 instance->highlightDUChain(context.data()); 0184 0185 auto* highlighting = new DocumentHighlighting; 0186 highlighting->m_document = url; 0187 highlighting->m_waitingRevision = revision; 0188 highlighting->m_waiting = instance->m_highlight; 0189 std::sort(highlighting->m_waiting.begin(), highlighting->m_waiting.end()); 0190 0191 QMetaObject::invokeMethod(this, "applyHighlighting", Qt::QueuedConnection, Q_ARG(void*, highlighting)); 0192 0193 delete instance; 0194 } 0195 0196 void CodeHighlightingInstance::highlightDUChain(TopDUContext* context) 0197 { 0198 m_contextClasses.clear(); 0199 m_useClassCache = true; 0200 0201 //Highlight 0202 highlightDUChain(context, QHash<Declaration*, uint>(), emptyColorMap()); 0203 0204 m_functionColorsForDeclarations.clear(); 0205 m_functionDeclarationsForColors.clear(); 0206 0207 m_useClassCache = false; 0208 m_contextClasses.clear(); 0209 } 0210 0211 void CodeHighlightingInstance::highlightDUChain(DUContext* context, QHash<Declaration*, uint> colorsForDeclarations, 0212 ColorMap declarationsForColors) 0213 { 0214 DUChainReadLocker lock; 0215 0216 TopDUContext* top = context->topContext(); 0217 0218 //Merge the colors from the function arguments 0219 const auto importedParentContexts = context->importedParentContexts(); 0220 for (const DUContext::Import& imported : importedParentContexts) { 0221 if (!imported.context(top) || 0222 (imported.context(top)->type() != DUContext::Other && imported.context(top)->type() != DUContext::Function)) 0223 continue; 0224 //For now it's enough simply copying them, because we only pass on colors within function bodies. 0225 const auto functionColorsIt = m_functionColorsForDeclarations.constFind(imported.context(top)); 0226 if (functionColorsIt != m_functionColorsForDeclarations.constEnd()) 0227 colorsForDeclarations = *functionColorsIt; 0228 const auto functionDeclarationsIt = m_functionDeclarationsForColors.constFind(imported.context(top)); 0229 if (functionDeclarationsIt != m_functionDeclarationsForColors.constEnd()) 0230 declarationsForColors = *functionDeclarationsIt; 0231 } 0232 0233 QList<Declaration*> takeFreeColors; 0234 0235 bool noRainbow = ICore::self()->languageController()->completionSettings()->localColorizationLevel() == 0; 0236 const auto localDeclarations = context->localDeclarations(); 0237 for (Declaration* dec : localDeclarations) { 0238 if (noRainbow || !useRainbowColor(dec)) { 0239 highlightDeclaration(dec, QColor(QColor::Invalid)); 0240 continue; 0241 } 0242 //Initially pick a color using the hash, so the chances are good that the same identifier gets the same color always. 0243 uint colorNum = dec->identifier().hash() % ColorCache::self()->primaryColorCount(); 0244 0245 if (declarationsForColors[colorNum]) { 0246 takeFreeColors << dec; //Use one of the colors that stays free 0247 continue; 0248 } 0249 0250 colorsForDeclarations[dec] = colorNum; 0251 declarationsForColors[colorNum] = dec; 0252 0253 highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum)); 0254 } 0255 0256 for (Declaration* dec : qAsConst(takeFreeColors)) { 0257 uint colorNum = dec->identifier().hash() % ColorCache::self()->primaryColorCount(); 0258 uint oldColorNum = colorNum; 0259 while (declarationsForColors[colorNum]) { 0260 colorNum = (colorNum + 1) % ColorCache::self()->primaryColorCount(); 0261 if (colorNum == oldColorNum) { 0262 colorNum = ColorCache::self()->primaryColorCount(); 0263 break; 0264 } 0265 } 0266 0267 if (colorNum < ColorCache::self()->primaryColorCount()) { 0268 // Use primary color 0269 colorsForDeclarations[dec] = colorNum; 0270 declarationsForColors[colorNum] = dec; 0271 highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum)); 0272 } else { 0273 // Try to use supplementary color 0274 colorNum = ColorCache::self()->primaryColorCount(); 0275 while (declarationsForColors[colorNum]) { 0276 colorNum++; 0277 if (colorNum == ColorCache::self()->validColorCount()) { 0278 //If no color could be found, use default color 0279 highlightDeclaration(dec, QColor(QColor::Invalid)); 0280 break; 0281 } 0282 } 0283 if (colorNum < ColorCache::self()->validColorCount()) { 0284 // Use supplementary color 0285 colorsForDeclarations[dec] = colorNum; 0286 declarationsForColors[colorNum] = dec; 0287 highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum)); 0288 } 0289 } 0290 } 0291 0292 for (int a = 0; a < context->usesCount(); ++a) { 0293 Declaration* decl = context->topContext()->usedDeclarationForIndex(context->uses()[a].m_declarationIndex); 0294 QColor color(QColor::Invalid); 0295 const auto colorsIt = colorsForDeclarations.constFind(decl); 0296 if (colorsIt != colorsForDeclarations.constEnd()) 0297 color = ColorCache::self()->generatedColor(*colorsIt); 0298 highlightUse(context, a, color); 0299 } 0300 0301 if (context->type() == DUContext::Other || context->type() == DUContext::Function) { 0302 const auto indexed = IndexedDUContext(context); 0303 m_functionColorsForDeclarations[indexed] = colorsForDeclarations; 0304 m_functionDeclarationsForColors[indexed] = declarationsForColors; 0305 } 0306 0307 const QVector<DUContext*> children = context->childContexts(); 0308 0309 lock.unlock(); // Periodically release the lock, so that the UI won't be blocked too much 0310 0311 for (DUContext* child : children) { 0312 highlightDUChain(child, colorsForDeclarations, declarationsForColors); 0313 } 0314 } 0315 0316 KTextEditor::Attribute::Ptr CodeHighlighting::attributeForDepth(int depth) const 0317 { 0318 while (depth >= m_depthAttributes.count()) { 0319 KTextEditor::Attribute::Ptr a(new KTextEditor::Attribute()); 0320 a->setBackground(QColor(Qt::white).darker(100 + (m_depthAttributes.count() * 25))); 0321 a->setBackgroundFillWhitespace(true); 0322 if (depth % 2) 0323 a->setOutline(Qt::red); 0324 m_depthAttributes.append(a); 0325 } 0326 0327 return m_depthAttributes[depth]; 0328 } 0329 0330 KDevelop::Declaration* CodeHighlightingInstance::localClassFromCodeContext(KDevelop::DUContext* context) const 0331 { 0332 if (!context) 0333 return nullptr; 0334 0335 const auto classIt = m_contextClasses.constFind(context); 0336 if (classIt != m_contextClasses.constEnd()) 0337 return *classIt; 0338 0339 DUContext* startContext = context; 0340 0341 while (context->type() == DUContext::Other) { 0342 //Move context to the top context of type "Other". This is needed because every compound-statement creates a new sub-context. 0343 auto parent = context->parentContext(); 0344 if (!parent || (parent->type() != DUContext::Other && parent->type() != DUContext::Function)) { 0345 break; 0346 } 0347 context = context->parentContext(); 0348 } 0349 0350 ///Step 1: Find the function-declaration for the function we are in 0351 Declaration* functionDeclaration = nullptr; 0352 0353 if (auto* def = dynamic_cast<FunctionDefinition*>(context->owner())) { 0354 const auto classIt = m_contextClasses.constFind(context); 0355 if (classIt != m_contextClasses.constEnd()) 0356 return *classIt; 0357 0358 functionDeclaration = def->declaration(startContext->topContext()); 0359 } 0360 0361 if (!functionDeclaration && context->owner()) 0362 functionDeclaration = context->owner(); 0363 0364 if (!functionDeclaration) { 0365 if (m_useClassCache) 0366 m_contextClasses[context] = nullptr; 0367 return nullptr; 0368 } 0369 0370 Declaration* decl = functionDeclaration->context()->owner(); 0371 0372 if (m_useClassCache) 0373 m_contextClasses[context] = decl; 0374 0375 return decl; 0376 } 0377 0378 CodeHighlightingType CodeHighlightingInstance::typeForDeclaration(Declaration* dec, DUContext* context) const 0379 { 0380 /** 0381 * We highlight in 3 steps by priority: 0382 * 1. Is the item in the local class or an inherited class? If yes, highlight. 0383 * 2. What kind of item is it? If it's a type/function/enumerator, highlight by type. 0384 * 3. Else, highlight by scope. 0385 * 0386 * */ 0387 0388 if (!dec) 0389 return CodeHighlightingType::Error; 0390 0391 auto type = CodeHighlightingType::LocalVariable; 0392 if (dec->kind() == Declaration::Namespace) 0393 return CodeHighlightingType::Namespace; 0394 0395 if (dec->kind() == Declaration::Macro) { 0396 return CodeHighlightingType::Macro; 0397 } 0398 0399 if (context && dec->context() && dec->context()->type() == DUContext::Class) { 0400 //It is a use. 0401 //Determine the class we're in 0402 Declaration* klass = localClassFromCodeContext(context); 0403 if (klass) { 0404 if (klass->internalContext() == dec->context()) { 0405 // Using Member of the local class 0406 if (dec->type<KDevelop::FunctionType>()) 0407 type = CodeHighlightingType::LocalMemberFunction; 0408 else 0409 type = CodeHighlightingType::LocalClassMember; 0410 } else if (klass->internalContext() && klass->internalContext()->imports(dec->context())) { 0411 // Using Member of an inherited clas 0412 if (dec->type<KDevelop::FunctionType>()) 0413 type = CodeHighlightingType::InheritedMemberFunction; 0414 else 0415 type = CodeHighlightingType::InheritedClassMember; 0416 } 0417 } 0418 } 0419 0420 if (type == CodeHighlightingType::LocalVariable) { 0421 if (dec->kind() == Declaration::Type || dec->type<KDevelop::FunctionType>() || 0422 dec->type<KDevelop::EnumeratorType>()) { 0423 if (dec->isForwardDeclaration()) 0424 type = CodeHighlightingType::ForwardDeclaration; 0425 else if (dec->type<KDevelop::FunctionType>()) 0426 type = CodeHighlightingType::Function; 0427 else if (dec->type<StructureType>()) 0428 type = CodeHighlightingType::Class; 0429 else if (dec->type<KDevelop::TypeAliasType>()) 0430 type = CodeHighlightingType::TypeAlias; 0431 else if (dec->type<EnumerationType>()) 0432 type = CodeHighlightingType::Enum; 0433 else if (dec->type<KDevelop::EnumeratorType>()) 0434 type = CodeHighlightingType::Enumerator; 0435 } 0436 } 0437 0438 if (type == CodeHighlightingType::LocalVariable) { 0439 switch (dec->context()->type()) { 0440 case DUContext::Namespace: 0441 type = CodeHighlightingType::NamespaceVariable; 0442 break; 0443 case DUContext::Class: 0444 type = CodeHighlightingType::MemberVariable; 0445 break; 0446 case DUContext::Function: 0447 type = CodeHighlightingType::FunctionVariable; 0448 break; 0449 case DUContext::Global: 0450 type = CodeHighlightingType::GlobalVariable; 0451 break; 0452 default: 0453 break; 0454 } 0455 } 0456 0457 return type; 0458 } 0459 0460 bool CodeHighlightingInstance::useRainbowColor(Declaration* dec) const 0461 { 0462 return dec->context()->type() == DUContext::Function || 0463 (dec->context()->type() == DUContext::Other && dec->context()->owner()); 0464 } 0465 0466 void CodeHighlightingInstance::highlightDeclaration(Declaration* declaration, const QColor& color) 0467 { 0468 HighlightedRange h; 0469 h.range = declaration->range(); 0470 h.attribute = m_highlighting->attributeForType(typeForDeclaration(declaration, nullptr), 0471 CodeHighlightingContext::Declaration, color); 0472 m_highlight.push_back(h); 0473 } 0474 0475 void CodeHighlightingInstance::highlightUse(DUContext* context, int index, const QColor& color) 0476 { 0477 Declaration* decl = context->topContext()->usedDeclarationForIndex(context->uses()[index].m_declarationIndex); 0478 0479 auto type = typeForDeclaration(decl, context); 0480 0481 if (type != CodeHighlightingType::Error 0482 || ICore::self()->languageController()->completionSettings()->highlightSemanticProblems()) { 0483 HighlightedRange h; 0484 h.range = context->uses()[index].m_range; 0485 h.attribute = m_highlighting->attributeForType(type, CodeHighlightingContext::Reference, color); 0486 m_highlight.push_back(h); 0487 } 0488 } 0489 0490 void CodeHighlightingInstance::highlightUses(DUContext* context) 0491 { 0492 for (int a = 0; a < context->usesCount(); ++a) 0493 highlightUse(context, a, QColor(QColor::Invalid)); 0494 } 0495 0496 void CodeHighlighting::clearHighlightingForDocument(const IndexedString& document) 0497 { 0498 VERIFY_FOREGROUND_LOCKED 0499 QMutexLocker lock(&m_dataMutex); 0500 DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(document); 0501 auto highlightingIt = m_highlights.find(tracker); 0502 if (highlightingIt != m_highlights.end()) { 0503 disconnect(tracker, &DocumentChangeTracker::destroyed, this, nullptr); 0504 auto& highlighting = *highlightingIt; 0505 qDeleteAll(highlighting->m_highlightedRanges); 0506 delete highlighting; 0507 m_highlights.erase(highlightingIt); 0508 } 0509 } 0510 0511 void CodeHighlighting::applyHighlighting(void* _highlighting) 0512 { 0513 auto* highlighting = 0514 static_cast<CodeHighlighting::DocumentHighlighting*>(_highlighting); 0515 0516 VERIFY_FOREGROUND_LOCKED 0517 QMutexLocker lock(&m_dataMutex); 0518 DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl( 0519 highlighting->m_document); 0520 0521 if (!tracker) { 0522 qCDebug(LANGUAGE) << "no document found for the planned highlighting of" << highlighting->m_document.str(); 0523 delete highlighting; 0524 return; 0525 } 0526 0527 if (!tracker->holdingRevision(highlighting->m_waitingRevision)) { 0528 qCDebug(LANGUAGE) << "not holding revision" << highlighting->m_waitingRevision << "not applying highlighting;" 0529 << "probably a new parse job has already updated the context"; 0530 delete highlighting; 0531 return; 0532 } 0533 0534 QVector<MovingRange*> oldHighlightedRanges; 0535 0536 const auto highlightingIt = m_highlights.find(tracker); 0537 if (highlightingIt != m_highlights.end()) { 0538 oldHighlightedRanges = (*highlightingIt)->m_highlightedRanges; 0539 delete *highlightingIt; 0540 *highlightingIt = highlighting; 0541 } else { 0542 // we newly add this tracker, so add the connection 0543 // This can't use new style connect syntax since MovingInterface is not a QObject 0544 connect(tracker->document(), SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)), 0545 this, SLOT(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*))); 0546 connect(tracker->document(), SIGNAL(aboutToRemoveText(KTextEditor::Range)), 0547 this, SLOT(aboutToRemoveText(KTextEditor::Range))); 0548 connect(tracker, &DocumentChangeTracker::destroyed, this, [this, tracker]() { 0549 // Called when a document is destroyed 0550 VERIFY_FOREGROUND_LOCKED 0551 QMutexLocker lock(&m_dataMutex); 0552 Q_ASSERT(m_highlights.contains(tracker)); 0553 delete m_highlights[tracker]; // No need to care about the individual ranges, as the document is being 0554 // destroyed 0555 m_highlights.remove(tracker); 0556 }); 0557 m_highlights.insert(tracker, highlighting); 0558 } 0559 0560 // Now create MovingRanges (match old ones with the incoming ranges) 0561 0562 KTextEditor::Range tempRange; 0563 0564 QVector<MovingRange*>::iterator movingIt = oldHighlightedRanges.begin(); 0565 QVector<HighlightedRange>::iterator rangeIt = highlighting->m_waiting.begin(); 0566 0567 while (rangeIt != highlighting->m_waiting.end()) { 0568 // Translate the range into the current revision 0569 KTextEditor::Range transformedRange = tracker->transformToCurrentRevision(rangeIt->range, 0570 highlighting->m_waitingRevision); 0571 0572 while (movingIt != oldHighlightedRanges.end() && 0573 ((*movingIt)->start().line() < transformedRange.start().line() || 0574 ((*movingIt)->start().line() == transformedRange.start().line() && 0575 (*movingIt)->start().column() < transformedRange.start().column()))) { 0576 delete *movingIt; // Skip ranges that are in front of the current matched range 0577 ++movingIt; 0578 } 0579 0580 tempRange = transformedRange; 0581 0582 if (movingIt == oldHighlightedRanges.end() || 0583 transformedRange.start().line() != (*movingIt)->start().line() || 0584 transformedRange.start().column() != (*movingIt)->start().column() || 0585 transformedRange.end().line() != (*movingIt)->end().line() || 0586 transformedRange.end().column() != (*movingIt)->end().column()) { 0587 Q_ASSERT(rangeIt->attribute); 0588 // The moving range is behind or unequal, create a new range 0589 highlighting->m_highlightedRanges.push_back(tracker->documentMovingInterface()->newMovingRange(tempRange)); 0590 highlighting->m_highlightedRanges.back()->setAttribute(rangeIt->attribute); 0591 highlighting->m_highlightedRanges.back()->setZDepth(highlightingZDepth); 0592 } else 0593 { 0594 // Update the existing moving range 0595 (*movingIt)->setAttribute(rangeIt->attribute); 0596 (*movingIt)->setRange(tempRange); 0597 highlighting->m_highlightedRanges.push_back(*movingIt); 0598 ++movingIt; 0599 } 0600 ++rangeIt; 0601 } 0602 0603 for (; movingIt != oldHighlightedRanges.end(); ++movingIt) 0604 delete *movingIt; // Delete unmatched moving ranges behind 0605 } 0606 0607 void CodeHighlighting::aboutToInvalidateMovingInterfaceContent(Document* doc) 0608 { 0609 clearHighlightingForDocument(IndexedString(doc->url())); 0610 } 0611 0612 void CodeHighlighting::aboutToRemoveText(const KTextEditor::Range& range) 0613 { 0614 if (range.onSingleLine()) // don't try to optimize this 0615 return; 0616 0617 VERIFY_FOREGROUND_LOCKED 0618 QMutexLocker lock(&m_dataMutex); 0619 Q_ASSERT(qobject_cast<KTextEditor::Document*>(sender())); 0620 auto* doc = static_cast<KTextEditor::Document*>(sender()); 0621 0622 DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser() 0623 ->trackerForUrl(IndexedString(doc->url())); 0624 const auto highlightingIt = m_highlights.constFind(tracker); 0625 if (highlightingIt != m_highlights.constEnd()) { 0626 QVector<MovingRange*>& ranges = (*highlightingIt)->m_highlightedRanges; 0627 QVector<MovingRange*>::iterator it = ranges.begin(); 0628 while (it != ranges.end()) { 0629 if (range.contains((*it)->toRange())) { 0630 delete (*it); 0631 it = ranges.erase(it); 0632 } else { 0633 ++it; 0634 } 0635 } 0636 } 0637 } 0638 } 0639 0640 #include "moc_codehighlighting.cpp"