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