Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
SyntaxColoring.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include <algorithm>
7#include <cctype>
8
9#include "SyntaxColoring.h"
10
11using namespace Stroika::Foundation;
12using namespace Stroika::Frameworks;
13using namespace Stroika::Frameworks::Led;
14
16
17#if qStroika_Frameworks_Led_SupportGDI
18
19using FontChangeStyleMarker = SyntaxColoringMarkerOwner::FontChangeStyleMarker;
20using ColoredStyleMarker = SyntaxColoringMarkerOwner::ColoredStyleMarker;
21
22/*
23 ********************************************************************************
24 ******************************** TrivialRGBSyntaxAnalyzer **********************
25 ********************************************************************************
26 */
27void TrivialRGBSyntaxAnalyzer::AdjustLookBackRange (TextStore* /*ts*/, size_t* /*lookBackStart*/, size_t* /*lookBackTo*/) const
28{
29}
30
31void TrivialRGBSyntaxAnalyzer::AddMarkers (TextStore* ts, TextInteractor* /*interactor*/, MarkerOwner* owner, size_t lookBackStart,
32 size_t lookBackTo, vector<Marker*>* appendNewMarkersToList) const
33{
34 RequireNotNull (ts);
35 Require (lookBackStart <= lookBackTo);
36
37 size_t len = lookBackTo - lookBackStart;
38 StackBuffer<Led_tChar> buf{Memory::eUninitialized, len};
39 ts->CopyOut (lookBackStart, len, buf.data ());
40 for (size_t i = 0; i < len; ++i) {
41 Led_tChar c = buf[i];
42 if (c == 'r' or c == 'R') {
43 Marker* m = new ColoredStyleMarker (Color::kRed);
44 ts->AddMarker (m, i + lookBackStart, 1, owner);
45 if (appendNewMarkersToList != NULL) {
46 appendNewMarkersToList->push_back (m);
47 }
48 }
49 if (c == 'g' or c == 'G') {
50 Marker* m = new ColoredStyleMarker (Color::kGreen);
51 ts->AddMarker (m, i + lookBackStart, 1, owner);
52 if (appendNewMarkersToList != NULL) {
53 appendNewMarkersToList->push_back (m);
54 }
55 }
56 if (c == 'b' or c == 'B') {
57 Marker* m = new ColoredStyleMarker (Color::kBlue);
58 ts->AddMarker (m, i + lookBackStart, 1, owner);
59 if (appendNewMarkersToList != NULL) {
60 appendNewMarkersToList->push_back (m);
61 }
62 }
63 }
64}
65
66/*
67 ********************************************************************************
68 ************************* TableDrivenKeywordSyntaxAnalyzer *********************
69 ********************************************************************************
70 */
71const Led_tChar* kCPlusPlusKeywordTable[] = {
72 //nb: do to quirky lookup code, arrange table so no prefixing keyword comes before
73 // longer one. Cuz we always match shortest one first!
74 LED_TCHAR_OF ("#define"),
75 LED_TCHAR_OF ("#ifdef"),
76 LED_TCHAR_OF ("#ifndef"),
77 LED_TCHAR_OF ("#if"),
78 LED_TCHAR_OF ("#else"),
79 LED_TCHAR_OF ("#elif"),
80 LED_TCHAR_OF ("#endif"),
81 LED_TCHAR_OF ("#include"),
82 LED_TCHAR_OF ("#pragma"),
83 LED_TCHAR_OF ("auto"),
84 LED_TCHAR_OF ("break"),
85 LED_TCHAR_OF ("bool"),
86 LED_TCHAR_OF ("case"),
87 LED_TCHAR_OF ("catch"),
88 LED_TCHAR_OF ("char"),
89 LED_TCHAR_OF ("const_cast"),
90 LED_TCHAR_OF ("const"),
91 LED_TCHAR_OF ("class"),
92 LED_TCHAR_OF ("continue"),
93 LED_TCHAR_OF ("default"),
94 LED_TCHAR_OF ("delete"),
95 LED_TCHAR_OF ("double"),
96 LED_TCHAR_OF ("do"),
97 LED_TCHAR_OF ("dynamic_cast"),
98 LED_TCHAR_OF ("else"),
99 LED_TCHAR_OF ("enum"),
100 LED_TCHAR_OF ("explicit"),
101 LED_TCHAR_OF ("extern"),
102 LED_TCHAR_OF ("false"),
103 LED_TCHAR_OF ("float"),
104 LED_TCHAR_OF ("for"),
105 LED_TCHAR_OF ("friend"),
106 LED_TCHAR_OF ("goto"),
107 LED_TCHAR_OF ("if"),
108 LED_TCHAR_OF ("inline"),
109 LED_TCHAR_OF ("int"),
110 LED_TCHAR_OF ("inherited"),
111 LED_TCHAR_OF ("long"),
112 LED_TCHAR_OF ("main"),
113 LED_TCHAR_OF ("mutable"),
114 LED_TCHAR_OF ("namespace"),
115 LED_TCHAR_OF ("new"),
116 LED_TCHAR_OF ("nonvirtual"),
117 LED_TCHAR_OF ("operator"),
118 LED_TCHAR_OF ("public"),
119 LED_TCHAR_OF ("private"),
120 LED_TCHAR_OF ("protected"),
121 LED_TCHAR_OF ("register"),
122 LED_TCHAR_OF ("reinterpret_cast"),
123 LED_TCHAR_OF ("return"),
124 LED_TCHAR_OF ("signed"),
125 LED_TCHAR_OF ("sizeof"),
126 LED_TCHAR_OF ("short"),
127 LED_TCHAR_OF ("struct"),
128 LED_TCHAR_OF ("static"),
129 LED_TCHAR_OF ("static_cast"),
130 LED_TCHAR_OF ("switch"),
131 LED_TCHAR_OF ("template"),
132 LED_TCHAR_OF ("this"),
133 LED_TCHAR_OF ("throw"),
134 LED_TCHAR_OF ("true"),
135 LED_TCHAR_OF ("try"),
136 LED_TCHAR_OF ("typedef"),
137 LED_TCHAR_OF ("typeid"),
138 LED_TCHAR_OF ("typename"),
139 LED_TCHAR_OF ("union"),
140 LED_TCHAR_OF ("unsigned"),
141 LED_TCHAR_OF ("using"),
142 LED_TCHAR_OF ("virtual"),
143 LED_TCHAR_OF ("volatile"),
144 LED_TCHAR_OF ("void"),
145 LED_TCHAR_OF ("while")};
146TableDrivenKeywordSyntaxAnalyzer::KeywordTable TableDrivenKeywordSyntaxAnalyzer::kCPlusPlusKeywords (kCPlusPlusKeywordTable,
147 Memory::NEltsOf (kCPlusPlusKeywordTable));
148
149const Led_tChar* kVisualBasicKeywordTable[] = {
150 //nb: do to quirky lookup code, arrange table so no prefixing keyword comes before
151 // longer one. Cuz we always match shortest one first!
152 LED_TCHAR_OF ("abs"),
153 LED_TCHAR_OF ("add"),
154 LED_TCHAR_OF ("+"),
155 LED_TCHAR_OF ("and"),
156 LED_TCHAR_OF ("array"),
157 LED_TCHAR_OF ("asc"),
158 LED_TCHAR_OF ("="),
159 LED_TCHAR_OF ("AtEndOfLine"),
160 LED_TCHAR_OF ("AtEndOfStream"),
161 LED_TCHAR_OF ("Atn"),
162 LED_TCHAR_OF ("Attributes"),
163 LED_TCHAR_OF ("AvailableSpace"),
164 LED_TCHAR_OF ("BuildPath"),
165 LED_TCHAR_OF ("Call"),
166 LED_TCHAR_OF ("Case"),
167 LED_TCHAR_OF ("CBool"),
168 LED_TCHAR_OF ("CByte"),
169 LED_TCHAR_OF ("CCur"),
170 LED_TCHAR_OF ("CDate"),
171 LED_TCHAR_OF ("CDbl"),
172 LED_TCHAR_OF ("Chr"),
173 LED_TCHAR_OF ("CInt"),
174 LED_TCHAR_OF ("Clear"),
175 LED_TCHAR_OF ("CLng"),
176 LED_TCHAR_OF ("Close"),
177 LED_TCHAR_OF ("Column"),
178 LED_TCHAR_OF ("CompareMode"),
179 LED_TCHAR_OF ("&"),
180 LED_TCHAR_OF ("Const"),
181 LED_TCHAR_OF ("CopyFile"),
182 LED_TCHAR_OF ("CopyFolder"),
183 LED_TCHAR_OF ("Copy"),
184 LED_TCHAR_OF ("Cos"),
185 LED_TCHAR_OF ("Count"),
186 LED_TCHAR_OF ("CreateFolder"),
187 LED_TCHAR_OF ("CreateObject"),
188 LED_TCHAR_OF ("CreateTextFile"),
189 LED_TCHAR_OF ("CSng"),
190 LED_TCHAR_OF ("CStr"),
191 LED_TCHAR_OF ("DateAddFunction"),
192 LED_TCHAR_OF ("DateCreated"),
193 LED_TCHAR_OF ("DateDiff"),
194 LED_TCHAR_OF ("DateLastAccessed"),
195 LED_TCHAR_OF ("DateLastModified"),
196 LED_TCHAR_OF ("DatePart"),
197 LED_TCHAR_OF ("DateSerial"),
198 LED_TCHAR_OF ("DateValue"),
199 LED_TCHAR_OF ("Date"),
200 LED_TCHAR_OF ("Day"),
201 LED_TCHAR_OF ("DeleteFile"),
202 LED_TCHAR_OF ("DeleteFolder"),
203 LED_TCHAR_OF ("Delete"),
204 LED_TCHAR_OF ("Description"),
205 LED_TCHAR_OF ("Dictionary"),
206 LED_TCHAR_OF ("Dim"),
207 LED_TCHAR_OF ("Division"),
208 LED_TCHAR_OF ("Do"),
209 LED_TCHAR_OF ("DriveExists"),
210 LED_TCHAR_OF ("DriveLetter"),
211 LED_TCHAR_OF ("DriveType"),
212 LED_TCHAR_OF ("Drives"),
213 LED_TCHAR_OF ("Drive"),
214 LED_TCHAR_OF ("Each"),
215 LED_TCHAR_OF ("Empty"),
216 LED_TCHAR_OF ("Eqv"),
217 LED_TCHAR_OF ("Else"),
218 LED_TCHAR_OF ("Err"),
219 LED_TCHAR_OF ("Erase"),
220 LED_TCHAR_OF ("Exists"),
221 LED_TCHAR_OF ("Exit"),
222 LED_TCHAR_OF ("Explicit"),
223 LED_TCHAR_OF ("Exp"),
224 LED_TCHAR_OF ("^"),
225 LED_TCHAR_OF ("False"),
226 LED_TCHAR_OF ("FileExists"),
227 LED_TCHAR_OF ("FileSystemObject"),
228 LED_TCHAR_OF ("FileSystem"),
229 LED_TCHAR_OF ("Files"),
230 LED_TCHAR_OF ("File"),
231 LED_TCHAR_OF ("Filter"),
232 LED_TCHAR_OF ("Fix"),
233 LED_TCHAR_OF ("Folders"),
234 LED_TCHAR_OF ("FolderExists"),
235 LED_TCHAR_OF ("Folder"),
236 LED_TCHAR_OF ("FormatCurrency"),
237 LED_TCHAR_OF ("FormatDateTime"),
238 LED_TCHAR_OF ("FormatNumber"),
239 LED_TCHAR_OF ("FormatPercent"),
240 LED_TCHAR_OF ("For"),
241 LED_TCHAR_OF ("FreeSpace"),
242 LED_TCHAR_OF ("Function"),
243 LED_TCHAR_OF ("GetAbsolutePathName"),
244 LED_TCHAR_OF ("GetBaseName"),
245 LED_TCHAR_OF ("GetDriveName"),
246 LED_TCHAR_OF ("GetDrive"),
247 LED_TCHAR_OF ("GetExtensionName"),
248 LED_TCHAR_OF ("GetFileName"),
249 LED_TCHAR_OF ("GetFile"),
250 LED_TCHAR_OF ("GetFolder"),
251 LED_TCHAR_OF ("GetObject"),
252 LED_TCHAR_OF ("GetParentFolderName"),
253 LED_TCHAR_OF ("GetSpecialFolder"),
254 LED_TCHAR_OF ("GetTempName"),
255 LED_TCHAR_OF ("Hex"),
256 LED_TCHAR_OF ("HelpContext"),
257 LED_TCHAR_OF ("HelpFile"),
258 LED_TCHAR_OF ("Hour"),
259 LED_TCHAR_OF ("If"),
260 LED_TCHAR_OF ("Imp"),
261 LED_TCHAR_OF ("InputBox"),
262 LED_TCHAR_OF ("InStrRev"),
263 LED_TCHAR_OF ("InStr"),
264 LED_TCHAR_OF ("Int"),
265 LED_TCHAR_OF ("\\"),
266 LED_TCHAR_OF ("IsArray"),
267 LED_TCHAR_OF ("IsDate"),
268 LED_TCHAR_OF ("IsEmpty"),
269 LED_TCHAR_OF ("IsNull"),
270 LED_TCHAR_OF ("IsNumeric"),
271 LED_TCHAR_OF ("IsObject"),
272 LED_TCHAR_OF ("IsReady"),
273 LED_TCHAR_OF ("IsRootFolder"),
274 LED_TCHAR_OF ("Is"),
275 LED_TCHAR_OF ("Items"),
276 LED_TCHAR_OF ("Item"),
277 LED_TCHAR_OF ("Join"),
278 LED_TCHAR_OF ("Keys"),
279 LED_TCHAR_OF ("Key"),
280 LED_TCHAR_OF ("LBound"),
281 LED_TCHAR_OF ("LCase"),
282 LED_TCHAR_OF ("Left"),
283 LED_TCHAR_OF ("Len"),
284 LED_TCHAR_OF ("Line"),
285 LED_TCHAR_OF ("LoadPicture"),
286 LED_TCHAR_OF ("Log"),
287 LED_TCHAR_OF ("Loop"),
288 LED_TCHAR_OF ("LTrim"),
289 LED_TCHAR_OF ("Mid"),
290 LED_TCHAR_OF ("Minute"),
291 LED_TCHAR_OF ("Mod"),
292 LED_TCHAR_OF ("MonthName"),
293 LED_TCHAR_OF ("Month"),
294 LED_TCHAR_OF ("MoveFile"),
295 LED_TCHAR_OF ("MoveFolder"),
296 LED_TCHAR_OF ("Move"),
297 LED_TCHAR_OF ("MsgBox"),
298 LED_TCHAR_OF ("*"),
299 LED_TCHAR_OF ("Name"),
300 LED_TCHAR_OF ("Next"),
301 LED_TCHAR_OF ("-"),
302 LED_TCHAR_OF ("Nothing"),
303 LED_TCHAR_OF ("Not"),
304 LED_TCHAR_OF ("Now"),
305 LED_TCHAR_OF ("Null"),
306 LED_TCHAR_OF ("Number"),
307 LED_TCHAR_OF ("Oct"),
308 LED_TCHAR_OF ("On"),
309 LED_TCHAR_OF ("OpenAsTextStream"),
310 LED_TCHAR_OF ("OpenTextFile"),
311 LED_TCHAR_OF ("Option"),
312 LED_TCHAR_OF ("Or"),
313 LED_TCHAR_OF ("ParentFolder"),
314 LED_TCHAR_OF ("Path"),
315 LED_TCHAR_OF ("Private"),
316 LED_TCHAR_OF ("Public"),
317 LED_TCHAR_OF ("Raise"),
318 LED_TCHAR_OF ("Randomize"),
319 LED_TCHAR_OF ("ReadAll"),
320 LED_TCHAR_OF ("ReadLine"),
321 LED_TCHAR_OF ("Read"),
322 LED_TCHAR_OF ("ReDim"),
323 LED_TCHAR_OF ("RemoveAll"),
324 LED_TCHAR_OF ("Remove"),
325 LED_TCHAR_OF ("Rem"),
326 LED_TCHAR_OF ("Replace"),
327 LED_TCHAR_OF ("RGB"),
328 LED_TCHAR_OF ("Right"),
329 LED_TCHAR_OF ("Rnd"),
330 LED_TCHAR_OF ("RootFolder"),
331 LED_TCHAR_OF ("Round"),
332 LED_TCHAR_OF ("RTrim"),
333 LED_TCHAR_OF ("ScriptEngineBuildVersion"),
334 LED_TCHAR_OF ("ScriptEngineMajorVersion"),
335 LED_TCHAR_OF ("ScriptEngineMinorVersion"),
336 LED_TCHAR_OF ("ScriptEngine"),
337 LED_TCHAR_OF ("Second"),
338 LED_TCHAR_OF ("Select"),
339 LED_TCHAR_OF ("SerialNumber"),
340 LED_TCHAR_OF ("Set"),
341 LED_TCHAR_OF ("Sgn"),
342 LED_TCHAR_OF ("ShareName"),
343 LED_TCHAR_OF ("ShortName"),
344 LED_TCHAR_OF ("ShortPath"),
345 LED_TCHAR_OF ("Sin"),
346 LED_TCHAR_OF ("Size"),
347 LED_TCHAR_OF ("SkipLine"),
348 LED_TCHAR_OF ("Skip"),
349 LED_TCHAR_OF ("Source"),
350 LED_TCHAR_OF ("Space"),
351 LED_TCHAR_OF ("Split"),
352 LED_TCHAR_OF ("Sqr"),
353 LED_TCHAR_OF ("StrComp"),
354 LED_TCHAR_OF ("String"),
355 LED_TCHAR_OF ("StrReverse"),
356 LED_TCHAR_OF ("SubFolders"),
357 LED_TCHAR_OF ("Sub"),
358 LED_TCHAR_OF ("-"),
359 LED_TCHAR_OF ("Tan"),
360 LED_TCHAR_OF ("TextStream"),
361 LED_TCHAR_OF ("TimeSerial"),
362 LED_TCHAR_OF ("TimeValue"),
363 LED_TCHAR_OF ("Time"),
364 LED_TCHAR_OF ("Then"),
365 LED_TCHAR_OF ("TotalSize"),
366 LED_TCHAR_OF ("Trim"),
367 LED_TCHAR_OF ("True"),
368 LED_TCHAR_OF ("TypeName"),
369 LED_TCHAR_OF ("Type"),
370 LED_TCHAR_OF ("UBound"),
371 LED_TCHAR_OF ("UCase"),
372 LED_TCHAR_OF ("VarType"),
373 LED_TCHAR_OF ("VolumeName"),
374 LED_TCHAR_OF ("WeekdayName"),
375 LED_TCHAR_OF ("Weekday"),
376 LED_TCHAR_OF ("While"),
377 LED_TCHAR_OF ("Wend"),
378 LED_TCHAR_OF ("WriteBlankLines"),
379 LED_TCHAR_OF ("WriteLine"),
380 LED_TCHAR_OF ("Write"),
381 LED_TCHAR_OF ("Xor"),
382 LED_TCHAR_OF ("Year"),
383};
384TableDrivenKeywordSyntaxAnalyzer::KeywordTable
385 TableDrivenKeywordSyntaxAnalyzer::kVisualBasicKeywords (kVisualBasicKeywordTable, Memory::NEltsOf (kVisualBasicKeywordTable), Led_tStrniCmp);
386
387TableDrivenKeywordSyntaxAnalyzer::TableDrivenKeywordSyntaxAnalyzer (const KeywordTable& keyTable)
388 : inherited ()
389 , fKeywordTable (keyTable)
390{
391}
392
393void TableDrivenKeywordSyntaxAnalyzer::AdjustLookBackRange (TextStore* ts, size_t* lookBackStart, size_t* lookBackTo) const
394{
395 RequireNotNull (ts);
396 RequireNotNull (lookBackStart);
397 RequireNotNull (lookBackTo);
398 Require (*lookBackStart <= *lookBackTo);
399
400 // Now adjust for scanning algorithm sluff
401 // for our trivial keyword stuff, only look back at most one keyword length
402 *lookBackStart = max (0, int (*lookBackStart) - int (fKeywordTable.MaxKeywordLength () - 1));
403 *lookBackTo = min (ts->GetEnd (), *lookBackTo + fKeywordTable.MaxKeywordLength () - 1);
404 Ensure (*lookBackStart <= *lookBackTo);
405}
406
407void TableDrivenKeywordSyntaxAnalyzer::AddMarkers (TextStore* ts, TextInteractor* interactor, MarkerOwner* owner, size_t lookBackStart,
408 size_t lookBackTo, vector<Marker*>* appendNewMarkersToList) const
409{
410 RequireNotNull (ts);
411 RequireNotNull (interactor);
412 Require (lookBackStart <= lookBackTo);
413
414 size_t len = lookBackTo - lookBackStart;
415 StackBuffer<Led_tChar> buf{Memory::eUninitialized, len};
416 ts->CopyOut (lookBackStart, len, buf.data ());
417 for (size_t i = 0; i < len; ++i) {
418 size_t kwl = fKeywordTable.KeywordLength (&buf[i], len - i);
419 if (kwl != 0) {
420 // Check if preceeding and following characters look like delimiters
421 {
422 size_t pc = ts->FindPreviousCharacter (i + lookBackStart);
423 if (pc < i + lookBackStart) {
424 Led_tChar c;
425 ts->CopyOut (pc, 1, &c);
426 if (not isspace (c) and not ispunct (c)) {
427 continue;
428 }
429 }
430 if (i + lookBackStart + kwl < ts->GetEnd ()) {
431 Led_tChar c;
432 ts->CopyOut (i + lookBackStart + kwl, 1, &c);
433 if (not isspace (c) and not ispunct (c)) {
434 continue;
435 }
436 }
437 }
438
439 Marker* m = new ColoredStyleMarker (Color::kBlue);
440 ts->AddMarker (m, i + lookBackStart, kwl, owner);
441 // could be far more efficient, and keep markers in sorted order, but this is easier
442 if (appendNewMarkersToList != NULL) {
443 appendNewMarkersToList->push_back (m);
444 }
445 i += kwl - 1;
446 interactor->Refresh (m, TextInteractor::eDelayedUpdate);
447 }
448 }
449}
450
451/*
452 ********************************************************************************
453 ************************** SyntaxColoringMarkerOwner ***************************
454 ********************************************************************************
455 */
456SyntaxColoringMarkerOwner::SyntaxColoringMarkerOwner (TextInteractor& interactor, TextStore& textStore, const SyntaxAnalyzer& syntaxAnalyzer)
457 : inherited ()
458 , fInteractor (interactor)
459 , fTextStore (textStore)
460 , fSyntaxAnalyzer (syntaxAnalyzer)
461{
462 fTextStore.AddMarkerOwner (this);
463}
464
465SyntaxColoringMarkerOwner::~SyntaxColoringMarkerOwner ()
466{
467 fTextStore.RemoveMarkerOwner (this);
468}
469
470TextStore* SyntaxColoringMarkerOwner::PeekAtTextStore () const
471{
472 return &fTextStore;
473}
474
475void SyntaxColoringMarkerOwner::RecheckAll ()
476{
477 RecheckRange (fTextStore.GetStart (), fTextStore.GetEnd ());
478}
479
480/*
481 ********************************************************************************
482 ************************* SimpleSyntaxColoringMarkerOwner **********************
483 ********************************************************************************
484 */
485SimpleSyntaxColoringMarkerOwner::SimpleSyntaxColoringMarkerOwner (TextInteractor& interactor, TextStore& textStore, const SyntaxAnalyzer& syntaxAnalyzer)
486 : inherited (interactor, textStore, syntaxAnalyzer)
487 , fMarkers ()
488{
489}
490
491SimpleSyntaxColoringMarkerOwner::~SimpleSyntaxColoringMarkerOwner ()
492{
493 GetTextStore ().RemoveMarkers (&(*fMarkers.begin ()), fMarkers.size ());
494 for (size_t i = 0; i < fMarkers.size (); ++i) {
495 delete (fMarkers[i]);
496 }
497 fInteractor.Refresh ();
498}
499
500void SimpleSyntaxColoringMarkerOwner::DidUpdateText (const UpdateInfo& updateInfo) noexcept
501{
502 inherited::DidUpdateText (updateInfo);
503 RecheckRange (updateInfo.fReplaceFrom, updateInfo.fReplaceFrom + updateInfo.fTextLength);
504}
505
506void SimpleSyntaxColoringMarkerOwner::RecheckRange (size_t updateFrom, size_t updateTo)
507{
508 Require (updateFrom <= updateTo);
509
510 /*
511 * We must compute a bounds which must be re-analyzed (based on what was updated).
512 * Then we must walk our marker array, and eliminate any inappropriate ones. And we must
513 * the create any NEW appropriate ones.
514 *
515 * How far back you must search will depend on the nature of your lexical analysis.
516 */
517 size_t lookBackStart = updateFrom;
518 size_t lookBackTo = updateTo;
519 Assert (lookBackStart <= lookBackTo);
520 fSyntaxAnalyzer.AdjustLookBackRange (&fTextStore, &lookBackStart, &lookBackTo);
521 Assert (lookBackStart <= lookBackTo);
522
523 // eliminate any invalidated markers.
524 {
525 for (size_t i = 0; i < fMarkers.size ();) {
526 Marker* m = fMarkers[i];
527 AssertNotNull (m);
528 DISABLE_COMPILER_MSC_WARNING_START (28182)
529 if ((lookBackStart <= m->GetStart () and m->GetEnd () <= lookBackTo) or m->GetLength () == 0) {
530 // This update is needed cuz Led's normal typing update might not extend as far as the effect of
531 // this change in styled text (coloring) might.
532 fInteractor.Refresh (m, TextInteractor::eDelayedUpdate);
533
534 // NB: we only remove them here, and don't invalidate their region cuz they were zero sized.
535 // Invaling wouldn't hurt, but just a waste of time.
536 fTextStore.RemoveMarker (m);
537 delete m;
538 fMarkers.erase (fMarkers.begin () + i);
539 continue;
540 }
541 DISABLE_COMPILER_MSC_WARNING_END (28182)
542 ++i;
543 }
544 }
545
546 fSyntaxAnalyzer.AddMarkers (&fTextStore, &fInteractor, this, lookBackStart, lookBackTo, &fMarkers);
547}
548
549/*
550 ********************************************************************************
551 *************************** WindowedSyntaxColoringMarkerOwner ******************
552 ********************************************************************************
553 */
554WindowedSyntaxColoringMarkerOwner::WindowedSyntaxColoringMarkerOwner (TextInteractor& interactor, TextStore& textStore, const SyntaxAnalyzer& syntaxAnalyzer)
555 : inherited (interactor, textStore, syntaxAnalyzer)
556 , fMarkers ()
557 , fDeletedLines (false)
558 , fCachedWindowStart (0)
559 , fCachedWindowEnd (0)
560{
561}
562
563WindowedSyntaxColoringMarkerOwner::~WindowedSyntaxColoringMarkerOwner ()
564{
565 GetTextStore ().RemoveMarkers (&(*fMarkers.begin ()), fMarkers.size ());
566 for (size_t i = 0; i < fMarkers.size (); ++i) {
567 delete (fMarkers[i]);
568 }
569 fInteractor.Refresh ();
570}
571
572void WindowedSyntaxColoringMarkerOwner::RecheckScrolling ()
573{
574 // could be smarter and cache old window boundaries, but lets cheap out, and do the simple thing
575 // for now. After all, this is just a demo...
576 //RecheckAll ();
577 size_t windowStart = fInteractor.GetMarkerPositionOfStartOfWindow ();
578 size_t windowEnd = fInteractor.GetMarkerPositionOfEndOfWindow ();
579 // Any amount scrolled OFF screen we don't need to check cuz the RecheckRange () algorithm will
580 // automatically blow anything away it can off screen. All we need todo is
581 // see what NEW stuff is being displayed, and assure AT LEAST THAT gets checked for new
582 // hilight markers.
583 size_t checkStart = windowStart;
584 size_t checkEnd = windowEnd;
585 if (fCachedWindowEnd >= checkEnd and fCachedWindowStart < checkEnd) {
586 checkEnd = fCachedWindowStart;
587 }
588 if (fCachedWindowStart <= checkStart and fCachedWindowEnd > checkStart) {
589 checkStart = fCachedWindowEnd;
590 }
591 if (checkStart < checkEnd) {
592 RecheckRange (checkStart, checkEnd);
593 }
594}
595
596void WindowedSyntaxColoringMarkerOwner::AboutToUpdateText (const UpdateInfo& updateInfo)
597{
598 inherited::AboutToUpdateText (updateInfo);
599 // If we're deleting any NLs, set flag, so on later DidUpdate (), we will recheck all, cuz we must
600 // also check newly scrolled onto screen rows.
601 if (updateInfo.fTextModified) {
602 size_t len = updateInfo.fReplaceTo - updateInfo.fReplaceFrom;
603 StackBuffer<Led_tChar> buf{Memory::eUninitialized, len};
604 fTextStore.CopyOut (updateInfo.fReplaceFrom, len, buf.data ());
605 for (size_t i = 0; i < len; ++i) {
606 Led_tChar c = buf[i];
607 if (c == '\n') {
608 fDeletedLines = true;
609 break;
610 }
611 }
612 }
613}
614
615void WindowedSyntaxColoringMarkerOwner::DidUpdateText (const UpdateInfo& updateInfo) noexcept
616{
617 inherited::DidUpdateText (updateInfo);
618 if (fDeletedLines) {
619 fDeletedLines = false;
620 RecheckAll ();
621 }
622 else {
623 RecheckRange (updateInfo.fReplaceFrom, updateInfo.fReplaceFrom + updateInfo.fTextLength);
624 }
625}
626
627void WindowedSyntaxColoringMarkerOwner::RecheckRange (size_t updateFrom, size_t updateTo)
628{
629 Require (updateFrom <= updateTo);
630
631 /*
632 * We must compute a bounds which must be re-analyzed (based on what was updated).
633 * Then we must walk our marker array, and eliminate any inappropriate ones. And we must
634 * the create any NEW appropriate ones.
635 *
636 * How far back you must search will depend on the nature of your lexical analysis.
637 */
638 size_t windowStart = fInteractor.GetMarkerPositionOfStartOfWindow ();
639 size_t windowEnd = fInteractor.GetMarkerPositionOfEndOfWindow ();
640
641 size_t lookBackStart = updateFrom;
642 size_t lookBackTo = updateTo;
643
644 // never bother looking outside the window
645 lookBackStart = max (lookBackStart, windowStart);
646 lookBackTo = min (lookBackTo, windowEnd);
647 lookBackTo = max (lookBackTo, lookBackStart); // assure lookBackStart <= lookBackTo
648
649 Assert (lookBackStart <= lookBackTo);
650 fSyntaxAnalyzer.AdjustLookBackRange (&fTextStore, &lookBackStart, &lookBackTo);
651 Assert (lookBackStart <= lookBackTo);
652
653 // eliminate any invalidated markers.
654 {
655 for (size_t i = 0; i < fMarkers.size ();) {
656 Marker* m = fMarkers[i];
657 AssertNotNull (m);
658 DISABLE_COMPILER_MSC_WARNING_START (28182)
659 if ((lookBackStart <= m->GetStart () and m->GetEnd () <= lookBackTo) or
660 (m->GetEnd () <= windowStart or m->GetStart () >= windowEnd) or m->GetLength () == 0) {
661
662 // This update is needed cuz Led's normal typing update might not extend as far as the effect of
663 // this change in styled text (coloring) might.
664 fInteractor.Refresh (m, TextInteractor::eDelayedUpdate);
665
666 // NB: we only remove them here, and don't invalidate their region cuz they were zero sized or
667 // outside the window. Invaling wouldn't hurt, but just a waste of time.
668 fTextStore.RemoveMarker (m);
669 delete m;
670 fMarkers.erase (fMarkers.begin () + i);
671 continue;
672 }
673 DISABLE_COMPILER_MSC_WARNING_END (28182)
674 ++i;
675 }
676 }
677
678 fSyntaxAnalyzer.AddMarkers (&fTextStore, &fInteractor, this, lookBackStart, lookBackTo, &fMarkers);
679
680 fCachedWindowStart = windowStart;
681 fCachedWindowEnd = windowEnd;
682}
683
684/*
685 ********************************************************************************
686 ******************************** ColoredStyleMarker ****************************
687 ********************************************************************************
688 */
689FontSpecification ColoredStyleMarker::MakeFontSpec (const StyledTextImager* imager, const StyleRunElement& /*runElement*/) const
690{
691 RequireNotNull (imager);
692 FontSpecification fsp = imager->GetDefaultFont ();
693 fsp.SetTextColor (fColor);
694 return fsp;
695}
696#endif
#define AssertNotNull(p)
Definition Assertions.h:333
#define RequireNotNull(p)
Definition Assertions.h:347
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...