diff options
author | Neil <nyamatongwe@gmail.com> | 2020-05-03 19:40:15 +1000 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2020-05-03 19:40:15 +1000 |
commit | 4b450a69452a14fd9af6c426b91d04165fedc94a (patch) | |
tree | 47c4806178b43f175f56433b7ed1ebafb0446f1e | |
parent | b24183b5a90b4ebeb951668d48f0e95a1a2819dd (diff) | |
download | scintilla-mirror-4b450a69452a14fd9af6c426b91d04165fedc94a.tar.gz |
Feature [feature-requests:1347]. Add InsertLines method to PerLine interface and
all implementations. This will allow insertion of lines in batches in a future
change set.
Added tests for PerLine implementations.
-rw-r--r-- | src/CellBuffer.h | 1 | ||||
-rw-r--r-- | src/Document.cxx | 7 | ||||
-rw-r--r-- | src/Document.h | 1 | ||||
-rw-r--r-- | src/PerLine.cxx | 37 | ||||
-rw-r--r-- | src/PerLine.h | 5 | ||||
-rw-r--r-- | test/unit/UnitTester.vcxproj | 1 | ||||
-rw-r--r-- | test/unit/makefile | 3 | ||||
-rw-r--r-- | test/unit/test.mak | 3 | ||||
-rw-r--r-- | test/unit/testPerLine.cxx | 363 |
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)); + } +} |