codehighlighting.cpp 21.6 KB
Newer Older
1
2
3
/*
 * This file is part of KDevelop
 *
David nolden's avatar
David nolden committed
4
 * Copyright 2007-2010 David Nolden <david.nolden.kdevelop@art-master.de>
5
 * Copyright 2006 Hamish Rodda <rodda@kde.org>
6
 * Copyright 2009 Milian Wolff <mail@milianw.de>
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "codehighlighting.h"

#include <KTextEditor/Document>

28
29
30
#include "../../interfaces/icore.h"
#include "../../interfaces/ilanguagecontroller.h"
#include "../../interfaces/icompletionsettings.h"
Kevin Funk's avatar
Kevin Funk committed
31
#include "../../util/foregroundlock.h"
32
#include <debug.h>
33

34
35
36
37
38
39
40
41
#include "../duchain/declaration.h"
#include "../duchain/types/functiontype.h"
#include "../duchain/types/enumeratortype.h"
#include "../duchain/types/typealiastype.h"
#include "../duchain/types/enumerationtype.h"
#include "../duchain/types/structuretype.h"
#include "../duchain/functiondefinition.h"
#include "../duchain/use.h"
42
43
44

#include "colorcache.h"
#include "configurablecolors.h"
David nolden's avatar
David nolden committed
45
46
47
#include <duchain/parsingenvironment.h>
#include <backgroundparser/backgroundparser.h>
#include <ktexteditor/movinginterface.h>
48
#include <backgroundparser/urlparselock.h>
49
50
51

using namespace KTextEditor;

52
53
static const float highlightingZDepth = -500;

54
55
#define ifDebug(x)

56
57
namespace KDevelop {

David nolden's avatar
David nolden committed
58
///@todo Don't highlighting everything, only what is visible on-demand
59

60
CodeHighlighting::CodeHighlighting( QObject * parent )
David nolden's avatar
David nolden committed
61
  : QObject(parent), m_localColorization(true), m_globalColorization(true), m_dataMutex(QMutex::Recursive)
62
{
David nolden's avatar
David nolden committed
63
64
  qRegisterMetaType<KDevelop::IndexedString>("KDevelop::IndexedString");

65
66
  adaptToColorChanges();

67
68
  connect(ColorCache::self(), &ColorCache::colorsGotChanged,
           this, &CodeHighlighting::adaptToColorChanges);
69
70
71
72
}

CodeHighlighting::~CodeHighlighting( )
{
73
  qDeleteAll(m_highlights);
74
75
}

76
77
void CodeHighlighting::adaptToColorChanges()
{
78
  QMutexLocker lock(&m_dataMutex);
79
80
81
82
83
  // disable local highlighting if the ratio is set to 0
  m_localColorization = ICore::self()->languageController()->completionSettings()->localColorizationLevel() > 0;
  // disable global highlighting if the ratio is set to 0
  m_globalColorization = ICore::self()->languageController()->completionSettings()->globalColorizationLevel() > 0;

84
85
86
87
88
89
  m_declarationAttributes.clear();
  m_definitionAttributes.clear();
  m_depthAttributes.clear();
  m_referenceAttributes.clear();
}

90
KTextEditor::Attribute::Ptr CodeHighlighting::attributeForType( Types type, Contexts context, const QColor &color ) const
91
{
92
  QMutexLocker lock(&m_dataMutex);
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  KTextEditor::Attribute::Ptr a;
  switch (context) {
    case DefinitionContext:
      a = m_definitionAttributes[type];
      break;

    case DeclarationContext:
      a = m_declarationAttributes[type];
      break;

    case ReferenceContext:
      a = m_referenceAttributes[type];
      break;
  }

108
  if ( !a || color.isValid() ) {
109

110
    a = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute(*ColorCache::self()->defaultColors()->attribute(type)));
111

112
    if ( context == DefinitionContext || context == DeclarationContext ) {
113
114
115
      if (ICore::self()->languageController()->completionSettings()->boldDeclarations()) {
        a->setFontBold();
      }
116
117
    }

118
119
    if( color.isValid() ) {
      a->setForeground(color);
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//       a->setBackground(QColor(mix(0xffffff-color, backgroundColor(), 255-backgroundTinting)));
    } else {
      switch (context) {
        case DefinitionContext:
          m_definitionAttributes.insert(type, a);
          break;
        case DeclarationContext:
          m_declarationAttributes.insert(type, a);
          break;
        case ReferenceContext:
          m_referenceAttributes.insert(type, a);
          break;
      }
    }
  }

  return a;
}

ColorMap emptyColorMap() {
140
 ColorMap ret(ColorCache::self()->validColorCount()+1, nullptr);
141
142
143
 return ret;
}

144
145
146
147
148
CodeHighlightingInstance* CodeHighlighting::createInstance() const
{
  return new CodeHighlightingInstance(this);
}

149
150
151
152
153
154
155
156
157
158
159
bool CodeHighlighting::hasHighlighting(IndexedString url) const
{
  DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url);
  if(tracker)
  {
    QMutexLocker lock(&m_dataMutex);
    return m_highlights.contains(tracker) && !m_highlights[tracker]->m_highlightedRanges.isEmpty();
  }
  return false;
}

160
void CodeHighlighting::highlightDUChain(ReferencedTopDUContext context)
161
{
162
163
  ENSURE_CHAIN_NOT_LOCKED

164
165
166
167
  IndexedString url;

  {
    DUChainReadLocker lock;
168
169
170
    if (!context)
        return;

171
172
    url = context->url();
  }
David nolden's avatar
David nolden committed
173

174
175
176
177
  // This prevents the background-parser from updating the top-context while we're working with it
  UrlParseLock urlLock(context->url());

  DUChainReadLocker lock;
178

David nolden's avatar
David nolden committed
179
180
  qint64 revision = context->parsingEnvironmentFile()->modificationRevision().revision;

Dāvis Mosāns's avatar
Dāvis Mosāns committed
181
  qCDebug(LANGUAGE) << "highlighting du chain" << url.toUrl();
182

183
  if ( !m_localColorization && !m_globalColorization ) {
Dāvis Mosāns's avatar
Dāvis Mosāns committed
184
    qCDebug(LANGUAGE) << "highlighting disabled";
David nolden's avatar
David nolden committed
185
    QMetaObject::invokeMethod(this, "clearHighlightingForDocument", Qt::QueuedConnection, Q_ARG(KDevelop::IndexedString, url));
186
187
    return;
  }
188

189
190
  CodeHighlightingInstance* instance = createInstance();

David nolden's avatar
David nolden committed
191
  lock.unlock();
192

193
194
  instance->highlightDUChain(context.data());

David nolden's avatar
David nolden committed
195
196
197
198
  DocumentHighlighting* highlighting = new DocumentHighlighting;
  highlighting->m_document = url;
  highlighting->m_waitingRevision = revision;
  highlighting->m_waiting = instance->m_highlight;
Kevin Funk's avatar
Kevin Funk committed
199
  std::sort(highlighting->m_waiting.begin(), highlighting->m_waiting.end());
200

201
  QMetaObject::invokeMethod(this, "applyHighlighting", Qt::QueuedConnection, Q_ARG(void*, highlighting));
202

David nolden's avatar
David nolden committed
203
  delete instance;
204
205
}

206
void CodeHighlightingInstance::highlightDUChain(TopDUContext* context)
207
{
208
209
210
211
  m_contextClasses.clear();
  m_useClassCache = true;

  //Highlight
212
  highlightDUChain(context, QHash<Declaration*, uint>(), emptyColorMap());
213
214
215
216
217
218
219
220

  m_functionColorsForDeclarations.clear();
  m_functionDeclarationsForColors.clear();

  m_useClassCache = false;
  m_contextClasses.clear();
}

David nolden's avatar
David nolden committed
221
void CodeHighlightingInstance::highlightDUChain(DUContext* context, QHash<Declaration*, uint> colorsForDeclarations, ColorMap declarationsForColors)
222
{
223
224
  DUChainReadLocker lock;

225
  TopDUContext* top = context->topContext();
226

227
228
229
230
231
232
233
234
235
236
237
238
239
240
  //Merge the colors from the function arguments
  foreach( const DUContext::Import &imported, context->importedParentContexts() ) {
    if(!imported.context(top) || (imported.context(top)->type() != DUContext::Other && imported.context(top)->type() != DUContext::Function))
      continue;
    //For now it's enough simply copying them, because we only pass on colors within function bodies.
    if (m_functionColorsForDeclarations.contains(imported.context(top)))
      colorsForDeclarations = m_functionColorsForDeclarations[imported.context(top)];
    if (m_functionDeclarationsForColors.contains(imported.context(top)))
      declarationsForColors = m_functionDeclarationsForColors[imported.context(top)];
  }

  QList<Declaration*> takeFreeColors;

  foreach (Declaration* dec, context->localDeclarations()) {
241
242
243
244
    if (!useRainbowColor(dec)) {
      highlightDeclaration(dec, QColor(QColor::Invalid));
      continue;
    }
245
    //Initially pick a color using the hash, so the chances are good that the same identifier gets the same color always.
246
    uint colorNum = dec->identifier().hash() % ColorCache::self()->primaryColorCount();
247
248
249
250
251
252
253
254
255

    if( declarationsForColors[colorNum] ) {
      takeFreeColors << dec; //Use one of the colors that stays free
      continue;
    }

    colorsForDeclarations[dec] = colorNum;
    declarationsForColors[colorNum] = dec;

256
    highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum));
257
258
  }

259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
    foreach (Declaration* dec, takeFreeColors) {
        uint colorNum = dec->identifier().hash() % ColorCache::self()->primaryColorCount();
        uint oldColorNum = colorNum;
        while (declarationsForColors[colorNum]) {
            colorNum = (colorNum + 1) % ColorCache::self()->primaryColorCount();
            if (colorNum == oldColorNum) {
                colorNum = ColorCache::self()->primaryColorCount();
                break;
            }
        }

        if (colorNum < ColorCache::self()->primaryColorCount()) {
           // Use primary color
            colorsForDeclarations[dec] = colorNum;
            declarationsForColors[colorNum] = dec;
            highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum));
        } else {
            // Try to use supplementary color
            colorNum = ColorCache::self()->primaryColorCount();
            while (declarationsForColors[colorNum]) {
                colorNum++;
                if (colorNum == ColorCache::self()->validColorCount()) {
                    //If no color could be found, use default color
                    highlightDeclaration(dec, QColor(QColor::Invalid));
                    break;
                }
            }
            if (colorNum < ColorCache::self()->validColorCount()) {
                // Use supplementary color
                colorsForDeclarations[dec] = colorNum;
                declarationsForColors[colorNum] = dec;
                highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum));
            }

        }
294
    }
295
296
297

  for(int a = 0; a < context->usesCount(); ++a) {
    Declaration* decl = context->topContext()->usedDeclarationForIndex(context->uses()[a].m_declarationIndex);
298
    QColor color(QColor::Invalid);
299
    if( colorsForDeclarations.contains(decl) )
300
      color = ColorCache::self()->generatedColor(colorsForDeclarations[decl]);
301
    highlightUse(context, a, color);
302
303
304
305
306
307
  }

  if(context->type() == DUContext::Other || context->type() == DUContext::Function) {
    m_functionColorsForDeclarations[IndexedDUContext(context)] = colorsForDeclarations;
    m_functionDeclarationsForColors[IndexedDUContext(context)] = declarationsForColors;
  }
308

309
  const QVector<DUContext*> children = context->childContexts();
310
311
312

  lock.unlock(); // Periodically release the lock, so that the UI won't be blocked too much

313
  for (DUContext* child : children) {
314
    highlightDUChain(child,  colorsForDeclarations, declarationsForColors );
315
  }
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
}

KTextEditor::Attribute::Ptr CodeHighlighting::attributeForDepth(int depth) const
{
  while (depth >= m_depthAttributes.count()) {
    KTextEditor::Attribute::Ptr a(new KTextEditor::Attribute());
    a->setBackground(QColor(Qt::white).dark(100 + (m_depthAttributes.count() * 25)));
    a->setBackgroundFillWhitespace(true);
    if (depth % 2)
      a->setOutline(Qt::red);
    m_depthAttributes.append(a);
  }

  return m_depthAttributes[depth];
}

332
KDevelop::Declaration* CodeHighlightingInstance::localClassFromCodeContext(KDevelop::DUContext* context) const
333
334
{
  if(!context)
335
    return nullptr;
336
337
338
339
340
341

  if(m_contextClasses.contains(context))
    return m_contextClasses[context];

  DUContext* startContext = context;

342
343
344
345
346
347
348
  while( context->type() == DUContext::Other )
  {
    //Move context to the top context of type "Other". This is needed because every compound-statement creates a new sub-context.
    auto parent = context->parentContext();
    if (!parent || (parent->type() != DUContext::Other && parent->type() != DUContext::Function)) {
      break;
    }
349
350
351
352
    context = context->parentContext();
  }

  ///Step 1: Find the function-declaration for the function we are in
353
  Declaration* functionDeclaration = nullptr;
354
355
356
357
358
359
360
361
362
363
364
365
366
367

  if( FunctionDefinition* def = dynamic_cast<FunctionDefinition*>(context->owner()) ) {

    if(m_contextClasses.contains(context))
      return m_contextClasses[context];

    functionDeclaration = def->declaration(startContext->topContext());
  }

  if( !functionDeclaration && context->owner() )
    functionDeclaration = context->owner();

  if(!functionDeclaration) {
    if(m_useClassCache)
368
369
      m_contextClasses[context] = nullptr;
    return nullptr;
370
371
372
373
374
375
376
377
378
379
  }

  Declaration* decl  = functionDeclaration->context()->owner();

  if(m_useClassCache)
    m_contextClasses[context] = decl;

  return decl;
}

380
CodeHighlightingInstance::Types CodeHighlightingInstance::typeForDeclaration(Declaration * dec, DUContext* context) const
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
{
  /**
   * We highlight in 3 steps by priority:
   * 1. Is the item in the local class or an inherited class? If yes, highlight.
   * 2. What kind of item is it? If it's a type/function/enumerator, highlight by type.
   * 3. Else, highlight by scope.
   *
   * */

//   if(ClassMemberDeclaration* classMember = dynamic_cast<ClassMemberDeclaration*>(dec))
//     if(!Cpp::isAccessible(context, classMember))
//       return ErrorVariableType;

  if(!dec)
    return ErrorVariableType;

  Types type = LocalVariableType;
  if(dec->kind() == Declaration::Namespace)
    return NamespaceType;
400

401
402
403
404
  if(dec->kind() == Declaration::Macro){
    return MacroType;
  }

405
  if (context && dec->context() && dec->context()->type() == DUContext::Class) {
406
407
408
409
410
411
    //It is a use.
    //Determine the class we're in
    Declaration* klass = localClassFromCodeContext(context);
    if(klass) {
      if (klass->internalContext() == dec->context())
        type = LocalClassMemberType; //Using Member of the local class
Milian Wolff's avatar
Milian Wolff committed
412
      else if (klass->internalContext() && klass->internalContext()->imports(dec->context()))
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
        type = InheritedClassMemberType; //Using Member of an inherited class
    }
  }

  if (type == LocalVariableType) {
    if (dec->kind() == Declaration::Type || dec->type<KDevelop::FunctionType>() || dec->type<KDevelop::EnumeratorType>()) {
      if (dec->isForwardDeclaration())
        type = ForwardDeclarationType;
      else if (dec->type<KDevelop::FunctionType>())
          type = FunctionType;
      else if(dec->type<StructureType>())
          type = ClassType;
      else if(dec->type<KDevelop::TypeAliasType>())
          type = TypeAliasType;
      else if(dec->type<EnumerationType>())
        type = EnumType;
      else if(dec->type<KDevelop::EnumeratorType>())
        type = EnumeratorType;
    }
  }

  if (type == LocalVariableType) {

    switch (dec->context()->type()) {
      case DUContext::Namespace:
        type = NamespaceVariableType;
        break;
      case DUContext::Class:
        type = MemberVariableType;
        break;
      case DUContext::Function:
        type = FunctionVariableType;
        break;
446
447
448
      case DUContext::Global:
        type = GlobalVariableType;
        break;
449
450
451
452
453
454
455
456
      default:
        break;
    }
  }

  return type;
}

457
458
459
460
461
bool CodeHighlightingInstance::useRainbowColor(Declaration* dec) const
{
  return dec->context()->type() == DUContext::Function || (dec->context()->type() == DUContext::Other && dec->context()->owner());
}

David nolden's avatar
David nolden committed
462
463
464
465
void CodeHighlightingInstance::highlightDeclaration(Declaration * declaration, const QColor &color)
{
  HighlightedRange h;
  h.range = declaration->range();
466
  h.attribute = m_highlighting->attributeForType(typeForDeclaration(declaration, nullptr), DeclarationContext, color);
David nolden's avatar
David nolden committed
467
468
469
470
  m_highlight.push_back(h);
}

void CodeHighlightingInstance::highlightUse(DUContext* context, int index, const QColor &color)
471
{
David nolden's avatar
David nolden committed
472
473
  Types type = ErrorVariableType;
  Declaration* decl = context->topContext()->usedDeclarationForIndex(context->uses()[index].m_declarationIndex);
474

David nolden's avatar
David nolden committed
475
  type = typeForDeclaration(decl, context);
476

David nolden's avatar
David nolden committed
477
478
479
480
481
482
  if(type != ErrorVariableType || ICore::self()->languageController()->completionSettings()->highlightSemanticProblems())
  {
    HighlightedRange h;
    h.range = context->uses()[index].m_range;
    h.attribute = m_highlighting->attributeForType(type, ReferenceContext, color);
    m_highlight.push_back(h);
483
484
485
  }
}

David nolden's avatar
David nolden committed
486
void CodeHighlightingInstance::highlightUses(DUContext* context)
487
{
David nolden's avatar
David nolden committed
488
489
490
  for(int a = 0; a < context->usesCount(); ++a)
    highlightUse(context, a, QColor(QColor::Invalid));
}
491

492

493
void CodeHighlighting::clearHighlightingForDocument(const IndexedString& document)
David nolden's avatar
David nolden committed
494
495
496
497
498
499
{
  VERIFY_FOREGROUND_LOCKED
  QMutexLocker lock(&m_dataMutex);
  DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(document);
  if(m_highlights.contains(tracker))
  {
500
    disconnect(tracker, &DocumentChangeTracker::destroyed, this, &CodeHighlighting::trackerDestroyed);
David nolden's avatar
David nolden committed
501
502
503
504
505
506
    qDeleteAll(m_highlights[tracker]->m_highlightedRanges);
    delete m_highlights[tracker];
    m_highlights.remove(tracker);
  }
}

507
void CodeHighlighting::applyHighlighting(void* _highlighting)
David nolden's avatar
David nolden committed
508
{
509
510
  CodeHighlighting::DocumentHighlighting* highlighting = static_cast<CodeHighlighting::DocumentHighlighting*>(_highlighting);

David nolden's avatar
David nolden committed
511
512
513
  VERIFY_FOREGROUND_LOCKED
  QMutexLocker lock(&m_dataMutex);
  DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(highlighting->m_document);
514

David nolden's avatar
David nolden committed
515
516
  if(!tracker)
  {
Dāvis Mosāns's avatar
Dāvis Mosāns committed
517
    qCDebug(LANGUAGE) << "no document found for the planned highlighting of" << highlighting->m_document.str();
David nolden's avatar
David nolden committed
518
519
520
521
    delete highlighting;
    return;
  }

522
523
524
525
526
527
528
  if(!tracker->holdingRevision(highlighting->m_waitingRevision)) {
    qCDebug(LANGUAGE) << "not holding revision" << highlighting->m_waitingRevision << "not applying highlighting;"
                      << "probably a new parse job has already updated the context";
    delete highlighting;
    return;
  }

David nolden's avatar
David nolden committed
529
530
531
532
533
534
535
536
  QVector< MovingRange* > oldHighlightedRanges;

  if(m_highlights.contains(tracker))
  {
    oldHighlightedRanges = m_highlights[tracker]->m_highlightedRanges;
    delete m_highlights[tracker];
  }else{
    // we newly add this tracker, so add the connection
537
    // This can't use new style connect syntax since MovingInterface is not a QObject
538
539
    connect(tracker->document(), SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)),
            this, SLOT(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)));
540
541
    connect(tracker->document(), SIGNAL(aboutToRemoveText(KTextEditor::Range)),
            this, SLOT(aboutToRemoveText(KTextEditor::Range)));
542
    connect(tracker, &DocumentChangeTracker::destroyed, this, &CodeHighlighting::trackerDestroyed);
David nolden's avatar
David nolden committed
543
  }
544

David nolden's avatar
David nolden committed
545
546
547
548
549
550
551
552
553
554
555
556
  m_highlights[tracker] = highlighting;

  // Now create MovingRanges (match old ones with the incoming ranges)

  KTextEditor::Range tempRange;

  QVector<MovingRange*>::iterator movingIt = oldHighlightedRanges.begin();
  QVector<HighlightedRange>::iterator rangeIt = highlighting->m_waiting.begin();

  while(rangeIt != highlighting->m_waiting.end())
  {
    // Translate the range into the current revision
557
    KTextEditor::Range transformedRange = tracker->transformToCurrentRevision(rangeIt->range, highlighting->m_waitingRevision);
David nolden's avatar
David nolden committed
558
559

    while(movingIt != oldHighlightedRanges.end() &&
560
561
      ((*movingIt)->start().line() < transformedRange.start().line() ||
      ((*movingIt)->start().line() == transformedRange.start().line() && (*movingIt)->start().column() < transformedRange.start().column())))
David nolden's avatar
David nolden committed
562
563
564
    {
      delete *movingIt; // Skip ranges that are in front of the current matched range
      ++movingIt;
565
566
    }

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
567

568
    tempRange = transformedRange;
David nolden's avatar
David nolden committed
569
570

    if(movingIt == oldHighlightedRanges.end() ||
571
572
573
574
      transformedRange.start().line() != (*movingIt)->start().line() ||
      transformedRange.start().column() != (*movingIt)->start().column() ||
      transformedRange.end().line() != (*movingIt)->end().line() ||
      transformedRange.end().column() != (*movingIt)->end().column())
David nolden's avatar
David nolden committed
575
    {
576
      Q_ASSERT(rangeIt->attribute);
David nolden's avatar
David nolden committed
577
578
579
      // The moving range is behind or unequal, create a new range
      highlighting->m_highlightedRanges.push_back(tracker->documentMovingInterface()->newMovingRange(tempRange));
      highlighting->m_highlightedRanges.back()->setAttribute(rangeIt->attribute);
580
      highlighting->m_highlightedRanges.back()->setZDepth(highlightingZDepth);
David nolden's avatar
David nolden committed
581
    }
582
    else
David nolden's avatar
David nolden committed
583
584
585
586
    {
      // Update the existing moving range
      (*movingIt)->setAttribute(rangeIt->attribute);
      (*movingIt)->setRange(tempRange);
587
      highlighting->m_highlightedRanges.push_back(*movingIt);
David nolden's avatar
David nolden committed
588
589
      ++movingIt;
    }
590
    ++rangeIt;
591
  }
David nolden's avatar
David nolden committed
592
593
594

  for(; movingIt != oldHighlightedRanges.end(); ++movingIt)
    delete *movingIt; // Delete unmatched moving ranges behind
595
596
}

David nolden's avatar
David nolden committed
597
void CodeHighlighting::trackerDestroyed(QObject* object)
598
{
David nolden's avatar
David nolden committed
599
600
601
602
603
604
605
  // Called when a document is destroyed
  VERIFY_FOREGROUND_LOCKED
  QMutexLocker lock(&m_dataMutex);
  DocumentChangeTracker* tracker = static_cast<DocumentChangeTracker*>(object);
  Q_ASSERT(m_highlights.contains(tracker));
  delete m_highlights[tracker]; // No need to care about the individual ranges, as the document is being destroyed
  m_highlights.remove(tracker);
606
607
}

608
609
610
611
void CodeHighlighting::aboutToInvalidateMovingInterfaceContent(Document* doc)
{
  clearHighlightingForDocument(IndexedString(doc->url()));
}
David nolden's avatar
David nolden committed
612

613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
void CodeHighlighting::aboutToRemoveText( const KTextEditor::Range& range )
{
  if (range.onSingleLine()) // don't try to optimize this
    return;

  VERIFY_FOREGROUND_LOCKED
  QMutexLocker lock(&m_dataMutex);
  Q_ASSERT(dynamic_cast<KTextEditor::Document*>(sender()));
  KTextEditor::Document* doc = static_cast<KTextEditor::Document*>(sender());

  DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()
                                      ->trackerForUrl(IndexedString(doc->url()));
  if(m_highlights.contains(tracker))
  {
    QVector<MovingRange*>& ranges = m_highlights.value(tracker)->m_highlightedRanges;
    QVector<MovingRange*>::iterator it = ranges.begin();
    while(it != ranges.end()) {
      if (range.contains((*it)->toRange())) {
        delete (*it);
        it = ranges.erase(it);
      } else {
        ++it;
      }
    }
  }
}
David nolden's avatar
David nolden committed
639

640
641
}

642

643
// kate: space-indent on; indent-width 2; remove-trailing-spaces all; show-tabs on; tab-indents on; tab-width 2;