# HG changeset patch
# User Neil <nyamatongwe@gmail.com>
# Date 1520648054 -39600
#      Sat Mar 10 13:14:14 2018 +1100
# Node ID 184b4d8ed2633fb4e040d25c4d08148d08a0183d
# Parent  e84a1ec0a6b3745f154365ab534b8177946d6d52
Split ContractionState into interface and implementation classes to allow future
choice between 32-bit and 64-bit position implementations.

diff -r e84a1ec0a6b3 -r 184b4d8ed263 src/ContractionState.cxx
--- a/src/ContractionState.cxx	Sat Mar 10 13:11:49 2018 +1100
+++ b/src/ContractionState.cxx	Sat Mar 10 13:14:14 2018 +1100
@@ -26,6 +26,66 @@
 
 using namespace Scintilla;
 
+namespace {
+
+class ContractionState : public IContractionState {
+	// These contain 1 element for every document line.
+	std::unique_ptr<RunStyles<Sci::Line, char>> visible;
+	std::unique_ptr<RunStyles<Sci::Line, char>> expanded;
+	std::unique_ptr<RunStyles<Sci::Line, int>> heights;
+	std::unique_ptr<SparseVector<UniqueString>> foldDisplayTexts;
+	std::unique_ptr<Partitioning<Sci::Line>> displayLines;
+	Sci::Line linesInDocument;
+
+	void EnsureData();
+
+	bool OneToOne() const {
+		// True when each document line is exactly one display line so need for
+		// complex data structures.
+		return visible == nullptr;
+	}
+
+public:
+	ContractionState();
+	// Deleted so ContractionState objects can not be copied.
+	ContractionState(const ContractionState &) = delete;
+	void operator=(const ContractionState &) = delete;
+	virtual ~ContractionState();
+
+	void InsertLine(Sci::Line lineDoc);
+	void DeleteLine(Sci::Line lineDoc);
+
+	void Clear() override;
+
+	Sci::Line LinesInDoc() const override;
+	Sci::Line LinesDisplayed() const override;
+	Sci::Line DisplayFromDoc(Sci::Line lineDoc) const override;
+	Sci::Line DisplayLastFromDoc(Sci::Line lineDoc) const override;
+	Sci::Line DocFromDisplay(Sci::Line lineDisplay) const override;
+
+	void InsertLines(Sci::Line lineDoc, Sci::Line lineCount) override;
+	void DeleteLines(Sci::Line lineDoc, Sci::Line lineCount) override;
+
+	bool GetVisible(Sci::Line lineDoc) const override;
+	bool SetVisible(Sci::Line lineDocStart, Sci::Line lineDocEnd, bool isVisible) override;
+	bool HiddenLines() const override;
+
+	const char *GetFoldDisplayText(Sci::Line lineDoc) const override;
+	bool SetFoldDisplayText(Sci::Line lineDoc, const char *text) override;
+
+	bool GetExpanded(Sci::Line lineDoc) const override;
+	bool SetExpanded(Sci::Line lineDoc, bool isExpanded) override;
+	bool GetFoldDisplayTextShown(Sci::Line lineDoc) const override;
+	Sci::Line ContractedNext(Sci::Line lineDocStart) const override;
+
+	int GetHeight(Sci::Line lineDoc) const override;
+	bool SetHeight(Sci::Line lineDoc, int height) override;
+
+	void ShowAll() override;
+
+	void Check() const;
+};
+
 ContractionState::ContractionState() : linesInDocument(1) {
 }
 
@@ -44,6 +104,39 @@
 	}
 }
 
+void ContractionState::InsertLine(Sci::Line lineDoc) {
+	if (OneToOne()) {
+		linesInDocument++;
+	} else {
+		visible->InsertSpace(lineDoc, 1);
+		visible->SetValueAt(lineDoc, 1);
+		expanded->InsertSpace(lineDoc, 1);
+		expanded->SetValueAt(lineDoc, 1);
+		heights->InsertSpace(lineDoc, 1);
+		heights->SetValueAt(lineDoc, 1);
+		foldDisplayTexts->InsertSpace(lineDoc, 1);
+		foldDisplayTexts->SetValueAt(lineDoc, nullptr);
+		const Sci::Line lineDisplay = DisplayFromDoc(lineDoc);
+		displayLines->InsertPartition(lineDoc, lineDisplay);
+		displayLines->InsertText(lineDoc, 1);
+	}
+}
+
+void ContractionState::DeleteLine(Sci::Line lineDoc) {
+	if (OneToOne()) {
+		linesInDocument--;
+	} else {
+		if (GetVisible(lineDoc)) {
+			displayLines->InsertText(lineDoc, -heights->ValueAt(lineDoc));
+		}
+		displayLines->RemovePartition(lineDoc);
+		visible->DeleteRange(lineDoc, 1);
+		expanded->DeleteRange(lineDoc, 1);
+		heights->DeleteRange(lineDoc, 1);
+		foldDisplayTexts->DeletePosition(lineDoc);
+	}
+}
+
 void ContractionState::Clear() {
 	visible.reset();
 	expanded.reset();
@@ -99,24 +192,6 @@
 	}
 }
 
-void ContractionState::InsertLine(Sci::Line lineDoc) {
-	if (OneToOne()) {
-		linesInDocument++;
-	} else {
-		visible->InsertSpace(lineDoc, 1);
-		visible->SetValueAt(lineDoc, 1);
-		expanded->InsertSpace(lineDoc, 1);
-		expanded->SetValueAt(lineDoc, 1);
-		heights->InsertSpace(lineDoc, 1);
-		heights->SetValueAt(lineDoc, 1);
-		foldDisplayTexts->InsertSpace(lineDoc, 1);
-		foldDisplayTexts->SetValueAt(lineDoc, nullptr);
-		const Sci::Line lineDisplay = DisplayFromDoc(lineDoc);
-		displayLines->InsertPartition(lineDoc, lineDisplay);
-		displayLines->InsertText(lineDoc, 1);
-	}
-}
-
 void ContractionState::InsertLines(Sci::Line lineDoc, Sci::Line lineCount) {
 	for (int l = 0; l < lineCount; l++) {
 		InsertLine(lineDoc + l);
@@ -124,21 +199,6 @@
 	Check();
 }
 
-void ContractionState::DeleteLine(Sci::Line lineDoc) {
-	if (OneToOne()) {
-		linesInDocument--;
-	} else {
-		if (GetVisible(lineDoc)) {
-			displayLines->InsertText(lineDoc, -heights->ValueAt(lineDoc));
-		}
-		displayLines->RemovePartition(lineDoc);
-		visible->DeleteRange(lineDoc, 1);
-		expanded->DeleteRange(lineDoc, 1);
-		heights->DeleteRange(lineDoc, 1);
-		foldDisplayTexts->DeletePosition(lineDoc);
-	}
-}
-
 void ContractionState::DeleteLines(Sci::Line lineDoc, Sci::Line lineCount) {
 	for (Sci::Line l = 0; l < lineCount; l++) {
 		DeleteLine(lineDoc);
@@ -310,3 +370,13 @@
 	}
 #endif
 }
+
+}
+
+namespace Scintilla {
+
+std::unique_ptr<IContractionState> CreateContractionState(bool /*largeDocument*/) {
+	return std::make_unique<ContractionState>();
+}
+
+}
diff -r e84a1ec0a6b3 -r 184b4d8ed263 src/ContractionState.h
--- a/src/ContractionState.h	Sat Mar 10 13:11:49 2018 +1100
+++ b/src/ContractionState.h	Sat Mar 10 13:14:14 2018 +1100
@@ -10,66 +10,42 @@
 
 namespace Scintilla {
 
-template<class T>
-class SparseVector;
+/**
+*/
+class IContractionState {
+public:
+	virtual ~IContractionState() {};
 
-/**
- */
-class ContractionState {
-	// These contain 1 element for every document line.
-	std::unique_ptr<RunStyles<Sci::Line, char>> visible;
-	std::unique_ptr<RunStyles<Sci::Line, char>> expanded;
-	std::unique_ptr<RunStyles<Sci::Line, int>> heights;
-	std::unique_ptr<SparseVector<UniqueString>> foldDisplayTexts;
-	std::unique_ptr<Partitioning<Sci::Line>> displayLines;
-	Sci::Line linesInDocument;
+	virtual void Clear()=0;
 
-	void EnsureData();
+	virtual Sci::Line LinesInDoc() const=0;
+	virtual Sci::Line LinesDisplayed() const=0;
+	virtual Sci::Line DisplayFromDoc(Sci::Line lineDoc) const=0;
+	virtual Sci::Line DisplayLastFromDoc(Sci::Line lineDoc) const=0;
+	virtual Sci::Line DocFromDisplay(Sci::Line lineDisplay) const=0;
 
-	bool OneToOne() const {
-		// True when each document line is exactly one display line so need for
-		// complex data structures.
-		return visible == nullptr;
-	}
-
-public:
-	ContractionState();
-	// Deleted so ContractionState objects can not be copied.
-	ContractionState(const ContractionState &) = delete;
-	void operator=(const ContractionState &) = delete;
-	virtual ~ContractionState();
+	virtual void InsertLines(Sci::Line lineDoc, Sci::Line lineCount)=0;
+	virtual void DeleteLines(Sci::Line lineDoc, Sci::Line lineCount)=0;
 
-	void Clear();
+	virtual bool GetVisible(Sci::Line lineDoc) const=0;
+	virtual bool SetVisible(Sci::Line lineDocStart, Sci::Line lineDocEnd, bool isVisible)=0;
+	virtual bool HiddenLines() const=0;
 
-	Sci::Line LinesInDoc() const;
-	Sci::Line LinesDisplayed() const;
-	Sci::Line DisplayFromDoc(Sci::Line lineDoc) const;
-	Sci::Line DisplayLastFromDoc(Sci::Line lineDoc) const;
-	Sci::Line DocFromDisplay(Sci::Line lineDisplay) const;
-
-	void InsertLine(Sci::Line lineDoc);
-	void InsertLines(Sci::Line lineDoc, Sci::Line lineCount);
-	void DeleteLine(Sci::Line lineDoc);
-	void DeleteLines(Sci::Line lineDoc, Sci::Line lineCount);
+	virtual const char *GetFoldDisplayText(Sci::Line lineDoc) const=0;
+	virtual bool SetFoldDisplayText(Sci::Line lineDoc, const char *text)=0;
 
-	bool GetVisible(Sci::Line lineDoc) const;
-	bool SetVisible(Sci::Line lineDocStart, Sci::Line lineDocEnd, bool isVisible);
-	bool HiddenLines() const;
-
-	const char *GetFoldDisplayText(Sci::Line lineDoc) const;
-	bool SetFoldDisplayText(Sci::Line lineDoc, const char *text);
+	virtual bool GetExpanded(Sci::Line lineDoc) const=0;
+	virtual bool SetExpanded(Sci::Line lineDoc, bool isExpanded)=0;
+	virtual bool GetFoldDisplayTextShown(Sci::Line lineDoc) const=0;
+	virtual Sci::Line ContractedNext(Sci::Line lineDocStart) const=0;
 
-	bool GetExpanded(Sci::Line lineDoc) const;
-	bool SetExpanded(Sci::Line lineDoc, bool isExpanded);
-	bool GetFoldDisplayTextShown(Sci::Line lineDoc) const;
-	Sci::Line ContractedNext(Sci::Line lineDocStart) const;
+	virtual int GetHeight(Sci::Line lineDoc) const=0;
+	virtual bool SetHeight(Sci::Line lineDoc, int height)=0;
 
-	int GetHeight(Sci::Line lineDoc) const;
-	bool SetHeight(Sci::Line lineDoc, int height);
+	virtual void ShowAll()=0;
+};
 
-	void ShowAll();
-	void Check() const;
-};
+std::unique_ptr<IContractionState> CreateContractionState(bool largeDocument);
 
 }
 
diff -r e84a1ec0a6b3 -r 184b4d8ed263 src/EditModel.cxx
--- a/src/EditModel.cxx	Sat Mar 10 13:11:49 2018 +1100
+++ b/src/EditModel.cxx	Sat Mar 10 13:14:14 2018 +1100
@@ -71,6 +71,7 @@
 	wrapWidth = LineLayout::wrapWidthInfinite;
 	pdoc = new Document(SC_DOCUMENTOPTION_DEFAULT);
 	pdoc->AddRef();
+	pcs = CreateContractionState(pdoc->IsLarge());
 }
 
 EditModel::~EditModel() {
diff -r e84a1ec0a6b3 -r 184b4d8ed263 src/EditModel.h
--- a/src/EditModel.h	Sat Mar 10 13:11:49 2018 +1100
+++ b/src/EditModel.h	Sat Mar 10 13:14:14 2018 +1100
@@ -42,7 +42,7 @@
 
 	int foldFlags;
 	int foldDisplayTextStyle;
-	ContractionState cs;
+	std::unique_ptr<IContractionState> pcs;
 	// Hotspot support
 	Range hotspot;
 	Sci::Position hoverIndicatorPos;
diff -r e84a1ec0a6b3 -r 184b4d8ed263 src/EditView.cxx
--- a/src/EditView.cxx	Sat Mar 10 13:11:49 2018 +1100
+++ b/src/EditView.cxx	Sat Mar 10 13:14:14 2018 +1100
@@ -602,7 +602,7 @@
 		lineDoc--;
 		posLineStart = static_cast<Sci::Position>(model.pdoc->LineStart(lineDoc));
 	}
-	const Sci::Line lineVisible = model.cs.DisplayFromDoc(lineDoc);
+	const Sci::Line lineVisible = model.pcs->DisplayFromDoc(lineDoc);
 	AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
 	if (surface && ll) {
 		LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
@@ -620,12 +620,12 @@
 	if (lineVisible < 0) {
 		return rangeSubLine;
 	}
-	const Sci::Line lineDoc = model.cs.DocFromDisplay(lineVisible);
+	const Sci::Line lineDoc = model.pcs->DocFromDisplay(lineVisible);
 	const Sci::Position positionLineStart = static_cast<Sci::Position>(model.pdoc->LineStart(lineDoc));
 	AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
 	if (surface && ll) {
 		LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
-		const Sci::Line lineStartSet = model.cs.DisplayFromDoc(lineDoc);
+		const Sci::Line lineStartSet = model.pcs->DisplayFromDoc(lineDoc);
 		const int subLine = static_cast<int>(lineVisible - lineStartSet);
 		if (subLine < ll->lines) {
 			rangeSubLine = ll->SubLineRange(subLine);
@@ -645,7 +645,7 @@
 	Sci::Line visibleLine = static_cast<int>(floor(pt.y / vs.lineHeight));
 	if (!canReturnInvalid && (visibleLine < 0))
 		visibleLine = 0;
-	const Sci::Line lineDoc = model.cs.DocFromDisplay(visibleLine);
+	const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine);
 	if (canReturnInvalid && (lineDoc < 0))
 		return SelectionPosition(INVALID_POSITION);
 	if (lineDoc >= model.pdoc->LinesTotal())
@@ -655,7 +655,7 @@
 	AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
 	if (surface && ll) {
 		LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
-		const Sci::Line lineStartSet = model.cs.DisplayFromDoc(lineDoc);
+		const Sci::Line lineStartSet = model.pcs->DisplayFromDoc(lineDoc);
 		const int subLine = static_cast<int>(visibleLine - lineStartSet);
 		if (subLine < ll->lines) {
 			const Range rangeSubLine = ll->SubLineRange(subLine);
@@ -712,7 +712,7 @@
 
 Sci::Line EditView::DisplayFromPosition(Surface *surface, const EditModel &model, Sci::Position pos, const ViewStyle &vs) {
 	const Sci::Line lineDoc = static_cast<Sci::Line>(model.pdoc->LineFromPosition(pos));
-	Sci::Line lineDisplay = model.cs.DisplayFromDoc(lineDoc);
+	Sci::Line lineDisplay = model.pcs->DisplayFromDoc(lineDoc);
 	AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc, model));
 	if (surface && ll) {
 		LayoutLine(model, lineDoc, surface, vs, ll, model.wrapWidth);
@@ -978,7 +978,7 @@
 		rcSegment.left = rcLine.left;
 	rcSegment.right = rcLine.right;
 
-	const bool fillRemainder = !lastSubLine || model.foldDisplayTextStyle == SC_FOLDDISPLAYTEXT_HIDDEN || !model.cs.GetFoldDisplayTextShown(line);
+	const bool fillRemainder = !lastSubLine || model.foldDisplayTextStyle == SC_FOLDDISPLAYTEXT_HIDDEN || !model.pcs->GetFoldDisplayTextShown(line);
 	if (fillRemainder) {
 		// Fill the remainder of the line
 		FillLineRemainder(surface, model, vsDraw, ll, line, rcSegment, subLine);
@@ -1098,11 +1098,11 @@
 	if (!lastSubLine)
 		return;
 
-	if ((model.foldDisplayTextStyle == SC_FOLDDISPLAYTEXT_HIDDEN) || !model.cs.GetFoldDisplayTextShown(line))
+	if ((model.foldDisplayTextStyle == SC_FOLDDISPLAYTEXT_HIDDEN) || !model.pcs->GetFoldDisplayTextShown(line))
 		return;
 
 	PRectangle rcSegment = rcLine;
-	const char *foldDisplayText = model.cs.GetFoldDisplayText(line);
+	const char *foldDisplayText = model.pcs->GetFoldDisplayText(line);
 	const int lengthFoldDisplayText = static_cast<int>(strlen(foldDisplayText));
 	FontAlias fontText = vsDraw.styles[STYLE_FOLDDISPLAYTEXT].font;
 	const int widthFoldDisplayText = static_cast<int>(surface->WidthText(fontText, foldDisplayText, lengthFoldDisplayText));
@@ -1943,7 +1943,7 @@
 }
 
 static void DrawFoldLines(Surface *surface, const EditModel &model, const ViewStyle &vsDraw, Sci::Line line, PRectangle rcLine) {
-	const bool expanded = model.cs.GetExpanded(line);
+	const bool expanded = model.pcs->GetExpanded(line);
 	const int level = model.pdoc->GetLevel(line);
 	const int levelNext = model.pdoc->GetLevel(line + 1);
 	if ((level & SC_FOLDLEVELHEADERFLAG) &&
@@ -2035,12 +2035,12 @@
 				ypos += screenLinePaintFirst * vsDraw.lineHeight;
 			int yposScreen = screenLinePaintFirst * vsDraw.lineHeight;
 			Sci::Line visibleLine = model.TopLineOfMain() + screenLinePaintFirst;
-			while (visibleLine < model.cs.LinesDisplayed() && yposScreen < rcArea.bottom) {
+			while (visibleLine < model.pcs->LinesDisplayed() && yposScreen < rcArea.bottom) {
 
-				const Sci::Line lineDoc = model.cs.DocFromDisplay(visibleLine);
+				const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine);
 				// Only visible lines should be handled by the code within the loop
-				PLATFORM_ASSERT(model.cs.GetVisible(lineDoc));
-				const Sci::Line lineStartSet = model.cs.DisplayFromDoc(lineDoc);
+				PLATFORM_ASSERT(model.pcs->GetVisible(lineDoc));
+				const Sci::Line lineStartSet = model.pcs->DisplayFromDoc(lineDoc);
 				const int subLine = static_cast<int>(visibleLine - lineStartSet);
 
 				// Copy this line and its styles from the document into local arrays
@@ -2120,7 +2120,7 @@
 		PRectangle rcBeyondEOF = (vsDraw.marginInside) ? rcClient : rcArea;
 		rcBeyondEOF.left = static_cast<XYPOSITION>(vsDraw.textStart);
 		rcBeyondEOF.right = rcBeyondEOF.right - ((vsDraw.marginInside) ? vsDraw.rightMarginWidth : 0);
-		rcBeyondEOF.top = static_cast<XYPOSITION>((model.cs.LinesDisplayed() - model.TopLineOfMain()) * vsDraw.lineHeight);
+		rcBeyondEOF.top = static_cast<XYPOSITION>((model.pcs->LinesDisplayed() - model.TopLineOfMain()) * vsDraw.lineHeight);
 		if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
 			surfaceWindow->FillRectangle(rcBeyondEOF, vsDraw.styles[STYLE_DEFAULT].back);
 			if (vsDraw.edgeState == EDGE_LINE) {
diff -r e84a1ec0a6b3 -r 184b4d8ed263 src/Editor.cxx
--- a/src/Editor.cxx	Sat Mar 10 13:11:49 2018 +1100
+++ b/src/Editor.cxx	Sat Mar 10 13:14:14 2018 +1100
@@ -339,7 +339,7 @@
 Sci::Line Editor::MaxScrollPos() const {
 	//Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
 	//LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
-	Sci::Line retVal = cs.LinesDisplayed();
+	Sci::Line retVal = pcs->LinesDisplayed();
 	if (endAtLastLine) {
 		retVal -= LinesOnScreen();
 	} else {
@@ -428,7 +428,7 @@
 }
 
 Sci::Line Editor::LineFromLocation(Point pt) const {
-	return cs.DocFromDisplay(static_cast<int>(pt.y) / vs.lineHeight + topLine);
+	return pcs->DocFromDisplay(static_cast<int>(pt.y) / vs.lineHeight + topLine);
 }
 
 void Editor::SetTopLine(Sci::Line topLineNew) {
@@ -436,7 +436,7 @@
 		topLine = topLineNew;
 		ContainerNeedsUpdate(SC_UPDATE_V_SCROLL);
 	}
-	posTopLine = static_cast<Sci::Position>(pdoc->LineStart(cs.DocFromDisplay(topLine)));
+	posTopLine = static_cast<Sci::Position>(pdoc->LineStart(pcs->DocFromDisplay(topLine)));
 }
 
 /**
@@ -528,9 +528,9 @@
 }
 
 PRectangle Editor::RectangleFromRange(Range r, int overlap) {
-	const Sci::Line minLine = cs.DisplayFromDoc(
+	const Sci::Line minLine = pcs->DisplayFromDoc(
 		static_cast<Sci::Line>(pdoc->LineFromPosition(r.First())));
-	const Sci::Line maxLine = cs.DisplayLastFromDoc(
+	const Sci::Line maxLine = pcs->DisplayLastFromDoc(
 		static_cast<Sci::Line>(pdoc->LineFromPosition(r.Last())));
 	const PRectangle rcClientDrawing = GetClientDrawingRectangle();
 	PRectangle rc;
@@ -901,19 +901,19 @@
 	pos = ClampPositionIntoDocument(pos);
 	pos = MovePositionOutsideChar(pos, moveDir);
 	const Sci::Line lineDoc = static_cast<Sci::Line>(pdoc->LineFromPosition(pos.Position()));
-	if (cs.GetVisible(lineDoc)) {
+	if (pcs->GetVisible(lineDoc)) {
 		return pos;
 	} else {
-		Sci::Line lineDisplay = cs.DisplayFromDoc(lineDoc);
+		Sci::Line lineDisplay = pcs->DisplayFromDoc(lineDoc);
 		if (moveDir > 0) {
 			// lineDisplay is already line before fold as lines in fold use display line of line after fold
-			lineDisplay = std::clamp(lineDisplay, static_cast<Sci::Line>(0), cs.LinesDisplayed());
+			lineDisplay = std::clamp(lineDisplay, static_cast<Sci::Line>(0), pcs->LinesDisplayed());
 			return SelectionPosition(static_cast<Sci::Position>(
-				pdoc->LineStart(cs.DocFromDisplay(lineDisplay))));
+				pdoc->LineStart(pcs->DocFromDisplay(lineDisplay))));
 		} else {
-			lineDisplay = std::clamp(lineDisplay - 1, static_cast<Sci::Line>(0), cs.LinesDisplayed());
+			lineDisplay = std::clamp(lineDisplay - 1, static_cast<Sci::Line>(0), pcs->LinesDisplayed());
 			return SelectionPosition(static_cast<Sci::Position>(
-				pdoc->LineEnd(cs.DocFromDisplay(lineDisplay))));
+				pdoc->LineEnd(pcs->DocFromDisplay(lineDisplay))));
 		}
 	}
 }
@@ -985,7 +985,7 @@
 void Editor::VerticalCentreCaret() {
 	const Sci::Line lineDoc = static_cast<Sci::Line>(
 		pdoc->LineFromPosition(sel.IsRectangular() ? sel.Rectangular().caret.Position() : sel.MainCaret()));
-	const Sci::Line lineDisplay = cs.DisplayFromDoc(lineDoc);
+	const Sci::Line lineDisplay = pcs->DisplayFromDoc(lineDoc);
 	const Sci::Line newTop = lineDisplay - (LinesOnScreen() / 2);
 	if (topLine != newTop) {
 		SetTopLine(newTop > 0 ? newTop : 0);
@@ -1482,7 +1482,7 @@
 		view.LayoutLine(*this, lineToWrap, surface, vs, ll, wrapWidth);
 		linesWrapped = ll->lines;
 	}
-	return cs.SetHeight(lineToWrap, linesWrapped +
+	return pcs->SetHeight(lineToWrap, linesWrapped +
 		(vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0));
 }
 
@@ -1498,7 +1498,7 @@
 		if (wrapWidth != LineLayout::wrapWidthInfinite) {
 			wrapWidth = LineLayout::wrapWidthInfinite;
 			for (Sci::Line lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) {
-				cs.SetHeight(lineDoc, 1 +
+				pcs->SetHeight(lineDoc, 1 +
 					(vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0));
 			}
 			wrapOccurred = true;
@@ -1514,8 +1514,8 @@
 		// Decide where to start wrapping
 		Sci::Line lineToWrap = wrapPending.start;
 		Sci::Line lineToWrapEnd = std::min(wrapPending.end, pdoc->LinesTotal());
-		const Sci::Line lineDocTop = cs.DocFromDisplay(topLine);
-		const int subLineTop = static_cast<int>(topLine - cs.DisplayFromDoc(lineDocTop));
+		const Sci::Line lineDocTop = pcs->DocFromDisplay(topLine);
+		const int subLineTop = static_cast<int>(topLine - pcs->DisplayFromDoc(lineDocTop));
 		if (ws == WrapScope::wsVisible) {
 			lineToWrap = std::clamp(lineDocTop-5, wrapPending.start, pdoc->LinesTotal());
 			// Priority wrap to just after visible area.
@@ -1523,8 +1523,8 @@
 			// as taking only one display line.
 			lineToWrapEnd = lineDocTop;
 			Sci::Line lines = LinesOnScreen() + 1;
-			while ((lineToWrapEnd < cs.LinesInDoc()) && (lines>0)) {
-				if (cs.GetVisible(lineToWrapEnd))
+			while ((lineToWrapEnd < pcs->LinesInDoc()) && (lines>0)) {
+				if (pcs->GetVisible(lineToWrapEnd))
 					lines--;
 				lineToWrapEnd++;
 			}
@@ -1561,7 +1561,7 @@
 					lineToWrap++;
 				}
 
-				goodTopLine = cs.DisplayFromDoc(lineDocTop) + std::min(subLineTop, cs.GetHeight(lineDocTop)-1);
+				goodTopLine = pcs->DisplayFromDoc(lineDocTop) + std::min(subLineTop, pcs->GetHeight(lineDocTop)-1);
 			}
 		}
 
@@ -1765,7 +1765,7 @@
 			if (paintAbandonedByStyling) {
 				// Styling has spilled over a line end, such as occurs by starting a multiline
 				// comment. The width of subsequent text may have changed, so rewrap.
-				NeedWrapping(cs.DocFromDisplay(topLine));
+				NeedWrapping(pcs->DocFromDisplay(topLine));
 			}
 		}
 		return;
@@ -2095,7 +2095,7 @@
 			pdoc->DeleteChars(0, static_cast<Sci::Position>(pdoc->Length()));
 		}
 		if (!pdoc->IsReadOnly()) {
-			cs.Clear();
+			pcs->Clear();
 			pdoc->AnnotationClearAll();
 			pdoc->MarginClearAll();
 		}
@@ -2113,7 +2113,7 @@
 	pdoc->decorations.DeleteLexerDecorations();
 	pdoc->StartStyling(0);
 	pdoc->SetStyleFor(pdoc->Length(), 0);
-	cs.ShowAll();
+	pcs->ShowAll();
 	SetAnnotationHeights(0, pdoc->LinesTotal());
 	pdoc->ClearLevels();
 }
@@ -2583,7 +2583,7 @@
 			braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length);
 			braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length);
 		}
-		if ((mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) && cs.HiddenLines()) {
+		if ((mh.modificationType & (SC_MOD_BEFOREINSERT | SC_MOD_BEFOREDELETE)) && pcs->HiddenLines()) {
 			// Some lines are hidden so may need shown.
 			const Sci::Line lineOfPos = static_cast<Sci::Line>(pdoc->LineFromPosition(mh.position));
 			Sci::Position endNeedShown = mh.position;
@@ -2611,16 +2611,16 @@
 			if (mh.position > pdoc->LineStart(lineOfPos))
 				lineOfPos++;	// Affecting subsequent lines
 			if (mh.linesAdded > 0) {
-				cs.InsertLines(lineOfPos, mh.linesAdded);
+				pcs->InsertLines(lineOfPos, mh.linesAdded);
 			} else {
-				cs.DeleteLines(lineOfPos, -mh.linesAdded);
+				pcs->DeleteLines(lineOfPos, -mh.linesAdded);
 			}
 			view.LinesAddedOrRemoved(lineOfPos, mh.linesAdded);
 		}
 		if (mh.modificationType & SC_MOD_CHANGEANNOTATION) {
 			const Sci::Line lineDoc = static_cast<Sci::Line>(pdoc->LineFromPosition(mh.position));
 			if (vs.annotationVisible) {
-				if (cs.SetHeight(lineDoc, static_cast<int>(cs.GetHeight(lineDoc) + mh.annotationLinesAdded))) {
+				if (pcs->SetHeight(lineDoc, static_cast<int>(pcs->GetHeight(lineDoc) + mh.annotationLinesAdded))) {
 					SetScrollBars();
 				}
 				Redraw();
@@ -3088,11 +3088,11 @@
 		const int subLine = static_cast<int>(pt.y - ptStartLine.y) / vs.lineHeight;
 
 		if (direction < 0 && subLine == 0) {
-			const Sci::Line lineDisplay = cs.DisplayFromDoc(lineDoc);
+			const Sci::Line lineDisplay = pcs->DisplayFromDoc(lineDoc);
 			if (lineDisplay > 0) {
-				skipLines = pdoc->AnnotationLines(cs.DocFromDisplay(lineDisplay - 1));
+				skipLines = pdoc->AnnotationLines(pcs->DocFromDisplay(lineDisplay - 1));
 			}
-		} else if (direction > 0 && subLine >= (cs.GetHeight(lineDoc) - 1 - pdoc->AnnotationLines(lineDoc))) {
+		} else if (direction > 0 && subLine >= (pcs->GetHeight(lineDoc) - 1 - pdoc->AnnotationLines(lineDoc))) {
 			skipLines = pdoc->AnnotationLines(lineDoc);
 		}
 	}
@@ -3181,14 +3181,14 @@
 		MovePositionTo(SelectionPosition(direction > 0 ? pdoc->ParaDown(sel.MainCaret()) : pdoc->ParaUp(sel.MainCaret())), selt);
 		lineDoc = static_cast<Sci::Line>(pdoc->LineFromPosition(sel.MainCaret()));
 		if (direction > 0) {
-			if (sel.MainCaret() >= pdoc->Length() && !cs.GetVisible(lineDoc)) {
+			if (sel.MainCaret() >= pdoc->Length() && !pcs->GetVisible(lineDoc)) {
 				if (selt == Selection::noSel) {
 					MovePositionTo(SelectionPosition(pdoc->LineEndPosition(savedPos)));
 				}
 				break;
 			}
 		}
-	} while (!cs.GetVisible(lineDoc));
+	} while (!pcs->GetVisible(lineDoc));
 }
 
 Range Editor::RangeDisplayLine(Sci::Line lineVisible) {
@@ -5022,8 +5022,8 @@
 	// This often means that the line after a modification is restyled which helps
 	// detect multiline comment additions and heals single line comments
 	const Sci::Line lineAfter = TopLineOfMain() + static_cast<Sci::Line>(rcArea.bottom - 1) / vs.lineHeight + 1;
-	if (lineAfter < cs.LinesDisplayed())
-		return static_cast<Sci::Position>(pdoc->LineStart(cs.DocFromDisplay(lineAfter) + 1));
+	if (lineAfter < pcs->LinesDisplayed())
+		return static_cast<Sci::Position>(pdoc->LineStart(pcs->DocFromDisplay(lineAfter) + 1));
 	else
 		return static_cast<Sci::Position>(pdoc->Length());
 }
@@ -5193,7 +5193,7 @@
 					linesWrapped = ll->lines;
 				}
 			}
-			if (cs.SetHeight(line, pdoc->AnnotationLines(line) + linesWrapped))
+			if (pcs->SetHeight(line, pdoc->AnnotationLines(line) + linesWrapped))
 				changedHeight = true;
 		}
 		if (changedHeight) {
@@ -5212,6 +5212,7 @@
 		pdoc = document;
 	}
 	pdoc->AddRef();
+	pcs = CreateContractionState(pdoc->IsLarge());
 
 	// Ensure all positions within document
 	sel.Clear();
@@ -5226,8 +5227,8 @@
 	SetRepresentations();
 
 	// Reset the contraction state to fully shown.
-	cs.Clear();
-	cs.InsertLines(0, pdoc->LinesTotal() - 1);
+	pcs->Clear();
+	pcs->InsertLines(0, pdoc->LinesTotal() - 1);
 	SetAnnotationHeights(0, pdoc->LinesTotal());
 	view.llc.Deallocate();
 	NeedWrapping();
@@ -5251,7 +5252,7 @@
 			for (Sci::Line line=0; line<pdoc->LinesTotal(); line++) {
 				const int annotationLines = pdoc->AnnotationLines(line);
 				if (annotationLines > 0) {
-					cs.SetHeight(line, cs.GetHeight(line) + annotationLines * dir);
+					pcs->SetHeight(line, pcs->GetHeight(line) + annotationLines * dir);
 				}
 			}
 			SetScrollBars();
@@ -5267,10 +5268,10 @@
 	const Sci::Line lineMaxSubord = pdoc->GetLastChild(line);
 	line++;
 	while (line <= lineMaxSubord) {
-		cs.SetVisible(line, line, true);
+		pcs->SetVisible(line, line, true);
 		const int level = pdoc->GetLevel(line);
 		if (level & SC_FOLDLEVELHEADERFLAG) {
-			if (cs.GetExpanded(line)) {
+			if (pcs->GetExpanded(line)) {
 				line = ExpandLine(line);
 			} else {
 				line = pdoc->GetLastChild(line);
@@ -5282,7 +5283,7 @@
 }
 
 void Editor::SetFoldExpanded(Sci::Line lineDoc, bool expanded) {
-	if (cs.SetExpanded(lineDoc, expanded)) {
+	if (pcs->SetExpanded(lineDoc, expanded)) {
 		RedrawSelMargin();
 	}
 }
@@ -5295,14 +5296,14 @@
 				if (line < 0)
 					return;
 			}
-			action = (cs.GetExpanded(line)) ? SC_FOLDACTION_CONTRACT : SC_FOLDACTION_EXPAND;
+			action = (pcs->GetExpanded(line)) ? SC_FOLDACTION_CONTRACT : SC_FOLDACTION_EXPAND;
 		}
 
 		if (action == SC_FOLDACTION_CONTRACT) {
 			const Sci::Line lineMaxSubord = pdoc->GetLastChild(line);
 			if (lineMaxSubord > line) {
-				cs.SetExpanded(line, false);
-				cs.SetVisible(line + 1, lineMaxSubord, false);
+				pcs->SetExpanded(line, false);
+				pcs->SetVisible(line + 1, lineMaxSubord, false);
 
 				const Sci::Line lineCurrent = static_cast<Sci::Line>(
 					pdoc->LineFromPosition(sel.MainCaret()));
@@ -5313,11 +5314,11 @@
 			}
 
 		} else {
-			if (!(cs.GetVisible(line))) {
+			if (!(pcs->GetVisible(line))) {
 				EnsureLineVisible(line, false);
 				GoToLine(line);
 			}
-			cs.SetExpanded(line, true);
+			pcs->SetExpanded(line, true);
 			ExpandLine(line);
 		}
 
@@ -5329,18 +5330,18 @@
 void Editor::FoldExpand(Sci::Line line, int action, int level) {
 	bool expanding = action == SC_FOLDACTION_EXPAND;
 	if (action == SC_FOLDACTION_TOGGLE) {
-		expanding = !cs.GetExpanded(line);
+		expanding = !pcs->GetExpanded(line);
 	}
 	// Ensure child lines lexed and fold information extracted before
 	// flipping the state.
 	pdoc->GetLastChild(line, LevelNumber(level));
 	SetFoldExpanded(line, expanding);
-	if (expanding && (cs.HiddenLines() == 0))
+	if (expanding && (pcs->HiddenLines() == 0))
 		// Nothing to do
 		return;
 	const Sci::Line lineMaxSubord = pdoc->GetLastChild(line, LevelNumber(level));
 	line++;
-	cs.SetVisible(line, lineMaxSubord, expanding);
+	pcs->SetVisible(line, lineMaxSubord, expanding);
 	while (line <= lineMaxSubord) {
 		const int levelLine = pdoc->GetLevel(line);
 		if (levelLine & SC_FOLDLEVELHEADERFLAG) {
@@ -5354,9 +5355,9 @@
 
 Sci::Line Editor::ContractedFoldNext(Sci::Line lineStart) const {
 	for (Sci::Line line = lineStart; line<pdoc->LinesTotal();) {
-		if (!cs.GetExpanded(line) && (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG))
+		if (!pcs->GetExpanded(line) && (pdoc->GetLevel(line) & SC_FOLDLEVELHEADERFLAG))
 			return line;
-		line = cs.ContractedNext(line+1);
+		line = pcs->ContractedNext(line+1);
 		if (line < 0)
 			return -1;
 	}
@@ -5377,7 +5378,7 @@
 		}
 	}
 
-	if (!cs.GetVisible(lineDoc)) {
+	if (!pcs->GetVisible(lineDoc)) {
 		// Back up to find a non-blank line
 		Sci::Line lookLine = lineDoc;
 		int lookLineLevel = pdoc->GetLevel(lookLine);
@@ -5392,8 +5393,8 @@
 		if (lineParent >= 0) {
 			if (lineDoc != lineParent)
 				EnsureLineVisible(lineParent, enforcePolicy);
-			if (!cs.GetExpanded(lineParent)) {
-				cs.SetExpanded(lineParent, true);
+			if (!pcs->GetExpanded(lineParent)) {
+				pcs->SetExpanded(lineParent, true);
 				ExpandLine(lineParent);
 			}
 		}
@@ -5401,7 +5402,7 @@
 		Redraw();
 	}
 	if (enforcePolicy) {
-		const Sci::Line lineDisplay = cs.DisplayFromDoc(lineDoc);
+		const Sci::Line lineDisplay = pcs->DisplayFromDoc(lineDoc);
 		if (visiblePolicy & VISIBLE_SLOP) {
 			if ((topLine > lineDisplay) || ((visiblePolicy & VISIBLE_STRICT) && (topLine + visibleSlop > lineDisplay))) {
 				SetTopLine(std::clamp(lineDisplay - visibleSlop, static_cast<Sci::Line>(0), MaxScrollPos()));
@@ -5431,13 +5432,13 @@
 		// Discover current state
 		for (int lineSeek = 0; lineSeek < maxLine; lineSeek++) {
 			if (pdoc->GetLevel(lineSeek) & SC_FOLDLEVELHEADERFLAG) {
-				expanding = !cs.GetExpanded(lineSeek);
+				expanding = !pcs->GetExpanded(lineSeek);
 				break;
 			}
 		}
 	}
 	if (expanding) {
-		cs.SetVisible(0, maxLine-1, true);
+		pcs->SetVisible(0, maxLine-1, true);
 		for (int line = 0; line < maxLine; line++) {
 			const int levelLine = pdoc->GetLevel(line);
 			if (levelLine & SC_FOLDLEVELHEADERFLAG) {
@@ -5452,7 +5453,7 @@
 				SetFoldExpanded(line, false);
 				const Sci::Line lineMaxSubord = pdoc->GetLastChild(line, -1);
 				if (lineMaxSubord > line) {
-					cs.SetVisible(line + 1, lineMaxSubord, false);
+					pcs->SetVisible(line + 1, lineMaxSubord, false);
 				}
 			}
 		}
@@ -5465,7 +5466,7 @@
 	if (levelNow & SC_FOLDLEVELHEADERFLAG) {
 		if (!(levelPrev & SC_FOLDLEVELHEADERFLAG)) {
 			// Adding a fold point.
-			if (cs.SetExpanded(line, true)) {
+			if (pcs->SetExpanded(line, true)) {
 				RedrawSelMargin();
 			}
 			FoldExpand(line, SC_FOLDACTION_EXPAND, levelPrev);
@@ -5475,13 +5476,13 @@
 		const int prevLineLevel = pdoc->GetLevel(prevLine);
 
 		// Combining two blocks where the first block is collapsed (e.g. by deleting the line(s) which separate(s) the two blocks)
-		if ((LevelNumber(prevLineLevel) == LevelNumber(levelNow)) && !cs.GetVisible(prevLine))
+		if ((LevelNumber(prevLineLevel) == LevelNumber(levelNow)) && !pcs->GetVisible(prevLine))
 			FoldLine(pdoc->GetFoldParent(prevLine), SC_FOLDACTION_EXPAND);
 
-		if (!cs.GetExpanded(line)) {
+		if (!pcs->GetExpanded(line)) {
 			// Removing the fold from one that has been contracted so should expand
 			// otherwise lines are left invisible with no way to make them visible
-			if (cs.SetExpanded(line, true)) {
+			if (pcs->SetExpanded(line, true)) {
 				RedrawSelMargin();
 			}
 			// Combining two blocks where the second one is collapsed (e.g. by adding characters in the line which separates the two blocks)
@@ -5490,11 +5491,11 @@
 	}
 	if (!(levelNow & SC_FOLDLEVELWHITEFLAG) &&
 	        (LevelNumber(levelPrev) > LevelNumber(levelNow))) {
-		if (cs.HiddenLines()) {
+		if (pcs->HiddenLines()) {
 			// See if should still be hidden
 			const Sci::Line parentLine = pdoc->GetFoldParent(line);
-			if ((parentLine < 0) || (cs.GetExpanded(parentLine) && cs.GetVisible(parentLine))) {
-				cs.SetVisible(line, line, true);
+			if ((parentLine < 0) || (pcs->GetExpanded(parentLine) && pcs->GetVisible(parentLine))) {
+				pcs->SetVisible(line, line, true);
 				SetScrollBars();
 				Redraw();
 			}
@@ -5503,9 +5504,9 @@
 
 	// Combining two blocks where the first one is collapsed (e.g. by adding characters in the line which separates the two blocks)
 	if (!(levelNow & SC_FOLDLEVELWHITEFLAG) && (LevelNumber(levelPrev) < LevelNumber(levelNow))) {
-		if (cs.HiddenLines()) {
+		if (pcs->HiddenLines()) {
 			const Sci::Line parentLine = pdoc->GetFoldParent(line);
-			if (!cs.GetExpanded(parentLine) && cs.GetVisible(line))
+			if (!pcs->GetExpanded(parentLine) && pcs->GetVisible(line))
 				FoldLine(parentLine, SC_FOLDACTION_EXPAND);
 		}
 	}
@@ -6421,8 +6422,8 @@
 
 	case SCI_SETLINEENDTYPESALLOWED:
 		if (pdoc->SetLineEndTypesAllowed(static_cast<int>(wParam))) {
-			cs.Clear();
-			cs.InsertLines(0, pdoc->LinesTotal() - 1);
+			pcs->Clear();
+			pcs->InsertLines(0, pdoc->LinesTotal() - 1);
 			SetAnnotationHeights(0, pdoc->LinesTotal());
 			InvalidateStyleRedraw();
 		}
@@ -6762,8 +6763,8 @@
 	case SCI_SETCODEPAGE:
 		if (ValidCodePage(static_cast<int>(wParam))) {
 			if (pdoc->SetDBCSCodePage(static_cast<int>(wParam))) {
-				cs.Clear();
-				cs.InsertLines(0, pdoc->LinesTotal() - 1);
+				pcs->Clear();
+				pcs->InsertLines(0, pdoc->LinesTotal() - 1);
 				SetAnnotationHeights(0, pdoc->LinesTotal());
 				InvalidateStyleRedraw();
 				SetRepresentations();
@@ -7078,10 +7079,10 @@
 		// Folding messages
 
 	case SCI_VISIBLEFROMDOCLINE:
-		return cs.DisplayFromDoc(static_cast<int>(wParam));
+		return pcs->DisplayFromDoc(static_cast<int>(wParam));
 
 	case SCI_DOCLINEFROMVISIBLE:
-		return cs.DocFromDisplay(static_cast<int>(wParam));
+		return pcs->DocFromDisplay(static_cast<int>(wParam));
 
 	case SCI_WRAPCOUNT:
 		return WrapCount(static_cast<int>(wParam));
@@ -7103,30 +7104,30 @@
 		return pdoc->GetFoldParent(static_cast<int>(wParam));
 
 	case SCI_SHOWLINES:
-		cs.SetVisible(static_cast<int>(wParam), static_cast<int>(lParam), true);
+		pcs->SetVisible(static_cast<int>(wParam), static_cast<int>(lParam), true);
 		SetScrollBars();
 		Redraw();
 		break;
 
 	case SCI_HIDELINES:
 		if (wParam > 0)
-			cs.SetVisible(static_cast<int>(wParam), static_cast<int>(lParam), false);
+			pcs->SetVisible(static_cast<int>(wParam), static_cast<int>(lParam), false);
 		SetScrollBars();
 		Redraw();
 		break;
 
 	case SCI_GETLINEVISIBLE:
-		return cs.GetVisible(static_cast<int>(wParam));
+		return pcs->GetVisible(static_cast<int>(wParam));
 
 	case SCI_GETALLLINESVISIBLE:
-		return cs.HiddenLines() ? 0 : 1;
+		return pcs->HiddenLines() ? 0 : 1;
 
 	case SCI_SETFOLDEXPANDED:
 		SetFoldExpanded(static_cast<int>(wParam), lParam != 0);
 		break;
 
 	case SCI_GETFOLDEXPANDED:
-		return cs.GetExpanded(static_cast<int>(wParam));
+		return pcs->GetExpanded(static_cast<int>(wParam));
 
 	case SCI_SETAUTOMATICFOLD:
 		foldAutomatic = static_cast<int>(wParam);
@@ -7141,7 +7142,7 @@
 		break;
 
 	case SCI_TOGGLEFOLDSHOWTEXT:
-		cs.SetFoldDisplayText(static_cast<int>(wParam), CharPtrFromSPtr(lParam));
+		pcs->SetFoldDisplayText(static_cast<int>(wParam), CharPtrFromSPtr(lParam));
 		FoldLine(static_cast<int>(wParam), SC_FOLDACTION_TOGGLE);
 		break;
 
@@ -7602,6 +7603,7 @@
 			Document *doc = new Document(static_cast<int>(lParam));
 			doc->AddRef();
 			doc->Allocate(static_cast<int>(wParam));
+			pcs = CreateContractionState(pdoc->IsLarge());
 			return reinterpret_cast<sptr_t>(doc);
 		}
 
@@ -7618,6 +7620,7 @@
 			doc->AddRef();
 			doc->Allocate(static_cast<int>(wParam));
 			doc->SetUndoCollection(false);
+			pcs = CreateContractionState(pdoc->IsLarge());
 			return reinterpret_cast<sptr_t>(static_cast<ILoader *>(doc));
 		}
 
diff -r e84a1ec0a6b3 -r 184b4d8ed263 src/MarginView.cxx
--- a/src/MarginView.cxx	Sat Mar 10 13:11:49 2018 +1100
+++ b/src/MarginView.cxx	Sat Mar 10 13:14:14 2018 +1100
@@ -231,9 +231,9 @@
 			// be displayed until the last of a sequence of whitespace.
 			bool needWhiteClosure = false;
 			if (vs.ms[margin].mask & SC_MASK_FOLDERS) {
-				const int level = model.pdoc->GetLevel(model.cs.DocFromDisplay(visibleLine));
+				const int level = model.pdoc->GetLevel(model.pcs->DocFromDisplay(visibleLine));
 				if (level & SC_FOLDLEVELWHITEFLAG) {
-					Sci::Line lineBack = model.cs.DocFromDisplay(visibleLine);
+					Sci::Line lineBack = model.pcs->DocFromDisplay(visibleLine);
 					int levelPrev = level;
 					while ((lineBack > 0) && (levelPrev & SC_FOLDLEVELWHITEFLAG)) {
 						lineBack--;
@@ -245,7 +245,7 @@
 					}
 				}
 				if (highlightDelimiter.isEnabled) {
-					const Sci::Line lastLine = model.cs.DocFromDisplay(topLine + model.LinesOnScreen()) + 1;
+					const Sci::Line lastLine = model.pcs->DocFromDisplay(topLine + model.LinesOnScreen()) + 1;
 					model.pdoc->GetHighlightDelimiters(highlightDelimiter,
 						static_cast<Sci::Line>(model.pdoc->LineFromPosition(model.sel.MainCaret())), lastLine);
 				}
@@ -257,13 +257,13 @@
 			const int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
 				SC_MARKNUM_FOLDER, vs);
 
-			while ((visibleLine < model.cs.LinesDisplayed()) && yposScreen < rc.bottom) {
+			while ((visibleLine < model.pcs->LinesDisplayed()) && yposScreen < rc.bottom) {
 
-				PLATFORM_ASSERT(visibleLine < model.cs.LinesDisplayed());
-				const Sci::Line lineDoc = model.cs.DocFromDisplay(visibleLine);
-				PLATFORM_ASSERT(model.cs.GetVisible(lineDoc));
-				const Sci::Line firstVisibleLine = model.cs.DisplayFromDoc(lineDoc);
-				const Sci::Line lastVisibleLine = model.cs.DisplayLastFromDoc(lineDoc);
+				PLATFORM_ASSERT(visibleLine < model.pcs->LinesDisplayed());
+				const Sci::Line lineDoc = model.pcs->DocFromDisplay(visibleLine);
+				PLATFORM_ASSERT(model.pcs->GetVisible(lineDoc));
+				const Sci::Line firstVisibleLine = model.pcs->DisplayFromDoc(lineDoc);
+				const Sci::Line lastVisibleLine = model.pcs->DisplayLastFromDoc(lineDoc);
 				const bool firstSubLine = visibleLine == firstVisibleLine;
 				const bool lastSubLine = visibleLine == lastVisibleLine;
 
@@ -282,7 +282,7 @@
 					if (level & SC_FOLDLEVELHEADERFLAG) {
 						if (firstSubLine) {
 							if (levelNum < levelNextNum) {
-								if (model.cs.GetExpanded(lineDoc)) {
+								if (model.pcs->GetExpanded(lineDoc)) {
 									if (levelNum == SC_FOLDLEVELBASE)
 										marks |= 1 << SC_MARKNUM_FOLDEROPEN;
 									else
@@ -298,7 +298,7 @@
 							}
 						} else {
 							if (levelNum < levelNextNum) {
-								if (model.cs.GetExpanded(lineDoc)) {
+								if (model.pcs->GetExpanded(lineDoc)) {
 									marks |= 1 << SC_MARKNUM_FOLDERSUB;
 								} else if (levelNum > SC_FOLDLEVELBASE) {
 									marks |= 1 << SC_MARKNUM_FOLDERSUB;
@@ -308,10 +308,10 @@
 							}
 						}
 						needWhiteClosure = false;
-						const Sci::Line firstFollowupLine = model.cs.DocFromDisplay(model.cs.DisplayFromDoc(lineDoc + 1));
+						const Sci::Line firstFollowupLine = model.pcs->DocFromDisplay(model.pcs->DisplayFromDoc(lineDoc + 1));
 						const int firstFollowupLineLevel = model.pdoc->GetLevel(firstFollowupLine);
 						const int secondFollowupLineLevelNum = LevelNumber(model.pdoc->GetLevel(firstFollowupLine + 1));
-						if (!model.cs.GetExpanded(lineDoc)) {
+						if (!model.pcs->GetExpanded(lineDoc)) {
 							if ((firstFollowupLineLevel & SC_FOLDLEVELWHITEFLAG) &&
 								(levelNum > secondFollowupLineLevelNum))
 								needWhiteClosure = true;
@@ -436,7 +436,7 @@
 									if (firstSubLine) {
 										tFold = headWithTail ? LineMarker::headWithTail : LineMarker::head;
 									} else {
-										if (model.cs.GetExpanded(lineDoc) || headWithTail) {
+										if (model.pcs->GetExpanded(lineDoc) || headWithTail) {
 											tFold = LineMarker::body;
 										} else {
 											tFold = LineMarker::undefined;
diff -r e84a1ec0a6b3 -r 184b4d8ed263 test/unit/testContractionState.cxx
--- a/test/unit/testContractionState.cxx	Sat Mar 10 13:11:49 2018 +1100
+++ b/test/unit/testContractionState.cxx	Sat Mar 10 13:14:14 2018 +1100
@@ -24,134 +24,134 @@
 
 TEST_CASE("ContractionState") {
 
-	ContractionState cs;
+	std::unique_ptr<IContractionState> pcs = CreateContractionState(false);
 
 	SECTION("IsEmptyInitially") {
-		REQUIRE(1 == cs.LinesInDoc());
-		REQUIRE(1 == cs.LinesDisplayed());
-		REQUIRE(0 == cs.DisplayFromDoc(0));
-		REQUIRE(0 == cs.DocFromDisplay(0));
+		REQUIRE(1 == pcs->LinesInDoc());
+		REQUIRE(1 == pcs->LinesDisplayed());
+		REQUIRE(0 == pcs->DisplayFromDoc(0));
+		REQUIRE(0 == pcs->DocFromDisplay(0));
 	}
 
 	SECTION("OneLine") {
-		cs.InsertLine(0);
-		REQUIRE(2 == cs.LinesInDoc());
-		REQUIRE(2 == cs.LinesDisplayed());
-		REQUIRE(0 == cs.DisplayFromDoc(0));
-		REQUIRE(0 == cs.DocFromDisplay(0));
-		REQUIRE(1 == cs.DisplayFromDoc(1));
-		REQUIRE(1 == cs.DocFromDisplay(1));
+		pcs->InsertLines(0, 1);
+		REQUIRE(2 == pcs->LinesInDoc());
+		REQUIRE(2 == pcs->LinesDisplayed());
+		REQUIRE(0 == pcs->DisplayFromDoc(0));
+		REQUIRE(0 == pcs->DocFromDisplay(0));
+		REQUIRE(1 == pcs->DisplayFromDoc(1));
+		REQUIRE(1 == pcs->DocFromDisplay(1));
 	}
 
 	SECTION("InsertionThenDeletions") {
-		cs.InsertLines(0,4);
-		cs.DeleteLine(1);
+		pcs->InsertLines(0,4);
+		pcs->DeleteLines(1, 1);
 
-		REQUIRE(4 == cs.LinesInDoc());
-		REQUIRE(4 == cs.LinesDisplayed());
+		REQUIRE(4 == pcs->LinesInDoc());
+		REQUIRE(4 == pcs->LinesDisplayed());
 		for (int l=0;l<4;l++) {
-			REQUIRE(l == cs.DisplayFromDoc(l));
-			REQUIRE(l == cs.DocFromDisplay(l));
+			REQUIRE(l == pcs->DisplayFromDoc(l));
+			REQUIRE(l == pcs->DocFromDisplay(l));
 		}
 
-		cs.DeleteLines(0,2);
-		REQUIRE(2 == cs.LinesInDoc());
-		REQUIRE(2 == cs.LinesDisplayed());
+		pcs->DeleteLines(0,2);
+		REQUIRE(2 == pcs->LinesInDoc());
+		REQUIRE(2 == pcs->LinesDisplayed());
 		for (int l=0;l<2;l++) {
-			REQUIRE(l == cs.DisplayFromDoc(l));
-			REQUIRE(l == cs.DocFromDisplay(l));
+			REQUIRE(l == pcs->DisplayFromDoc(l));
+			REQUIRE(l == pcs->DocFromDisplay(l));
 		}
 	}
 
 	SECTION("ShowHide") {
-		cs.InsertLines(0,4);
-		REQUIRE(true == cs.GetVisible(0));
-		REQUIRE(true == cs.GetVisible(1));
-		REQUIRE(true == cs.GetVisible(2));
-		REQUIRE(5 == cs.LinesDisplayed());
+		pcs->InsertLines(0,4);
+		REQUIRE(true == pcs->GetVisible(0));
+		REQUIRE(true == pcs->GetVisible(1));
+		REQUIRE(true == pcs->GetVisible(2));
+		REQUIRE(5 == pcs->LinesDisplayed());
 
-		cs.SetVisible(1, 1, false);
-		REQUIRE(true == cs.GetVisible(0));
-		REQUIRE(false == cs.GetVisible(1));
-		REQUIRE(true == cs.GetVisible(2));
-		REQUIRE(4 == cs.LinesDisplayed());
-		REQUIRE(true == cs.HiddenLines());
+		pcs->SetVisible(1, 1, false);
+		REQUIRE(true == pcs->GetVisible(0));
+		REQUIRE(false == pcs->GetVisible(1));
+		REQUIRE(true == pcs->GetVisible(2));
+		REQUIRE(4 == pcs->LinesDisplayed());
+		REQUIRE(true == pcs->HiddenLines());
 
-		cs.SetVisible(1, 2, true);
+		pcs->SetVisible(1, 2, true);
 		for (int l=0;l<4;l++) {
-			REQUIRE(true == cs.GetVisible(0));
+			REQUIRE(true == pcs->GetVisible(0));
 		}
 
-		cs.SetVisible(1, 1, false);
-		REQUIRE(false == cs.GetVisible(1));
-		cs.ShowAll();
+		pcs->SetVisible(1, 1, false);
+		REQUIRE(false == pcs->GetVisible(1));
+		pcs->ShowAll();
 		for (int l=0;l<4;l++) {
-			REQUIRE(true == cs.GetVisible(0));
+			REQUIRE(true == pcs->GetVisible(0));
 		}
-		REQUIRE(false == cs.HiddenLines());
+		REQUIRE(false == pcs->HiddenLines());
 	}
 
 	SECTION("Hidden") {
-		cs.InsertLines(0,1);
+		pcs->InsertLines(0,1);
 		for (int l=0;l<2;l++) {
-			REQUIRE(true == cs.GetVisible(0));
+			REQUIRE(true == pcs->GetVisible(0));
 		}
-		REQUIRE(false == cs.HiddenLines());
+		REQUIRE(false == pcs->HiddenLines());
 
-		cs.SetVisible(1, 1, false);
-		REQUIRE(true == cs.GetVisible(0));
-		REQUIRE(false == cs.GetVisible(1));
-		REQUIRE(true == cs.HiddenLines());
+		pcs->SetVisible(1, 1, false);
+		REQUIRE(true == pcs->GetVisible(0));
+		REQUIRE(false == pcs->GetVisible(1));
+		REQUIRE(true == pcs->HiddenLines());
 
-		cs.SetVisible(1, 1, true);
+		pcs->SetVisible(1, 1, true);
 		for (int l=0;l<2;l++) {
-			REQUIRE(true == cs.GetVisible(0));
+			REQUIRE(true == pcs->GetVisible(0));
 		}
-		REQUIRE(false == cs.HiddenLines());
+		REQUIRE(false == pcs->HiddenLines());
 	}
 
 	SECTION("Contracting") {
-		cs.InsertLines(0,4);
+		pcs->InsertLines(0,4);
 		for (int l=0;l<4;l++) {
-			REQUIRE(true == cs.GetExpanded(l));
+			REQUIRE(true == pcs->GetExpanded(l));
 		}
 
-		cs.SetExpanded(2, false);
-		REQUIRE(true == cs.GetExpanded(1));
-		REQUIRE(false == cs.GetExpanded(2));
-		REQUIRE(true == cs.GetExpanded(3));
+		pcs->SetExpanded(2, false);
+		REQUIRE(true == pcs->GetExpanded(1));
+		REQUIRE(false == pcs->GetExpanded(2));
+		REQUIRE(true == pcs->GetExpanded(3));
 
-		REQUIRE(2 == cs.ContractedNext(0));
-		REQUIRE(2 == cs.ContractedNext(1));
-		REQUIRE(2 == cs.ContractedNext(2));
-		REQUIRE(-1 == cs.ContractedNext(3));
+		REQUIRE(2 == pcs->ContractedNext(0));
+		REQUIRE(2 == pcs->ContractedNext(1));
+		REQUIRE(2 == pcs->ContractedNext(2));
+		REQUIRE(-1 == pcs->ContractedNext(3));
 
-		cs.SetExpanded(2, true);
-		REQUIRE(true == cs.GetExpanded(1));
-		REQUIRE(true == cs.GetExpanded(2));
-		REQUIRE(true == cs.GetExpanded(3));
+		pcs->SetExpanded(2, true);
+		REQUIRE(true == pcs->GetExpanded(1));
+		REQUIRE(true == pcs->GetExpanded(2));
+		REQUIRE(true == pcs->GetExpanded(3));
 	}
 
 	SECTION("ChangeHeight") {
-		cs.InsertLines(0,4);
+		pcs->InsertLines(0,4);
 		for (int l=0;l<4;l++) {
-			REQUIRE(1 == cs.GetHeight(l));
+			REQUIRE(1 == pcs->GetHeight(l));
 		}
 
-		cs.SetHeight(1, 2);
-		REQUIRE(1 == cs.GetHeight(0));
-		REQUIRE(2 == cs.GetHeight(1));
-		REQUIRE(1 == cs.GetHeight(2));
+		pcs->SetHeight(1, 2);
+		REQUIRE(1 == pcs->GetHeight(0));
+		REQUIRE(2 == pcs->GetHeight(1));
+		REQUIRE(1 == pcs->GetHeight(2));
 	}
 
 	SECTION("SetFoldDisplayText") {
-		cs.InsertLines(0, 4);
-		cs.SetFoldDisplayText(1, "abc");
-		REQUIRE(strcmp(cs.GetFoldDisplayText(1), "abc") == 0);
-		cs.SetFoldDisplayText(1, "def");
-		REQUIRE(strcmp(cs.GetFoldDisplayText(1), "def") == 0);
-		cs.SetFoldDisplayText(1, nullptr);
-		REQUIRE(static_cast<const char *>(nullptr) == cs.GetFoldDisplayText(1));
+		pcs->InsertLines(0, 4);
+		pcs->SetFoldDisplayText(1, "abc");
+		REQUIRE(strcmp(pcs->GetFoldDisplayText(1), "abc") == 0);
+		pcs->SetFoldDisplayText(1, "def");
+		REQUIRE(strcmp(pcs->GetFoldDisplayText(1), "def") == 0);
+		pcs->SetFoldDisplayText(1, nullptr);
+		REQUIRE(static_cast<const char *>(nullptr) == pcs->GetFoldDisplayText(1));
 	}
 
 }
