Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
SyntaxColoring.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Frameworks_Led_SyntaxColoring_h_
5#define _Stroika_Frameworks_Led_SyntaxColoring_h_ 1
6
7/*
8@MODULE: SyntaxColoring
9@DESCRIPTION:
10 <p>The basic idea is that we will be - to some extent - mimicking the implementation of
11 @'StandardStyledTextImager'.
12 Recall that the class @'StyledTextImager' is what provides the basic infrastructure
13 for displaying styled text.
14 It introduces the special marker class @'StyledTextImager::StyleMarker' - which we can subclass todo
15 our own kind of special display of text.
16 And @'StandardStyledTextImager' simply leverages off this generic implementation, and maintains a database
17 of non-overlapping StyleMarkers according to the usual editing, and style application conventions most
18 standard text editing packages support (eg. apply style to region of text etc).
19 </p>
20
21 <p>Where we will diverge, is that we won't generate our style markers from external function calls or UI commands.
22 Instead, we will programmaticly generate the style markers ourselves based on a simple
23 lexical analysis of the text (@'SyntaxAnalyzer').
24 </p>
25 */
26
27#include "Stroika/Frameworks/StroikaPreComp.h"
28
29#include "Stroika/Frameworks/Led/StyledTextImager.h"
30#include "Stroika/Frameworks/Led/Support.h"
31#include "Stroika/Frameworks/Led/TextInteractor.h"
32
33namespace Stroika::Frameworks::Led {
34
35#if qStroika_Frameworks_Led_SupportGDI
36
37 /*
38 @CLASS: SyntaxAnalyzer
39 @DESCRIPTION: <p>This abstract class is the basic for defining the rules for hooking in arbitrary syntactical analyses into the
40 syntax coloring code.</p>
41 <p>See the @'TrivialRGBSyntaxAnalyzer' class as a trivial example, and the @'TableDrivenKeywordSyntaxAnalyzer' as a more
42 useful starting point for various syntax coloring strategies.</p>
43 */
44 class SyntaxAnalyzer {
45 public:
46 virtual void AdjustLookBackRange (TextStore* ts, size_t* lookBackStart, size_t* lookBackTo) const = 0;
47 virtual void AddMarkers (TextStore* ts, TextInteractor* interactor, MarkerOwner* owner, size_t lookBackStart, size_t lookBackTo,
48 vector<Marker*>* appendNewMarkersToList) const = 0;
49 };
50
51 /*
52 @CLASS: TrivialRGBSyntaxAnalyzer
53 @BASES: @'SyntaxAnalyzer'
54 @DESCRIPTION: <p>A simple example @'SyntaxAnalyzer', which demonstrates the little you need todo to hook in your own
55 syntax analysis rules.</p>
56 */
57 class TrivialRGBSyntaxAnalyzer : public SyntaxAnalyzer {
58 public:
59 virtual void AdjustLookBackRange (TextStore* ts, size_t* lookBackStart, size_t* lookBackTo) const override;
60 virtual void AddMarkers (TextStore* ts, TextInteractor* interactor, MarkerOwner* owner, size_t lookBackStart, size_t lookBackTo,
61 vector<Marker*>* appendNewMarkersToList) const override;
62 };
63
64 /*
65 @CLASS: TableDrivenKeywordSyntaxAnalyzer
66 @BASES: @'SyntaxAnalyzer'
67 @DESCRIPTION: <p>A simple table-driven @'SyntaxAnalyzer', which looks up keywords from (constructor argument) tables.
68 The elements of the argument table can be in any order - but no initial substring of a later string can come before
69 an earlier one. You can specify an arbitrary compare function for matching keywords - but the two most obtious are
70 @'Led_tStrnCmp' and @'Led_tStrniCmp'.</p>
71 <p>This class also has two pre-built static tables for two common syntax coloring cases you may want to use,
72 or start from: kCPlusPlusKeywords and kVisualBasicKeywords.</p>
73 */
74 class TableDrivenKeywordSyntaxAnalyzer : public SyntaxAnalyzer {
75 private:
76 using inherited = SyntaxAnalyzer;
77
78 public:
79 class KeywordTable {
80 public:
81 KeywordTable (const Led_tChar* keyWords[], size_t nKeywords, int (*cmpFunction) (const Led_tChar*, const Led_tChar*, size_t) = Led_tStrnCmp);
82
83 public:
84 nonvirtual size_t MaxKeywordLength () const;
85 nonvirtual size_t KeywordLength (const Led_tChar* t, size_t nTChars) const;
86
87 private:
88 const Led_tChar** fKeywords;
89 size_t fNKeywords;
90 size_t fMaxKeywordLength;
91 int (*fCmpFunction) (const Led_tChar*, const Led_tChar*, size_t);
92 };
93
94 public:
95 static KeywordTable kCPlusPlusKeywords;
96 static KeywordTable kVisualBasicKeywords;
97
98 public:
99 TableDrivenKeywordSyntaxAnalyzer (const KeywordTable& keyTable);
100
101 public:
102 virtual void AdjustLookBackRange (TextStore* ts, size_t* lookBackStart, size_t* lookBackTo) const override;
103 virtual void AddMarkers (TextStore* ts, TextInteractor* interactor, MarkerOwner* owner, size_t lookBackStart, size_t lookBackTo,
104 vector<Marker*>* appendNewMarkersToList) const override;
105
106 private:
107 KeywordTable fKeywordTable;
108 };
109
110 /*
111 @CLASS: SyntaxColoringMarkerOwner
112 @DESCRIPTION: <p>An abstract class for controling the basic syntax coloring functionality. Try one of the subclasses,
113 like @'SimpleSyntaxColoringMarkerOwner or @'WindowedSyntaxColoringMarkerOwner'.</p>
114 <p>This class is usually used by instantiating a concrete subclass in your @'TextImager::HookGainedNewTextStore' override,
115 and then destroyed in your @'TextImager::HookLosingTextStore' override.
116 You must also override @'TextImager::TabletChangedMetrics' to @'SyntaxColoringMarkerOwner::RecheckAll'.</p>
117 */
118 class SyntaxColoringMarkerOwner : public MarkerOwner {
119 private:
120 using inherited = MarkerOwner;
121
122 public:
123 SyntaxColoringMarkerOwner (TextInteractor& interactor, TextStore& textStore, const SyntaxAnalyzer& syntaxAnalyzer);
124 virtual ~SyntaxColoringMarkerOwner ();
125
126 public:
127 nonvirtual void RecheckAll ();
128
129 protected:
130 virtual void RecheckRange (size_t updateFrom, size_t updateTo) = 0;
131
132 public:
133 class ColoredStyleMarker;
134
135 public:
136 /*
137 @CLASS: SyntaxColoringMarkerOwner::FontChangeStyleMarker
138 @BASES: @'TrivialFontSpecStyleMarker'
139 @DESCRIPTION: <p>This is used internally by the syntax coloring code, and is exposed only in case you want to write your own
140 Syntax Analyzer code. This simply takes a @'FontSpecification' object and applies that to the given text.</p>
141 */
142 using FontChangeStyleMarker = TrivialFontSpecStyleMarker;
143
144 public:
145 virtual TextStore* PeekAtTextStore () const override;
146
147 protected:
148 TextInteractor& fInteractor;
149 TextStore& fTextStore;
150 const SyntaxAnalyzer& fSyntaxAnalyzer;
151 };
152
153 /*
154 @CLASS: SimpleSyntaxColoringMarkerOwner
155 @BASES: @'SyntaxColoringMarkerOwner'
156 @DESCRIPTION: <p>A simple but effective brute-force coloring algorithm. This simply colors the entire document.
157 And when any part of the document changes - this simply recolors the document. This runs very quickly. But
158 for large documents, where you may never scroll to view large subsets of the document (or where you need to be able
159 to open quickly) - this may not be your best choice.</p>
160 <p>See also @'WindowedSyntaxColoringMarkerOwner'.</p>
161 */
162 class SimpleSyntaxColoringMarkerOwner : public SyntaxColoringMarkerOwner {
163 private:
164 using inherited = SyntaxColoringMarkerOwner;
165
166 public:
167 SimpleSyntaxColoringMarkerOwner (TextInteractor& interactor, TextStore& textStore, const SyntaxAnalyzer& syntaxAnalyzer);
168 virtual ~SimpleSyntaxColoringMarkerOwner ();
169
170 protected:
171 virtual void RecheckRange (size_t updateFrom, size_t updateTo) override;
172
173 public:
174 virtual void DidUpdateText (const UpdateInfo& updateInfo) noexcept override;
175
176 private:
177 vector<Marker*> fMarkers;
178 };
179
180 /*
181 @CLASS: WindowedSyntaxColoringMarkerOwner
182 @BASES: @'SyntaxColoringMarkerOwner'
183 @DESCRIPTION: <p>This @'SyntaxColoringMarkerOwner' tries to be clever about what areas to syntax analyze. It only analyzes
184 the current window. This makes for very fast opening of large documents (independent of actual file size). But it can make
185 typing and scrolling somewhat slower. This really doesn't matter as long as its faster than some particular user-measurable
186 threshold. I think on a 400Mz or faster Pentium machine - this will always be fast enuf to be a better choice than
187 @'SimpleSyntaxColoringMarkerOwner'. But you can easily try both, and see for yourself.</p>
188 <p>In addition to settup according to the docs in @'SyntaxColoringMarkerOwner' - you must also override @'TextInteractor::UpdateScrollBars' to
189 call @'WindowedSyntaxColoringMarkerOwner::RecheckScrolling'.</p>
190 <p>See also @'SimpleSyntaxColoringMarkerOwner'.</p>
191 */
192 class WindowedSyntaxColoringMarkerOwner : public SyntaxColoringMarkerOwner {
193 private:
194 using inherited = SyntaxColoringMarkerOwner;
195
196 public:
197 WindowedSyntaxColoringMarkerOwner (TextInteractor& interactor, TextStore& textStore, const SyntaxAnalyzer& syntaxAnalyzer);
198 virtual ~WindowedSyntaxColoringMarkerOwner ();
199
200 public:
201 nonvirtual void RecheckScrolling ();
202
203 protected:
204 virtual void RecheckRange (size_t updateFrom, size_t updateTo) override;
205
206 public:
207 virtual void AboutToUpdateText (const UpdateInfo& updateInfo) override;
208 virtual void DidUpdateText (const UpdateInfo& updateInfo) noexcept override;
209
210 private:
211 vector<Marker*> fMarkers;
212 bool fDeletedLines;
213 // scrolling speed tweek - so we don't inval too much!
214 size_t fCachedWindowStart;
215 size_t fCachedWindowEnd;
216 };
217
218 /*
219 @CLASS: SyntaxColoringMarkerOwner::ColoredStyleMarker
220 @BASES: @'SimpleStyleMarkerByFontSpec'
221 @DESCRIPTION: <p>This is used internally by the syntax coloring code, and is exposed only in case you want to write your own
222 Syntax Analyzer code. This simply takes a @'Color' object and uses that to color the given text.</p>
223 */
224 class SyntaxColoringMarkerOwner::ColoredStyleMarker : public SimpleStyleMarkerByFontSpec<>,
225 public Foundation::Memory::UseBlockAllocationIfAppropriate<ColoredStyleMarker> {
226 private:
227 using inherited = SimpleStyleMarkerByFontSpec<>;
228
229 public:
230 ColoredStyleMarker (const Color& color);
231
232 protected:
233 virtual FontSpecification MakeFontSpec (const StyledTextImager* imager, const StyleRunElement& runElement) const override;
234
235 public:
236 Color fColor;
237 };
238#endif
239
240}
241
242/*
243 ********************************************************************************
244 ***************************** Implementation Details ***************************
245 ********************************************************************************
246 */
247#include "SyntaxColoring.inl"
248
249#endif /*_Stroika_Frameworks_Led_SyntaxColoring_h_*/