source: trunk/BFHighlighter.pas

Last change on this file was 145, checked in by chronos, 11 months ago
  • Modified: Remove U prefix from unit names.
  • Modified: Updated Common package.
File size: 9.1 KB
Line 
1unit BFHighlighter;
2(*
3 This is an example how to implement your own highlighter.
4
5 This example does allow to specify different colors for
6 - text (defaults to not-highlighted)
7 - spaces (defaults to silver frame)
8 - words, separated by spaces, that start with a,e,i,o,u (defaults to bold)
9 - the word "not" (defaults to red background)
10
11 See comments below and http://wiki.lazarus.freepascal.org/SynEdit_Highlighter
12
13 How it works:
14
15 - Creation
16 The Highlighter creates Attributes that it can return the Words and Spaces.
17
18 - SetLine
19 Is called by SynEdit before a line gets painted (or before highlight info is needed)
20 This is also called, each time the text changes fol *all* changed lines
21 and may even be called for all lines after the change up to the end of text.
22
23 After SetLine was called "GetToken*" should return information about the
24 first token on the line.
25 Note: Spaces are token too.
26
27 - Next
28 Scan to the next token, on the line that was set by "SetLine"
29 "GetToken*" should return info about that next token.
30
31 - GetEOL
32 Returns True, if "Next" was called while on the last token of the line.
33
34 - GetTokenEx, GetTokenAttribute
35 Provide info about the token found by "Next"
36
37 - Next, GetEOL. GetToken*
38 Are used by SynEdit to iterate over the Line.
39 Important: The tokens returned for each line, must represent the original
40 line-text (mothing added, nothing left out), and be returned in the correct order.
41
42 They are called very often and should perform ath high speed.
43
44 - GetToken, GetTokenPos, GetTokenKind
45 SynEdit uses them e.g for finding matching brackets. If GetTokenKind returns different values per Attribute, then brackets only match, if they are of the same kind (e.g, if there was a string attribute, brackets outside a string would not match brackets inside a string)
46
47
48*)
49
50interface
51
52uses
53 Classes, SysUtils, Graphics, SynEditHighlighter;
54
55type
56
57 { TSynBrainFuckHl }
58
59
60 TSynBrainFuckHl = class(TSynCustomHighlighter)
61 private
62 FCommentAttri: TSynHighlighterAttributes;
63 FIoAttri: TSynHighlighterAttributes;
64 FLoopAttri: TSynHighlighterAttributes;
65 FMemoryAttri: TSynHighlighterAttributes;
66 FPointerAttri: TSynHighlighterAttributes;
67 FSpaceAttri: TSynHighlighterAttributes;
68 procedure SetCommentAttri(AValue: TSynHighlighterAttributes);
69 procedure SetMemoryAttri(AValue: TSynHighlighterAttributes);
70 procedure SetPointerAttri(AValue: TSynHighlighterAttributes);
71 procedure SetSpaceAttri(AValue: TSynHighlighterAttributes);
72 procedure SetIoAttri(AValue: TSynHighlighterAttributes);
73 procedure SetLoopAttri(AValue: TSynHighlighterAttributes);
74 function IsWhiteSpace(C: Char): Boolean;
75 protected
76 // accesible for the other examples
77 FTokenPos, FTokenEnd: Integer;
78 FLineText: String;
79 public
80 procedure SetLine(const NewValue: String; LineNumber: Integer); override;
81 procedure Next; override;
82 function GetEol: Boolean; override;
83 procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer); override;
84 function GetTokenAttribute: TSynHighlighterAttributes; override;
85 public
86 function GetToken: String; override;
87 function GetTokenPos: Integer; override;
88 function GetTokenKind: integer; override;
89 function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;
90 constructor Create(AOwner: TComponent); override;
91 published
92 property IoAttri: TSynHighlighterAttributes read FIoAttri
93 write SetIoAttri;
94 property LoopAttri: TSynHighlighterAttributes read FLoopAttri
95 write SetLoopAttri;
96 property PointerAttri: TSynHighlighterAttributes read FPointerAttri
97 write SetPointerAttri;
98 property MemoryAttri: TSynHighlighterAttributes read FMemoryAttri
99 write SetMemoryAttri;
100 property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
101 write SetSpaceAttri;
102 property CommentAttri: TSynHighlighterAttributes read FCommentAttri
103 write SetCommentAttri;
104 end;
105
106implementation
107
108constructor TSynBrainFuckHl.Create(AOwner: TComponent);
109begin
110 inherited;
111
112 (* Create and initialize the attributes *)
113 FIoAttri := TSynHighlighterAttributes.Create('keyword', 'keyword');
114 AddAttribute(FIoAttri);
115 FIoAttri.Style := [fsBold];
116
117 FLoopAttri := TSynHighlighterAttributes.Create('loop', 'loop');
118 AddAttribute(FLoopAttri);
119 FLoopAttri.Style := [fsBold];
120 FLoopAttri.Foreground := clRed;
121
122 FPointerAttri := TSynHighlighterAttributes.Create('pointer', 'pointer');
123 AddAttribute(FPointerAttri);
124 FPointerAttri.Style := [fsBold];
125 FPointerAttri.Foreground := clBlue;
126
127 FMemoryAttri := TSynHighlighterAttributes.Create('memory', 'memory');
128 AddAttribute(FMemoryAttri);
129 FMemoryAttri.Style := [fsBold];
130 FMemoryAttri.Foreground := clGreen;
131
132 FCommentAttri := TSynHighlighterAttributes.Create('comment', 'comment');
133 AddAttribute(FCommentAttri);
134 FCommentAttri.Foreground := clSilver;
135
136 FSpaceAttri := TSynHighlighterAttributes.Create('space', 'space');
137 AddAttribute(FSpaceAttri);
138 //FSpaceAttri.FrameColor := clSilver;
139 //FSpaceAttri.FrameEdges := sfeAround;
140
141 // Ensure the HL reacts to changes in the attributes. Do this once, if all attributes are created
142 SetAttributesOnChange(DefHighlightChange);
143end;
144
145(* Setters for attributes / This allows using in Object inspector*)
146procedure TSynBrainFuckHl.SetCommentAttri(AValue: TSynHighlighterAttributes);
147begin
148 FCommentAttri.Assign(AValue);
149end;
150
151procedure TSynBrainFuckHl.SetMemoryAttri(AValue: TSynHighlighterAttributes);
152begin
153 FMemoryAttri.Assign(AValue);
154end;
155
156procedure TSynBrainFuckHl.SetPointerAttri(AValue: TSynHighlighterAttributes);
157begin
158 FPointerAttri.Assign(AValue);
159end;
160
161procedure TSynBrainFuckHl.SetSpaceAttri(AValue: TSynHighlighterAttributes);
162begin
163 FSpaceAttri.Assign(AValue);
164end;
165
166procedure TSynBrainFuckHl.SetIoAttri(AValue: TSynHighlighterAttributes);
167begin
168 FIoAttri.Assign(AValue);
169end;
170
171procedure TSynBrainFuckHl.SetLoopAttri(AValue: TSynHighlighterAttributes);
172begin
173 FLoopAttri.Assign(AValue);
174end;
175
176function TSynBrainFuckHl.IsWhiteSpace(C: Char): Boolean;
177begin
178 Result := C in [#9, ' '];
179end;
180
181procedure TSynBrainFuckHl.SetLine(const NewValue: String; LineNumber: Integer);
182begin
183 inherited;
184 FLineText := NewValue;
185 // Next will start at "FTokenEnd", so set this to 1
186 FTokenEnd := 1;
187 Next;
188end;
189
190procedure TSynBrainFuckHl.Next;
191var
192 L: Integer;
193begin
194 // FTokenEnd should be at the start of the next Token (which is the Token we want)
195 FTokenPos := FTokenEnd;
196 // assume empty, will only happen for EOL
197 FTokenEnd := FTokenPos;
198
199 // Scan forward
200 // FTokenEnd will be set 1 after the last char. That is:
201 // - The first char of the next token
202 // - or past the end of line (which allows GetEOL to work)
203
204 L := Length(FLineText);
205 If FTokenPos > L then
206 // At line end
207 Exit
208 else
209 if FLineText[FTokenEnd] in [#9, ' '] then
210 // At Space? Find end of spaces
211 while (FTokenEnd <= L) and (FLineText[FTokenEnd] in [#0..#32]) do
212 Inc(FTokenEnd)
213 else
214 // At None-Space? Find end of None-spaces
215 //while (FTokenEnd <= L) and not(FLineText[FTokenEnd] in [#9, ' ']) do
216 Inc(FTokenEnd);
217end;
218
219function TSynBrainFuckHl.GetEol: Boolean;
220begin
221 Result := FTokenPos > Length(FLineText);
222end;
223
224procedure TSynBrainFuckHl.GetTokenEx(out TokenStart: PChar; out TokenLength: integer);
225begin
226 TokenStart := @FLineText[FTokenPos];
227 TokenLength := FTokenEnd - FTokenPos;
228end;
229
230function TSynBrainFuckHl.GetTokenAttribute: TSynHighlighterAttributes;
231begin
232 // Match the text, specified by FTokenPos and FTokenEnd
233 if IsWhiteSpace(FLineText[FTokenPos]) then
234 Result := SpaceAttri
235 else
236 if FLineText[FTokenPos] in ['[', ']'] then
237 Result := LoopAttri
238 else
239 if FLineText[FTokenPos] in ['<', '>'] then
240 Result := PointerAttri
241 else
242 if FLineText[FTokenPos] in ['+', '-'] then
243 Result := MemoryAttri
244 else
245 if FLineText[FTokenPos] in ['.', ','] then
246 Result := IoAttri
247 else
248 Result := CommentAttri;
249end;
250
251function TSynBrainFuckHl.GetToken: String;
252begin
253 Result := Copy(FLineText, FTokenPos, FTokenEnd - FTokenPos);
254end;
255
256function TSynBrainFuckHl.GetTokenPos: Integer;
257begin
258 Result := FTokenPos - 1;
259end;
260
261function TSynBrainFuckHl.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
262begin
263 // Some default attributes
264 case Index of
265 SYN_ATTR_COMMENT: Result := FCommentAttri;
266 SYN_ATTR_KEYWORD: Result := FIoAttri;
267 SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
268 else Result := nil;
269 end;
270end;
271
272function TSynBrainFuckHl.GetTokenKind: integer;
273var
274 a: TSynHighlighterAttributes;
275begin
276 // Map Attribute into a unique number
277 a := GetTokenAttribute;
278 Result := 0;
279 if a = FSpaceAttri then Result := 1
280 else if a = FIoAttri then Result := 2
281 else if a = FCommentAttri then Result := 3
282 else if a = FLoopAttri then Result := 4
283 else if a = FPointerAttri then Result := 5
284 else if a = FMemoryAttri then Result := 6;
285end;
286
287end.
288
Note: See TracBrowser for help on using the repository browser.