1 /** @file Decoration.cxx
2 ** Visual elements added over text.
3 **/
4 // Copyright 1998-2007 by Neil Hodgson <[email protected]>
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