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 38 explicit Decoration(int indicator_) : indicator(indicator_) { 39 } 40 ~Decoration() override { 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 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 93 const std::vector<const IDecoration*> &View() const noexcept override { 94 return decorationView; 95 } 96 97 void SetCurrentIndicator(int indicator) override; 98 int GetCurrentIndicator() const noexcept override { return currentIndicator; } 99 100 void SetCurrentValue(int value) override; 101 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 116 bool ClickNotified() const noexcept override { 117 return clickNotified; 118 } 119 void SetClickNotified(bool notified) noexcept override { 120 clickNotified = notified; 121 } 122 }; 123 124 template <typename POS> 125 DecorationList<POS>::DecorationList() : currentIndicator(0), currentValue(1), current(nullptr), 126 lengthDocument(0), clickNotified(false) { 127 } 128 129 template <typename POS> 130 DecorationList<POS>::~DecorationList() { 131 current = nullptr; 132 } 133 134 template <typename POS> 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> 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> 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> 174 void DecorationList<POS>::SetCurrentIndicator(int indicator) { 175 currentIndicator = indicator; 176 current = DecorationFromIndicator(indicator); 177 currentValue = 1; 178 } 179 180 template <typename POS> 181 void DecorationList<POS>::SetCurrentValue(int value) { 182 currentValue = value ? value : 1; 183 } 184 185 template <typename POS> 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> 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> 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> 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> 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> 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> 259 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> 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> 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> 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 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 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