7#include "katetexthistory.h"
8#include "katetextbuffer.h"
12TextHistory::TextHistory(TextBuffer &buffer)
14 , m_lastSavedRevision(-1)
15 , m_firstHistoryEntryRevision(0)
21TextHistory::~TextHistory() =
default;
23qint64 TextHistory::revision()
const
26 return m_buffer.revision();
29void TextHistory::clear()
32 m_lastSavedRevision = -1;
35 m_historyEntries.clear();
36 m_historyEntries.push_back(Entry());
39 m_firstHistoryEntryRevision = 0;
42void TextHistory::setLastSavedRevision()
45 m_lastSavedRevision = revision();
52 entry.type = Entry::WrapLine;
53 entry.line = position.
line();
54 entry.column = position.
column();
58void TextHistory::unwrapLine(
int line,
int oldLineLength)
62 entry.type = Entry::UnwrapLine;
65 entry.oldLineLength = oldLineLength;
69void TextHistory::insertText(
const KTextEditor::Cursor position,
int length,
int oldLineLength)
73 entry.type = Entry::InsertText;
74 entry.line = position.
line();
75 entry.column = position.
column();
76 entry.length = length;
77 entry.oldLineLength = oldLineLength;
85 entry.type = Entry::RemoveText;
89 entry.oldLineLength = oldLineLength;
93void TextHistory::addEntry(
const Entry &entry)
96 Q_ASSERT(!m_historyEntries.empty());
100 if ((m_historyEntries.size() == 1) && !m_historyEntries.front().referenceCounter) {
102 m_firstHistoryEntryRevision = revision() + 1;
105 m_historyEntries.front() = entry;
112 m_historyEntries.push_back(entry);
115void TextHistory::lockRevision(qint64 revision)
118 Q_ASSERT(!m_historyEntries.empty());
119 Q_ASSERT(revision >= m_firstHistoryEntryRevision);
120 Q_ASSERT(revision < (m_firstHistoryEntryRevision + qint64(m_historyEntries.size())));
123 Entry &entry = m_historyEntries[revision - m_firstHistoryEntryRevision];
124 ++entry.referenceCounter;
127void TextHistory::unlockRevision(qint64 revision)
130 Q_ASSERT(!m_historyEntries.empty());
131 Q_ASSERT(revision >= m_firstHistoryEntryRevision);
132 Q_ASSERT(revision < (m_firstHistoryEntryRevision + qint64(m_historyEntries.size())));
135 Entry &entry = m_historyEntries[revision - m_firstHistoryEntryRevision];
136 Q_ASSERT(entry.referenceCounter);
137 --entry.referenceCounter;
140 if (!entry.referenceCounter) {
142 qint64 unreferencedEdits = 0;
143 for (qint64 i = 0; i + 1 < qint64(m_historyEntries.size()); ++i) {
144 if (m_historyEntries[i].referenceCounter) {
153 if (unreferencedEdits > 0) {
155 m_historyEntries.erase(m_historyEntries.begin(), m_historyEntries.begin() + unreferencedEdits);
158 m_firstHistoryEntryRevision += unreferencedEdits;
163void TextHistory::Entry::transformCursor(
int &cursorLine,
int &cursorColumn,
bool moveOnInsert)
const
168 if (line > cursorLine) {
177 if (cursorLine == line) {
179 if (cursorColumn <= column) {
180 if (cursorColumn < column || !moveOnInsert) {
186 cursorColumn = cursorColumn - column;
196 if (cursorLine == line) {
197 cursorColumn += oldLineLength;
207 if (cursorLine != line) {
212 if (cursorColumn <= column) {
213 if (cursorColumn < column || !moveOnInsert) {
219 if (cursorColumn <= oldLineLength) {
220 cursorColumn += length;
224 else if (cursorColumn < oldLineLength + length) {
225 cursorColumn = oldLineLength + length;
233 if (cursorLine != line) {
238 if (cursorColumn <= column) {
243 if (cursorColumn <= column + length) {
244 cursorColumn = column;
246 cursorColumn -= length;
257void TextHistory::Entry::reverseTransformCursor(
int &cursorLine,
int &cursorColumn,
bool moveOnInsert)
const
264 if (cursorLine <= line) {
269 if (cursorLine == line + 1) {
271 cursorColumn = cursorColumn + column;
281 if (cursorLine < line - 1) {
286 if (cursorLine == line - 1) {
288 if (cursorColumn <= oldLineLength) {
289 if (cursorColumn < oldLineLength || !moveOnInsert) {
294 cursorColumn -= oldLineLength;
304 if (cursorLine != line) {
309 if (cursorColumn <= column) {
314 if (cursorColumn - length < column) {
315 cursorColumn = column;
317 cursorColumn -= length;
325 if (cursorLine != line) {
330 if (cursorColumn <= column) {
331 if (cursorColumn < column || !moveOnInsert) {
337 if (cursorColumn <= oldLineLength) {
338 cursorColumn += length;
342 else if (cursorColumn < oldLineLength + length) {
343 cursorColumn = oldLineLength + length;
356 if (fromRevision == -1) {
357 fromRevision = revision();
360 if (toRevision == -1) {
361 toRevision = revision();
365 if (fromRevision == toRevision) {
370 Q_ASSERT(!m_historyEntries.empty());
371 Q_ASSERT(fromRevision != toRevision);
372 Q_ASSERT(fromRevision >= m_firstHistoryEntryRevision);
373 Q_ASSERT(fromRevision < (m_firstHistoryEntryRevision + qint64(m_historyEntries.size())));
374 Q_ASSERT(toRevision >= m_firstHistoryEntryRevision);
375 Q_ASSERT(toRevision < (m_firstHistoryEntryRevision + qint64(m_historyEntries.size())));
381 if (toRevision > fromRevision) {
382 for (
int rev = fromRevision - m_firstHistoryEntryRevision + 1; rev <= (toRevision - m_firstHistoryEntryRevision); ++rev) {
383 const Entry &entry = m_historyEntries.at(rev);
384 entry.transformCursor(line, column, moveOnInsert);
387 for (
int rev = fromRevision - m_firstHistoryEntryRevision; rev >= (toRevision - m_firstHistoryEntryRevision + 1); --rev) {
388 const Entry &entry = m_historyEntries.at(rev);
389 entry.reverseTransformCursor(line, column, moveOnInsert);
402 if (invalidateIfEmpty && range.
end() <= range.
start()) {
408 if (fromRevision == -1) {
409 fromRevision = revision();
412 if (toRevision == -1) {
413 toRevision = revision();
417 if (fromRevision == toRevision) {
422 Q_ASSERT(!m_historyEntries.empty());
423 Q_ASSERT(fromRevision != toRevision);
424 Q_ASSERT(fromRevision >= m_firstHistoryEntryRevision);
425 Q_ASSERT(fromRevision < (m_firstHistoryEntryRevision + qint64(m_historyEntries.size())));
426 Q_ASSERT(toRevision >= m_firstHistoryEntryRevision);
427 Q_ASSERT(toRevision < (m_firstHistoryEntryRevision + qint64(m_historyEntries.size())));
434 int endLine = range.
end().
line();
441 if (toRevision > fromRevision) {
442 for (
int rev = fromRevision - m_firstHistoryEntryRevision + 1; rev <= (toRevision - m_firstHistoryEntryRevision); ++rev) {
443 const Entry &entry = m_historyEntries.at(rev);
445 entry.transformCursor(startLine, startColumn, moveOnInsertStart);
447 entry.transformCursor(endLine, endColumn, moveOnInsertEnd);
450 if (endLine < startLine || (endLine == startLine && endColumn <= startColumn)) {
451 if (invalidateIfEmpty) {
457 endColumn = startColumn;
462 for (
int rev = fromRevision - m_firstHistoryEntryRevision; rev >= (toRevision - m_firstHistoryEntryRevision + 1); --rev) {
463 const Entry &entry = m_historyEntries.at(rev);
465 entry.reverseTransformCursor(startLine, startColumn, moveOnInsertStart);
467 entry.reverseTransformCursor(endLine, endColumn, moveOnInsertEnd);
470 if (endLine < startLine || (endLine == startLine && endColumn <= startColumn)) {
471 if (invalidateIfEmpty) {
477 endColumn = startColumn;
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.
InsertBehavior
Insert behavior of this cursor, should it stay if text is insert at its position or should it move.
@ MoveOnInsert
move on insert
EmptyBehavior
Behavior of range if it becomes empty.
@ InvalidateIfEmpty
invalidate range, if it becomes empty
@ ExpandRight
Expand to encapsulate new characters to the right of the range.
@ ExpandLeft
Expand to encapsulate new characters to the left of the range.
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.
void setRange(Range range) noexcept
Set the start and end cursors to range.start() and range.end() respectively.
static constexpr Range invalid() noexcept
Returns an invalid range.