diff --git a/src/completion/katecompletiondelegate.cpp b/src/completion/katecompletiondelegate.cpp --- a/src/completion/katecompletiondelegate.cpp +++ b/src/completion/katecompletiondelegate.cpp @@ -155,8 +155,7 @@ m_currentColumnStart = m_cachedColumnStarts[index.column()]; - NormalRenderRange rr; - QVector ret = renderer()->decorationsForLine(thisLine, 0, false, &rr, option.state & QStyle::State_Selected); + QVector ret = renderer()->decorationsForLine(thisLine, 0, false, true, option.state & QStyle::State_Selected); //Remove background-colors for (QVector::iterator it = ret.begin(); it != ret.end(); ++it) { diff --git a/src/render/katerenderer.h b/src/render/katerenderer.h --- a/src/render/katerenderer.h +++ b/src/render/katerenderer.h @@ -287,7 +287,7 @@ * * \param selectionsOnly return decorations for selections and/or dynamic highlighting. */ - QVector decorationsForLine(const Kate::TextLine &textLine, int line, bool selectionsOnly = false, KateRenderRange *completionHighlight = nullptr, bool completionSelected = false) const; + QVector decorationsForLine(const Kate::TextLine &textLine, int line, bool selectionsOnly = false, bool completionHighlight = false, bool completionSelected = false) const; // Width calculators qreal spaceWidth() const; diff --git a/src/render/katerenderer.cpp b/src/render/katerenderer.cpp --- a/src/render/katerenderer.cpp +++ b/src/render/katerenderer.cpp @@ -386,157 +386,152 @@ return false; } -QVector KateRenderer::decorationsForLine(const Kate::TextLine &textLine, int line, bool selectionsOnly, KateRenderRange *completionHighlight, bool completionSelected) const +QVector KateRenderer::decorationsForLine(const Kate::TextLine &textLine, int line, bool selectionsOnly, bool completionHighlight, bool completionSelected) const { - QVector newHighlight; + // limit number of attributes we can highlight in reasonable time + const int limitOfRanges = 1024; + auto rangesWithAttributes = m_doc->buffer().rangesForLine(line, m_printerFriendly ? nullptr : m_view, true); + if (rangesWithAttributes.size() > limitOfRanges) { + rangesWithAttributes.clear(); + } + const auto &al = (textLine->attributesList().size() > limitOfRanges) ? QVector() : textLine->attributesList(); // Don't compute the highlighting if there isn't going to be any highlighting - QList rangesWithAttributes = m_doc->buffer().rangesForLine(line, m_printerFriendly ? nullptr : m_view, true); - if (selectionsOnly || !textLine->attributesList().isEmpty() || !rangesWithAttributes.isEmpty()) { - RenderRangeList renderRanges; + if (!(selectionsOnly || !al.isEmpty() || !rangesWithAttributes.isEmpty())) { + return QVector(); + } - // Add the inbuilt highlighting to the list - NormalRenderRange *inbuiltHighlight = new NormalRenderRange(); - const QVector &al = textLine->attributesList(); + // Add the inbuilt highlighting to the list + RenderRangeVector renderRanges; + if (!al.isEmpty()) { + auto ¤tRange = renderRanges.pushNewRange(); for (int i = 0; i < al.count(); ++i) if (al[i].length > 0 && al[i].attributeValue > 0) { - inbuiltHighlight->addRange(new KTextEditor::Range(KTextEditor::Cursor(line, al[i].offset), al[i].length), specificAttribute(al[i].attributeValue)); + currentRange.addRange(KTextEditor::Range(KTextEditor::Cursor(line, al[i].offset), al[i].length), specificAttribute(al[i].attributeValue)); } - renderRanges.append(inbuiltHighlight); - - if (!completionHighlight) { - // check for dynamic hl stuff - const QSet *rangesMouseIn = m_view ? m_view->rangesMouseIn() : nullptr; - const QSet *rangesCaretIn = m_view ? m_view->rangesCaretIn() : nullptr; - bool anyDynamicHlsActive = m_view && (!rangesMouseIn->empty() || !rangesCaretIn->empty()); - - // sort all ranges, we want that the most specific ranges win during rendering, multiple equal ranges are kind of random, still better than old smart rangs behavior ;) - std::sort(rangesWithAttributes.begin(), rangesWithAttributes.end(), rangeLessThanForRenderer); - - // loop over all ranges - for (int i = 0; i < rangesWithAttributes.size(); ++i) { - // real range - Kate::TextRange *kateRange = rangesWithAttributes[i]; - - // calculate attribute, default: normal attribute - KTextEditor::Attribute::Ptr attribute = kateRange->attribute(); - if (anyDynamicHlsActive) { - // check mouse in - if (KTextEditor::Attribute::Ptr attributeMouseIn = attribute->dynamicAttribute(KTextEditor::Attribute::ActivateMouseIn)) { - if (rangesMouseIn->contains(kateRange)) { - attribute = attributeMouseIn; - } - } + } - // check caret in - if (KTextEditor::Attribute::Ptr attributeCaretIn = attribute->dynamicAttribute(KTextEditor::Attribute::ActivateCaretIn)) { - if (rangesCaretIn->contains(kateRange)) { - attribute = attributeCaretIn; - } + if (!completionHighlight) { + // check for dynamic hl stuff + const QSet *rangesMouseIn = m_view ? m_view->rangesMouseIn() : nullptr; + const QSet *rangesCaretIn = m_view ? m_view->rangesCaretIn() : nullptr; + bool anyDynamicHlsActive = m_view && (!rangesMouseIn->empty() || !rangesCaretIn->empty()); + + // sort all ranges, we want that the most specific ranges win during rendering, multiple equal ranges are kind of random, still better than old smart rangs behavior ;) + std::sort(rangesWithAttributes.begin(), rangesWithAttributes.end(), rangeLessThanForRenderer); + + // loop over all ranges + for (int i = 0; i < rangesWithAttributes.size(); ++i) { + // real range + Kate::TextRange *kateRange = rangesWithAttributes[i]; + + // calculate attribute, default: normal attribute + KTextEditor::Attribute::Ptr attribute = kateRange->attribute(); + if (anyDynamicHlsActive) { + // check mouse in + if (KTextEditor::Attribute::Ptr attributeMouseIn = attribute->dynamicAttribute(KTextEditor::Attribute::ActivateMouseIn)) { + if (rangesMouseIn->contains(kateRange)) { + attribute = attributeMouseIn; } } - // span range - NormalRenderRange *additionaHl = new NormalRenderRange(); - additionaHl->addRange(new KTextEditor::Range(*kateRange), attribute); - renderRanges.append(additionaHl); + // check caret in + if (KTextEditor::Attribute::Ptr attributeCaretIn = attribute->dynamicAttribute(KTextEditor::Attribute::ActivateCaretIn)) { + if (rangesCaretIn->contains(kateRange)) { + attribute = attributeCaretIn; + } + } } - } else { - // Add the code completion arbitrary highlight to the list - renderRanges.append(completionHighlight); + + // span range + renderRanges.pushNewRange().addRange(*kateRange, attribute); } + } - // Add selection highlighting if we're creating the selection decorations - if ((m_view && selectionsOnly && showSelections() && m_view->selection()) || (completionHighlight && completionSelected) || (m_view && m_view->blockSelection())) { - NormalRenderRange *selectionHighlight = new NormalRenderRange(); + // Add selection highlighting if we're creating the selection decorations + if ((m_view && selectionsOnly && showSelections() && m_view->selection()) || (completionHighlight && completionSelected) || (m_view && m_view->blockSelection())) { + auto ¤tRange = renderRanges.pushNewRange(); - // Set up the selection background attribute TODO: move this elsewhere, eg. into the config? - static KTextEditor::Attribute::Ptr backgroundAttribute; - if (!backgroundAttribute) { - backgroundAttribute = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute()); - } + // Set up the selection background attribute TODO: move this elsewhere, eg. into the config? + static KTextEditor::Attribute::Ptr backgroundAttribute; + if (!backgroundAttribute) { + backgroundAttribute = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute()); + } - backgroundAttribute->setBackground(config()->selectionColor()); - backgroundAttribute->setForeground(attribute(KTextEditor::dsNormal)->selectedForeground().color()); + backgroundAttribute->setBackground(config()->selectionColor()); + backgroundAttribute->setForeground(attribute(KTextEditor::dsNormal)->selectedForeground().color()); - // Create a range for the current selection - if (completionHighlight && completionSelected) { - selectionHighlight->addRange(new KTextEditor::Range(line, 0, line + 1, 0), backgroundAttribute); - } else if (m_view->blockSelection() && m_view->selectionRange().overlapsLine(line)) { - selectionHighlight->addRange(new KTextEditor::Range(m_doc->rangeOnLine(m_view->selectionRange(), line)), backgroundAttribute); - } else { - selectionHighlight->addRange(new KTextEditor::Range(m_view->selectionRange()), backgroundAttribute); - } - - renderRanges.append(selectionHighlight); - // highlighting for the vi visual modes + // Create a range for the current selection + if (completionHighlight && completionSelected) { + currentRange.addRange(KTextEditor::Range(line, 0, line + 1, 0), backgroundAttribute); + } else if (m_view->blockSelection() && m_view->selectionRange().overlapsLine(line)) { + currentRange.addRange(m_doc->rangeOnLine(m_view->selectionRange(), line), backgroundAttribute); + } else { + currentRange.addRange(m_view->selectionRange(), backgroundAttribute); } + } - KTextEditor::Cursor currentPosition, endPosition; - - // Calculate the range which we need to iterate in order to get the highlighting for just this line - if (m_view && selectionsOnly) { - if (m_view->blockSelection()) { - KTextEditor::Range subRange = m_doc->rangeOnLine(m_view->selectionRange(), line); - currentPosition = subRange.start(); - endPosition = subRange.end(); - } else { - KTextEditor::Range rangeNeeded = m_view->selectionRange() & KTextEditor::Range(line, 0, line + 1, 0); + // no render ranges, nothing to do, else we loop below endless! + if (renderRanges.isEmpty()) { + return QVector(); + } - currentPosition = qMax(KTextEditor::Cursor(line, 0), rangeNeeded.start()); - endPosition = qMin(KTextEditor::Cursor(line + 1, 0), rangeNeeded.end()); - } + // Calculate the range which we need to iterate in order to get the highlighting for just this line + KTextEditor::Cursor currentPosition, endPosition; + if (m_view && selectionsOnly) { + if (m_view->blockSelection()) { + KTextEditor::Range subRange = m_doc->rangeOnLine(m_view->selectionRange(), line); + currentPosition = subRange.start(); + endPosition = subRange.end(); } else { - currentPosition = KTextEditor::Cursor(line, 0); - endPosition = KTextEditor::Cursor(line + 1, 0); + KTextEditor::Range rangeNeeded = m_view->selectionRange() & KTextEditor::Range(line, 0, line + 1, 0); + + currentPosition = qMax(KTextEditor::Cursor(line, 0), rangeNeeded.start()); + endPosition = qMin(KTextEditor::Cursor(line + 1, 0), rangeNeeded.end()); } + } else { + currentPosition = KTextEditor::Cursor(line, 0); + endPosition = KTextEditor::Cursor(line + 1, 0); + } - // Main iterative loop. This walks through each set of highlighting ranges, and stops each - // time the highlighting changes. It then creates the corresponding QTextLayout::FormatRanges. - while (currentPosition < endPosition) { - renderRanges.advanceTo(currentPosition); + // Main iterative loop. This walks through each set of highlighting ranges, and stops each + // time the highlighting changes. It then creates the corresponding QTextLayout::FormatRanges. + QVector newHighlight; + while (currentPosition < endPosition) { + renderRanges.advanceTo(currentPosition); - if (!renderRanges.hasAttribute()) { - // No attribute, don't need to create a FormatRange for this text range - currentPosition = renderRanges.nextBoundary(); - continue; - } + if (!renderRanges.hasAttribute()) { + // No attribute, don't need to create a FormatRange for this text range + currentPosition = renderRanges.nextBoundary(); + continue; + } - KTextEditor::Cursor nextPosition = renderRanges.nextBoundary(); + KTextEditor::Cursor nextPosition = renderRanges.nextBoundary(); - // Create the format range and populate with the correct start, length and format info - QTextLayout::FormatRange fr; - fr.start = currentPosition.column(); + // Create the format range and populate with the correct start, length and format info + QTextLayout::FormatRange fr; + fr.start = currentPosition.column(); - if (nextPosition < endPosition || endPosition.line() <= line) { - fr.length = nextPosition.column() - currentPosition.column(); + if (nextPosition < endPosition || endPosition.line() <= line) { + fr.length = nextPosition.column() - currentPosition.column(); - } else { - // +1 to force background drawing at the end of the line when it's warranted - fr.length = textLine->length() - currentPosition.column() + 1; - } + } else { + // +1 to force background drawing at the end of the line when it's warranted + fr.length = textLine->length() - currentPosition.column() + 1; + } - KTextEditor::Attribute::Ptr a = renderRanges.generateAttribute(); - if (a) { - fr.format = *a; + KTextEditor::Attribute::Ptr a = renderRanges.generateAttribute(); + if (a) { + fr.format = *a; - if (selectionsOnly) { - assignSelectionBrushesFromAttribute(fr, *a); - } + if (selectionsOnly) { + assignSelectionBrushesFromAttribute(fr, *a); } - - newHighlight.append(fr); - - currentPosition = nextPosition; } - if (completionHighlight) - // Don't delete external completion render range - { - renderRanges.removeAll(completionHighlight); - } + newHighlight.append(fr); - qDeleteAll(renderRanges); + currentPosition = nextPosition; } return newHighlight; diff --git a/src/render/katerenderrange.h b/src/render/katerenderrange.h --- a/src/render/katerenderrange.h +++ b/src/render/katerenderrange.h @@ -25,50 +25,42 @@ #include #include -#include -#include +#include +#include -class KateRenderRange -{ -public: - virtual ~KateRenderRange() {} - virtual KTextEditor::Cursor nextBoundary() const = 0; - virtual bool advanceTo(const KTextEditor::Cursor &pos) = 0; - virtual KTextEditor::Attribute::Ptr currentAttribute() const = 0; - virtual bool isReady() const; -}; - -typedef QPair pairRA; - -class NormalRenderRange : public KateRenderRange +class NormalRenderRange { public: NormalRenderRange(); - ~NormalRenderRange() override; - void addRange(KTextEditor::Range *range, KTextEditor::Attribute::Ptr attribute); + void addRange(const KTextEditor::Range &range, KTextEditor::Attribute::Ptr attribute); - KTextEditor::Cursor nextBoundary() const override; - bool advanceTo(const KTextEditor::Cursor &pos) override; - KTextEditor::Attribute::Ptr currentAttribute() const override; + KTextEditor::Cursor nextBoundary() const; + bool advanceTo(const KTextEditor::Cursor &pos); + KTextEditor::Attribute::Ptr currentAttribute() const; private: - QVector m_ranges; + std::vector> m_ranges; KTextEditor::Cursor m_nextBoundary; KTextEditor::Attribute::Ptr m_currentAttribute; - int m_currentRange = 0; + size_t m_currentRange = 0; }; -class RenderRangeList : public QVector +class RenderRangeVector { public: - ~RenderRangeList(); KTextEditor::Cursor nextBoundary() const; void advanceTo(const KTextEditor::Cursor &pos); bool hasAttribute() const; KTextEditor::Attribute::Ptr generateAttribute() const; + NormalRenderRange &pushNewRange(); + bool isEmpty() const + { + return m_ranges.empty(); + } private: + std::vector m_ranges; KTextEditor::Cursor m_currentPos; }; diff --git a/src/render/katerenderrange.cpp b/src/render/katerenderrange.cpp --- a/src/render/katerenderrange.cpp +++ b/src/render/katerenderrange.cpp @@ -76,26 +76,13 @@ } } -bool KateRenderRange::isReady() const -{ - return false; -} - NormalRenderRange::NormalRenderRange() { } -NormalRenderRange::~NormalRenderRange() -{ - QVectorIterator it = m_ranges; - while (it.hasNext()) { - delete it.next().first; - } -} - -void NormalRenderRange::addRange(KTextEditor::Range *range, KTextEditor::Attribute::Ptr attribute) +void NormalRenderRange::addRange(const KTextEditor::Range &range, KTextEditor::Attribute::Ptr attribute) { - m_ranges.append(pairRA(range, attribute)); + m_ranges.push_back(std::make_pair(range, attribute)); } KTextEditor::Cursor NormalRenderRange::nextBoundary() const @@ -105,22 +92,22 @@ bool NormalRenderRange::advanceTo(const KTextEditor::Cursor &pos) { - int index = m_currentRange; - while (index < m_ranges.count()) { - const pairRA &p = m_ranges.at(index); - KTextEditor::Range *r = p.first; - if (r->end() <= pos) { + size_t index = m_currentRange; + while (index < m_ranges.size()) { + const auto &p = m_ranges[index]; + const auto &r = p.first; + if (r.end() <= pos) { ++index; } else { bool ret = index != m_currentRange; m_currentRange = index; - if (r->start() > pos) { - m_nextBoundary = r->start(); + if (r.start() > pos) { + m_nextBoundary = r.start(); } else { - m_nextBoundary = r->end(); + m_nextBoundary = r.end(); } - if (r->contains(pos)) { + if (r.contains(pos)) { m_currentAttribute = p.second; } else { m_currentAttribute.reset(); @@ -140,62 +127,56 @@ return m_currentAttribute; } -KTextEditor::Cursor RenderRangeList::nextBoundary() const +KTextEditor::Cursor RenderRangeVector::nextBoundary() const { KTextEditor::Cursor ret = m_currentPos; bool first = true; - foreach (KateRenderRange *r, *this) { + for (auto &r : m_ranges) { if (first) { - ret = r->nextBoundary(); + ret = r.nextBoundary(); first = false; } else { - KTextEditor::Cursor nb = r->nextBoundary(); + KTextEditor::Cursor nb = r.nextBoundary(); if (ret > nb) { ret = nb; } } } return ret; } -RenderRangeList::~RenderRangeList() +NormalRenderRange &RenderRangeVector::pushNewRange() { + m_ranges.push_back(NormalRenderRange()); + return m_ranges.back(); } -void RenderRangeList::advanceTo(const KTextEditor::Cursor &pos) +void RenderRangeVector::advanceTo(const KTextEditor::Cursor &pos) { - foreach (KateRenderRange *r, *this) { - r->advanceTo(pos); - } - - //Delete lists that are ready, else the list may get too large due to temporaries - for (int a = size() - 1; a >= 0; --a) { - KateRenderRange *r = at(a); - if (r->isReady()) { - delete r; - removeAt(a); - } + for (auto &r : m_ranges) { + r.advanceTo(pos); } } -bool RenderRangeList::hasAttribute() const +bool RenderRangeVector::hasAttribute() const { - foreach (KateRenderRange *r, *this) - if (r->currentAttribute()) { + for (auto &r : m_ranges) { + if (r.currentAttribute()) { return true; } + } return false; } -KTextEditor::Attribute::Ptr RenderRangeList::generateAttribute() const +KTextEditor::Attribute::Ptr RenderRangeVector::generateAttribute() const { KTextEditor::Attribute::Ptr a; bool ownsAttribute = false; - foreach (KateRenderRange *r, *this) { - if (KTextEditor::Attribute::Ptr a2 = r->currentAttribute()) { + for (auto &r : m_ranges) { + if (KTextEditor::Attribute::Ptr a2 = r.currentAttribute()) { if (!a) { a = a2; } else {