14#include "katebuffer.h"
15#include "katedocument.h"
16#include "kateundomanager.h"
19#include <ktexteditor/cursor.h>
20#include <ktexteditor/view.h>
25 : m_undoSelection(selection)
26 , m_redoSelection(-1, -1, -1, -1)
27 , m_undoCursor(cursorPosition)
28 , m_undoSecondaryCursors(secondary)
29 , m_redoCursor(-1, -1)
35 if (m_items.empty()) {
41 auto doc = manager->document();
42 auto updateDocLine = [doc](
const UndoItem &item) {
44 tl.markAsModified(item.lineModFlags.testFlag(UndoItem::UndoLine1Modified));
45 tl.markAsSavedOnDisk(item.lineModFlags.testFlag(UndoItem::UndoLine1Saved));
46 doc->buffer().setLineMetaData(item.line, tl);
49 for (
auto rit = m_items.rbegin(); rit != m_items.rend(); ++rit) {
52 case UndoItem::editInsertText:
53 doc->editRemoveText(item.line, item.col, item.text.size());
56 case UndoItem::editRemoveText:
57 doc->editInsertText(item.line, item.col, item.text);
60 case UndoItem::editWrapLine:
61 doc->editUnWrapLine(item.line, item.newLine, item.len);
64 case UndoItem::editUnWrapLine: {
65 doc->editWrapLine(item.line, item.col, item.removeLine);
68 auto next = doc->plainKateTextLine(item.line + 1);
69 next.markAsModified(item.lineModFlags.testFlag(UndoItem::UndoLine2Modified));
70 next.markAsSavedOnDisk(item.lineModFlags.testFlag(UndoItem::UndoLine2Saved));
71 doc->buffer().setLineMetaData(item.line + 1, next);
73 case UndoItem::editInsertLine:
74 doc->editRemoveLine(item.line);
76 case UndoItem::editRemoveLine:
77 doc->editInsertLine(item.line, item.text);
80 case UndoItem::editMarkLineAutoWrapped:
81 doc->editMarkLineAutoWrapped(item.line, item.autowrapped);
83 case UndoItem::editInvalid:
88 if (view !=
nullptr) {
89 if (m_undoSelection.
isValid()) {
90 view->setSelection(m_undoSelection);
92 view->removeSelection();
94 view->clearSecondaryCursors();
95 view->addSecondaryCursorsWithSelection(m_undoSecondaryCursors);
98 view->setCursorPosition(m_undoCursor);
107 if (m_items.empty()) {
111 manager->startUndo();
113 auto doc = manager->document();
114 auto updateDocLine = [doc](
const UndoItem &item) {
116 tl.markAsModified(item.lineModFlags.testFlag(UndoItem::RedoLine1Modified));
117 tl.markAsSavedOnDisk(item.lineModFlags.testFlag(UndoItem::RedoLine1Saved));
118 doc->buffer().setLineMetaData(item.line, tl);
121 for (
auto &item : m_items) {
123 case UndoItem::editInsertText:
124 doc->editInsertText(item.line, item.col, item.text);
127 case UndoItem::editRemoveText:
128 doc->editRemoveText(item.line, item.col, item.text.size());
131 case UndoItem::editWrapLine: {
132 doc->editWrapLine(item.line, item.col, item.newLine);
136 next.markAsModified(item.lineModFlags.testFlag(UndoItem::RedoLine2Modified));
137 next.markAsSavedOnDisk(item.lineModFlags.testFlag(UndoItem::RedoLine2Saved));
138 doc->buffer().setLineMetaData(item.line + 1, next);
140 case UndoItem::editUnWrapLine:
141 doc->editUnWrapLine(item.line, item.removeLine, item.len);
144 case UndoItem::editInsertLine:
145 doc->editInsertLine(item.line, item.text);
148 case UndoItem::editRemoveLine:
149 doc->editRemoveLine(item.line);
151 case UndoItem::editMarkLineAutoWrapped:
152 doc->editMarkLineAutoWrapped(item.line, item.autowrapped);
154 case UndoItem::editInvalid:
159 if (view !=
nullptr) {
160 if (m_redoSelection.
isValid()) {
161 view->setSelection(m_redoSelection);
163 view->removeSelection();
165 view->clearSecondaryCursors();
166 view->addSecondaryCursorsWithSelection(m_redoSecondaryCursors);
169 view->setCursorPosition(m_redoCursor);
180 m_redoCursor = cursorPosition;
181 m_redoSecondaryCursors = secondaryCursors;
182 m_redoSelection = selectionRange;
185static bool mergeUndoItems(UndoItem &base,
const UndoItem &u)
187 if (base.type == UndoItem::editInsertText && u.type == UndoItem::editWrapLine) {
189 if (base.col == 0 && base.line == u.line && base.col + base.text.
length() == u.col && u.newLine) {
190 base.type = UndoItem::editInsertLine;
191 base.lineModFlags.
setFlag(UndoItem::RedoLine1Modified);
196 if (base.type == UndoItem::editRemoveText && base.type == u.type) {
197 if (base.line == u.line && base.col == (u.col + u.text.
size())) {
204 if (base.type == UndoItem::editInsertText && base.type == u.type) {
205 if (base.line == u.line && (base.col + base.text.
size()) == u.col) {
217 if (!m_items.empty() && mergeUndoItems(m_items.back(), u)) {
222 m_items.push_back(std::move(u));
231 if (newGroup->isOnlyType(singleType()) || complex) {
233 for (
auto &item : newGroup->m_items) {
236 newGroup->m_items.clear();
238 if (newGroup->m_safePoint) {
242 m_redoCursor = newGroup->m_redoCursor;
243 m_redoSecondaryCursors = newGroup->m_redoSecondaryCursors;
244 m_redoSelection = newGroup->m_redoSelection;
260 for (UndoItem &item : m_items) {
261 if (item.lineModFlags.testFlag(UndoItem::UndoLine1Saved)) {
262 item.lineModFlags.setFlag(UndoItem::UndoLine1Saved,
false);
263 item.lineModFlags.setFlag(UndoItem::UndoLine1Modified,
true);
266 if (item.lineModFlags.testFlag(UndoItem::UndoLine2Saved)) {
267 item.lineModFlags.setFlag(UndoItem::UndoLine2Saved,
false);
268 item.lineModFlags.setFlag(UndoItem::UndoLine2Modified,
true);
271 if (item.lineModFlags.testFlag(UndoItem::RedoLine1Saved)) {
272 item.lineModFlags.setFlag(UndoItem::RedoLine1Saved,
false);
273 item.lineModFlags.setFlag(UndoItem::RedoLine1Modified,
true);
276 if (item.lineModFlags.testFlag(UndoItem::RedoLine2Saved)) {
277 item.lineModFlags.setFlag(UndoItem::RedoLine2Saved,
false);
278 item.lineModFlags.setFlag(UndoItem::RedoLine2Modified,
true);
283static void updateUndoSavedOnDiskFlag(UndoItem &item,
QBitArray &lines)
285 const int line = item.line;
286 if (line >= lines.
size()) {
290 const bool wasBitSet = lines.
testBit(line);
295 auto &lineFlags = item.lineModFlags;
298 case UndoItem::editInsertText:
299 case UndoItem::editRemoveText:
300 case UndoItem::editRemoveLine:
302 lineFlags.setFlag(UndoItem::UndoLine1Modified,
false);
303 lineFlags.setFlag(UndoItem::UndoLine1Saved,
true);
306 case UndoItem::editWrapLine:
307 if (lineFlags.testFlag(UndoItem::UndoLine1Modified) && !wasBitSet) {
308 lineFlags.setFlag(UndoItem::UndoLine1Modified,
false);
309 lineFlags.setFlag(UndoItem::UndoLine1Saved,
true);
312 case UndoItem::editUnWrapLine:
313 if (line + 1 >= lines.
size()) {
316 if (lineFlags.testFlag(UndoItem::UndoLine1Modified) && !wasBitSet) {
317 lineFlags.setFlag(UndoItem::UndoLine1Modified,
false);
318 lineFlags.setFlag(UndoItem::UndoLine1Saved,
true);
321 if (lineFlags.testFlag(UndoItem::UndoLine2Modified) && !lines.
testBit(line + 1)) {
324 lineFlags.setFlag(UndoItem::UndoLine2Modified,
false);
325 lineFlags.setFlag(UndoItem::UndoLine2Saved,
true);
328 case UndoItem::editInsertLine:
329 case UndoItem::editMarkLineAutoWrapped:
330 case UndoItem::editInvalid:
335void KateUndoGroup::markUndoAsSaved(
QBitArray &lines)
337 for (
auto rit = m_items.rbegin(); rit != m_items.rend(); ++rit) {
338 updateUndoSavedOnDiskFlag(*rit, lines);
342static void updateRedoSavedOnDiskFlag(UndoItem &item,
QBitArray &lines)
344 const int line = item.line;
345 if (line >= lines.
size()) {
349 const bool wasBitSet = lines.
testBit(line);
353 auto &lineFlags = item.lineModFlags;
356 case UndoItem::editInsertText:
357 case UndoItem::editRemoveText:
358 case UndoItem::editInsertLine:
359 lineFlags.setFlag(UndoItem::RedoLine1Modified,
false);
360 lineFlags.setFlag(UndoItem::RedoLine1Saved,
true);
362 case UndoItem::editUnWrapLine:
363 if (lineFlags.testFlag(UndoItem::RedoLine1Modified) && !wasBitSet) {
364 lineFlags.setFlag(UndoItem::RedoLine1Modified,
false);
365 lineFlags.setFlag(UndoItem::RedoLine1Saved,
true);
368 case UndoItem::editWrapLine:
369 if (line + 1 >= lines.
size()) {
373 if (lineFlags.testFlag(UndoItem::RedoLine1Modified) && !wasBitSet) {
374 lineFlags.setFlag(UndoItem::RedoLine1Modified,
false);
375 lineFlags.setFlag(UndoItem::RedoLine1Saved,
true);
378 if (lineFlags.testFlag(UndoItem::RedoLine2Modified) && !lines.
testBit(line + 1)) {
379 lineFlags.setFlag(UndoItem::RedoLine2Modified,
false);
380 lineFlags.setFlag(UndoItem::RedoLine2Saved,
true);
383 case UndoItem::editRemoveLine:
384 case UndoItem::editMarkLineAutoWrapped:
385 case UndoItem::editInvalid:
390void KateUndoGroup::markRedoAsSaved(
QBitArray &lines)
392 for (
auto rit = m_items.rbegin(); rit != m_items.rend(); ++rit) {
393 updateRedoSavedOnDiskFlag(*rit, lines);
397UndoItem::UndoType KateUndoGroup::singleType()
const
399 UndoItem::UndoType ret = UndoItem::editInvalid;
401 for (
const auto &item : m_items) {
402 if (ret == UndoItem::editInvalid) {
404 }
else if (ret != item.type) {
405 return UndoItem::editInvalid;
412bool KateUndoGroup::isOnlyType(UndoItem::UndoType type)
const
414 if (type == UndoItem::editInvalid) {
417 for (
const auto &item : m_items) {
418 if (item.type != type)
The Cursor represents a position in a Document.
constexpr bool isValid() const noexcept
Returns whether the current position of this cursor is a valid position (line + column must both be >...
An object representing a section of text, from one Cursor to another.
constexpr bool isValid() const noexcept
Validity check.
Class to manage a group of undo items.
KateUndoGroup(const KTextEditor::Cursor cursorPosition, KTextEditor::Range selection, const QList< KTextEditor::ViewPrivate::PlainSecondaryCursor > &)
Constructor.
void addItem(UndoItem u)
add an undo item
void flagSavedAsModified()
Change all LineSaved flags to LineModified of the line modification system.
void redo(KateUndoManager *manager, KTextEditor::ViewPrivate *view)
Redo the contained undo items.
void safePoint(bool safePoint=true)
set group as as savepoint.
void undo(KateUndoManager *manager, KTextEditor::ViewPrivate *view)
Undo the contained undo items.
bool merge(KateUndoGroup *newGroup, bool complex)
merge this group with an other
KateUndoManager implements a document's history.
Class representing a single text line.
void resize(qsizetype size)
qsizetype size() const const
bool testBit(qsizetype i) const const
QFlags< T > & setFlag(Enum flag, bool on)
qsizetype length() const const
QString & prepend(QChar ch)
qsizetype size() const const