aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/CellBuffer.h1
-rw-r--r--src/Document.cxx7
-rw-r--r--src/Document.h1
-rw-r--r--src/PerLine.cxx37
-rw-r--r--src/PerLine.h5
-rw-r--r--test/unit/UnitTester.vcxproj1
-rw-r--r--test/unit/makefile3
-rw-r--r--test/unit/test.mak3
-rw-r--r--test/unit/testPerLine.cxx363
9 files changed, 418 insertions, 3 deletions
diff --git a/src/CellBuffer.h b/src/CellBuffer.h
index 5138fd0aa..3e16bcdc8 100644
--- a/src/CellBuffer.h
+++ b/src/CellBuffer.h
@@ -16,6 +16,7 @@ public:
virtual ~PerLine() {}
virtual void Init()=0;
virtual void InsertLine(Sci::Line line)=0;
+ virtual void InsertLines(Sci::Line line, Sci::Line lines) = 0;
virtual void RemoveLine(Sci::Line line)=0;
};
diff --git a/src/Document.cxx b/src/Document.cxx
index 2382e1c21..ff009ee3e 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -178,6 +178,13 @@ void Document::InsertLine(Sci::Line line) {
}
}
+void Document::InsertLines(Sci::Line line, Sci::Line lines) {
+ for (const auto &pl : perLineData) {
+ if (pl)
+ pl->InsertLines(line, lines);
+ }
+}
+
void Document::RemoveLine(Sci::Line line) {
for (const std::unique_ptr<PerLine> &pl : perLineData) {
if (pl)
diff --git a/src/Document.h b/src/Document.h
index a1d9ff7c2..2ff0e8b27 100644
--- a/src/Document.h
+++ b/src/Document.h
@@ -298,6 +298,7 @@ public:
// From PerLine
void Init() override;
void InsertLine(Sci::Line line) override;
+ void InsertLines(Sci::Line line, Sci::Line lines) override;
void RemoveLine(Sci::Line line) override;
int LineEndTypesSupported() const;
diff --git a/src/PerLine.cxx b/src/PerLine.cxx
index 47556f3ae..c7204e31a 100644
--- a/src/PerLine.cxx
+++ b/src/PerLine.cxx
@@ -102,6 +102,12 @@ void LineMarkers::InsertLine(Sci::Line line) {
}
}
+void LineMarkers::InsertLines(Sci::Line line, Sci::Line lines) {
+ if (markers.Length()) {
+ markers.InsertEmpty(line, lines);
+ }
+}
+
void LineMarkers::RemoveLine(Sci::Line line) {
// Retain the markers from the deleted line by oring them into the previous line
if (markers.Length()) {
@@ -219,7 +225,14 @@ void LineLevels::Init() {
void LineLevels::InsertLine(Sci::Line line) {
if (levels.Length()) {
const int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE;
- levels.InsertValue(line, 1, level);
+ levels.Insert(line, level);
+ }
+}
+
+void LineLevels::InsertLines(Sci::Line line, Sci::Line lines) {
+ if (levels.Length()) {
+ const int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE;
+ levels.InsertValue(line, lines, level);
}
}
@@ -281,6 +294,14 @@ void LineState::InsertLine(Sci::Line line) {
}
}
+void LineState::InsertLines(Sci::Line line, Sci::Line lines) {
+ if (lineStates.Length()) {
+ lineStates.EnsureLength(line);
+ const int val = (line < lineStates.Length()) ? lineStates[line] : 0;
+ lineStates.InsertValue(line, lines, val);
+ }
+}
+
void LineState::RemoveLine(Sci::Line line) {
if (lineStates.Length() > line) {
lineStates.Delete(line);
@@ -343,6 +364,13 @@ void LineAnnotation::InsertLine(Sci::Line line) {
}
}
+void LineAnnotation::InsertLines(Sci::Line line, Sci::Line lines) {
+ if (annotations.Length()) {
+ annotations.EnsureLength(line);
+ annotations.InsertEmpty(line, lines);
+ }
+}
+
void LineAnnotation::RemoveLine(Sci::Line line) {
if (annotations.Length() && (line > 0) && (line <= annotations.Length())) {
annotations[line-1].reset();
@@ -459,6 +487,13 @@ void LineTabstops::InsertLine(Sci::Line line) {
}
}
+void LineTabstops::InsertLines(Sci::Line line, Sci::Line lines) {
+ if (tabstops.Length()) {
+ tabstops.EnsureLength(line);
+ tabstops.InsertEmpty(line, lines);
+ }
+}
+
void LineTabstops::RemoveLine(Sci::Line line) {
if (tabstops.Length() > line) {
tabstops[line].reset();
diff --git a/src/PerLine.h b/src/PerLine.h
index b6565fcc1..b43b0a18b 100644
--- a/src/PerLine.h
+++ b/src/PerLine.h
@@ -59,6 +59,7 @@ public:
~LineMarkers() override;
void Init() override;
void InsertLine(Sci::Line line) override;
+ void InsertLines(Sci::Line line, Sci::Line lines) override;
void RemoveLine(Sci::Line line) override;
int MarkValue(Sci::Line line) const noexcept;
@@ -85,6 +86,7 @@ public:
~LineLevels() override;
void Init() override;
void InsertLine(Sci::Line line) override;
+ void InsertLines(Sci::Line line, Sci::Line lines) override;
void RemoveLine(Sci::Line line) override;
void ExpandLevels(Sci::Line sizeNew=-1);
@@ -106,6 +108,7 @@ public:
~LineState() override;
void Init() override;
void InsertLine(Sci::Line line) override;
+ void InsertLines(Sci::Line line, Sci::Line lines) override;
void RemoveLine(Sci::Line line) override;
int SetLineState(Sci::Line line, int state);
@@ -126,6 +129,7 @@ public:
~LineAnnotation() override;
void Init() override;
void InsertLine(Sci::Line line) override;
+ void InsertLines(Sci::Line line, Sci::Line lines) override;
void RemoveLine(Sci::Line line) override;
bool MultipleStyles(Sci::Line line) const noexcept;
@@ -155,6 +159,7 @@ public:
~LineTabstops() override;
void Init() override;
void InsertLine(Sci::Line line) override;
+ void InsertLines(Sci::Line line, Sci::Line lines) override;
void RemoveLine(Sci::Line line) override;
bool ClearTabstops(Sci::Line line) noexcept;
diff --git a/test/unit/UnitTester.vcxproj b/test/unit/UnitTester.vcxproj
index 361f41083..65d4c58dc 100644
--- a/test/unit/UnitTester.vcxproj
+++ b/test/unit/UnitTester.vcxproj
@@ -155,6 +155,7 @@
<ClCompile Include="..\..\src\CharClassify.cxx" />
<ClCompile Include="..\..\src\ContractionState.cxx" />
<ClCompile Include="..\..\src\Decoration.cxx" />
+ <ClCompile Include="..\..\src\PerLine.cxx" />
<ClCompile Include="..\..\src\RunStyles.cxx" />
<ClCompile Include="..\..\src\UniConversion.cxx" />
<ClCompile Include="..\..\src\UniqueString.cxx" />
diff --git a/test/unit/makefile b/test/unit/makefile
index 6d5ead6cd..05bbed944 100644
--- a/test/unit/makefile
+++ b/test/unit/makefile
@@ -3,7 +3,7 @@
# On Windows g++ is used, on OS X clang, and on Linux G++ is used by default
# but clang can be used by defining CLANG when invoking make
# clang works only with libc++, not libstdc++
-# Tested with clang 3.3 and g++ 4.8
+# Tested with clang 9 and g++ 9
CXXSTD=c++17
@@ -54,6 +54,7 @@ TESTEDSRC=\
../../src/CharClassify.cxx \
../../src/ContractionState.cxx \
../../src/Decoration.cxx \
+ ../../src/PerLine.cxx \
../../src/RunStyles.cxx \
../../src/UniConversion.cxx \
../../src/UniqueString.cxx
diff --git a/test/unit/test.mak b/test/unit/test.mak
index 42b17e556..6503acba4 100644
--- a/test/unit/test.mak
+++ b/test/unit/test.mak
@@ -1,5 +1,5 @@
# Build all the unit tests with Microsoft Visual C++ using nmake
-# Tested with Visual C++ 2010 and 2013
+# Tested with Visual C++ 2019
DEL = del /q
EXE = unitTest.exe
@@ -17,6 +17,7 @@ TESTEDSRC=\
../../src/CharClassify.cxx \
../../src/ContractionState.cxx \
../../src/Decoration.cxx \
+ ../../src/PerLine.cxx \
../../src/RunStyles.cxx \
../../src/UniConversion.cxx \
../../src/UniqueString.cxx
diff --git a/test/unit/testPerLine.cxx b/test/unit/testPerLine.cxx
new file mode 100644
index 000000000..b2a84793d
--- /dev/null
+++ b/test/unit/testPerLine.cxx
@@ -0,0 +1,363 @@
+// Unit Tests for Scintilla internal data structures
+
+#include <cstddef>
+#include <cstring>
+#include <stdexcept>
+#include <string_view>
+#include <vector>
+#include <forward_list>
+#include <algorithm>
+#include <memory>
+
+#include "Platform.h"
+
+#include "Scintilla.h"
+#include "Position.h"
+#include "SplitVector.h"
+#include "Partitioning.h"
+#include "RunStyles.h"
+#include "CellBuffer.h"
+#include "PerLine.h"
+
+#include "catch.hpp"
+
+using namespace Scintilla;
+
+// Test MarkerHandleSet.
+
+TEST_CASE("MarkerHandleSet") {
+
+ MarkerHandleSet mhs;
+
+ SECTION("Initial") {
+ // Initial State
+ REQUIRE(mhs.Empty());
+ REQUIRE(0 == mhs.MarkValue());
+ REQUIRE(!mhs.Contains(1));
+ }
+
+ SECTION("InsertDelete") {
+ // Test knows that InsertHandle inserts at front (0)
+ // Insert 1 with handle 100
+ REQUIRE(mhs.InsertHandle(100,1));
+ REQUIRE(!mhs.Empty());
+ REQUIRE(2 == mhs.MarkValue());
+ REQUIRE(mhs.Contains(100));
+
+ // Insert 2 with handle 200
+ REQUIRE(mhs.InsertHandle(200,2));
+ REQUIRE(!mhs.Empty());
+ REQUIRE(mhs.Contains(100));
+ REQUIRE(mhs.Contains(200));
+ REQUIRE(6 == mhs.MarkValue());
+
+ const MarkerHandleNumber *mhn0 = mhs.GetMarkerHandleNumber(0);
+ REQUIRE(200 == mhn0->handle);
+ REQUIRE(2 == mhn0->number);
+ const MarkerHandleNumber *mhn1 = mhs.GetMarkerHandleNumber(1);
+ REQUIRE(100 == mhn1->handle);
+ REQUIRE(1 == mhn1->number);
+ const MarkerHandleNumber *mhn2 = mhs.GetMarkerHandleNumber(2);
+ REQUIRE(nullptr == mhn2);
+
+ // Remove first insertion
+ mhs.RemoveHandle(100);
+ REQUIRE(!mhs.Empty());
+ REQUIRE(mhs.Contains(200));
+ REQUIRE(4 == mhs.MarkValue());
+
+ // Remove remaining element
+ REQUIRE(mhs.RemoveNumber(2, true));
+ REQUIRE(mhs.Empty());
+ REQUIRE(!mhs.Contains(200));
+ REQUIRE(0 == mhs.MarkValue());
+ }
+
+ SECTION("Combine") {
+ mhs.InsertHandle(100, 1);
+ MarkerHandleSet mhsOther;
+ mhsOther.InsertHandle(200, 2);
+ mhs.CombineWith(&mhsOther);
+ REQUIRE(mhsOther.Empty());
+ mhs.RemoveHandle(100);
+ mhs.RemoveHandle(200);
+ REQUIRE(mhs.Empty());
+ }
+}
+
+TEST_CASE("LineMarkers") {
+
+ LineMarkers lm;
+
+ SECTION("Initial") {
+ // Initial State
+ REQUIRE(0 == lm.MarkValue(0));
+ }
+
+ SECTION("AddDelete") {
+ // Test knows the way handles are allocated, starting from 1
+ lm.InsertLines(0, 5);
+ const int handle1 = lm.AddMark(0, 1, 5);
+ REQUIRE(1 == handle1);
+ REQUIRE(2 == lm.MarkValue(0));
+ REQUIRE(1 == lm.HandleFromLine(0, 0));
+ REQUIRE(1 == lm.NumberFromLine(0, 0));
+ REQUIRE(-1 == lm.HandleFromLine(0, 1));
+ REQUIRE(-1 == lm.NumberFromLine(0, 1));
+ REQUIRE(0 == lm.LineFromHandle(handle1));
+
+ REQUIRE(lm.DeleteMark(0, 1, true));
+ REQUIRE(0 == lm.MarkValue(0));
+
+ const int handle2 = lm.AddMark(0, 2, 5);
+ REQUIRE(2 == handle2);
+ REQUIRE(4 == lm.MarkValue(0));
+ lm.DeleteMarkFromHandle(handle2);
+ REQUIRE(0 == lm.MarkValue(0));
+ }
+
+ SECTION("MarkerNext") {
+ lm.AddMark(1, 1, 5);
+ lm.AddMark(2, 2, 5);
+ const Sci::Line line1 = lm.MarkerNext(0, 6);
+ REQUIRE(1 == line1);
+ const Sci::Line line2 = lm.MarkerNext(line1+1, 6);
+ REQUIRE(2 == line2);
+ const Sci::Line line3 = lm.MarkerNext(line2+1, 6);
+ REQUIRE(-1 == line3);
+ }
+
+ SECTION("MergeMarkers") {
+ lm.AddMark(1, 1, 5);
+ lm.AddMark(2, 2, 5);
+ lm.MergeMarkers(1);
+ REQUIRE(6 == lm.MarkValue(1));
+ REQUIRE(0 == lm.MarkValue(2));
+ }
+
+ SECTION("InsertRemoveLine") {
+ const int handle1 = lm.AddMark(1, 1, 5);
+ const int handle2 = lm.AddMark(2, 2, 5);
+ lm.InsertLine(2);
+ REQUIRE(0 == lm.MarkValue(0));
+ REQUIRE(2 == lm.MarkValue(1));
+ REQUIRE(0 == lm.MarkValue(2));
+ REQUIRE(4 == lm.MarkValue(3));
+ REQUIRE(0 == lm.MarkValue(4));
+ lm.RemoveLine(2);
+ REQUIRE(0 == lm.MarkValue(0));
+ REQUIRE(2 == lm.MarkValue(1));
+ REQUIRE(4 == lm.MarkValue(2));
+ REQUIRE(0 == lm.MarkValue(3));
+ lm.InsertLines(2, 2);
+ REQUIRE(0 == lm.MarkValue(0));
+ REQUIRE(2 == lm.MarkValue(1));
+ REQUIRE(0 == lm.MarkValue(2));
+ REQUIRE(0 == lm.MarkValue(3));
+ REQUIRE(4 == lm.MarkValue(4));
+ REQUIRE(0 == lm.MarkValue(5));
+ REQUIRE(1 == lm.LineFromHandle(handle1));
+ REQUIRE(4 == lm.LineFromHandle(handle2));
+ }
+}
+
+TEST_CASE("LineLevels") {
+
+ LineLevels ll;
+
+ SECTION("Initial") {
+ // Initial State
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(0));
+ }
+
+ SECTION("SetLevel") {
+ REQUIRE(SC_FOLDLEVELBASE == ll.SetLevel(1, 200, 5));
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(0));
+ REQUIRE(200 == ll.GetLevel(1));
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(2));
+ ll.ClearLevels();
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(1));
+ ll.ExpandLevels(5);
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(7));
+ }
+
+ SECTION("InsertRemoveLine") {
+ ll.SetLevel(1, 1, 5);
+ ll.SetLevel(2, 2, 5);
+ ll.InsertLine(2);
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(0));
+ REQUIRE(1 == ll.GetLevel(1));
+ REQUIRE(2 == ll.GetLevel(2));
+ REQUIRE(2 == ll.GetLevel(3));
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(4));
+ ll.RemoveLine(2);
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(0));
+ REQUIRE(1 == ll.GetLevel(1));
+ REQUIRE(2 == ll.GetLevel(2));
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(3));
+ ll.InsertLines(2, 2);
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(0));
+ REQUIRE(1 == ll.GetLevel(1));
+ REQUIRE(2 == ll.GetLevel(2));
+ REQUIRE(2 == ll.GetLevel(3));
+ REQUIRE(2 == ll.GetLevel(4));
+ REQUIRE(SC_FOLDLEVELBASE == ll.GetLevel(5));
+ }
+}
+
+TEST_CASE("LineState") {
+
+ LineState ls;
+
+ SECTION("Initial") {
+ // Initial State
+ REQUIRE(0 == ls.GetMaxLineState());
+ REQUIRE(0 == ls.GetLineState(0));
+ REQUIRE(1 == ls.GetMaxLineState());
+ ls.Init();
+ REQUIRE(0 == ls.GetMaxLineState());
+ REQUIRE(0 == ls.GetLineState(0));
+ }
+
+ SECTION("SetLineState") {
+ REQUIRE(0 == ls.SetLineState(1, 200));
+ REQUIRE(0 == ls.GetLineState(0));
+ REQUIRE(200 == ls.GetLineState(1));
+ REQUIRE(0 == ls.GetLineState(2));
+ REQUIRE(0 == ls.SetLineState(2, 400));
+ REQUIRE(0 == ls.GetLineState(0));
+ REQUIRE(200 == ls.GetLineState(1));
+ REQUIRE(400 == ls.GetLineState(2));
+ REQUIRE(0 == ls.GetLineState(3));
+ // GetLineState(3) expands to 4 lines
+ REQUIRE(4 == ls.GetMaxLineState());
+ ls.Init();
+ REQUIRE(0 == ls.GetLineState(0));
+ REQUIRE(1 == ls.GetMaxLineState());
+ }
+
+ SECTION("InsertRemoveLine") {
+ REQUIRE(0 == ls.GetMaxLineState());
+ ls.SetLineState(1, 1);
+ ls.SetLineState(2, 2);
+ REQUIRE(3 == ls.GetMaxLineState());
+ ls.InsertLine(2);
+ REQUIRE(4 == ls.GetMaxLineState());
+ REQUIRE(0 == ls.GetLineState(0));
+ REQUIRE(1 == ls.GetLineState(1));
+ REQUIRE(2 == ls.GetLineState(2));
+ REQUIRE(2 == ls.GetLineState(3));
+ REQUIRE(0 == ls.GetLineState(4));
+ REQUIRE(5 == ls.GetMaxLineState());
+ ls.RemoveLine(2);
+ REQUIRE(4 == ls.GetMaxLineState());
+ REQUIRE(0 == ls.GetLineState(0));
+ REQUIRE(1 == ls.GetLineState(1));
+ REQUIRE(2 == ls.GetLineState(2));
+ REQUIRE(0 == ls.GetLineState(3));
+ ls.InsertLines(2, 2);
+ REQUIRE(6 == ls.GetMaxLineState());
+ REQUIRE(0 == ls.GetLineState(0));
+ REQUIRE(1 == ls.GetLineState(1));
+ REQUIRE(2 == ls.GetLineState(2));
+ REQUIRE(2 == ls.GetLineState(3));
+ REQUIRE(2 == ls.GetLineState(4));
+ REQUIRE(0 == ls.GetLineState(5));
+ }
+}
+
+TEST_CASE("LineAnnotation") {
+
+ LineAnnotation la;
+
+ SECTION("Initial") {
+ // Initial State
+ REQUIRE(0 == la.Length(0));
+ REQUIRE(0 == la.Lines(0));
+ REQUIRE(0 == la.Style(0));
+ REQUIRE(false == la.MultipleStyles(0));
+ }
+
+ SECTION("SetText") {
+ la.SetText(0, "Text");
+ REQUIRE(4 == la.Length(0));
+ REQUIRE(1 == la.Lines(0));
+ REQUIRE(memcmp(la.Text(0), "Text", 4) == 0);
+ REQUIRE(nullptr == la.Styles(0));
+ REQUIRE(0 == la.Style(0));
+ la.SetStyle(0, 9);
+ REQUIRE(9 == la.Style(0));
+
+ la.SetText(0, "Ant\nBird\nCat");
+ REQUIRE(3 == la.Lines(0));
+
+ la.ClearAll();
+ REQUIRE(nullptr == la.Text(0));
+ }
+
+ SECTION("SetStyles") {
+ la.SetText(0, "Text");
+ const unsigned char styles[] { 1,2,3,4 };
+ la.SetStyles(0, styles);
+ REQUIRE(memcmp(la.Text(0), "Text", 4) == 0);
+ REQUIRE(memcmp(la.Styles(0), styles, 4) == 0);
+ REQUIRE(la.MultipleStyles(0));
+ }
+
+ SECTION("InsertRemoveLine") {
+ la.SetText(0, "Ant");
+ la.SetText(1, "Bird");
+ REQUIRE(3 == la.Length(0));
+ REQUIRE(4 == la.Length(1));
+ REQUIRE(1 == la.Lines(0));
+ la.InsertLine(1);
+ REQUIRE(3 == la.Length(0));
+ REQUIRE(0 == la.Length(1));
+ REQUIRE(4 == la.Length(2));
+ la.RemoveLine(2);
+ REQUIRE(3 == la.Length(0));
+ REQUIRE(4 == la.Length(1));
+ la.InsertLines(1, 2);
+ REQUIRE(3 == la.Length(0));
+ REQUIRE(0 == la.Length(1));
+ REQUIRE(0 == la.Length(2));
+ REQUIRE(4 == la.Length(3));
+ }
+}
+
+TEST_CASE("LineTabstops") {
+
+ LineTabstops lt;
+
+ SECTION("Initial") {
+ // Initial State
+ REQUIRE(0 == lt.GetNextTabstop(0, 0));
+ }
+
+ SECTION("AddClearTabstops") {
+ lt.AddTabstop(0, 100);
+ REQUIRE(100 == lt.GetNextTabstop(0, 0));
+ REQUIRE(0 == lt.GetNextTabstop(0, 100));
+ lt.ClearTabstops(0);
+ REQUIRE(0 == lt.GetNextTabstop(0, 0));
+ }
+
+ SECTION("InsertRemoveLine") {
+ lt.AddTabstop(0, 100);
+ lt.AddTabstop(1, 200);
+ lt.InsertLine(1);
+ REQUIRE(100 == lt.GetNextTabstop(0, 0));
+ REQUIRE(0 == lt.GetNextTabstop(1, 0));
+ REQUIRE(200 == lt.GetNextTabstop(2, 0));
+ lt.RemoveLine(1);
+ REQUIRE(100 == lt.GetNextTabstop(0, 0));
+ REQUIRE(200 == lt.GetNextTabstop(1, 0));
+ lt.InsertLines(1, 2);
+ REQUIRE(100 == lt.GetNextTabstop(0, 0));
+ REQUIRE(0 == lt.GetNextTabstop(1, 0));
+ REQUIRE(0 == lt.GetNextTabstop(2, 0));
+ REQUIRE(200 == lt.GetNextTabstop(3, 0));
+ lt.Init();
+ REQUIRE(0 == lt.GetNextTabstop(0, 0));
+ }
+}