source: trunk/VCardHighlighter.pas

Last change on this file was 149, checked in by chronos, 18 months ago
  • Modified: Remove U prefix from unit names.
File size: 9.9 KB
Line 
1unit VCardHighlighter;
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 { TSynVCardHighlighter }
58
59
60 TSynVCardHighlighter = class(TSynCustomHighlighter)
61 private
62 FSpaceAttri: TSynHighlighterAttributes;
63 FKeywordAttri: TSynHighlighterAttributes;
64 FIdentAttri: TSynHighlighterAttributes;
65 FNumberAttri: TSynHighlighterAttributes;
66 FPropertyAttri: TSynHighlighterAttributes;
67 procedure SetIdentAttri(AValue: TSynHighlighterAttributes);
68 procedure SetKeywordAttri(AValue: TSynHighlighterAttributes);
69 procedure SetNumberAttri(AValue: TSynHighlighterAttributes);
70 procedure SetPropertyAttri(AValue: TSynHighlighterAttributes);
71 procedure SetSpaceAttri(AValue: TSynHighlighterAttributes);
72 function IsDigit(C: Char): Boolean;
73 function IsWhiteSpace(C: Char): Boolean;
74 function IsNumber(Text: string): Boolean;
75 function IsProperty(Text: string): Boolean;
76 protected
77 // accesible for the other examples
78 FTokenPos: Integer;
79 FTokenEnd: Integer;
80 FLineText: String;
81 public
82 procedure SetLine(const NewValue: String; LineNumber: Integer); override;
83 procedure Next; override;
84 function GetEol: Boolean; override;
85 procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer); override;
86 function GetTokenAttribute: TSynHighlighterAttributes; override;
87 public
88 Properties: array of string;
89 function GetToken: String; override;
90 function GetTokenPos: Integer; override;
91 function GetTokenKind: integer; override;
92 function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;
93 constructor Create(AOwner: TComponent); override;
94 published
95 property KeywordAttri: TSynHighlighterAttributes read FKeywordAttri
96 write SetKeywordAttri;
97 property IdentAttri: TSynHighlighterAttributes read FIdentAttri
98 write SetIdentAttri;
99 property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
100 write SetSpaceAttri;
101 property NumberAttri: TSynHighlighterAttributes read FNumberAttri
102 write SetNumberAttri;
103 property PropertyAttri: TSynHighlighterAttributes read FPropertyAttri
104 write SetPropertyAttri;
105 end;
106
107implementation
108
109constructor TSynVCardHighlighter.Create(AOwner: TComponent);
110begin
111 inherited;
112
113 (* Create and initialize the attributes *)
114 FKeywordAttri := TSynHighlighterAttributes.Create('keyword', 'keyword');
115 AddAttribute(FKeywordAttri);
116 FKeywordAttri.Style := [fsBold];
117 FKeywordAttri.Foreground := clBlue;
118
119 FIdentAttri := TSynHighlighterAttributes.Create('ident', 'ident');
120 AddAttribute(FIdentAttri);
121 FIdentAttri.Style := [];
122
123 FNumberAttri := TSynHighlighterAttributes.Create('number', 'number');
124 AddAttribute(FNumberAttri);
125 FNumberAttri.Style := [];
126
127 FPropertyAttri := TSynHighlighterAttributes.Create('property', 'property');
128 AddAttribute(FPropertyAttri);
129 FPropertyAttri.Style := [fsBold];
130
131 FSpaceAttri := TSynHighlighterAttributes.Create('space', 'space');
132 AddAttribute(FSpaceAttri);
133
134 // Ensure the HL reacts to changes in the attributes. Do this once, if all attributes are created
135 SetAttributesOnChange(DefHighlightChange);
136end;
137
138(* Setters for attributes / This allows using in Object inspector*)
139procedure TSynVCardHighlighter.SetKeywordAttri(AValue: TSynHighlighterAttributes);
140begin
141 FKeywordAttri.Assign(AValue);
142end;
143
144procedure TSynVCardHighlighter.SetIdentAttri(AValue: TSynHighlighterAttributes);
145begin
146 FIdentAttri.Assign(AValue);
147end;
148
149function TSynVCardHighlighter.IsWhiteSpace(C: Char): Boolean;
150begin
151 Result := C in [#9, ' '];
152end;
153
154function TSynVCardHighlighter.IsNumber(Text: string): Boolean;
155var
156 I: Integer;
157 DecimalPointUsed: Boolean;
158begin
159 DecimalPointUsed := False;
160 if Length(Text) > 0 then begin
161 Result := True;
162 for I := 1 to Length(Text) do begin
163 if not IsDigit(Text[I]) and not (not DecimalPointUsed and (Text[I] = '.')) then begin
164 Result := False;
165 Break;
166 end;
167 if Text[I] = '.' then DecimalPointUsed := True;
168 end;
169 end else Result := False;
170end;
171
172function TSynVCardHighlighter.IsProperty(Text: string): Boolean;
173var
174 I: Integer;
175begin
176 Result := False;
177 for I := 0 to Length(Properties) - 1 do
178 if Properties[I] = Text then begin
179 Result := True;
180 Break;
181 end;
182end;
183
184procedure TSynVCardHighlighter.SetNumberAttri(AValue: TSynHighlighterAttributes
185 );
186begin
187 FNumberAttri.Assign(AValue);
188end;
189
190procedure TSynVCardHighlighter.SetPropertyAttri(
191 AValue: TSynHighlighterAttributes);
192begin
193 FPropertyAttri.Assign(AValue);
194end;
195
196procedure TSynVCardHighlighter.SetSpaceAttri(AValue: TSynHighlighterAttributes);
197begin
198 FSpaceAttri.Assign(AValue);
199end;
200
201function TSynVCardHighlighter.IsDigit(C: Char): Boolean;
202begin
203 Result := C in ['0'..'9'];
204end;
205
206procedure TSynVCardHighlighter.SetLine(const NewValue: String; LineNumber: Integer);
207begin
208 inherited;
209 FLineText := NewValue;
210 // Next will start at "FTokenEnd", so set this to 1
211 FTokenEnd := 1;
212 Next;
213end;
214
215procedure TSynVCardHighlighter.Next;
216var
217 L: Integer;
218 DecimalPointUsed: Boolean;
219begin
220 // FTokenEnd should be at the start of the next Token (which is the Token we want)
221 FTokenPos := FTokenEnd;
222 // assume empty, will only happen for EOL
223 FTokenEnd := FTokenPos;
224
225 // Scan forward
226 // FTokenEnd will be set 1 after the last char. That is:
227 // - The first char of the next token
228 // - or past the end of line (which allows GetEOL to work)
229
230 L := Length(FLineText);
231 If FTokenPos > L then begin
232 // At line end
233 Exit;
234 end
235 else
236 if FLineText[FTokenEnd] in [#9, ' '] then begin
237 // At Space? Find end of spaces
238 while (FTokenEnd <= L) and (FLineText[FTokenEnd] in [#0..#32]) do
239 Inc(FTokenEnd)
240 end else
241 if FLineText[FTokenEnd] in [':', ',', ';'] then begin
242 Inc(FTokenEnd);
243 end else
244 if IsDigit(FLineText[FTokenEnd]) then begin
245 DecimalPointUsed := False;
246 while (FTokenEnd <= L) and (IsDigit(FLineText[FTokenEnd]) or
247 (not DecimalPointUsed and (FLineText[FTokenEnd] = '.'))) do begin
248 if FLineText[FTokenEnd] = '.' then DecimalPointUsed := True;
249 Inc(FTokenEnd);
250 end;
251 end else begin
252 // At None-Space? Find end of None-spaces
253 while (FTokenEnd <= L) and not (FLineText[FTokenEnd] in [#9, ' ', ':', ',', ';']) do
254 Inc(FTokenEnd);
255 end;
256end;
257
258function TSynVCardHighlighter.GetEol: Boolean;
259begin
260 Result := FTokenPos > Length(FLineText);
261end;
262
263procedure TSynVCardHighlighter.GetTokenEx(out TokenStart: PChar; out TokenLength: integer);
264begin
265 TokenStart := @FLineText[FTokenPos];
266 TokenLength := FTokenEnd - FTokenPos;
267end;
268
269function TSynVCardHighlighter.GetTokenAttribute: TSynHighlighterAttributes;
270var
271 Token: string;
272begin
273 Token := LowerCase(Copy(FLineText, FTokenPos, FTokenEnd - FTokenPos));
274
275 // Match the text, specified by FTokenPos and FTokenEnd
276 if IsWhiteSpace(FLineText[FTokenPos]) then
277 Result := SpaceAttri
278 else
279 if IsNumber(Token) then
280 Result := NumberAttri
281 else
282 if IsProperty(Token) then
283 Result := PropertyAttri
284 else
285 if (Token = 'begin') or (Token = 'end') or (Token = 'vcard') then
286 Result := KeywordAttri
287 else
288 Result := IdentAttri;
289end;
290
291function TSynVCardHighlighter.GetToken: String;
292begin
293 Result := Copy(FLineText, FTokenPos, FTokenEnd - FTokenPos);
294end;
295
296function TSynVCardHighlighter.GetTokenPos: Integer;
297begin
298 Result := FTokenPos - 1;
299end;
300
301function TSynVCardHighlighter.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
302begin
303 // Some default attributes
304 case Index of
305 SYN_ATTR_IDENTIFIER: Result := FIdentAttri;
306 SYN_ATTR_KEYWORD: Result := FKeywordAttri;
307 SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
308 SYN_ATTR_NUMBER: Result := FNumberAttri;
309 SYN_ATTR_SYMBOL: Result := FPropertyAttri;
310 else Result := nil;
311 end;
312end;
313
314function TSynVCardHighlighter.GetTokenKind: integer;
315var
316 Attr: TSynHighlighterAttributes;
317begin
318 // Map Attribute into Attribute unique number
319 Attr := GetTokenAttribute;
320 Result := 0;
321 if Attr = FSpaceAttri then Result := 1
322 else if Attr = FKeywordAttri then Result := 2
323 else if Attr = FIdentAttri then Result := 3
324 else if Attr = FNumberAttri then Result := 4
325 else if Attr = FPropertyAttri then Result := 5;
326end;
327
328end.
329
Note: See TracBrowser for help on using the repository browser.