• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • applications API Reference
  • KDE Home
  • Contact Us
 

Kate

  • kde-4.14
  • applications
  • kate
  • part
  • buffer
katetexthistory.cpp
Go to the documentation of this file.
1 /* This file is part of the Kate project.
2  *
3  * Copyright (C) 2010 Christoph Cullmann <cullmann@kde.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB. If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "katetexthistory.h"
22 #include "katetextbuffer.h"
23 
24 namespace Kate {
25 
26 TextHistory::TextHistory (TextBuffer &buffer)
27  : m_buffer (buffer)
28  , m_lastSavedRevision (-1)
29  , m_firstHistoryEntryRevision (0)
30 {
31  // just call clear to init
32  clear ();
33 }
34 
35 TextHistory::~TextHistory ()
36 {
37 }
38 
39 qint64 TextHistory::revision () const
40 {
41  // just output last revisions of buffer
42  return m_buffer.revision ();
43 }
44 
45 void TextHistory::clear ()
46 {
47  // reset last saved revision
48  m_lastSavedRevision = -1;
49 
50  // remove all history entries and add no-change dummy for first revision
51  m_historyEntries.clear ();
52  m_historyEntries.push_back (Entry ());
53 
54  // first entry will again belong to first revision
55  m_firstHistoryEntryRevision = 0;
56 }
57 
58 void TextHistory::setLastSavedRevision ()
59 {
60  // current revision was successful saved
61  m_lastSavedRevision = revision ();
62 }
63 
64 void TextHistory::wrapLine (const KTextEditor::Cursor &position)
65 {
66  // create and add new entry
67  Entry entry;
68  entry.type = Entry::WrapLine;
69  entry.line = position.line ();
70  entry.column = position.column ();
71  addEntry (entry);
72 }
73 
74 void TextHistory::unwrapLine (int line, int oldLineLength)
75 {
76  // create and add new entry
77  Entry entry;
78  entry.type = Entry::UnwrapLine;
79  entry.line = line;
80  entry.column = 0;
81  entry.oldLineLength = oldLineLength;
82  addEntry (entry);
83 }
84 
85 void TextHistory::insertText (const KTextEditor::Cursor &position, int length, int oldLineLength)
86 {
87  // create and add new entry
88  Entry entry;
89  entry.type = Entry::InsertText;
90  entry.line = position.line ();
91  entry.column = position.column ();
92  entry.length = length;
93  entry.oldLineLength = oldLineLength;
94  addEntry (entry);
95 }
96 
97 void TextHistory::removeText (const KTextEditor::Range &range, int oldLineLength)
98 {
99  // create and add new entry
100  Entry entry;
101  entry.type = Entry::RemoveText;
102  entry.line = range.start().line ();
103  entry.column = range.start().column ();
104  entry.length = range.end().column() - range.start().column();
105  entry.oldLineLength = oldLineLength;
106  addEntry (entry);
107 }
108 
109 void TextHistory::addEntry (const Entry &entry)
110 {
114  Q_ASSERT (!m_historyEntries.empty ());
115 
120  if ((m_historyEntries.size () == 1) && !m_historyEntries.first().referenceCounter) {
124  m_firstHistoryEntryRevision = revision () + 1;
125 
129  m_historyEntries.first() = entry;
130 
134  return;
135  }
136 
140  m_historyEntries.push_back (entry);
141 }
142 
143 void TextHistory::lockRevision (qint64 revision)
144 {
148  Q_ASSERT (!m_historyEntries.empty ());
149  Q_ASSERT (revision >= m_firstHistoryEntryRevision);
150  Q_ASSERT (revision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
151 
155  Entry &entry = m_historyEntries[revision - m_firstHistoryEntryRevision];
156  ++entry.referenceCounter;
157 }
158 
159 void TextHistory::unlockRevision (qint64 revision)
160 {
164  Q_ASSERT (!m_historyEntries.empty ());
165  Q_ASSERT (revision >= m_firstHistoryEntryRevision);
166  Q_ASSERT (revision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
167 
171  Entry &entry = m_historyEntries[revision - m_firstHistoryEntryRevision];
172  Q_ASSERT (entry.referenceCounter);
173  --entry.referenceCounter;
174 
178  if (!entry.referenceCounter) {
182  int unreferencedEdits = 0;
183  for (int i = 0; i + 1 < m_historyEntries.size(); ++i) {
184  if (m_historyEntries.at(i).referenceCounter)
185  break;
186 
187  // remember deleted count
188  ++unreferencedEdits;
189  }
190 
194  if (unreferencedEdits > 0) {
195  // remove stuff from history
196  m_historyEntries.erase (m_historyEntries.begin(), m_historyEntries.begin() + unreferencedEdits);
197 
198  // patch first entry revision
199  m_firstHistoryEntryRevision += unreferencedEdits;
200  }
201  }
202 }
203 
204 void TextHistory::Entry::transformCursor (int &cursorLine, int &cursorColumn, bool moveOnInsert) const
205 {
213  if (line > cursorLine)
214  return;
215 
219  switch (type) {
223  case WrapLine:
227  if (cursorLine == line) {
231  if (cursorColumn <= column) {
232  if (cursorColumn < column || !moveOnInsert)
233  return;
234  }
235 
239  cursorColumn = cursorColumn - column;
240  }
241 
245  cursorLine += 1;
246  return;
247 
251  case UnwrapLine:
255  if (cursorLine == line)
256  cursorColumn += oldLineLength;
257 
261  cursorLine -= 1;
262  return;
263 
267  case InsertText:
271  if (cursorLine != line)
272  return;
273 
274  // skip cursors with too small column
275  if (cursorColumn <= column)
276  if (cursorColumn < column || !moveOnInsert)
277  return;
278 
279  // patch column of cursor
280  if (cursorColumn <= oldLineLength)
281  cursorColumn += length;
282 
283  // special handling if cursor behind the real line, e.g. non-wrapping cursor in block selection mode
284  else if (cursorColumn < oldLineLength + length)
285  cursorColumn = oldLineLength + length;
286 
287  return;
288 
292  case RemoveText:
296  if (cursorLine != line)
297  return;
298 
299  // skip cursors with too small column
300  if (cursorColumn <= column)
301  return;
302 
303  // patch column of cursor
304  if (cursorColumn <= column + length)
305  cursorColumn = column;
306  else
307  cursorColumn -= length;
308 
309  return;
310 
314  default:
315  return;
316  }
317 }
318 
319 void TextHistory::Entry::reverseTransformCursor (int &cursorLine, int &cursorColumn, bool moveOnInsert) const
320 {
324  switch (type) {
328  case WrapLine:
332  if (cursorLine <= line)
333  return;
334 
338  if (cursorLine == line + 1) {
342  cursorColumn = cursorColumn + column;
343  }
344 
348  cursorLine -= 1;
349  return;
350 
354  case UnwrapLine:
358  if (cursorLine < line - 1)
359  return;
360 
364  if (cursorLine == line - 1) {
368  if (cursorColumn <= oldLineLength) {
369  if (cursorColumn < oldLineLength || !moveOnInsert)
370  return;
371  }
372 
373  cursorColumn -= oldLineLength;
374  }
375 
379  cursorLine += 1;
380  return;
381 
385  case InsertText:
389  if (cursorLine != line)
390  return;
391 
392  // skip cursors with too small column
393  if (cursorColumn <= column)
394  return;
395 
396  // patch column of cursor
397  if (cursorColumn - length < column)
398  cursorColumn = column;
399  else
400  cursorColumn -= length;
401 
402  return;
403 
407  case RemoveText:
411  if (cursorLine != line)
412  return;
413 
414  // skip cursors with too small column
415  if (cursorColumn <= column)
416  if (cursorColumn < column || !moveOnInsert)
417  return;
418 
419  // patch column of cursor
420  if (cursorColumn <= oldLineLength)
421  cursorColumn += length;
422 
423  // special handling if cursor behind the real line, e.g. non-wrapping cursor in block selection mode
424  else if (cursorColumn < oldLineLength + length)
425  cursorColumn = oldLineLength + length;
426  return;
427 
431  default:
432  return;
433  }
434 }
435 
436 void TextHistory::transformCursor (int& line, int& column, KTextEditor::MovingCursor::InsertBehavior insertBehavior, qint64 fromRevision, qint64 toRevision)
437 {
441  if (fromRevision == -1)
442  fromRevision = revision ();
443 
444  if (toRevision == -1)
445  toRevision = revision ();
446 
450  if (fromRevision == toRevision)
451  return;
452 
456  Q_ASSERT (!m_historyEntries.empty ());
457  Q_ASSERT (fromRevision != toRevision);
458  Q_ASSERT (fromRevision >= m_firstHistoryEntryRevision);
459  Q_ASSERT (fromRevision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
460  Q_ASSERT (toRevision >= m_firstHistoryEntryRevision);
461  Q_ASSERT (toRevision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
462 
466  bool moveOnInsert = insertBehavior == KTextEditor::MovingCursor::MoveOnInsert;
467 
471  if (toRevision > fromRevision) {
472  for (int rev = fromRevision - m_firstHistoryEntryRevision + 1; rev <= (toRevision - m_firstHistoryEntryRevision); ++rev) {
473  const Entry &entry = m_historyEntries.at(rev);
474  entry.transformCursor (line, column, moveOnInsert);
475  }
476  } else {
477  for (int rev = fromRevision - m_firstHistoryEntryRevision; rev >= (toRevision - m_firstHistoryEntryRevision + 1); --rev) {
478  const Entry &entry = m_historyEntries.at(rev);
479  entry.reverseTransformCursor (line, column, moveOnInsert);
480  }
481  }
482 }
483 
484 void TextHistory::transformRange (KTextEditor::Range &range, KTextEditor::MovingRange::InsertBehaviors insertBehaviors, KTextEditor::MovingRange::EmptyBehavior emptyBehavior, qint64 fromRevision, qint64 toRevision)
485 {
489  bool invalidateIfEmpty = emptyBehavior == KTextEditor::MovingRange::InvalidateIfEmpty;
490  if (invalidateIfEmpty && range.end() <= range.start()) {
491  range = KTextEditor::Range::invalid();
492  return;
493  }
494 
498  if (fromRevision == -1)
499  fromRevision = revision ();
500 
501  if (toRevision == -1)
502  toRevision = revision ();
503 
507  if (fromRevision == toRevision)
508  return;
509 
513  Q_ASSERT (!m_historyEntries.empty ());
514  Q_ASSERT (fromRevision != toRevision);
515  Q_ASSERT (fromRevision >= m_firstHistoryEntryRevision);
516  Q_ASSERT (fromRevision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
517  Q_ASSERT (toRevision >= m_firstHistoryEntryRevision);
518  Q_ASSERT (toRevision < (m_firstHistoryEntryRevision + m_historyEntries.size()));
519 
524  // first: copy cursors, without range association
525  int startLine = range.start().line(), startColumn = range.start().column(), endLine = range.end().line(), endColumn = range.end().column();
526 
527  bool moveOnInsertStart = !(insertBehaviors & KTextEditor::MovingRange::ExpandLeft);
528  bool moveOnInsertEnd = (insertBehaviors & KTextEditor::MovingRange::ExpandRight);
529 
533  if (toRevision > fromRevision) {
534  for (int rev = fromRevision - m_firstHistoryEntryRevision + 1; rev <= (toRevision - m_firstHistoryEntryRevision); ++rev) {
535  const Entry &entry = m_historyEntries.at(rev);
536 
537  entry.transformCursor (startLine, startColumn, moveOnInsertStart);
538 
539  entry.transformCursor (endLine, endColumn, moveOnInsertEnd);
540 
541  // got empty?
542  if(endLine < startLine || (endLine == startLine && endColumn <= startColumn))
543  {
544  if (invalidateIfEmpty) {
545  range = KTextEditor::Range::invalid();
546  return;
547  }
548  else{
549  // else normalize them
550  endLine = startLine;
551  endColumn = startColumn;
552  }
553  }
554  }
555  } else {
556  for (int rev = fromRevision - m_firstHistoryEntryRevision ; rev >= (toRevision - m_firstHistoryEntryRevision + 1); --rev) {
557  const Entry &entry = m_historyEntries.at(rev);
558 
559  entry.reverseTransformCursor (startLine, startColumn, moveOnInsertStart);
560 
561  entry.reverseTransformCursor (endLine, endColumn, moveOnInsertEnd);
562 
563  // got empty?
564  if(endLine < startLine || (endLine == startLine && endColumn <= startColumn))
565  {
566  if (invalidateIfEmpty) {
567  range = KTextEditor::Range::invalid();
568  return;
569  }
570  else{
571  // else normalize them
572  endLine = startLine;
573  endColumn = startColumn;
574  }
575  }
576  }
577  }
578 
579  // now, copy cursors back
580  range.start().setLine(startLine);
581  range.start().setColumn(startColumn);
582  range.end().setLine(endLine);
583  range.end().setColumn(endColumn);
584 
585 }
586 
587 }
QList::clear
void clear()
Kate::TextFolding::clear
void clear()
Clear the complete folding.
Definition: katetextfolding.cpp:66
katetextbuffer.h
QList::push_back
void push_back(const T &value)
QList::at
const T & at(int i) const
katetexthistory.h
QList::erase
iterator erase(iterator pos)
QList::size
int size() const
Kate::TextHistory::transformRange
void transformRange(KTextEditor::Range &range, KTextEditor::MovingRange::InsertBehaviors insertBehaviors, KTextEditor::MovingRange::EmptyBehavior emptyBehavior, qint64 fromRevision, qint64 toRevision=-1)
Transform a range from one revision to an other.
Definition: katetexthistory.cpp:484
QList::empty
bool empty() const
QList::first
T & first()
Kate::TextHistory::unlockRevision
void unlockRevision(qint64 revision)
Release a revision.
Definition: katetexthistory.cpp:159
Kate::TextHistory::revision
qint64 revision() const
Current revision, just relay the revision of the buffer.
Definition: katetexthistory.cpp:39
Kate::TextBuffer::revision
qint64 revision() const
Revision of this buffer.
Definition: katetextbuffer.h:196
Kate::TextHistory::transformCursor
void transformCursor(int &line, int &column, KTextEditor::MovingCursor::InsertBehavior insertBehavior, qint64 fromRevision, qint64 toRevision=-1)
Transform a cursor from one revision to an other.
Definition: katetexthistory.cpp:436
Kate::TextHistory::lockRevision
void lockRevision(qint64 revision)
Lock a revision, this will keep it around until released again.
Definition: katetexthistory.cpp:143
QList::begin
iterator begin()
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat May 9 2020 03:56:58 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

applications API Reference

Skip menu "applications API Reference"
  •   kate
  •       kate
  •   KTextEditor
  •   Kate
  • Konsole

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal