aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2023-10-04 14:48:19 +1100
committerNeil <nyamatongwe@gmail.com>2023-10-04 14:48:19 +1100
commit0d75d5544f21ecf2dca49af04b3467ccea4ab8db (patch)
tree1c98be77a4891db5b11dae10d677cfcfb6282e52
parent0f6ccb7a07532cf132c621c347e89c571bf171a9 (diff)
downloadscintilla-mirror-0d75d5544f21ecf2dca49af04b3467ccea4ab8db.tar.gz
Preparatory changes for fix in next commit. Does not change Scintilla behaviour.
Add tests for contiguous deletions in forward and backward directions. Use symbolic edition values. Rename InsertionSpan to ChangeSpan and insertions to changes as holds both insertions and deletions. Add ChangeStack::Check. Add comments.
-rw-r--r--src/ChangeHistory.cxx42
-rw-r--r--src/ChangeHistory.h8
-rw-r--r--test/unit/testCellBuffer.cxx49
3 files changed, 83 insertions, 16 deletions
diff --git a/src/ChangeHistory.cxx b/src/ChangeHistory.cxx
index 7295f89af..704f3f1c9 100644
--- a/src/ChangeHistory.cxx
+++ b/src/ChangeHistory.cxx
@@ -30,7 +30,7 @@ namespace Scintilla::Internal {
void ChangeStack::Clear() noexcept {
steps.clear();
- insertions.clear();
+ changes.clear();
}
void ChangeStack::AddStep() {
@@ -39,12 +39,12 @@ void ChangeStack::AddStep() {
void ChangeStack::PushDeletion(Sci::Position positionDeletion, int edition) {
steps.back()++;
- insertions.push_back({ positionDeletion, 0, edition, InsertionSpan::Direction::deletion });
+ changes.push_back({ positionDeletion, 0, edition, ChangeSpan::Direction::deletion });
}
void ChangeStack::PushInsertion(Sci::Position positionInsertion, Sci::Position length, int edition) {
steps.back()++;
- insertions.push_back({ positionInsertion, length, edition, InsertionSpan::Direction::insertion });
+ changes.push_back({ positionInsertion, length, edition, ChangeSpan::Direction::insertion });
}
size_t ChangeStack::PopStep() noexcept {
@@ -53,21 +53,33 @@ size_t ChangeStack::PopStep() noexcept {
return spans;
}
-InsertionSpan ChangeStack::PopSpan() noexcept {
- const InsertionSpan span = insertions.back();
- insertions.pop_back();
+ChangeSpan ChangeStack::PopSpan() noexcept {
+ const ChangeSpan span = changes.back();
+ changes.pop_back();
return span;
}
void ChangeStack::SetSavePoint() noexcept {
// Switch changeUnsaved to changeSaved
- for (InsertionSpan &x : insertions) {
+ for (ChangeSpan &x : changes) {
if (x.edition == changeModified) {
x.edition = changeSaved;
}
}
}
+void ChangeStack::Check() const noexcept {
+#ifdef _DEBUG
+ // Ensure count in steps same as insertions;
+ size_t sizeSteps = 0;
+ for (const size_t c : steps) {
+ sizeSteps += c;
+ }
+ const size_t sizeInsertions = changes.size();
+ assert(sizeSteps == sizeInsertions);
+#endif
+}
+
void ChangeLog::Clear(Sci::Position length) {
changeStack.Clear();
insertEdition.DeleteAll();
@@ -167,13 +179,16 @@ void ChangeLog::PopDeletion(Sci::Position position, Sci::Position deleteLength)
editions->pop_back();
const size_t inserts = changeStack.PopStep();
for (size_t i = 0; i < inserts; i++) {
- const InsertionSpan span = changeStack.PopSpan();
- if (span.direction == InsertionSpan::Direction::insertion) {
+ const ChangeSpan span = changeStack.PopSpan();
+ if (span.direction == ChangeSpan::Direction::insertion) {
insertEdition.FillRange(span.start, span.edition, span.length);
} else {
assert(editions);
assert(editions->back() == span.edition);
editions->pop_back();
+ // Iterating backwards (pop) through changeStack, reverse order of insertion
+ // and original deletion list.
+ // Therefore need to insert at front to recreate original order.
InsertFrontDeletionAt(span.start, span.edition);
}
}
@@ -242,6 +257,7 @@ size_t ChangeLog::DeletionCount(Sci::Position start, Sci::Position length) const
void ChangeLog::Check() const noexcept {
assert(insertEdition.Length() == deleteEdition.Length());
+ changeStack.Check();
}
ChangeHistory::ChangeHistory(Sci::Position length) {
@@ -270,7 +286,7 @@ void ChangeHistory::DeleteRange(Sci::Position position, Sci::Position deleteLeng
if (changeLogReversions) {
changeLogReversions->DeleteRangeSavingHistory(position, deleteLength);
if (reverting) {
- changeLogReversions->PushDeletionAt(position, 1);
+ changeLogReversions->PushDeletionAt(position, changeRevertedOriginal);
}
}
Check();
@@ -349,9 +365,9 @@ int ChangeHistory::EditionAt(Sci::Position pos) const noexcept {
if (changeLogReversions) {
const int editionReversion = changeLogReversions->insertEdition.ValueAt(pos);
if (editionReversion) {
- if (edition < 0)
- return 1;
- return edition ? 4 : 1;
+ if (edition < 0) // Historical revision
+ return changeRevertedOriginal;
+ return edition ? changeRevertedToChange : changeRevertedOriginal;
}
}
return edition;
diff --git a/src/ChangeHistory.h b/src/ChangeHistory.h
index 8a6e745dc..0475a3a6e 100644
--- a/src/ChangeHistory.h
+++ b/src/ChangeHistory.h
@@ -22,27 +22,29 @@ constexpr unsigned int bitSaved = 2;
constexpr unsigned int bitModified = 4;
constexpr unsigned int bitRevertedToModified = 8;
-struct InsertionSpan {
+struct ChangeSpan {
Sci::Position start;
Sci::Position length;
int edition;
enum class Direction { insertion, deletion } direction;
};
+// EditionSet is ordered from oldest to newest, its not really a set
using EditionSet = std::vector<int>;
using EditionSetOwned = std::unique_ptr<EditionSet>;
class ChangeStack {
std::vector<size_t> steps;
- std::vector<InsertionSpan> insertions;
+ std::vector<ChangeSpan> changes;
public:
void Clear() noexcept;
void AddStep();
void PushDeletion(Sci::Position positionDeletion, int edition);
void PushInsertion(Sci::Position positionInsertion, Sci::Position length, int edition);
[[nodiscard]] size_t PopStep() noexcept;
- [[nodiscard]] InsertionSpan PopSpan() noexcept;
+ [[nodiscard]] ChangeSpan PopSpan() noexcept;
void SetSavePoint() noexcept;
+ void Check() const noexcept;
};
struct ChangeLog {
diff --git a/test/unit/testCellBuffer.cxx b/test/unit/testCellBuffer.cxx
index cb69e7756..f7795c9e7 100644
--- a/test/unit/testCellBuffer.cxx
+++ b/test/unit/testCellBuffer.cxx
@@ -633,6 +633,55 @@ TEST_CASE("ChangeHistory") {
}
REQUIRE(il.DeletionCount(0, 10) == 0);
REQUIRE(il.Length() == 10);
+
+ }
+
+ SECTION("Delete Contiguous Backward") {
+ // Deletes that touch
+ constexpr size_t length = 20;
+ constexpr size_t rounds = 8;
+ il.Insert(0, length, false, true);
+ REQUIRE(il.Length() == length);
+ il.SetSavePoint();
+ for (size_t i = 0; i < rounds; i++) {
+ il.DeleteRangeSavingHistory(9-i, 1, false, false);
+ }
+
+ constexpr size_t lengthAfterDeletions = length - rounds;
+ REQUIRE(il.Length() == lengthAfterDeletions);
+ REQUIRE(il.DeletionCount(0, lengthAfterDeletions) == rounds);
+
+ for (size_t j = 0; j < rounds; j++) {
+ il.UndoDeleteStep(2+j, 1, false);
+ }
+
+ // Restored to original
+ REQUIRE(il.DeletionCount(0, length) == 0);
+ REQUIRE(il.Length() == length);
+ }
+
+ SECTION("Delete Contiguous Forward") {
+ // Deletes that touch
+ constexpr size_t length = 20;
+ constexpr size_t rounds = 8;
+ il.Insert(0, length, false, true);
+ REQUIRE(il.Length() == length);
+ il.SetSavePoint();
+ for (size_t i = 0; i < rounds; i++) {
+ il.DeleteRangeSavingHistory(2,1, false, false);
+ }
+
+ constexpr size_t lengthAfterDeletions = length - rounds;
+ REQUIRE(il.Length() == lengthAfterDeletions);
+ REQUIRE(il.DeletionCount(0, lengthAfterDeletions) == rounds);
+
+ for (size_t j = 0; j < rounds; j++) {
+ il.UndoDeleteStep(2, 1, false);
+ }
+
+ // Restored to original
+ REQUIRE(il.Length() == length);
+ REQUIRE(il.DeletionCount(0, length) == 0);
}
}