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_blockSize == 0);
26 Q_ASSERT(m_lines.empty());
27 Q_ASSERT(m_cursors.empty());
34 return m_buffer->m_startLines[m_blockIndex];
40 Q_ASSERT(
size_t(
line) < m_lines.size());
42 return m_lines.at(
line);
48 Q_ASSERT(
size_t(
line) < m_lines.size());
51 const QString originalText = m_lines.at(
line).text();
52 m_lines.at(
line) = textLine;
53 m_lines.at(
line).text() = originalText;
58 m_lines.emplace_back(textOfLine);
59 m_blockSize += textOfLine.
size();
71 for (
const auto &
line : m_lines) {
86 Q_ASSERT(position.
column() >= 0);
88 Q_ASSERT(fixStartLinesStartIndex == m_blockIndex);
97 if (position.
column() > 0 ||
text.size() == 0 || m_lines.at(
line).markedAsModified()) {
98 m_lines.at(
line + 1).markAsModified(
true);
99 }
else if (m_lines.at(
line).markedAsSavedOnDisk()) {
100 m_lines.at(
line + 1).markAsSavedOnDisk(
true);
112 m_lines.at(
line).markAsModified(
true);
118 m_buffer->fixStartLines(fixStartLinesStartIndex + 1, 1);
121 m_buffer->
history().wrapLine(position);
128 if (m_cursors.empty()) {
137 if (cursor->lineInBlock() <
line) {
142 if (cursor->lineInBlock() >
line) {
150 if (cursor->column() <= position.
column()) {
151 if (cursor->column() < position.
column() || !cursor->m_moveOnInsert) {
162 cursor->m_column -= position.
column();
166 auto range = cursor->kateRange();
167 if (range && !range->isValidityCheckRequired()) {
168 range->setValidityCheckRequired();
175 for (
TextRange *range : std::as_const(changedRanges)) {
177 range->checkValidity();
186 Q_ASSERT(previousBlock);
187 Q_ASSERT(previousBlock->
lines() > 0);
190 const TextLine oldFirst = m_lines.at(0);
191 const int lastLineOfPreviousBlock = previousBlock->
lines() - 1;
192 m_lines[0] = previousBlock->m_lines.back();
193 previousBlock->m_lines.erase(previousBlock->m_lines.begin() + (previousBlock->
lines() - 1));
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) {
243 cursor->m_block =
this;
244 m_cursors.insert(cursor);
247 auto range = cursor->kateRange();
248 if (range && !range->isValidityCheckRequired()) {
249 range->setValidityCheckRequired();
254 it = previousBlock->m_cursors.erase(it);
264 for (
TextRange *range : std::as_const(changedRanges)) {
266 range->checkValidity();
274 const int oldSizeOfPreviousLine = m_lines.at(
line - 1).length();
275 const int sizeOfCurrentLine = m_lines.at(
line).length();
276 if (sizeOfCurrentLine > 0) {
277 m_lines.at(
line - 1).text().append(m_lines.at(
line).text());
280 const bool lineChanged = (oldSizeOfPreviousLine > 0 && m_lines.at(
line - 1).markedAsModified())
281 || (sizeOfCurrentLine > 0 && (oldSizeOfPreviousLine > 0 || m_lines.at(
line).markedAsModified()));
282 m_lines.at(
line - 1).markAsModified(lineChanged);
283 if (oldSizeOfPreviousLine == 0 && m_lines.at(
line).markedAsSavedOnDisk()) {
284 m_lines.at(
line - 1).markAsSavedOnDisk(
true);
287 m_lines.erase(m_lines.begin() +
line);
292 m_buffer->fixStartLines(fixStartLinesStartIndex + 1, -1);
300 if (m_cursors.empty()) {
309 if (cursor->lineInBlock() <
line) {
314 if (cursor->lineInBlock() ==
line) {
316 cursor->m_column += oldSizeOfPreviousLine;
323 auto range = cursor->kateRange();
324 if (range && !range->isValidityCheckRequired()) {
325 range->setValidityCheckRequired();
332 for (
TextRange *range : std::as_const(changedRanges)) {
334 range->checkValidity();
345 int oldLength = textOfLine.
size();
346 m_lines.at(
line).markAsModified(
true);
349 Q_ASSERT(position.
column() >= 0);
350 Q_ASSERT(position.
column() <= textOfLine.
size());
356 m_buffer->
history().insertText(position,
text.size(), oldLength);
358 m_blockSize +=
text.size();
363 if (m_cursors.empty()) {
372 if (cursor->lineInBlock() !=
line) {
377 if (cursor->column() <= position.
column()) {
378 if (cursor->column() < position.
column() || !cursor->m_moveOnInsert) {
384 if (cursor->m_column <= oldLength) {
385 cursor->m_column +=
text.size();
389 else if (cursor->m_column < textOfLine.
size()) {
390 cursor->m_column = textOfLine.
size();
395 auto range = cursor->kateRange();
396 if (range && !range->isValidityCheckRequired() && (range->feedback() || range->start().line() == range->end().line())) {
397 range->setValidityCheckRequired();
404 for (
TextRange *range : std::as_const(changedRanges)) {
405 range->checkValidity();
416 int oldLength = textOfLine.
size();
429 m_lines.at(
line).markAsModified(
true);
432 m_buffer->
history().removeText(range, oldLength);
434 m_blockSize -= removedText.
size();
439 if (m_cursors.empty()) {
448 if (cursor->lineInBlock() !=
line) {
458 if (cursor->column() <= range.
end().
column()) {
461 cursor->m_column -= (range.
end().column() - range.
start().
column());
466 auto range = cursor->kateRange();
467 if (range && !range->isValidityCheckRequired() && (range->feedback() || range->
start().
line() == range->
end().
line())) {
468 range->setValidityCheckRequired();
475 for (
TextRange *range : std::as_const(changedRanges)) {
476 range->checkValidity();
483 for (
size_t i = 0; i < m_lines.size(); ++i) {
484 printf(
"%4d - %4llu : %4llu : '%s'\n",
487 (
unsigned long long)m_lines.at(i).text().size(),
488 qPrintable(m_lines.at(i).text()));
495 const int linesOfNewBlock =
lines() - fromLine;
498 newBlock->m_lines.reserve(linesOfNewBlock);
499 for (
size_t i = fromLine; i < m_lines.size(); ++i) {
500 auto line = std::move(m_lines[i]);
503 newBlock->m_lines.push_back(std::move(
line));
506 m_lines.resize(fromLine);
510 for (
auto it = m_cursors.begin(); it != m_cursors.end();) {
512 if (cursor->lineInBlock() >= fromLine) {
513 cursor->m_line = cursor->lineInBlock() - fromLine;
514 cursor->m_block = newBlock;
517 newBlock->m_cursors.insert(cursor);
518 it = m_cursors.erase(it);
519 if (cursor->kateRange()) {
520 ranges.
insert(cursor->kateRange());
528 for (
auto range : std::as_const(ranges)) {
529 if (range->spansMultipleBlocks()) {
540 cursor->m_line = cursor->lineInBlock() + targetBlock->
lines();
541 cursor->m_block = targetBlock;
542 targetBlock->m_cursors.insert(cursor);
543 if (cursor->kateRange()) {
544 ranges.
insert(cursor->kateRange());
549 for (
auto range : std::as_const(ranges)) {
550 if (!range->spansMultipleBlocks()) {
551 m_buffer->removeMultilineRange(range);
556 targetBlock->m_lines.reserve(targetBlock->
lines() +
lines());
557 for (
size_t i = 0; i < m_lines.size(); ++i) {
558 targetBlock->m_lines.push_back(m_lines.at(i));
560 targetBlock->m_blockSize += m_blockSize;
569 for (
auto it = m_cursors.begin(); it != m_cursors.end();) {
571 if (!cursor->kateRange()) {
573 it = m_cursors.erase(it);
592 for (
auto it = m_cursors.begin(); it != m_cursors.end();) {
594 if (!cursor->kateRange()) {
595 cursor->m_column = 0;
597 cursor->m_block = targetBlock;
598 targetBlock->m_cursors.insert(cursor);
601 it = m_cursors.erase(it);
623 for (
auto cursor : std::as_const(m_cursors)) {
624 if (!cursor->kateRange()) {
627 auto range = cursor->kateRange();
628 if (rangesWithAttributeOnly && !range->hasAttribute()) {
633 if (!view && range->attributeOnlyForViews()) {
638 if (range->view() && range->view() != view) {
643 if (cursor->lineInBlock() == lineInBlock) {
647 else if (range->startInternal().lineInternal() <=
line &&
line <= range->endInternal().lineInternal()) {
651 std::sort(outRanges.
begin(), outRanges.
end());
652 auto it = std::unique(outRanges.
begin(), outRanges.
end());
653 outRanges.
erase(it, outRanges.
end());
659 for (
auto &textLine : m_lines) {
660 if (textLine.markedAsModified()) {
661 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.
void clearBlockContent(TextBlock *targetBlock)
Clear the block content, delete all lines, move all cursors not bound to range to given block at 0,...
KTEXTEDITOR_EXPORT 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.
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.
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