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