7#include "katetextblock.h"
8#include "katetextbuffer.h"
9#include "katetextcursor.h"
10#include "katetextrange.h"
16 , m_startLine(startLine)
19 m_lines.reserve(BufferBlockSize);
25 Q_ASSERT(m_blockSize == 0);
26 Q_ASSERT(m_lines.empty());
27 Q_ASSERT(m_cursors.empty());
63 m_lines.emplace_back(textOfLine);
64 m_blockSize += textOfLine.
size();
76 for (
size_t i = 0; i < m_lines.size(); ++i) {
82 text.append(m_lines.at(i).text());
95 Q_ASSERT(position.
column() >= 0);
105 if (position.
column() > 0 ||
text.size() == 0 || m_lines.at(
line).markedAsModified()) {
106 m_lines.at(
line + 1).markAsModified(
true);
107 }
else if (m_lines.at(
line).markedAsSavedOnDisk()) {
108 m_lines.at(
line + 1).markAsSavedOnDisk(
true);
120 m_lines.at(
line).markAsModified(
true);
126 m_buffer->fixStartLines(fixStartLinesStartIndex);
129 m_buffer->
history().wrapLine(position);
136 if (m_cursors.empty()) {
145 if (cursor->lineInBlock() <
line) {
150 if (cursor->lineInBlock() >
line) {
158 if (cursor->column() <= position.
column()) {
159 if (cursor->column() < position.
column() || !cursor->m_moveOnInsert) {
170 cursor->m_column -= position.
column();
174 auto range = cursor->kateRange();
175 if (range && !range->isValidityCheckRequired()) {
176 range->setValidityCheckRequired();
183 for (
TextRange *range : std::as_const(changedRanges)) {
189 range->checkValidity(range->toLineRange());
201 Q_ASSERT(previousBlock);
202 Q_ASSERT(previousBlock->
lines() > 0);
205 const TextLine oldFirst = m_lines.at(0);
206 int lastLineOfPreviousBlock = previousBlock->
lines() - 1;
207 m_lines[0] = previousBlock->m_lines.back();
208 previousBlock->m_lines.erase(previousBlock->m_lines.begin() + (previousBlock->
lines() - 1));
210 const int oldSizeOfPreviousLine = m_lines[0].text().size();
211 if (oldFirst.
length() > 0) {
213 m_lines[0].text().append(oldFirst.
text());
216 m_lines[0].markAsModified(
true);
225 m_buffer->fixStartLines(fixStartLinesStartIndex);
233 if (m_cursors.empty() && previousBlock->m_cursors.empty()) {
242 if (cursor->lineInBlock() == 0) {
244 cursor->m_column += oldSizeOfPreviousLine;
247 auto range = cursor->kateRange();
248 if (range && !range->isValidityCheckRequired()) {
249 range->setValidityCheckRequired();
256 for (
auto it = previousBlock->m_cursors.begin(); it != previousBlock->m_cursors.end();) {
258 if (cursor->lineInBlock() == lastLineOfPreviousBlock) {
260 cursor->m_block =
this;
261 m_cursors.insert(cursor);
264 auto range = cursor->kateRange();
265 if (range && !range->isValidityCheckRequired()) {
266 range->setValidityCheckRequired();
271 it = previousBlock->m_cursors.erase(it);
281 for (
TextRange *range : std::as_const(changedRanges)) {
287 range->checkValidity(range->toLineRange());
295 const int oldSizeOfPreviousLine = m_lines.at(
line - 1).length();
296 const int sizeOfCurrentLine = m_lines.at(
line).length();
297 if (sizeOfCurrentLine > 0) {
298 m_lines.at(
line - 1).text().append(m_lines.at(
line).text());
301 const bool lineChanged = (oldSizeOfPreviousLine > 0 && m_lines.at(
line - 1).markedAsModified())
302 || (sizeOfCurrentLine > 0 && (oldSizeOfPreviousLine > 0 || m_lines.at(
line).markedAsModified()));
303 m_lines.at(
line - 1).markAsModified(lineChanged);
304 if (oldSizeOfPreviousLine == 0 && m_lines.at(
line).markedAsSavedOnDisk()) {
305 m_lines.at(
line - 1).markAsSavedOnDisk(
true);
308 m_lines.erase(m_lines.begin() +
line);
313 m_buffer->fixStartLines(fixStartLinesStartIndex);
321 if (m_cursors.empty()) {
330 if (cursor->lineInBlock() <
line) {
335 if (cursor->lineInBlock() ==
line) {
337 cursor->m_column += oldSizeOfPreviousLine;
344 auto range = cursor->kateRange();
345 if (range && !range->isValidityCheckRequired()) {
346 range->setValidityCheckRequired();
353 for (
TextRange *range : std::as_const(changedRanges)) {
359 range->checkValidity(range->toLineRange());
370 int oldLength = textOfLine.
size();
371 m_lines.at(
line).markAsModified(
true);
374 Q_ASSERT(position.
column() >= 0);
375 Q_ASSERT(position.
column() <= textOfLine.
size());
381 m_buffer->
history().insertText(position,
text.size(), oldLength);
383 m_blockSize +=
text.size();
388 if (m_cursors.empty()) {
397 if (cursor->lineInBlock() !=
line) {
402 if (cursor->column() <= position.
column()) {
403 if (cursor->column() < position.
column() || !cursor->m_moveOnInsert) {
409 if (cursor->m_column <= oldLength) {
414 else if (cursor->m_column < textOfLine.
size()) {
415 cursor->m_column = textOfLine.
size();
420 auto range = cursor->kateRange();
421 if (range && !range->isValidityCheckRequired() && (range->feedback() || range->start().line() == range->end().line())) {
422 range->setValidityCheckRequired();
429 for (
TextRange *range : std::as_const(changedRanges)) {
430 range->checkValidity(range->toLineRange());
441 int oldLength = textOfLine.
size();
454 m_lines.at(
line).markAsModified(
true);
457 m_buffer->
history().removeText(range, oldLength);
459 m_blockSize -= removedText.
size();
464 if (m_cursors.empty()) {
473 if (cursor->lineInBlock() !=
line) {
483 if (cursor->column() <= range.
end().
column()) {
491 auto range = cursor->kateRange();
492 if (range && !range->isValidityCheckRequired() && (range->feedback() || range->
start().
line() == range->
end().
line())) {
493 range->setValidityCheckRequired();
500 for (
TextRange *range : std::as_const(changedRanges)) {
508 for (
size_t i = 0; i < m_lines.size(); ++i) {
509 printf(
"%4d - %4llu : %4llu : '%s'\n",
512 (
unsigned long long)m_lines.at(i).text().size(),
513 qPrintable(m_lines.at(i).text()));
520 int linesOfNewBlock =
lines() - fromLine;
526 newBlock->m_lines.reserve(linesOfNewBlock);
527 for (
size_t i = fromLine; i < m_lines.size(); ++i) {
528 auto line = std::move(m_lines[i]);
531 newBlock->m_lines.push_back(std::move(
line));
534 m_lines.resize(fromLine);
537 for (
auto it = m_cursors.begin(); it != m_cursors.end();) {
539 if (cursor->lineInBlock() >= fromLine) {
540 cursor->m_line = cursor->lineInBlock() - fromLine;
541 cursor->m_block = newBlock;
544 newBlock->m_cursors.insert(cursor);
545 it = m_cursors.erase(it);
554 std::vector<TextRange *> allRanges;
555 allRanges.reserve(m_uncachedRanges.size() + m_cachedLineForRanges.size());
556 std::for_each(m_cachedLineForRanges.keyBegin(), m_cachedLineForRanges.keyEnd(), [&allRanges](
TextRange *range) {
557 allRanges.push_back(range);
559 allRanges.insert(allRanges.end(), m_uncachedRanges.begin(), m_uncachedRanges.end());
574 cursor->m_line = cursor->lineInBlock() + targetBlock->
lines();
575 cursor->m_block = targetBlock;
576 targetBlock->m_cursors.insert(cursor);
581 targetBlock->m_lines.reserve(targetBlock->
lines() +
lines());
582 for (
size_t i = 0; i < m_lines.size(); ++i) {
583 targetBlock->m_lines.push_back(m_lines.at(i));
585 targetBlock->m_blockSize += m_blockSize;
590 std::vector<TextRange *> allRanges;
591 allRanges.reserve(m_uncachedRanges.size() + m_cachedLineForRanges.size());
592 std::for_each(m_cachedLineForRanges.keyBegin(), m_cachedLineForRanges.keyEnd(), [&allRanges](
TextRange *range) {
593 allRanges.push_back(range);
595 allRanges.insert(allRanges.end(), m_uncachedRanges.begin(), m_uncachedRanges.end());
608 for (
auto it = m_cursors.begin(); it != m_cursors.end();) {
610 if (!cursor->kateRange()) {
612 it = m_cursors.erase(it);
631 for (
auto it = m_cursors.begin(); it != m_cursors.end();) {
633 if (!cursor->kateRange()) {
634 cursor->m_column = 0;
636 cursor->m_block = targetBlock;
637 targetBlock->m_cursors.insert(cursor);
640 it = m_cursors.erase(it);
653 const auto cachedRanges = cachedRangesForLine(
line);
655 ranges.
reserve(m_uncachedRanges.size() + (cachedRanges ? cachedRanges->size() : 0));
662 const auto cachedRanges = cachedRangesForLine(
line);
665 auto predicate = [
line, view, rangesWithAttributeOnly](
TextRange *range) {
666 if (rangesWithAttributeOnly && !range->hasAttribute()) {
671 if (!view && range->attributeOnlyForViews()) {
676 if (range->view() && range->view() != view) {
681 if (range->startInternal().lineInternal() <=
line &&
line <= range->endInternal().lineInternal()) {
688 std::copy_if(cachedRanges->begin(), cachedRanges->end(), std::back_inserter(outRanges), predicate);
690 std::copy_if(m_uncachedRanges.begin(), m_uncachedRanges.end(), std::back_inserter(outRanges), predicate);
696 for (
auto &textLine : m_lines) {
697 if (textLine.markedAsModified()) {
698 textLine.markAsSavedOnDisk(
true);
708 const bool isSingleLine =
startLine == endLine;
711 if ((endLine < m_startLine) || (
startLine >= (m_startLine +
lines()))) {
718 auto it = m_cachedLineForRanges.find(range);
719 if (it != m_cachedLineForRanges.end() && it.value() ==
startLine - m_startLine) {
725 if (!isSingleLine && m_uncachedRanges.contains(range)) {
735 m_uncachedRanges.append(range);
740 const int lineOffset =
startLine - m_startLine;
743 if (m_cachedRangesForLine.size() <= (
size_t)lineOffset) {
744 m_cachedRangesForLine.resize(lineOffset + 1);
748 if (!m_cachedRangesForLine[lineOffset].contains(range)) {
749 m_cachedRangesForLine[lineOffset].push_back(range);
751 m_cachedLineForRanges[range] = lineOffset;
757 int pos = m_uncachedRanges.indexOf(range);
759 m_uncachedRanges.remove(pos);
761 Q_ASSERT(m_cachedLineForRanges.find(range) == m_cachedLineForRanges.end());
766 auto it = m_cachedLineForRanges.find(range);
767 if (it != m_cachedLineForRanges.end()) {
769 Q_ASSERT(!m_uncachedRanges.contains(range));
771 int line = it.value();
774 int idx = m_cachedRangesForLine[
line].indexOf(range);
778 m_cachedRangesForLine[
line].remove(idx);
779 m_cachedLineForRanges.erase(it);
The Cursor represents a position in a Document.
constexpr int column() const noexcept
Retrieve the column on which this cursor is situated.
constexpr int line() const noexcept
Retrieve the line on which this cursor is situated.
An object representing a section of text, from one Cursor to another.
constexpr LineRange toLineRange() const noexcept
Convert this Range to a LineRange.
constexpr Cursor end() const noexcept
Get the end position of this range.
constexpr Cursor start() const noexcept
Get the start position of this range.
A text widget with KXMLGUIClient that represents a Document.
Class representing a text block.
void clearBlockContent(TextBlock *targetBlock)
Clear the block content, delete all lines, move all cursors not bound to range to given block at 0,...
void setStartLine(int startLine)
Set start line of this block.
int startLine() const
Start line of this block.
void wrapLine(const KTextEditor::Cursor position, int fixStartLinesStartIndex)
Wrap line at given cursor position.
void deleteBlockContent()
Delete the block content, delete all lines and delete all cursors not bound to ranges.
TextBlock(TextBuffer *buffer, int startLine)
Construct an empty text block.
void insertText(const KTextEditor::Cursor position, const QString &text)
Insert text at given cursor position.
void mergeBlock(TextBlock *targetBlock)
Merge this block with given one, the given one must be a direct predecessor.
void removeText(KTextEditor::Range range, QString &removedText)
Remove text at given range.
KTEXTEDITOR_EXPORT QList< TextRange * > rangesForLine(int line, KTextEditor::View *view, bool rangesWithAttributeOnly) const
Return all ranges in this block which might intersect the given line.
void text(QString &text) const
Retrieve text of block.
TextBlock * splitBlock(int fromLine)
Split given block.
void appendLine(const QString &textOfLine)
Append a new line with given text.
void setLineMetaData(int line, const TextLine &textLine)
Transfer all non text attributes for the given line from the given text line to the one in the block.
void clearLines()
Clear the lines.
~TextBlock()
Destruct the text block.
void markModifiedLinesAsSaved()
Flag all modified text lines as saved on disk.
TextLine line(int line) const
Retrieve a text line.
void updateRange(TextRange *range)
Update a range from this block.
void unwrapLine(int line, TextBlock *previousBlock, int fixStartLinesStartIndex)
Unwrap given line.
int lines() const
Number of lines in this block.
void debugPrint(int blockIndex) const
Debug output, print whole block content with line numbers and line length.
void removeRange(TextRange *range)
Remove a range from this block.
Class representing a text buffer.
TextHistory & history()
TextHistory of this buffer.
Class representing a 'clever' text cursor.
int lineInternal() const
Non-virtual version of line(), which is faster.
Class representing a single text line.
const QString & text() const
Accessor to the text contained in this line.
int length() const
Returns the line's length.
void reserve(qsizetype size)
QString & insert(qsizetype position, QChar ch)
QString mid(qsizetype position, qsizetype n) const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
qsizetype size() const const
qsizetype size() const const