7#include "katetextblock.h"
8#include "katetextbuffer.h"
9#include "katetextcursor.h"
10#include "katetextrange.h"
19 m_lines.reserve(BufferBlockSize);
25 Q_ASSERT(m_lines.empty());
26 Q_ASSERT(m_cursors.empty());
33 return m_buffer->m_startLines[m_blockIndex];
39 Q_ASSERT(
size_t(
line) < m_lines.size());
41 return m_lines.at(
line);
47 Q_ASSERT(
size_t(
line) < m_lines.size());
50 const QString originalText = m_lines.at(
line).text();
51 m_lines.at(
line) = textLine;
52 m_lines.at(
line).text() = originalText;
57 m_lines.emplace_back(textOfLine);
68 for (
const auto &
line : m_lines) {
83 Q_ASSERT(position.
column() >= 0);
85 Q_ASSERT(fixStartLinesStartIndex == m_blockIndex);
94 if (position.
column() > 0 ||
text.size() == 0 || m_lines.at(
line).markedAsModified()) {
95 m_lines.at(
line + 1).markAsModified(
true);
96 }
else if (m_lines.at(
line).markedAsSavedOnDisk()) {
97 m_lines.at(
line + 1).markAsSavedOnDisk(
true);
109 m_lines.at(
line).markAsModified(
true);
115 m_buffer->fixStartLines(fixStartLinesStartIndex + 1, 1);
118 m_buffer->
history().wrapLine(position);
125 if (m_cursors.empty()) {
134 if (cursor->lineInBlock() <
line) {
139 if (cursor->lineInBlock() >
line) {
147 if (cursor->column() <= position.
column()) {
148 if (cursor->column() < position.
column() || !cursor->m_moveOnInsert) {
159 cursor->m_column -= position.
column();
163 auto range = cursor->kateRange();
164 if (range && !range->isValidityCheckRequired()) {
165 range->setValidityCheckRequired();
172 for (
TextRange *range : std::as_const(changedRanges)) {
174 range->checkValidity();
183 Q_ASSERT(previousBlock);
184 Q_ASSERT(previousBlock->
lines() > 0);
187 const TextLine oldFirst = m_lines.at(0);
188 const int lastLineOfPreviousBlock = previousBlock->
lines() - 1;
189 m_lines[0] = previousBlock->m_lines.back();
190 previousBlock->m_lines.erase(previousBlock->m_lines.begin() + (previousBlock->
lines() - 1));
192 m_buffer->m_blockSizes[m_blockIndex - 1] -= m_lines[0].length() + 1;
193 m_buffer->m_blockSizes[m_blockIndex] += m_lines[0].length();
195 const int oldSizeOfPreviousLine = m_lines[0].text().size();
196 if (oldFirst.
length() > 0) {
198 m_lines[0].text().append(oldFirst.
text());
201 m_lines[0].markAsModified(
true);
207 Q_ASSERT(fixStartLinesStartIndex + 1 == m_blockIndex);
208 m_buffer->fixStartLines(fixStartLinesStartIndex + 1, -1);
216 if (m_cursors.empty() && previousBlock->m_cursors.empty()) {
225 if (cursor->lineInBlock() == 0) {
227 cursor->m_column += oldSizeOfPreviousLine;
230 auto range = cursor->kateRange();
231 if (range && !range->isValidityCheckRequired()) {
232 range->setValidityCheckRequired();
239 for (
auto it = previousBlock->m_cursors.begin(); it != previousBlock->m_cursors.end();) {
241 if (cursor->lineInBlock() == lastLineOfPreviousBlock) {
244 const bool spansMultipleBlocks = range && range->spansMultipleBlocks();
246 cursor->m_block =
this;
250 if (range && !range->isValidityCheckRequired()) {
251 range->setValidityCheckRequired();
253 changedRanges.
push_back({range, spansMultipleBlocks});
257 it = previousBlock->m_cursors.erase(it);
267 for (
auto [range, wasMultiblock] : changedRanges) {
269 if (!range->spansMultipleBlocks() && wasMultiblock) {
270 m_buffer->removeMultilineRange(range);
273 range->checkValidity();
280 m_buffer->m_blockSizes[m_blockIndex] -= 1;
283 const int oldSizeOfPreviousLine = m_lines.at(
line - 1).length();
284 const int sizeOfCurrentLine = m_lines.at(
line).length();
285 if (sizeOfCurrentLine > 0) {
286 m_lines.at(
line - 1).text().append(m_lines.at(
line).text());
289 const bool lineChanged = (oldSizeOfPreviousLine > 0 && m_lines.at(
line - 1).markedAsModified())
290 || (sizeOfCurrentLine > 0 && (oldSizeOfPreviousLine > 0 || m_lines.at(
line).markedAsModified()));
291 m_lines.at(
line - 1).markAsModified(lineChanged);
292 if (oldSizeOfPreviousLine == 0 && m_lines.at(
line).markedAsSavedOnDisk()) {
293 m_lines.at(
line - 1).markAsSavedOnDisk(
true);
296 m_lines.erase(m_lines.begin() +
line);
301 m_buffer->fixStartLines(fixStartLinesStartIndex + 1, -1);
309 if (m_cursors.empty()) {
318 if (cursor->lineInBlock() <
line) {
323 if (cursor->lineInBlock() ==
line) {
325 cursor->m_column += oldSizeOfPreviousLine;
332 auto range = cursor->kateRange();
333 if (range && !range->isValidityCheckRequired()) {
334 range->setValidityCheckRequired();
341 for (
TextRange *range : std::as_const(changedRanges)) {
343 range->checkValidity();
354 int oldLength = textOfLine.
size();
355 m_lines.at(
line).markAsModified(
true);
358 Q_ASSERT(position.
column() >= 0);
359 Q_ASSERT(position.
column() <= textOfLine.
size());
365 m_buffer->
history().insertText(position,
text.size(), oldLength);
370 if (m_cursors.empty()) {
379 if (cursor->lineInBlock() !=
line) {
384 if (cursor->column() <= position.
column()) {
385 if (cursor->column() < position.
column() || !cursor->m_moveOnInsert) {
391 if (cursor->m_column <= oldLength) {
392 cursor->m_column +=
text.size();
396 else if (cursor->m_column < textOfLine.
size()) {
397 cursor->m_column = textOfLine.
size();
402 auto range = cursor->kateRange();
403 if (range && !range->isValidityCheckRequired() && (range->feedback() || range->start().line() == range->end().line())) {
404 range->setValidityCheckRequired();
411 for (
TextRange *range : std::as_const(changedRanges)) {
412 range->checkValidity();
423 int oldLength = textOfLine.
size();
436 m_lines.at(
line).markAsModified(
true);
439 m_buffer->
history().removeText(range, oldLength);
444 if (m_cursors.empty()) {
453 if (cursor->lineInBlock() !=
line) {
463 if (cursor->column() <= range.
end().
column()) {
466 cursor->m_column -= (range.
end().column() - range.
start().
column());
471 auto range = cursor->kateRange();
472 if (range && !range->isValidityCheckRequired() && (range->feedback() || range->
start().
line() == range->
end().
line())) {
473 range->setValidityCheckRequired();
480 for (
TextRange *range : std::as_const(changedRanges)) {
481 range->checkValidity();
488 for (
size_t i = 0; i < m_lines.size(); ++i) {
489 printf(
"%4d - %4llu : %4llu : '%s'\n",
492 (
unsigned long long)m_lines.at(i).text().size(),
493 qPrintable(m_lines.at(i).text()));
500 const int linesOfNewBlock =
lines() - fromLine;
503 newBlock->m_lines.reserve(linesOfNewBlock);
504 for (
size_t i = fromLine; i < m_lines.size(); ++i) {
505 auto line = std::move(m_lines[i]);
507 m_buffer->m_blockSizes[m_blockIndex] -=
lineLength + 1;
508 m_buffer->m_blockSizes[newBlock->m_blockIndex] +=
lineLength + 1;
509 newBlock->m_lines.push_back(std::move(
line));
512 m_lines.resize(fromLine);
516 for (
auto it = m_cursors.begin(); it != m_cursors.end();) {
518 if (cursor->lineInBlock() >= fromLine) {
519 cursor->m_line = cursor->lineInBlock() - fromLine;
520 cursor->m_block = newBlock;
523 newBlock->m_cursors.push_back(cursor);
524 it = m_cursors.erase(it);
525 if (cursor->kateRange()) {
526 ranges.
insert(cursor->kateRange());
534 std::sort(newBlock->m_cursors.begin(), newBlock->m_cursors.end());
536 for (
auto range : std::as_const(ranges)) {
537 if (range->spansMultipleBlocks()) {
548 cursor->m_line = cursor->lineInBlock() + targetBlock->
lines();
549 cursor->m_block = targetBlock;
550 targetBlock->m_cursors.push_back(cursor);
551 if (cursor->kateRange()) {
552 ranges.
insert(cursor->kateRange());
556 std::sort(targetBlock->m_cursors.begin(), targetBlock->m_cursors.end());
558 for (
auto range : std::as_const(ranges)) {
559 if (!range->spansMultipleBlocks()) {
560 m_buffer->removeMultilineRange(range);
565 targetBlock->m_lines.reserve(targetBlock->
lines() +
lines());
566 for (
size_t i = 0; i < m_lines.size(); ++i) {
567 targetBlock->m_lines.push_back(m_lines.at(i));
583 for (
auto cursor : std::as_const(m_cursors)) {
584 if (!cursor->kateRange()) {
587 auto range = cursor->kateRange();
588 if (rangesWithAttributeOnly && !range->hasAttribute()) {
593 if (!view && range->attributeOnlyForViews()) {
598 if (range->view() && range->view() != view) {
603 if (cursor->lineInBlock() == lineInBlock) {
607 else if (range->startInternal().lineInternal() <=
line &&
line <= range->endInternal().lineInternal()) {
611 std::sort(outRanges.
begin(), outRanges.
end());
612 auto it = std::unique(outRanges.
begin(), outRanges.
end());
613 outRanges.
erase(it, outRanges.
end());
619 for (
auto &textLine : m_lines) {
620 if (textLine.markedAsModified()) {
621 textLine.markAsSavedOnDisk(
true);
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 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.
KTEXTEDITOR_EXPORT int startLine() const
Start line of this block.
void wrapLine(const KTextEditor::Cursor position, int fixStartLinesStartIndex)
Wrap line at given cursor position.
int lineLength(int line) const
Retrieve length for line.
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.
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 unwrapLine(int line, TextBlock *previousBlock, int fixStartLinesStartIndex)
Unwrap given line.
void splitBlock(int fromLine, TextBlock *newBlock)
Split given block.
TextBlock(TextBuffer *buffer, int blockIndex)
Construct an empty text block.
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 insertCursor(Kate::TextCursor *cursor)
Insert cursor into this block.
Class representing a text buffer.
TextHistory & history()
TextHistory of this buffer.
KTEXTEDITOR_NO_EXPORT void addMultilineRange(TextRange *range)
Add/Remove a multiline range that spans multiple blocks.
Class representing a 'clever' text cursor.
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 append(QList< T > &&value)
iterator erase(const_iterator begin, const_iterator end)
iterator insert(const T &value)
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