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