source: tags/1.0.0/UBFHighlighter.pas

Last change on this file was 97, checked in by chronos, 6 years ago
  • Added: Syntax highlighting.
File size: 9.1 KB
Line 
1unit UBFHighlighter;
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
50{$mode objfpc}{$H+}
51
52interface
53
54uses
55 Classes, SysUtils, Graphics, SynEditTypes, SynEditHighlighter;
56
57type
58
59 { TSynBrainFuckHl }
60
61
62 TSynBrainFuckHl = class(TSynCustomHighlighter)
63 private
64 FCommentAttri: TSynHighlighterAttributes;
65 FIoAttri: TSynHighlighterAttributes;
66 FLoopAttri: TSynHighlighterAttributes;
67 FMemoryAttri: TSynHighlighterAttributes;
68 FPointerAttri: TSynHighlighterAttributes;
69 FSpaceAttri: TSynHighlighterAttributes;
70 procedure SetCommentAttri(AValue: TSynHighlighterAttributes);
71 procedure SetMemoryAttri(AValue: TSynHighlighterAttributes);
72 procedure SetPointerAttri(AValue: TSynHighlighterAttributes);
73 procedure SetSpaceAttri(AValue: TSynHighlighterAttributes);
74 procedure SetIoAttri(AValue: TSynHighlighterAttributes);
75 procedure SetLoopAttri(AValue: TSynHighlighterAttributes);
76 function IsWhiteSpace(C: Char): Boolean;
77 protected
78 // accesible for the other examples
79 FTokenPos, 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 function GetToken: String; override;
89 function GetTokenPos: Integer; override;
90 function GetTokenKind: integer; override;
91 function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;
92 constructor Create(AOwner: TComponent); override;
93 published
94 property IoAttri: TSynHighlighterAttributes read FIoAttri
95 write SetIoAttri;
96 property LoopAttri: TSynHighlighterAttributes read FLoopAttri
97 write SetLoopAttri;
98 property PointerAttri: TSynHighlighterAttributes read FPointerAttri
99 write SetPointerAttri;
100 property MemoryAttri: TSynHighlighterAttributes read FMemoryAttri
101 write SetMemoryAttri;
102 property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
103 write SetSpaceAttri;
104 property CommentAttri: TSynHighlighterAttributes read FCommentAttri
105 write SetCommentAttri;
106 end;
107
108implementation
109
110constructor TSynBrainFuckHl.Create(AOwner: TComponent);
111begin
112 inherited Create(AOwner);
113
114 (* Create and initialize the attributes *)
115 FIoAttri := TSynHighlighterAttributes.Create('keyword', 'keyword');
116 AddAttribute(FIoAttri);
117 FIoAttri.Style := [fsBold];
118
119 FLoopAttri := TSynHighlighterAttributes.Create('loop', 'loop');
120 AddAttribute(FLoopAttri);
121 FLoopAttri.Style := [fsBold];
122 FLoopAttri.Foreground := clRed;
123
124 FPointerAttri := TSynHighlighterAttributes.Create('pointer', 'pointer');
125 AddAttribute(FPointerAttri);
126 FPointerAttri.Style := [fsBold];
127 FPointerAttri.Foreground := clBlue;
128
129 FMemoryAttri := TSynHighlighterAttributes.Create('memory', 'memory');
130 AddAttribute(FMemoryAttri);
131 FMemoryAttri.Style := [fsBold];
132 FMemoryAttri.Foreground := clGreen;
133
134 FCommentAttri := TSynHighlighterAttributes.Create('comment', 'comment');
135 AddAttribute(FCommentAttri);
136 FCommentAttri.Foreground := clSilver;
137
138 FSpaceAttri := TSynHighlighterAttributes.Create('space', 'space');
139 AddAttribute(FSpaceAttri);
140 //FSpaceAttri.FrameColor := clSilver;
141 //FSpaceAttri.FrameEdges := sfeAround;
142
143 // Ensure the HL reacts to changes in the attributes. Do this once, if all attributes are created
144 SetAttributesOnChange(@DefHighlightChange);
145end;
146
147(* Setters for attributes / This allows using in Object inspector*)
148procedure TSynBrainFuckHl.SetCommentAttri(AValue: TSynHighlighterAttributes);
149begin
150 FCommentAttri.Assign(AValue);
151end;
152
153procedure TSynBrainFuckHl.SetMemoryAttri(AValue: TSynHighlighterAttributes);
154begin
155 FMemoryAttri.Assign(AValue);
156end;
157
158procedure TSynBrainFuckHl.SetPointerAttri(AValue: TSynHighlighterAttributes);
159begin
160 FPointerAttri.Assign(AValue);
161end;
162
163procedure TSynBrainFuckHl.SetSpaceAttri(AValue: TSynHighlighterAttributes);
164begin
165 FSpaceAttri.Assign(AValue);
166end;
167
168procedure TSynBrainFuckHl.SetIoAttri(AValue: TSynHighlighterAttributes);
169begin
170 FIoAttri.Assign(AValue);
171end;
172
173procedure TSynBrainFuckHl.SetLoopAttri(AValue: TSynHighlighterAttributes);
174begin
175 FLoopAttri.Assign(AValue);
176end;
177
178function TSynBrainFuckHl.IsWhiteSpace(C: Char): Boolean;
179begin
180 Result := C in [#9, ' '];
181end;
182
183procedure TSynBrainFuckHl.SetLine(const NewValue: String; LineNumber: Integer);
184begin
185 inherited;
186 FLineText := NewValue;
187 // Next will start at "FTokenEnd", so set this to 1
188 FTokenEnd := 1;
189 Next;
190end;
191
192procedure TSynBrainFuckHl.Next;
193var
194 L: Integer;
195begin
196 // FTokenEnd should be at the start of the next Token (which is the Token we want)
197 FTokenPos := FTokenEnd;
198 // assume empty, will only happen for EOL
199 FTokenEnd := FTokenPos;
200
201 // Scan forward
202 // FTokenEnd will be set 1 after the last char. That is:
203 // - The first char of the next token
204 // - or past the end of line (which allows GetEOL to work)
205
206 L := Length(FLineText);
207 If FTokenPos > L then
208 // At line end
209 Exit
210 else
211 if FLineText[FTokenEnd] in [#9, ' '] then
212 // At Space? Find end of spaces
213 while (FTokenEnd <= L) and (FLineText[FTokenEnd] in [#0..#32]) do
214 Inc(FTokenEnd)
215 else
216 // At None-Space? Find end of None-spaces
217 //while (FTokenEnd <= L) and not(FLineText[FTokenEnd] in [#9, ' ']) do
218 Inc(FTokenEnd);
219end;
220
221function TSynBrainFuckHl.GetEol: Boolean;
222begin
223 Result := FTokenPos > Length(FLineText);
224end;
225
226procedure TSynBrainFuckHl.GetTokenEx(out TokenStart: PChar; out TokenLength: integer);
227begin
228 TokenStart := @FLineText[FTokenPos];
229 TokenLength := FTokenEnd - FTokenPos;
230end;
231
232function TSynBrainFuckHl.GetTokenAttribute: TSynHighlighterAttributes;
233begin
234 // Match the text, specified by FTokenPos and FTokenEnd
235 if IsWhiteSpace(FLineText[FTokenPos]) then
236 Result := SpaceAttri
237 else
238 if FLineText[FTokenPos] in ['[', ']'] then
239 Result := LoopAttri
240 else
241 if FLineText[FTokenPos] in ['<', '>'] then
242 Result := PointerAttri
243 else
244 if FLineText[FTokenPos] in ['+', '-'] then
245 Result := MemoryAttri
246 else
247 if FLineText[FTokenPos] in ['.', ','] then
248 Result := IoAttri
249 else
250 Result := CommentAttri;
251end;
252
253function TSynBrainFuckHl.GetToken: String;
254begin
255 Result := Copy(FLineText, FTokenPos, FTokenEnd - FTokenPos);
256end;
257
258function TSynBrainFuckHl.GetTokenPos: Integer;
259begin
260 Result := FTokenPos - 1;
261end;
262
263function TSynBrainFuckHl.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
264begin
265 // Some default attributes
266 case Index of
267 SYN_ATTR_COMMENT: Result := FCommentAttri;
268 SYN_ATTR_KEYWORD: Result := FIoAttri;
269 SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
270 else Result := nil;
271 end;
272end;
273
274function TSynBrainFuckHl.GetTokenKind: integer;
275var
276 a: TSynHighlighterAttributes;
277begin
278 // Map Attribute into a unique number
279 a := GetTokenAttribute;
280 Result := 0;
281 if a = FSpaceAttri then Result := 1
282 else if a = FIoAttri then Result := 2
283 else if a = FCommentAttri then Result := 3
284 else if a = FLoopAttri then Result := 4
285 else if a = FPointerAttri then Result := 5
286 else if a = FMemoryAttri then Result := 6;
287end;
288
289end.
290
Note: See TracBrowser for help on using the repository browser.