void TextBuffer::insertText (const KTextEditor::Cursor &position, const QString &text) { // only allowed if editing transaction running Q_ASSERT (m_editingTransactions > 0); // skip work, if no text to insert if (text.isEmpty()) return; // get block, this will assert on invalid line int blockIndex = blockForLine (position.line()); // let the block handle the insertText m_blocks.at(blockIndex)->insertText (position, text); // remember changes ++m_revision; // update changed line interval if (position.line () < m_editingMinimalLineChanged || m_editingMinimalLineChanged == -1) m_editingMinimalLineChanged = position.line (); if (position.line () > m_editingMaximalLineChanged) m_editingMaximalLineChanged = position.line (); // emit signal about done change emit textInserted (position, text); }
void TextBuffer::wrapLine (const KTextEditor::Cursor &position) { // only allowed if editing transaction running Q_ASSERT (m_editingTransactions > 0); // get block, this will assert on invalid line int blockIndex = blockForLine (position.line()); // let the block handle the wrapLine // this can only lead to one more line in this block // no other blocks will change ++m_lines; // first alter the line counter, as functions called will need the valid one m_blocks.at(blockIndex)->wrapLine (position); // remember changes ++m_revision; // update changed line interval if (position.line() < m_editingMinimalLineChanged || m_editingMinimalLineChanged == -1) m_editingMinimalLineChanged = position.line(); if (position.line() <= m_editingMaximalLineChanged) ++m_editingMaximalLineChanged; else m_editingMaximalLineChanged = position.line() + 1; // fixup all following blocks fixStartLines (blockIndex); // balance the changed block if needed balanceBlock (blockIndex); // emit signal about done change emit lineWrapped (position); }
TextLine TextBuffer::line (int line) const { // get block, this will assert on invalid line int blockIndex = blockForLine (line); // get line return m_blocks.at(blockIndex)->line (line); }
void TextBuffer::unwrapLine (int line) { // only allowed if editing transaction running Q_ASSERT (m_editingTransactions > 0); // line 0 can't be unwrapped Q_ASSERT (line > 0); // get block, this will assert on invalid line int blockIndex = blockForLine (line); // is this the first line in the block? bool firstLineInBlock = (line == m_blocks.at(blockIndex)->startLine()); // let the block handle the unwrapLine // this can either lead to one line less in this block or the previous one // the previous one could even end up with zero lines m_blocks.at(blockIndex)->unwrapLine (line, (blockIndex > 0) ? m_blocks.at(blockIndex-1) : 0); --m_lines; // decrement index for later fixup, if we modified the block in front of the found one if (firstLineInBlock) --blockIndex; // remember changes ++m_revision; // update changed line interval if ((line - 1) < m_editingMinimalLineChanged || m_editingMinimalLineChanged == -1) m_editingMinimalLineChanged = line - 1; if (line <= m_editingMaximalLineChanged) --m_editingMaximalLineChanged; else m_editingMaximalLineChanged = line -1; // fixup all following blocks fixStartLines (blockIndex); // balance the changed block if needed balanceBlock (blockIndex); // emit signal about done change emit lineUnwrapped (line); }
void QDocumentBuffer::insertLines(int after, const QVector<QDocumentLineHandle*>& l) { int index = after + 1; int blockIndex = blockForLine(index); if ( blockIndex == -1 ) { qWarning("cannot insert line at pos %i", index); return; } int n = l.count(); Block *b = m_blocks.at(blockIndex); if ( (b->size() + 1) >= m_forkThresold ) { // split block int bounds = b->start + m_optimalSize; Block *nb = new Block(bounds); nb->insert(bounds, b->lines.constData() + m_optimalSize, b->size() - m_optimalSize); nb->append(l.constData(), n); nb->end = bounds + nb->size(); m_blocks.insert(blockIndex + 1, nb); b->lines.resize(m_optimalSize); b->end = bounds; blockIndex += 2; } else { b->insert(index, l.constData(), n); } // update block boundaries while ( blockIndex < m_blocks.count() ) { b = m_blocks.at(blockIndex); b->start += n; b->end += n; } }
QList<TextRange *> TextBuffer::rangesForLine (int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const { // get block, this will assert on invalid line const int blockIndex = blockForLine (line); // get the ranges of the right block QList<TextRange *> rightRanges; foreach (const QSet<TextRange *> &ranges, m_blocks.at(blockIndex)->rangesForLine (line)) { foreach (TextRange * const range, ranges) { /** * we want only ranges with attributes, but this one has none */ if (rangesWithAttributeOnly && !range->hasAttribute()) continue; /** * we want ranges for no view, but this one's attribute is only valid for views */ if (!view && range->attributeOnlyForViews()) continue; /** * the range's attribute is not valid for this view */ if (range->view() && range->view() != view) continue; /** * if line is in the range, ok */ if (range->startInternal().lineInternal() <= line && line <= range->endInternal().lineInternal()) rightRanges.append (range); } } // return right ranges return rightRanges; }
void TextBuffer::removeText (const KTextEditor::Range &range) { // only allowed if editing transaction running Q_ASSERT (m_editingTransactions > 0); // only ranges on one line are supported Q_ASSERT (range.start().line() == range.end().line()); // start colum <= end column and >= 0 Q_ASSERT (range.start().column() <= range.end().column()); Q_ASSERT (range.start().column() >= 0); // skip work, if no text to remove if (range.isEmpty()) return; // get block, this will assert on invalid line int blockIndex = blockForLine (range.start().line()); // let the block handle the removeText, retrieve removed text QString text; m_blocks.at(blockIndex)->removeText (range, text); // remember changes ++m_revision; // update changed line interval if (range.start().line() < m_editingMinimalLineChanged || m_editingMinimalLineChanged == -1) m_editingMinimalLineChanged = range.start().line(); if (range.start().line() > m_editingMaximalLineChanged) m_editingMaximalLineChanged = range.start().line(); // emit signal about done change emit textRemoved (range, text); }
QDocumentLineHandle* QDocumentBuffer::at(int index) const { int blockIndex = blockForLine(index); return blockIndex != -1 ? m_blocks.at(blockIndex)->at(index) : 0; }
void QDocumentBuffer::removeLines(int after, int n) { int index = after + 1; int blockIndex = blockForLine(index); if ( blockIndex == -1 ) { qWarning("cannot remove line at pos %i", index); return; } // update block boundaries int count = n; Block *b = m_blocks.at(blockIndex); while ( count > 0 ) { int room = b->end - index; int toRem = qMin(room, count); b->remove(index, toRem); b->end -= toRem; count -= toRem; if ( !b->size() ) { m_blocks.remove(blockIndex); delete b; } else { ++blockIndex; } if ( blockIndex >= m_blocks.count() ) break; b = m_blocks.at(blockIndex); b->start -= toRem; } if ( index ) { qWarning("Troubles in line removal"); } if ( b->size() < m_mergeThresold ) { // "merge" block with its neighbors int sz = b->size(); sz += qMin(1, sz / m_safetyRoom); int roomPrev = blockIndex ? m_forkThresold - m_blocks.at(blockIndex - 1)->size() : 0; int roomNext = blockIndex + 1 < m_blocks.count() ? m_forkThresold - m_blocks.at(blockIndex + 1)->size() : 0; bool maxPrev = false; int maxRoom = 0, minRoom = 0; Block *moreRoom = 0, *lessRoom = 0; if ( roomPrev > roomNext ) { maxPrev = true; maxRoom = roomPrev; moreRoom = m_blocks.at(blockIndex - 1); minRoom = roomNext; if ( roomNext ) lessRoom = m_blocks.at(blockIndex + 1); } else { maxRoom = roomNext; if ( roomNext ) moreRoom = m_blocks.at(blockIndex + 1); minRoom = roomPrev; if ( roomPrev ) lessRoom = m_blocks.at(blockIndex - 1); } if ( maxRoom > sz ) { // put everything in one moreRoom->lines << b->lines; moreRoom->end += b->size(); m_blocks.remove(blockIndex); delete b; } else if ( (maxRoom + minRoom) > sz ) { // try to alloc evenly int part = b->size() * maxRoom / (maxRoom + minRoom); moreRoom->append(b->lines.constData(), part); moreRoom->end += part; lessRoom->end += b->size() - part; lessRoom->append(b->lines.constData() + part, b->size() - part); m_blocks.remove(blockIndex); delete b; } else { // cannot merge simply... let's forget about it for now as it is not vital ++blockIndex; } } else { ++blockIndex; } // update block boundaries while ( blockIndex < m_blocks.count() ) { b = m_blocks.at(blockIndex); b->start -= n; b->end -= n; } }
void QDocumentBuffer::removeLine(int index) { int blockIndex = blockForLine(index); if ( blockIndex == -1 ) { qWarning("cannot remove line at pos %i", index); return; } Block *b = m_blocks.at(blockIndex); b->remove(index); --b->end; // if block too small, merge it with blocks around? if ( !b->size() ) { // remove empty block m_blocks.remove(blockIndex); delete b; } else if ( b->size() < m_mergeThresold ) { // "merge" block with its neighbors int n = b->size(); n += qMin(1, n / m_safetyRoom); int roomPrev = blockIndex ? m_forkThresold - m_blocks.at(blockIndex - 1)->size() : 0; int roomNext = blockIndex + 1 < m_blocks.count() ? m_forkThresold - m_blocks.at(blockIndex + 1)->size() : 0; bool maxPrev = false; int maxRoom = 0, minRoom = 0; Block *moreRoom = 0, *lessRoom = 0; if ( roomPrev > roomNext ) { maxPrev = true; maxRoom = roomPrev; moreRoom = m_blocks.at(blockIndex - 1); minRoom = roomNext; if ( roomNext ) lessRoom = m_blocks.at(blockIndex + 1); } else { maxRoom = roomNext; if ( roomNext ) moreRoom = m_blocks.at(blockIndex + 1); minRoom = roomPrev; if ( roomPrev ) lessRoom = m_blocks.at(blockIndex - 1); } if ( maxRoom > n ) { // put everything in one moreRoom->lines << b->lines; moreRoom->end += b->size(); m_blocks.remove(blockIndex); delete b; } else if ( (maxRoom + minRoom) > n ) { // try to alloc evenly int part = b->size() * maxRoom / (maxRoom + minRoom); if ( maxPrev ) { moreRoom->append(b->lines.constData(), part); lessRoom->prepend(b->lines.constData() + part, b->size() - part); } else { moreRoom->prepend(b->lines.constData(), part); lessRoom->append(b->lines.constData() + part, b->size() - part); } moreRoom->end += part; lessRoom->end += b->size() - part; m_blocks.remove(blockIndex); delete b; } else { // cannot merge simply... let's forget about it for now as it is not vital ++blockIndex; } } else { ++blockIndex; } // update block boundaries while ( blockIndex < m_blocks.count() ) { b = m_blocks.at(blockIndex); --b->start; --b->end; } }