1 // Scintilla source code edit control 2 /** @file PerLine.cxx 3 ** Manages data associated with each line of the document 4 **/ 5 // Copyright 1998-2009 by Neil Hodgson <[email protected]> 6 // The License.txt file describes the conditions under which this software may be distributed. 7 8 #include <cstddef> 9 #include <cassert> 10 #include <cstring> 11 12 #include <stdexcept> 13 #include <string_view> 14 #include <vector> 15 #include <forward_list> 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 "CellBuffer.h" 26 #include "PerLine.h" 27 28 using namespace Scintilla; 29 30 MarkerHandleSet::MarkerHandleSet() { 31 } 32 33 MarkerHandleSet::~MarkerHandleSet() { 34 mhList.clear(); 35 } 36 37 bool MarkerHandleSet::Empty() const noexcept { 38 return mhList.empty(); 39 } 40 41 int MarkerHandleSet::MarkValue() const noexcept { 42 unsigned int m = 0; 43 for (const MarkerHandleNumber &mhn : mhList) { 44 m |= (1 << mhn.number); 45 } 46 return m; 47 } 48 49 bool MarkerHandleSet::Contains(int handle) const noexcept { 50 for (const MarkerHandleNumber &mhn : mhList) { 51 if (mhn.handle == handle) { 52 return true; 53 } 54 } 55 return false; 56 } 57 58 MarkerHandleNumber const *MarkerHandleSet::GetMarkerHandleNumber(int which) const noexcept { 59 for (const MarkerHandleNumber &mhn : mhList) { 60 if (which == 0) 61 return &mhn; 62 which--; 63 } 64 return nullptr; 65 } 66 67 bool MarkerHandleSet::InsertHandle(int handle, int markerNum) { 68 mhList.push_front(MarkerHandleNumber(handle, markerNum)); 69 return true; 70 } 71 72 void MarkerHandleSet::RemoveHandle(int handle) { 73 mhList.remove_if([handle](const MarkerHandleNumber &mhn) noexcept { return mhn.handle == handle; }); 74 } 75 76 bool MarkerHandleSet::RemoveNumber(int markerNum, bool all) { 77 bool performedDeletion = false; 78 mhList.remove_if([&](const MarkerHandleNumber &mhn) noexcept { 79 if ((all || !performedDeletion) && (mhn.number == markerNum)) { 80 performedDeletion = true; 81 return true; 82 } 83 return false; 84 }); 85 return performedDeletion; 86 } 87 88 void MarkerHandleSet::CombineWith(MarkerHandleSet *other) noexcept { 89 mhList.splice_after(mhList.before_begin(), other->mhList); 90 } 91 92 LineMarkers::~LineMarkers() { 93 } 94 95 void LineMarkers::Init() { 96 markers.DeleteAll(); 97 } 98 99 void LineMarkers::InsertLine(Sci::Line line) { 100 if (markers.Length()) { 101 markers.Insert(line, 0); 102 } 103 } 104 105 void LineMarkers::InsertLines(Sci::Line line, Sci::Line lines) { 106 if (markers.Length()) { 107 markers.InsertEmpty(line, lines); 108 } 109 } 110 111 void LineMarkers::RemoveLine(Sci::Line line) { 112 // Retain the markers from the deleted line by oring them into the previous line 113 if (markers.Length()) { 114 if (line > 0) { 115 MergeMarkers(line - 1); 116 } 117 markers.Delete(line); 118 } 119 } 120 121 Sci::Line LineMarkers::LineFromHandle(int markerHandle) const noexcept { 122 for (Sci::Line line = 0; line < markers.Length(); line++) { 123 if (markers[line] && markers[line]->Contains(markerHandle)) { 124 return line; 125 } 126 } 127 return -1; 128 } 129 130 int LineMarkers::HandleFromLine(Sci::Line line, int which) const noexcept { 131 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) { 132 MarkerHandleNumber const *pnmh = markers[line]->GetMarkerHandleNumber(which); 133 return pnmh ? pnmh->handle : -1; 134 } 135 return -1; 136 } 137 138 int LineMarkers::NumberFromLine(Sci::Line line, int which) const noexcept { 139 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) { 140 MarkerHandleNumber const *pnmh = markers[line]->GetMarkerHandleNumber(which); 141 return pnmh ? pnmh->number : -1; 142 } 143 return -1; 144 } 145 146 void LineMarkers::MergeMarkers(Sci::Line line) { 147 if (markers[line + 1]) { 148 if (!markers[line]) 149 markers[line] = std::make_unique<MarkerHandleSet>(); 150 markers[line]->CombineWith(markers[line + 1].get()); 151 markers[line + 1].reset(); 152 } 153 } 154 155 int LineMarkers::MarkValue(Sci::Line line) const noexcept { 156 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) 157 return markers[line]->MarkValue(); 158 else 159 return 0; 160 } 161 162 Sci::Line LineMarkers::MarkerNext(Sci::Line lineStart, int mask) const noexcept { 163 if (lineStart < 0) 164 lineStart = 0; 165 const Sci::Line length = markers.Length(); 166 for (Sci::Line iLine = lineStart; iLine < length; iLine++) { 167 const MarkerHandleSet *onLine = markers[iLine].get(); 168 if (onLine && ((onLine->MarkValue() & mask) != 0)) 169 return iLine; 170 } 171 return -1; 172 } 173 174 int LineMarkers::AddMark(Sci::Line line, int markerNum, Sci::Line lines) { 175 handleCurrent++; 176 if (!markers.Length()) { 177 // No existing markers so allocate one element per line 178 markers.InsertEmpty(0, lines); 179 } 180 if (line >= markers.Length()) { 181 return -1; 182 } 183 if (!markers[line]) { 184 // Need new structure to hold marker handle 185 markers[line] = std::make_unique<MarkerHandleSet>(); 186 } 187 markers[line]->InsertHandle(handleCurrent, markerNum); 188 189 return handleCurrent; 190 } 191 192 bool LineMarkers::DeleteMark(Sci::Line line, int markerNum, bool all) { 193 bool someChanges = false; 194 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) { 195 if (markerNum == -1) { 196 someChanges = true; 197 markers[line].reset(); 198 } else { 199 someChanges = markers[line]->RemoveNumber(markerNum, all); 200 if (markers[line]->Empty()) { 201 markers[line].reset(); 202 } 203 } 204 } 205 return someChanges; 206 } 207 208 void LineMarkers::DeleteMarkFromHandle(int markerHandle) { 209 const Sci::Line line = LineFromHandle(markerHandle); 210 if (line >= 0) { 211 markers[line]->RemoveHandle(markerHandle); 212 if (markers[line]->Empty()) { 213 markers[line].reset(); 214 } 215 } 216 } 217 218 LineLevels::~LineLevels() { 219 } 220 221 void LineLevels::Init() { 222 levels.DeleteAll(); 223 } 224 225 void LineLevels::InsertLine(Sci::Line line) { 226 if (levels.Length()) { 227 const int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE; 228 levels.Insert(line, level); 229 } 230 } 231 232 void LineLevels::InsertLines(Sci::Line line, Sci::Line lines) { 233 if (levels.Length()) { 234 const int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE; 235 levels.InsertValue(line, lines, level); 236 } 237 } 238 239 void LineLevels::RemoveLine(Sci::Line line) { 240 if (levels.Length()) { 241 // Move up following lines but merge header flag from this line 242 // to line before to avoid a temporary disappearance causing expansion. 243 int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG; 244 levels.Delete(line); 245 if (line == levels.Length()-1) // Last line loses the header flag 246 levels[line-1] &= ~SC_FOLDLEVELHEADERFLAG; 247 else if (line > 0) 248 levels[line-1] |= firstHeader; 249 } 250 } 251 252 void LineLevels::ExpandLevels(Sci::Line sizeNew) { 253 levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE); 254 } 255 256 void LineLevels::ClearLevels() { 257 levels.DeleteAll(); 258 } 259 260 int LineLevels::SetLevel(Sci::Line line, int level, Sci::Line lines) { 261 int prev = 0; 262 if ((line >= 0) && (line < lines)) { 263 if (!levels.Length()) { 264 ExpandLevels(lines + 1); 265 } 266 prev = levels[line]; 267 if (prev != level) { 268 levels[line] = level; 269 } 270 } 271 return prev; 272 } 273 274 int LineLevels::GetLevel(Sci::Line line) const noexcept { 275 if (levels.Length() && (line >= 0) && (line < levels.Length())) { 276 return levels[line]; 277 } else { 278 return SC_FOLDLEVELBASE; 279 } 280 } 281 282 LineState::~LineState() { 283 } 284 285 void LineState::Init() { 286 lineStates.DeleteAll(); 287 } 288 289 void LineState::InsertLine(Sci::Line line) { 290 if (lineStates.Length()) { 291 lineStates.EnsureLength(line); 292 const int val = (line < lineStates.Length()) ? lineStates[line] : 0; 293 lineStates.Insert(line, val); 294 } 295 } 296 297 void LineState::InsertLines(Sci::Line line, Sci::Line lines) { 298 if (lineStates.Length()) { 299 lineStates.EnsureLength(line); 300 const int val = (line < lineStates.Length()) ? lineStates[line] : 0; 301 lineStates.InsertValue(line, lines, val); 302 } 303 } 304 305 void LineState::RemoveLine(Sci::Line line) { 306 if (lineStates.Length() > line) { 307 lineStates.Delete(line); 308 } 309 } 310 311 int LineState::SetLineState(Sci::Line line, int state) { 312 lineStates.EnsureLength(line + 1); 313 const int stateOld = lineStates[line]; 314 lineStates[line] = state; 315 return stateOld; 316 } 317 318 int LineState::GetLineState(Sci::Line line) { 319 if (line < 0) 320 return 0; 321 lineStates.EnsureLength(line + 1); 322 return lineStates[line]; 323 } 324 325 Sci::Line LineState::GetMaxLineState() const noexcept { 326 return lineStates.Length(); 327 } 328 329 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader 330 // and then has text and optional styles. 331 332 struct AnnotationHeader { 333 short style; // Style IndividualStyles implies array of styles 334 short lines; 335 int length; 336 }; 337 338 namespace { 339 340 constexpr int IndividualStyles = 0x100; 341 342 size_t NumberLines(std::string_view sv) { 343 return std::count(sv.begin(), sv.end(), '\n') + 1; 344 } 345 346 std::unique_ptr<char[]>AllocateAnnotation(size_t length, int style) { 347 const size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0); 348 return std::make_unique<char[]>(len); 349 } 350 351 } 352 353 LineAnnotation::~LineAnnotation() { 354 } 355 356 void LineAnnotation::Init() { 357 ClearAll(); 358 } 359 360 void LineAnnotation::InsertLine(Sci::Line line) { 361 if (annotations.Length()) { 362 annotations.EnsureLength(line); 363 annotations.Insert(line, std::unique_ptr<char []>()); 364 } 365 } 366 367 void LineAnnotation::InsertLines(Sci::Line line, Sci::Line lines) { 368 if (annotations.Length()) { 369 annotations.EnsureLength(line); 370 annotations.InsertEmpty(line, lines); 371 } 372 } 373 374 void LineAnnotation::RemoveLine(Sci::Line line) { 375 if (annotations.Length() && (line > 0) && (line <= annotations.Length())) { 376 annotations[line-1].reset(); 377 annotations.Delete(line-1); 378 } 379 } 380 381 bool LineAnnotation::MultipleStyles(Sci::Line line) const noexcept { 382 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) 383 return reinterpret_cast<AnnotationHeader *>(annotations[line].get())->style == IndividualStyles; 384 else 385 return false; 386 } 387 388 int LineAnnotation::Style(Sci::Line line) const noexcept { 389 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) 390 return reinterpret_cast<AnnotationHeader *>(annotations[line].get())->style; 391 else 392 return 0; 393 } 394 395 const char *LineAnnotation::Text(Sci::Line line) const noexcept { 396 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) 397 return annotations[line].get()+sizeof(AnnotationHeader); 398 else 399 return nullptr; 400 } 401 402 const unsigned char *LineAnnotation::Styles(Sci::Line line) const noexcept { 403 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line] && MultipleStyles(line)) 404 return reinterpret_cast<unsigned char *>(annotations[line].get() + sizeof(AnnotationHeader) + Length(line)); 405 else 406 return nullptr; 407 } 408 409 void LineAnnotation::SetText(Sci::Line line, const char *text) { 410 if (text && (line >= 0)) { 411 annotations.EnsureLength(line+1); 412 const int style = Style(line); 413 annotations[line] = AllocateAnnotation(strlen(text), style); 414 char *pa = annotations[line].get(); 415 assert(pa); 416 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(pa); 417 pah->style = static_cast<short>(style); 418 pah->length = static_cast<int>(strlen(text)); 419 pah->lines = static_cast<short>(NumberLines(text)); 420 memcpy(pa+sizeof(AnnotationHeader), text, pah->length); 421 } else { 422 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) { 423 annotations[line].reset(); 424 } 425 } 426 } 427 428 void LineAnnotation::ClearAll() { 429 annotations.DeleteAll(); 430 } 431 432 void LineAnnotation::SetStyle(Sci::Line line, int style) { 433 annotations.EnsureLength(line+1); 434 if (!annotations[line]) { 435 annotations[line] = AllocateAnnotation(0, style); 436 } 437 reinterpret_cast<AnnotationHeader *>(annotations[line].get())->style = static_cast<short>(style); 438 } 439 440 void LineAnnotation::SetStyles(Sci::Line line, const unsigned char *styles) { 441 if (line >= 0) { 442 annotations.EnsureLength(line+1); 443 if (!annotations[line]) { 444 annotations[line] = AllocateAnnotation(0, IndividualStyles); 445 } else { 446 const AnnotationHeader *pahSource = reinterpret_cast<AnnotationHeader *>(annotations[line].get()); 447 if (pahSource->style != IndividualStyles) { 448 std::unique_ptr<char[]>allocation = AllocateAnnotation(pahSource->length, IndividualStyles); 449 AnnotationHeader *pahAlloc = reinterpret_cast<AnnotationHeader *>(allocation.get()); 450 pahAlloc->length = pahSource->length; 451 pahAlloc->lines = pahSource->lines; 452 memcpy(allocation.get() + sizeof(AnnotationHeader), annotations[line].get() + sizeof(AnnotationHeader), pahSource->length); 453 annotations[line] = std::move(allocation); 454 } 455 } 456 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line].get()); 457 pah->style = IndividualStyles; 458 memcpy(annotations[line].get() + sizeof(AnnotationHeader) + pah->length, styles, pah->length); 459 } 460 } 461 462 int LineAnnotation::Length(Sci::Line line) const noexcept { 463 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) 464 return reinterpret_cast<AnnotationHeader *>(annotations[line].get())->length; 465 else 466 return 0; 467 } 468 469 int LineAnnotation::Lines(Sci::Line line) const noexcept { 470 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) 471 return reinterpret_cast<AnnotationHeader *>(annotations[line].get())->lines; 472 else 473 return 0; 474 } 475 476 LineTabstops::~LineTabstops() { 477 } 478 479 void LineTabstops::Init() { 480 tabstops.DeleteAll(); 481 } 482 483 void LineTabstops::InsertLine(Sci::Line line) { 484 if (tabstops.Length()) { 485 tabstops.EnsureLength(line); 486 tabstops.Insert(line, nullptr); 487 } 488 } 489 490 void LineTabstops::InsertLines(Sci::Line line, Sci::Line lines) { 491 if (tabstops.Length()) { 492 tabstops.EnsureLength(line); 493 tabstops.InsertEmpty(line, lines); 494 } 495 } 496 497 void LineTabstops::RemoveLine(Sci::Line line) { 498 if (tabstops.Length() > line) { 499 tabstops[line].reset(); 500 tabstops.Delete(line); 501 } 502 } 503 504 bool LineTabstops::ClearTabstops(Sci::Line line) noexcept { 505 if (line < tabstops.Length()) { 506 TabstopList *tl = tabstops[line].get(); 507 if (tl) { 508 tl->clear(); 509 return true; 510 } 511 } 512 return false; 513 } 514 515 bool LineTabstops::AddTabstop(Sci::Line line, int x) { 516 tabstops.EnsureLength(line + 1); 517 if (!tabstops[line]) { 518 tabstops[line] = std::make_unique<TabstopList>(); 519 } 520 521 TabstopList *tl = tabstops[line].get(); 522 if (tl) { 523 // tabstop positions are kept in order - insert in the right place 524 std::vector<int>::iterator it = std::lower_bound(tl->begin(), tl->end(), x); 525 // don't insert duplicates 526 if (it == tl->end() || *it != x) { 527 tl->insert(it, x); 528 return true; 529 } 530 } 531 return false; 532 } 533 534 int LineTabstops::GetNextTabstop(Sci::Line line, int x) const noexcept { 535 if (line < tabstops.Length()) { 536 TabstopList *tl = tabstops[line].get(); 537 if (tl) { 538 for (const int i : *tl) { 539 if (i > x) { 540 return i; 541 } 542 } 543 } 544 } 545 return 0; 546 } 547