1 /** @file Decoration.cxx
2  ** Visual elements added over text.
3  **/
4 // Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
5 // The License.txt file describes the conditions under which this software may be distributed.
6 
7 #include <cstddef>
8 #include <cstdlib>
9 #include <cstring>
10 #include <cstdio>
11 #include <cstdarg>
12 
13 #include <stdexcept>
14 #include <vector>
15 #include <algorithm>
16 #include <memory>
17 
18 #include "Platform.h"
19 
20 #include "Scintilla.h"
21 #include "Position.h"
22 #include "SplitVector.h"
23 #include "Partitioning.h"
24 #include "RunStyles.h"
25 #include "Decoration.h"
26 
27 using namespace Scintilla;
28 
29 namespace {
30 
31 template <typename POS>
32 class Decoration : public IDecoration {
33 	int indicator;
34 public:
35 	RunStyles<POS, int> rs;
36 
Decoration(int indicator_)37 	explicit Decoration(int indicator_) : indicator(indicator_) {
38 	}
~Decoration()39 	~Decoration() override {
40 	}
41 
Empty() const42 	bool Empty() const override {
43 		return (rs.Runs() == 1) && (rs.AllSameAs(0));
44 	}
Indicator() const45 	int Indicator() const override {
46 		return indicator;
47 	}
Length() const48 	Sci::Position Length() const override {
49 		return rs.Length();
50 	}
ValueAt(Sci::Position position) const51 	int ValueAt(Sci::Position position) const override {
52 		return rs.ValueAt(static_cast<POS>(position));
53 	}
StartRun(Sci::Position position) const54 	Sci::Position StartRun(Sci::Position position) const override {
55 		return rs.StartRun(static_cast<POS>(position));
56 	}
EndRun(Sci::Position position) const57 	Sci::Position EndRun(Sci::Position position) const override {
58 		return rs.EndRun(static_cast<POS>(position));
59 	}
SetValueAt(Sci::Position position,int value)60 	void SetValueAt(Sci::Position position, int value) override {
61 		rs.SetValueAt(static_cast<POS>(position), value);
62 	}
InsertSpace(Sci::Position position,Sci::Position insertLength)63 	void InsertSpace(Sci::Position position, Sci::Position insertLength) override {
64 		rs.InsertSpace(static_cast<POS>(position), static_cast<POS>(insertLength));
65 	}
Runs() const66 	Sci::Position Runs() const override {
67 		return rs.Runs();
68 	}
69 };
70 
71 template <typename POS>
72 class DecorationList : public IDecorationList {
73 	int currentIndicator;
74 	int currentValue;
75 	Decoration<POS> *current;	// Cached so FillRange doesn't have to search for each call.
76 	Sci::Position lengthDocument;
77 	// Ordered by indicator
78 	std::vector<std::unique_ptr<Decoration<POS>>> decorationList;
79 	std::vector<const IDecoration*> decorationView;	// Read-only view of decorationList
80 	bool clickNotified;
81 
82 	Decoration<POS> *DecorationFromIndicator(int indicator);
83 	Decoration<POS> *Create(int indicator, Sci::Position length);
84 	void Delete(int indicator);
85 	void DeleteAnyEmpty();
86 	void SetView();
87 public:
88 
89 	DecorationList();
90 	~DecorationList() override;
91 
View() const92 	const std::vector<const IDecoration*> &View() const override {
93 		return decorationView;
94 	}
95 
96 	void SetCurrentIndicator(int indicator) override;
GetCurrentIndicator() const97 	int GetCurrentIndicator() const override { return currentIndicator; }
98 
99 	void SetCurrentValue(int value) override;
GetCurrentValue() const100 	int GetCurrentValue() const override { return currentValue; }
101 
102 	// Returns changed=true if some values may have changed
103 	FillResult<Sci::Position> FillRange(Sci::Position position, int value, Sci::Position fillLength) override;
104 
105 	void InsertSpace(Sci::Position position, Sci::Position insertLength) override;
106 	void DeleteRange(Sci::Position position, Sci::Position deleteLength) override;
107 
108 	void DeleteLexerDecorations() override;
109 
110 	int AllOnFor(Sci::Position position) const override;
111 	int ValueAt(int indicator, Sci::Position position) override;
112 	Sci::Position Start(int indicator, Sci::Position position) override;
113 	Sci::Position End(int indicator, Sci::Position position) override;
114 
ClickNotified() const115 	bool ClickNotified() const override {
116 		return clickNotified;
117 	}
SetClickNotified(bool notified)118 	void SetClickNotified(bool notified) override {
119 		clickNotified = notified;
120 	}
121 };
122 
123 template <typename POS>
DecorationList()124 DecorationList<POS>::DecorationList() : currentIndicator(0), currentValue(1), current(nullptr),
125 	lengthDocument(0), clickNotified(false) {
126 }
127 
128 template <typename POS>
~DecorationList()129 DecorationList<POS>::~DecorationList() {
130 	current = nullptr;
131 }
132 
133 template <typename POS>
DecorationFromIndicator(int indicator)134 Decoration<POS> *DecorationList<POS>::DecorationFromIndicator(int indicator) {
135 	for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) {
136 		if (deco->Indicator() == indicator) {
137 			return deco.get();
138 		}
139 	}
140 	return nullptr;
141 }
142 
143 template <typename POS>
Create(int indicator,Sci::Position length)144 Decoration<POS> *DecorationList<POS>::Create(int indicator, Sci::Position length) {
145 	currentIndicator = indicator;
146 	std::unique_ptr<Decoration<POS>> decoNew = std::unique_ptr<Decoration<POS>>(new Decoration<POS>(indicator));
147 	decoNew->rs.InsertSpace(0, static_cast<POS>(length));
148 
149 	typename std::vector<std::unique_ptr<Decoration<POS>>>::iterator it = std::lower_bound(
150 		decorationList.begin(), decorationList.end(), decoNew,
151 		[](const std::unique_ptr<Decoration<POS>> &a, const std::unique_ptr<Decoration<POS>> &b) {
152 		return a->Indicator() < b->Indicator();
153 	});
154 	typename std::vector<std::unique_ptr<Decoration<POS>>>::iterator itAdded =
155 		decorationList.insert(it, std::move(decoNew));
156 
157 	SetView();
158 
159 	return itAdded->get();
160 }
161 
162 template <typename POS>
Delete(int indicator)163 void DecorationList<POS>::Delete(int indicator) {
164 	decorationList.erase(std::remove_if(decorationList.begin(), decorationList.end(),
165 		[indicator](const std::unique_ptr<Decoration<POS>> &deco) {
166 		return deco->Indicator() == indicator;
167 	}), decorationList.end());
168 	current = nullptr;
169 	SetView();
170 }
171 
172 template <typename POS>
SetCurrentIndicator(int indicator)173 void DecorationList<POS>::SetCurrentIndicator(int indicator) {
174 	currentIndicator = indicator;
175 	current = DecorationFromIndicator(indicator);
176 	currentValue = 1;
177 }
178 
179 template <typename POS>
SetCurrentValue(int value)180 void DecorationList<POS>::SetCurrentValue(int value) {
181 	currentValue = value ? value : 1;
182 }
183 
184 template <typename POS>
FillRange(Sci::Position position,int value,Sci::Position fillLength)185 FillResult<Sci::Position> DecorationList<POS>::FillRange(Sci::Position position, int value, Sci::Position fillLength) {
186 	if (!current) {
187 		current = DecorationFromIndicator(currentIndicator);
188 		if (!current) {
189 			current = Create(currentIndicator, lengthDocument);
190 		}
191 	}
192 	// Converting result from POS to Sci::Position as callers not polymorphic.
193 	const FillResult<POS> frInPOS = current->rs.FillRange(static_cast<POS>(position), value, static_cast<POS>(fillLength));
194 	const FillResult<Sci::Position> fr { frInPOS.changed, frInPOS.position, frInPOS.fillLength };
195 	if (current->Empty()) {
196 		Delete(currentIndicator);
197 	}
198 	return fr;
199 }
200 
201 template <typename POS>
InsertSpace(Sci::Position position,Sci::Position insertLength)202 void DecorationList<POS>::InsertSpace(Sci::Position position, Sci::Position insertLength) {
203 	const bool atEnd = position == lengthDocument;
204 	lengthDocument += insertLength;
205 	for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) {
206 		deco->rs.InsertSpace(static_cast<POS>(position), static_cast<POS>(insertLength));
207 		if (atEnd) {
208 			deco->rs.FillRange(static_cast<POS>(position), 0, static_cast<POS>(insertLength));
209 		}
210 	}
211 }
212 
213 template <typename POS>
DeleteRange(Sci::Position position,Sci::Position deleteLength)214 void DecorationList<POS>::DeleteRange(Sci::Position position, Sci::Position deleteLength) {
215 	lengthDocument -= deleteLength;
216 	for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) {
217 		deco->rs.DeleteRange(static_cast<POS>(position), static_cast<POS>(deleteLength));
218 	}
219 	DeleteAnyEmpty();
220 	if (decorationList.size() != decorationView.size()) {
221 		// One or more empty decorations deleted so update view.
222 		current = nullptr;
223 		SetView();
224 	}
225 }
226 
227 template <typename POS>
DeleteLexerDecorations()228 void DecorationList<POS>::DeleteLexerDecorations() {
229 	decorationList.erase(std::remove_if(decorationList.begin(), decorationList.end(),
230 		[](const std::unique_ptr<Decoration<POS>> &deco) {
231 		return deco->Indicator() < INDIC_CONTAINER;
232 	}), decorationList.end());
233 	current = nullptr;
234 	SetView();
235 }
236 
237 template <typename POS>
DeleteAnyEmpty()238 void DecorationList<POS>::DeleteAnyEmpty() {
239 	if (lengthDocument == 0) {
240 		decorationList.clear();
241 	} else {
242 		decorationList.erase(std::remove_if(decorationList.begin(), decorationList.end(),
243 			[](const std::unique_ptr<Decoration<POS>> &deco) {
244 			return deco->Empty();
245 		}), decorationList.end());
246 	}
247 }
248 
249 template <typename POS>
SetView()250 void DecorationList<POS>::SetView() {
251 	decorationView.clear();
252 	for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) {
253 		decorationView.push_back(deco.get());
254 	}
255 }
256 
257 template <typename POS>
AllOnFor(Sci::Position position) const258 int DecorationList<POS>::AllOnFor(Sci::Position position) const {
259 	int mask = 0;
260 	for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) {
261 		if (deco->rs.ValueAt(static_cast<POS>(position))) {
262 			if (deco->Indicator() < INDIC_IME) {
263 				mask |= 1 << deco->Indicator();
264 			}
265 		}
266 	}
267 	return mask;
268 }
269 
270 template <typename POS>
ValueAt(int indicator,Sci::Position position)271 int DecorationList<POS>::ValueAt(int indicator, Sci::Position position) {
272 	const Decoration<POS> *deco = DecorationFromIndicator(indicator);
273 	if (deco) {
274 		return deco->rs.ValueAt(static_cast<POS>(position));
275 	}
276 	return 0;
277 }
278 
279 template <typename POS>
Start(int indicator,Sci::Position position)280 Sci::Position DecorationList<POS>::Start(int indicator, Sci::Position position) {
281 	const Decoration<POS> *deco = DecorationFromIndicator(indicator);
282 	if (deco) {
283 		return deco->rs.StartRun(static_cast<POS>(position));
284 	}
285 	return 0;
286 }
287 
288 template <typename POS>
End(int indicator,Sci::Position position)289 Sci::Position DecorationList<POS>::End(int indicator, Sci::Position position) {
290 	const Decoration<POS> *deco = DecorationFromIndicator(indicator);
291 	if (deco) {
292 		return deco->rs.EndRun(static_cast<POS>(position));
293 	}
294 	return 0;
295 }
296 
297 }
298 
299 namespace Scintilla {
300 
DecorationCreate(bool largeDocument,int indicator)301 std::unique_ptr<IDecoration> DecorationCreate(bool largeDocument, int indicator) {
302 	if (largeDocument)
303 		return std::unique_ptr<Decoration<Sci::Position>>(new Decoration<Sci::Position>(indicator));
304 	else
305 		return std::unique_ptr<Decoration<int>>(new Decoration<int>(indicator));
306 }
307 
DecorationListCreate(bool largeDocument)308 std::unique_ptr<IDecorationList> DecorationListCreate(bool largeDocument) {
309 	if (largeDocument)
310 		return std::unique_ptr<DecorationList<Sci::Position>>(new DecorationList<Sci::Position>());
311 	else
312 		return std::unique_ptr<DecorationList<int>>(new DecorationList<int>());
313 }
314 
315 }
316 
317