Sign in Join
Wiki copytemporary

Codetools: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
1-## Contents
2-
3- * 1 What are the codetools?
4- * 2 Using the codetools without the IDE
5- * 2.1 Defining search paths and macros
6- * 2.1.1 Example: Expand IncPath for a directory and/or its sub directories
7- * 2.1.2 Example: Expand global UnitPath
8- * 2.2 Define Template Macros
9- * 2.3 Define Template Actions
10- * 2.4 How to extend the include path of a directory
11- * 3 Using the codetools in the IDE with the IDEIntf
12- * 4 Codetools rules for FPC sources
13- * 4.1 Usage of testfpcsrcunitrules
14- * 4.2 Example for testfpcsrcunitrules
15- * 4.3 Duplicate source files
16- * 5 How the codetools parses sources differently from the compiler
17- * 6 Tool, Node, LinkScanner
18- * 6.1 Tool
19- * 6.2 LinkScanner
20- * 6.3 Node
21- * 7 CleanPos and CursorPos
22- * 8 Inserting, deleting, replacing - the TSourceChangeCache
23- * 8.1 Usage
24- * 8.2 BeginUpdate/EndUpdate
25- * 8.3 Saving changes to disk
26- * 9 Hints/Tips/Guide Lines
27- * 10 Test suite
28- * 11 Links
29-
301# What are the codetools?
312
32-Codetools is a Lazarus package providing tools to parse, explore, edit and refactor Pascal sources. The codetools have been packaged in their own module and are licensed under GPL. Many examples showing how to use the codetools in your own programs can be found under components/codetools/examples.
3+Codetools is a Lazarus package providing tools to parse, explore, edit and refactor Pascal sources. The codetools have been packaged in their own module and are licensed under GPL. Many examples showing how to use the codetools in your own programs can be found under components/codetools/examples.
334
34-svn:
5+svn:
356
36- * Lazarus: <http://svn.freepascal.org/svn/lazarus/trunk>
37- * Only CodeTools: <http://svn.freepascal.org/svn/lazarus/trunk/components/codetools>
7+- Lazarus: <http://svn.freepascal.org/svn/lazarus/trunk>
8+- Only CodeTools: <http://svn.freepascal.org/svn/lazarus/trunk/components/codetools>
389
3910# Using the codetools without the IDE
4011
41-You can use the codetools without the IDE. This can be used to test a new tool. An easy example is
42-```
43-<lazarusdir>/components/codetools/examples/methodjumping.lpi
44-```
12+You can use the codetools without the IDE. This can be used to test a new tool. An easy example is
4513
46-To test find declaration, the codetools need to parse sources. Especially the RTL and FCL sources. The examples use the following environment variables:
14+` <lazarusdir>/components/codetools/examples/methodjumping.lpi`
4715
48- * FPCDIR: path to the FPC sources, the default is _~/freepascal/fpc_.
49- * PP: path to the compiler executable (/usr/bin/fpc or /usr/bin/ppc386 or C:\lazarus\ppc386.exe). The codetools need to ask the compiler for the settings. The default is to search for 'fpc' via the PATH variable.
50- * FPCTARGETOS: tell the codetools to scan for another operating system (cross compiling). For example: linux, freebsd, darwin, win32, win64, wince
51- * FPCTARGETCPU: when scanning for another CPU. For example: i386, powerpc, x86_64, arm, sparc
52- * LAZARUSDIR: path of the lazarus sources. Only needed if you want to scan them.
16+To test find declaration, the codetools need to parse sources. Especially the RTL and FCL sources. The examples use the following environment variables:
5317
54-FPC is a very complex project with lots of search paths, include files and macros. The codetools need to know all these paths and macros in order to parse this jungle. To setup all this easily the codetools contain predefined templates for FPC, Lazarus, Delphi and Kylix source directories. See for a find declaration example
55-```
56-<lazarusdir>/components/codetools/examples/finddeclaration.lpi
57-```
18+- FPCDIR: path to the FPC sources, the default is *~/freepascal/fpc*.
19+- PP: path to the compiler executable (/usr/bin/fpc or /usr/bin/ppc386 or C:\lazarus\ppc386.exe). The codetools need to ask the compiler for the settings. The default is to search for 'fpc' via the PATH variable.
20+- FPCTARGETOS: tell the codetools to scan for another operating system (cross compiling). For example: linux, freebsd, darwin, win32, win64, wince
21+- FPCTARGETCPU: when scanning for another CPU. For example: i386, powerpc, x86_64, arm, sparc
22+- LAZARUSDIR: path of the lazarus sources. Only needed if you want to scan them.
5823
59-Because the FPC sources contain multiple versions of some units, and the FPC sources change often, the codetools do not use a fixed table of paths, but rather scan the whole FPC directory structure on first use, applying a set of rules specifying what is the correct source for the current TargetOS and TargetCPU. This scan may take a while depending on your disk speed. All examples save the result in **codetools.config** , so that the next time Lazarus is started this possibly lengthy scan is skipped.
24+FPC is a very complex project with lots of search paths, include files and macros. The codetools need to know all these paths and macros in order to parse this jungle. To setup all this easily the codetools contain predefined templates for FPC, Lazarus, Delphi and Kylix source directories. See for a find declaration example
6025
61-Whenever the FPC sources are changed or a unit is renamed, just delete the **codetools.config** file. The Lazarus IDE has its own config file and does a rescan whenever the compiler executable changes (or when the user forces a 'Tools > Rescan FPC source directory').
26+` <lazarusdir>/components/codetools/examples/finddeclaration.lpi`
6227
28+Because the FPC sources contain multiple versions of some units, and the FPC sources change often, the codetools do not use a fixed table of paths, but rather scan the whole FPC directory structure on first use, applying a set of rules specifying what is the correct source for the current TargetOS and TargetCPU. This scan may take a while depending on your disk speed. All examples save the result in **codetools.config**, so that the next time Lazarus is started this possibly lengthy scan is skipped.
29+
30+Whenever the FPC sources are changed or a unit is renamed, just delete the **codetools.config** file. The Lazarus IDE has its own config file and does a rescan whenever the compiler executable changes (or when the user forces a 'Tools \> Rescan FPC source directory').
31+
6332## Defining search paths and macros
6433
65-Important: Codetools assumes that you have multiple directories with different compiler settings, e.g. the FPC sources have different search paths than your sources. You can have FPC, Delphi and pas2js directories - all at the same time.
34+Important: Codetools assumes that you have multiple directories with different compiler settings, e.g. the FPC sources have different search paths than your sources. You can have FPC, Delphi and pas2js directories - all at the same time.
6635
67-The codetools uses "define templates" to generate search paths and macros. Define templates are trees of rules.
36+The codetools uses "define templates" to generate search paths and macros. Define templates are trees of rules.
6837
6938### Example: Expand IncPath for a directory and/or its sub directories
7039
71-The following demo demonstrate various ways to expand the IncPath for a directory and/or its sub directories:
72-```
40+The following demo demonstrate various ways to expand the IncPath for a directory and/or its sub directories:
41+
42+``` pascal
7343program SetIncludePath;
74-
75- {$mode objfpc}{$H+}
76-
77- uses
78- SysUtils, CodeToolManager, DefineTemplates, LazFileUtils;
79-
80- var
81- Directory: String;
82- DirectoryTemplate: TDefineTemplate;
83- IncPathTemplate: TDefineTemplate;
84- SubDirectory: String;
85- begin
86- // create a template for the current directory
87- // all child nodes of this template are only valid for this directory.
88- Directory:=ExpandFileNameUTF8(GetCurrentDirUTF8);
89- DirectoryTemplate:=TDefineTemplate.Create('Current working directory',
90- 'Example template for current working directory','',Directory,da_Directory);
91-
92- // Example 1:
93- // Add a sub template to extend the include search path #IncPath
94- // only for the current directory, not its sub directories.
95- // Note: 'myincludes' is a relative path, so it won't work for sub directories.
96- IncPathTemplate:=TDefineTemplate.Create('Add myincludes to the IncPath',
97- 'Add myincludes to the include search path',
98- IncludePathMacroName, // variable name: #IncPath
99- IncludePathMacro+';myincludes' // new value: $(#IncPath);myincludes
100- ,da_Define // da_Define extends the IncPath only for this directory
101- );
102- DirectoryTemplate.AddChild(IncPathTemplate);
103-
104- // Example 2:
105- // Add a sub template to extend the include search path #IncPath
106- // with an absolute path for the current directory and all its sub directories.
107- // Note: '/tmp/myincludes' is an absolute path, so works for sub directories.
108- IncPathTemplate:=TDefineTemplate.Create('Add /tmp/myincludes to the IncPath',
109- 'Add /tmp/myincludes to the include search path',
110- IncludePathMacroName, // variable name: #IncPath
111- IncludePathMacro+';'+SetDirSeparators('/tmp/myincludes') // new value: $(#IncPath);/tmp/myincludes
112- ,da_DefineRecurse // da_DefineRecuse extends the IncPath for this directory and all sub directories
113- );
114- DirectoryTemplate.AddChild(IncPathTemplate);
115-
116- // Example 3:
117- // Using the #DefinePath macro you can use the current directory to create absolute paths.
118- IncPathTemplate:=TDefineTemplate.Create('Add ./myincludes to the IncPath',
119- 'Add ./myincludes to the include search path',
120- IncludePathMacroName, // variable name: #IncPath
121- IncludePathMacro+';'+DefinePathMacro+'/myincludes' // new value: $(#IncPath);$(#DefinePath)/myincludes
122- ,da_DefineRecurse // da_DefineRecuse extends the IncPath for this directory and all sub directories
123- );
124- DirectoryTemplate.AddChild(IncPathTemplate);
125-
126- // add the directory template to the tree
127- CodeToolBoss.DefineTree.Add(DirectoryTemplate);
128-
129- writeln('Directory="',Directory,'"',
130- ' IncPath="',CodeToolBoss.GetIncludePathForDirectory(Directory),'"');
131- SubDirectory:=AppendPathDelim(Directory)+'sub';
132- writeln('SubDirectory="',SubDirectory,'"',
133- ' IncPath="',CodeToolBoss.GetIncludePathForDirectory(SubDirectory),'"');
134- end.
44+
45+{$mode objfpc}{$H+}
46+
47+uses
48+ SysUtils, CodeToolManager, DefineTemplates, LazFileUtils;
49+
50+var
51+ Directory: String;
52+ DirectoryTemplate: TDefineTemplate;
53+ IncPathTemplate: TDefineTemplate;
54+ SubDirectory: String;
55+begin
56+ // create a template for the current directory
57+ // all child nodes of this template are only valid for this directory.
58+ Directory:=ExpandFileNameUTF8(GetCurrentDirUTF8);
59+ DirectoryTemplate:=TDefineTemplate.Create('Current working directory',
60+ 'Example template for current working directory','',Directory,da_Directory);
61+
62+ // Example 1:
63+ // Add a sub template to extend the include search path #IncPath
64+ // only for the current directory, not its sub directories.
65+ // Note: 'myincludes' is a relative path, so it won't work for sub directories.
66+ IncPathTemplate:=TDefineTemplate.Create('Add myincludes to the IncPath',
67+ 'Add myincludes to the include search path',
68+ IncludePathMacroName, // variable name: #IncPath
69+ IncludePathMacro+';myincludes' // new value: $(#IncPath);myincludes
70+ ,da_Define // da_Define extends the IncPath only for this directory
71+ );
72+ DirectoryTemplate.AddChild(IncPathTemplate);
73+
74+ // Example 2:
75+ // Add a sub template to extend the include search path #IncPath
76+ // with an absolute path for the current directory and all its sub directories.
77+ // Note: '/tmp/myincludes' is an absolute path, so works for sub directories.
78+ IncPathTemplate:=TDefineTemplate.Create('Add /tmp/myincludes to the IncPath',
79+ 'Add /tmp/myincludes to the include search path',
80+ IncludePathMacroName, // variable name: #IncPath
81+ IncludePathMacro+';'+SetDirSeparators('/tmp/myincludes') // new value: $(#IncPath);/tmp/myincludes
82+ ,da_DefineRecurse // da_DefineRecuse extends the IncPath for this directory and all sub directories
83+ );
84+ DirectoryTemplate.AddChild(IncPathTemplate);
85+
86+ // Example 3:
87+ // Using the #DefinePath macro you can use the current directory to create absolute paths.
88+ IncPathTemplate:=TDefineTemplate.Create('Add ./myincludes to the IncPath',
89+ 'Add ./myincludes to the include search path',
90+ IncludePathMacroName, // variable name: #IncPath
91+ IncludePathMacro+';'+DefinePathMacro+'/myincludes' // new value: $(#IncPath);$(#DefinePath)/myincludes
92+ ,da_DefineRecurse // da_DefineRecuse extends the IncPath for this directory and all sub directories
93+ );
94+ DirectoryTemplate.AddChild(IncPathTemplate);
95+
96+ // add the directory template to the tree
97+ CodeToolBoss.DefineTree.Add(DirectoryTemplate);
98+
99+ writeln('Directory="',Directory,'"',
100+ ' IncPath="',CodeToolBoss.GetIncludePathForDirectory(Directory),'"');
101+ SubDirectory:=AppendPathDelim(Directory)+'sub';
102+ writeln('SubDirectory="',SubDirectory,'"',
103+ ' IncPath="',CodeToolBoss.GetIncludePathForDirectory(SubDirectory),'"');
104+end.
135105```
136106
137107### Example: Expand global UnitPath
138108
139-Here is an example how to extend the global (all directories) unit search path and query the unit path of one directory. This might be useful for single minded command line tools.
140-```
109+Here is an example how to extend the global (all directories) unit search path and query the unit path of one directory. This might be useful for single minded command line tools.
110+
111+``` pascal
141112uses
142- Classes, SysUtils, CodeToolManager, DefineTemplates, FileProcs;
143-
144- var
145- Directory: String;
146- UnitPathTemplate: TDefineTemplate;
147- begin
148- // add a sub template to extend the include search path #UnitPath.
149- UnitPathTemplate:=TDefineTemplate.Create(
150- 'Add myunits to the UnitPath', // optional: an arbitrary name of the template, useful for finding it later
151- 'Add /tmp/myunits to the unit search path', // optional: a description
152- UnitPathMacroName, // variable name: #UnitPath
153- UnitPathMacro+';/tmp/myunits' // new value: $(#UnitPath);/tmp/myunits
154- ,da_DefineRecurse
155- );
156- // add the unit path template to the tree
157- CodeToolBoss.DefineTree.Add(UnitPathTemplate);
158-
159- Directory:=ExpandFileNameUTF8(GetCurrentDirUTF8);
160- writeln('Directory="',Directory,'"',
161- ' UnitPath="',CodeToolBoss.GetUnitPathForDirectory(Directory),'"');
162- end.
113+ Classes, SysUtils, CodeToolManager, DefineTemplates, FileProcs;
114+
115+var
116+ Directory: String;
117+ UnitPathTemplate: TDefineTemplate;
118+begin
119+ // add a sub template to extend the include search path #UnitPath.
120+ UnitPathTemplate:=TDefineTemplate.Create(
121+ 'Add myunits to the UnitPath', // optional: an arbitrary name of the template, useful for finding it later
122+ 'Add /tmp/myunits to the unit search path', // optional: a description
123+ UnitPathMacroName, // variable name: #UnitPath
124+ UnitPathMacro+';/tmp/myunits' // new value: $(#UnitPath);/tmp/myunits
125+ ,da_DefineRecurse
126+ );
127+ // add the unit path template to the tree
128+ CodeToolBoss.DefineTree.Add(UnitPathTemplate);
129+
130+ Directory:=ExpandFileNameUTF8(GetCurrentDirUTF8);
131+ writeln('Directory="',Directory,'"',
132+ ' UnitPath="',CodeToolBoss.GetUnitPathForDirectory(Directory),'"');
133+end.
163134```
164135
165136## Define Template Macros
166137
167-Macros defined by define templates are used by the Pascal parser. The Codetools have functions to query the Free Pascal Compiler for its macros and convert them to define templates. This is done by CodeToolBoss.Init(Options); which you can find in many examples.
138+Macros defined by define templates are used by the Pascal parser. The Codetools have functions to query the Free Pascal Compiler for its macros and convert them to define templates. This is done by CodeToolBoss.Init(Options); which you can find in many examples.
168139
169-Additionally there some predefined macros, which start with a hash (#). See unit definetemplates for the full list. Here are some important ones:
170-```
171-ExternalMacroStart = '#';
172- // Standard macros
173- DefinePathMacroName = ExternalMacroStart+'DefinePath'; // the current directory
174- UnitPathMacroName = ExternalMacroStart+'UnitPath'; // unit search path separated by semicolon (same as given to FPC)
175- IncludePathMacroName = ExternalMacroStart+'IncPath'; // include file search path separated by semicolon (same as given to FPC)
176- SrcPathMacroName = ExternalMacroStart+'SrcPath'; // unit source search path separated by semicolon (not given to FPC)
140+Additionally there some predefined macros, which start with a hash (#). See unit definetemplates for the full list. Here are some important ones:
141+
142+``` pascal
143+ ExternalMacroStart = '#';
144+ // Standard macros
145+ DefinePathMacroName = ExternalMacroStart+'DefinePath'; // the current directory
146+ UnitPathMacroName = ExternalMacroStart+'UnitPath'; // unit search path separated by semicolon (same as given to FPC)
147+ IncludePathMacroName = ExternalMacroStart+'IncPath'; // include file search path separated by semicolon (same as given to FPC)
148+ SrcPathMacroName = ExternalMacroStart+'SrcPath'; // unit source search path separated by semicolon (not given to FPC)
177149```
178150
179-For example the **IncludePathMacroName** is **#IncPath** and is used to define the include file search path. Keep in mind that macro values depend on the directory.
151+For example the **IncludePathMacroName** is **\#IncPath** and is used to define the include file search path. Keep in mind that macro values depend on the directory.
180152
181-Define templates values can contain macros. The macro has to be enclosed in dollar and brackets: **$(macro)**.
153+Define templates values can contain macros. The macro has to be enclosed in dollar and brackets: **\$(macro)**.
182154
183-In the above example the value was _'$('+IncludePathMacroName+');/tmp/myincludes'_ , which is _'$(#IncPath);/tmp/myincludes'_ , which executes to the old include search path plus _';/tmp/myincludes'_ , which means a path is appended. For readability you can use the constant IncludePathMacro instead of _'$('+IncludePathMacroName+')'_ :
184-```
185-DefinePathMacro = '$('+DefinePathMacroName+')'; // the path of the define template
186- UnitPathMacro = '$('+UnitPathMacroName+')';
187- IncludePathMacro = '$('+IncludePathMacroName+')';
188- SrcPathMacro = '$('+SrcPathMacroName+')';
155+In the above example the value was *'\$('+IncludePathMacroName+');/tmp/myincludes'*, which is *'\$(#IncPath);/tmp/myincludes'*, which executes to the old include search path plus *';/tmp/myincludes'*, which means a path is appended. For readability you can use the constant IncludePathMacro instead of *'\$('+IncludePathMacroName+')'*:
156+
157+``` pascal
158+ DefinePathMacro = '$('+DefinePathMacroName+')'; // the path of the define template
159+ UnitPathMacro = '$('+UnitPathMacroName+')';
160+ IncludePathMacro = '$('+IncludePathMacroName+')';
161+ SrcPathMacro = '$('+SrcPathMacroName+')';
189162```
190163
191164## Define Template Actions
192165
193-A define template has a name, an optional description, a variable, a value and an action. The name and description are optional. The meaning of variable and value depends on the action. You can add define templates as children of define templates - creating a tree of define templates. You can see many examples for define templates in the Lazarus' dialog _Tools / CodeTools Defines Editor_.
166+A define template has a name, an optional description, a variable, a value and an action. The name and description are optional. The meaning of variable and value depends on the action. You can add define templates as children of define templates - creating a tree of define templates. You can see many examples for define templates in the Lazarus' dialog *Tools / CodeTools Defines Editor*.
194167
195- * da_Block - Used for grouping templates. When the block is executed all children are executed.
196- * da_Directory - Use this to define all rules of a directory. If this is a root directory set Value to the full expanded directory path (use function CleanAndExpandDirectory). If this is a sub directory (parent template is a directory) Value is the sub path. Can contain macros. Children are only executed if directory fits.
197- * da_Define - sets a macro (Variable) value (Value) of the current directory. The value can contain macros. Note that when a macro value is set to empty string _it is still defined, that means_{$IFDEF variable}_will still result in_ true _. Children are not executed._
198- * da_Undefine - clears a macro (Variable) of the current directory. _{$IFDEF macro}_ results in _false_. Children are not executed.
199- * da_DefineRecurse - as da_Define, but for current directory and sub directories.
200- * da_UndefineRecurse - as da_Undefine, but for current directory and sub directories.
201- * da_UndefineAll - clear all macro values.
202- * da_IfDef - if macro _Variable_ is defined then execute children and skip following da_Else and da_ElseIf.
203- * da_IfNDef - if macro _Variable_ is not defined then execute children and skip following da_Else and da_ElseIf.
204- * da_If,daElseIf - if the boolean expression _Value_ executes to true then execute children and skip following da_Else and da_ElseIf. Value can contain macros.
205- * da_Else - When this template is executed then execute all children.
168+- da_Block - Used for grouping templates. When the block is executed all children are executed.
169+- da_Directory - Use this to define all rules of a directory. If this is a root directory set Value to the full expanded directory path (use function CleanAndExpandDirectory). If this is a sub directory (parent template is a directory) Value is the sub path. Can contain macros. Children are only executed if directory fits.
170+- da_Define - sets a macro (Variable) value (Value) of the current directory. The value can contain macros. Note that when a macro value is set to empty string *it is still defined, that means*{\$IFDEF variable}*will still result in*true''. Children are not executed.
171+- da_Undefine - clears a macro (Variable) of the current directory. *{\$IFDEF macro}* results in *false*. Children are not executed.
172+- da_DefineRecurse - as da_Define, but for current directory and sub directories.
173+- da_UndefineRecurse - as da_Undefine, but for current directory and sub directories.
174+- da_UndefineAll - clear all macro values.
175+- da_IfDef - if macro *Variable* is defined then execute children and skip following da_Else and da_ElseIf.
176+- da_IfNDef - if macro *Variable* is not defined then execute children and skip following da_Else and da_ElseIf.
177+- da_If,daElseIf - if the boolean expression *Value* executes to true then execute children and skip following da_Else and da_ElseIf. Value can contain macros.
178+- da_Else - When this template is executed then execute all children.
206179
207180## How to extend the include path of a directory
208181
209-See the example lazarus/components/codetools/examples/setincludepath.lpr. It demonstrates the use of relative paths, absolute paths, how to use the DefinePathMacro and the difference between da_Define and da_DefineRecurse.
182+See the example lazarus/components/codetools/examples/setincludepath.lpr. It demonstrates the use of relative paths, absolute paths, how to use the DefinePathMacro and the difference between da_Define and da_DefineRecurse.
210183
211184# Using the codetools in the IDE with the IDEIntf
212185
213-See <lazarusdir>/examples/idequickfix/quickfixexample.lpk package. It demonstrates:
186+See \<lazarusdir\>/examples/idequickfix/quickfixexample.lpk package. It demonstrates:
214187
215- * How to write an IDE package. When you install this package it will register a Quick Fix item in the IDE.
216- * How to write a Quick Fix item for the compiler message: 'Parameter "Sender" not used'
217- * How to use the codetools to:
218- * parse a unit
219- * convert Filename, Line, and Column data into a codetools source position
220- * find a codetools node at a cursor position
221- * find a procedure node, and the begin..end node
222- * create a nice insertion position for a statement at the beginning of the begin..end block
223- * obtain line indentation information so that a new line will work in a sub-procedure as well
224- * insert code using the codetools
188+- How to write an IDE package. When you install this package it will register a Quick Fix item in the IDE.
189+- How to write a Quick Fix item for the compiler message: 'Parameter "Sender" not used'
190+- How to use the codetools to:
191+ - parse a unit
192+ - convert Filename, Line, and Column data into a codetools source position
193+ - find a codetools node at a cursor position
194+ - find a procedure node, and the begin..end node
195+ - create a nice insertion position for a statement at the beginning of the begin..end block
196+ - obtain line indentation information so that a new line will work in a sub-procedure as well
197+ - insert code using the codetools
225198
226199# Codetools rules for FPC sources
227200
228-When the codetools searches the source of a fpc ppu it uses a set of rules. You can write your own rules, but normally you will use the standard rules, which are defined in the include file components/codetools/fpcsrcrules.inc. You can test the rules with the command line utility: components/codetools/examples/testfpcsrcunitrules.lpi.
201+When the codetools searches the source of a fpc ppu it uses a set of rules. You can write your own rules, but normally you will use the standard rules, which are defined in the include file components/codetools/fpcsrcrules.inc. You can test the rules with the command line utility: components/codetools/examples/testfpcsrcunitrules.lpi.
229202
230203## Usage of testfpcsrcunitrules
231-```
232-Usage: lazarus/components/codetools/examples/testfpcsrcunitrules -h
233-
204+
205+ Usage: lazarus/components/codetools/examples/testfpcsrcunitrules -h
206+
234207 -c <compiler file name>, --compiler=<compiler file name>
235208 Default is to use environment variable PP.
236209 If this is not set, search for fpc
237-
210+
238211 -T <target OS>, --targetos=<target OS>
239212 Default is to use environment variable FPCTARGET.
240213 If this is not set, use the default of the compiler.
241-
214+
242215 -P <target CPU>, --targetcpu=<target CPU>
243216 Default is to use environment variable FPCTARGETCPU.
244217 If this is not set, use the default of the compiler.
245-
218+
246219 -F <FPC source directory>, --fpcsrcdir=<FPC source directory>
247220 Default is to use environment variable FPCDIR.
248221 There is no default.
249-
222+
250223 -u <unit name>, --checkunit=<unit name>
251224 Write a detailed report about this unit.
252-```
253225
254226## Example for testfpcsrcunitrules
255227
256-Open the testfpcsrcunitrules.lpi in the IDE and compile it. Then run the utility in a terminal/console:
257-```
258-./testfpcsrcunitrules -F ~/fpc/sources/2.5.1/fpc/
259-```
228+Open the testfpcsrcunitrules.lpi in the IDE and compile it. Then run the utility in a terminal/console:
260229
261-This will tell you which compiler is used, which compiler executes, which config files were tested and parsed, and it warns you about duplicate units in the FPC search path and about duplicated unit source files. **Note:** This example caches results in the file _codetools.config_. You should delete _codetools.config_ when you update the compiler or your fpc.cfg file.
230+`./testfpcsrcunitrules -F ~/fpc/sources/2.5.1/fpc/`
262231
232+This will tell you which compiler is used, which compiler executes, which config files were tested and parsed, and it warns you about duplicate units in the FPC search path and about duplicated unit source files. **Note:** This example caches results in the file *codetools.config*. You should delete *codetools.config* when you update the compiler or your fpc.cfg file.
233+
263234## Duplicate source files
264235
265-You find out that the codetools opens for target wince/arm the wrong source of the unit _mmsystem_. Run the tool with the -u parameter:
236+You find out that the codetools opens for target wince/arm the wrong source of the unit *mmsystem*. Run the tool with the -u parameter:
266237
267-./testfpcsrcunitrules -F ~/fpc/2.5.1/fpc/ -T wince -P arm -u mmsystem
238+./testfpcsrcunitrules -F ~/fpc/2.5.1/fpc/ -T wince -P arm -u mmsystem
268239
269-This will give you a detailed report where this unit was found and what score each source file got. For example:
270-```
271-Unit report for mmsystem
272- WARNING: mmsystem is not in PPU search path
273- GatherUnitsInFPCSources UnitName=mmsystem File=packages/winunits-base/src/mmsystem.pp Score=11
274- GatherUnitsInFPCSources UnitName=mmsystem File=packages/winceunits/src/mmsystem.pp Score=11 => duplicate
275-```
240+This will give you a detailed report where this unit was found and what score each source file got. For example:
276241
277-This means there are two source files with the same score, so the codetools took the first. The last one in winceunits is for target wince and the first one is for win32 and win64.
242+`Unit report for mmsystem`\
243+`  WARNING: mmsystem is not in PPU search path`\
244+`GatherUnitsInFPCSources UnitName=mmsystem File=packages/winunits-base/src/mmsystem.pp Score=11`\
245+`GatherUnitsInFPCSources UnitName=mmsystem File=packages/winceunits/src/mmsystem.pp Score=11 => duplicate`
278246
279-Now open the rules file fpcsrcrules.inc.
247+This means there are two source files with the same score, so the codetools took the first. The last one in winceunits is for target wince and the first one is for win32 and win64.
280248
281-Rules work like this:
282-```
249+Now open the rules file fpcsrcrules.inc.
250+
251+Rules work like this:
252+
253+``` pascal
283254Score:=10;
284- Targets:='wince';
285- Add('packages/winceunits');
255+Targets:='wince';
256+Add('packages/winceunits');
286257```
287258
288-The **Add** adds a rule for all files beginning with 'packages/winceunits' that adds a score of 10 to all these files. The **Targets** is a comma separated list of target operating systems and/or target processors. For example Targets='wince,linux,i386' means: apply this rules to TargetOS wince or linux and to all TargetCPU i386.
259+The **Add** adds a rule for all files beginning with 'packages/winceunits' that adds a score of 10 to all these files. The **Targets** is a comma separated list of target operating systems and/or target processors. For example Targets='wince,linux,i386' means: apply this rules to TargetOS wince or linux and to all TargetCPU i386.
289260
290261# How the codetools parses sources differently from the compiler
291262
292-A compiler is optimized to parse code linearly and to load needed units and include files as soon as it parses a uses section or a directive. The codetools are optimized to parse only certain code sections. For example jumping from the method declaration to the method body only needs the unit and its include files. When a codetool searches a declaration it searches backwards. That means it starts searching in the local variables, then upwards from the implementation. When it finds a uses section it searches the identifiers in the interface section of the units. When the identifier is found it stops. The result and some intervening steps are cached. Because it often only needs to parse a few interface sections it finds an individual identifier very quickly.
263+A compiler is optimized to parse code linearly and to load needed units and include files as soon as it parses a uses section or a directive. The codetools are optimized to parse only certain code sections. For example jumping from the method declaration to the method body only needs the unit and its include files. When a codetool searches a declaration it searches backwards. That means it starts searching in the local variables, then upwards from the implementation. When it finds a uses section it searches the identifiers in the interface section of the units. When the identifier is found it stops. The result and some intervening steps are cached. Because it often only needs to parse a few interface sections it finds an individual identifier very quickly.
293264
294-The codetools do not parse a source in a single step (as the compiler does) but in several steps, which depend on what the current codetool needs:
265+The codetools do not parse a source in a single step (as the compiler does) but in several steps, which depend on what the current codetool needs:
295266
296- * First a source file is loaded in a TCodeBuffer. The IDE uses this step to change the encoding to UTF8. The files are kept in memory and only reloaded if the modification date changes or if a file is manually reverted. There are several tools and functions which work directly on the buffer.
297- * The next step is to parse the unit (or include file). A unit must be parsed from the beginning, so the codetools tries to find the main file, the first file of a unit. It does that by looking for a directive in the first line like {%MainUnit ../lclintf.pp}. If that does not exist, it searches in the includelink cache. The IDE saves this cache to disk, so the IDE learns over time.
298- * After finding the main file a TCodeTool is created and a TLinkScanner parses the source. It handles compiler directives, such as include directives and conditional directives. The scanner can be given a range, so it might, for instance, parse only a unit's interface. The scanner creates the **clean source**. The clean source is put together from all include files, having been stripped of code in the _else_ part of conditional directives, which is skipped. It also creates a list of **links** which map the clean source to the real source files. The clean source is now Pascal containing no _else_ code. Note: there are also tools designed to scan a single source for all directives. These tools create a tree of directives.
299- * After creating the clean source a TCodeTool parses it and creates a tree of TCodeTreeNode. It can also be given a range. This parser skips a few parts, for example class members, begin..end blocks and parameter lists. Many tools don't need them. These sub nodes are created on demand. A TCodeTreeNode has a range StartPos..EndPos which are clean positions, that means positions in the clean source. There are only nodes for the important parts. Creating nodes for every detail would need more memory than the source itself and is seldom needed. There are plenty of functions to find out the details. For example if a function has the 'cdecl' calling convention.
300- * When searching for an identifier the search stores the base types it finds and creates caches for all identifiers in the interface section.
267+- First a source file is loaded in a TCodeBuffer. The IDE uses this step to change the encoding to UTF8. The files are kept in memory and only reloaded if the modification date changes or if a file is manually reverted. There are several tools and functions which work directly on the buffer.
268+- The next step is to parse the unit (or include file). A unit must be parsed from the beginning, so the codetools tries to find the main file, the first file of a unit. It does that by looking for a directive in the first line like {%MainUnit ../lclintf.pp}. If that does not exist, it searches in the includelink cache. The IDE saves this cache to disk, so the IDE learns over time.
269+- After finding the main file a TCodeTool is created and a TLinkScanner parses the source. It handles compiler directives, such as include directives and conditional directives. The scanner can be given a range, so it might, for instance, parse only a unit's interface. The scanner creates the **clean source**. The clean source is put together from all include files, having been stripped of code in the *else* part of conditional directives, which is skipped. It also creates a list of **links** which map the clean source to the real source files. The clean source is now Pascal containing no *else* code. Note: there are also tools designed to scan a single source for all directives. These tools create a tree of directives.
270+- After creating the clean source a TCodeTool parses it and creates a tree of TCodeTreeNode. It can also be given a range. This parser skips a few parts, for example class members, begin..end blocks and parameter lists. Many tools don't need them. These sub nodes are created on demand. A TCodeTreeNode has a range StartPos..EndPos which are clean positions, that means positions in the clean source. There are only nodes for the important parts. Creating nodes for every detail would need more memory than the source itself and is seldom needed. There are plenty of functions to find out the details. For example if a function has the 'cdecl' calling convention.
271+- When searching for an identifier the search stores the base types it finds and creates caches for all identifiers in the interface section.
301272
302-Every level has its own caches, which need to be checked and updated before calling a function. Many high level functions accessible via the CodeToolBoss do that automatically. For others it is the responsibility of the caller.
273+Every level has its own caches, which need to be checked and updated before calling a function. Many high level functions accessible via the CodeToolBoss do that automatically. For others it is the responsibility of the caller.
303274
304-Example for:
275+Example for:
305276
306-unit1.pas:
307-```
277+unit1.pas:
278+
279+``` pascal
308280unit Unit1;
309- {$I settings.inc}
310- interface
311- uses
312- {$IFDEF Flag}
313- unix,
314- {$ELSE}
315- windows,
316- {$ENDIF}
317- Classes;
281+{$I settings.inc}
282+interface
283+uses
284+ {$IFDEF Flag}
285+ unix,
286+ {$ELSE}
287+ windows,
288+ {$ENDIF}
289+ Classes;
318290```
319291
320-settings.inc:
321-```
292+settings.inc:
293+
294+``` pascal
322295{%MainUnit unit1.pas}
323- {$DEFINE Flag}
296+{$DEFINE Flag}
324297```
325298
326-clean source:
327-```
299+clean source:
300+
301+``` pascal
328302unit Unit1;
329- {$I settings.inc}{%MainUnit unit1.pas}
330- {$DEFINE Flag}
331- interface
332- uses
333- {$IFDEF Flag}
334- unix,
335- {$ELSE}{$ENDIF}
336- Classes;
303+{$I settings.inc}{%MainUnit unit1.pas}
304+{$DEFINE Flag}
305+interface
306+uses
307+ {$IFDEF Flag}
308+ unix,
309+ {$ELSE}{$ENDIF}
310+ Classes;
337311```
338312
339-
340-Hint: To easily parse a unit and build the nodes, use **CodeToolBoss.Explore**.
313+Hint: To easily parse a unit and build the nodes, use **CodeToolBoss.Explore**.
341314
342315# Tool, Node, LinkScanner
343316
344317## Tool
345318
346-A tool is a TCodeTool. For Pascal files every unit, program and package gets its own TCodeTool. These are automatically created by the CodetoolBoss when parsing sources. A tool has a Scanner (TLinkScanner) and a Root (TCodeTreeNode), which is the root node of the tree of Pascal nodes of the module (e.g. unit).
319+A tool is a TCodeTool. For Pascal files every unit, program and package gets its own TCodeTool. These are automatically created by the CodetoolBoss when parsing sources. A tool has a Scanner (TLinkScanner) and a Root (TCodeTreeNode), which is the root node of the tree of Pascal nodes of the module (e.g. unit).
347320
348321## LinkScanner
349322
350-Every TCodeTool creates a TLinkScanner to scan the files and creates the CleanedSrc, which is the parsed unit source, include files included and code in skipped $IF directives removed. When only the unit interface was parsed, the CleanedSrc may not be complete. TLinkScanner is not shared between TCodeTools. There is a 1:1 mapping between TLinkScanner and TCodeTool.
323+Every TCodeTool creates a TLinkScanner to scan the files and creates the CleanedSrc, which is the parsed unit source, include files included and code in skipped \$IF directives removed. When only the unit interface was parsed, the CleanedSrc may not be complete. TLinkScanner is not shared between TCodeTools. There is a 1:1 mapping between TLinkScanner and TCodeTool.
351324
352325## Node
353326
354- * A TCodeTreeNode is part of a tree of such nodes. The root node is stored in a TCodeTool.Root. Nodes are not shared between tool. Every node is associated with exactly one TCodeTool.
355- * When a function returns a Node, it always returns the associated Tool as well.
356- * Node.StartPos/EndPos are positions 1-based in the Scanner.CleanedSrc.
357- * To get from the cleaned postion to the file, line, column use Tool.CleanPosToCaret(Node.StartPos,xyp).
327+- A TCodeTreeNode is part of a tree of such nodes. The root node is stored in a TCodeTool.Root. Nodes are not shared between tool. Every node is associated with exactly one TCodeTool.
328+- When a function returns a Node, it always returns the associated Tool as well.
329+- Node.StartPos/EndPos are positions 1-based in the Scanner.CleanedSrc.
330+- To get from the cleaned postion to the file, line, column use Tool.CleanPosToCaret(Node.StartPos,xyp).
358331
359332# CleanPos and CursorPos
360333
361-There are several methods to define a position in the codetools.
334+There are several methods to define a position in the codetools.
362335
363-The codetools Absolute position is related to the source as a continuous string starting at character 1. For example a TCodeBuffer holds the file contents as a single string in its Source property. Caret or cursor positions are given as X,Y where X is the column number and Y the line number. Each value (X and Y) starts at 1. A TCodeBuffer provides the member functions **LineColToPosition'_and_** _AbsoluteToLineCol_ to convert between (X,Y) values and the Absolute codetools position. When working with multiple source files (such as a unit which may contain several include files), the clean position relates to the absolute position in the stripped code **Src**. Here Src is a string whose clean positions start at 1. Cursor positions are specified as TCodeXYPosition (Code,X,Y). A TCodeTool provides the functions **CaretToCleanPos** and **CleanPosToCaret** to convert between them.
336+The codetools Absolute position is related to the source as a continuous string starting at character 1. For example a TCodeBuffer holds the file contents as a single string in its Source property. Caret or cursor positions are given as X,Y where X is the column number and Y the line number. Each value (X and Y) starts at 1. A TCodeBuffer provides the member functions **LineColToPosition** and **AbsoluteToLineCol'' to convert between (X,Y) values and the Absolute codetools position. When working with multiple source files (such as a unit which may contain several include files), the clean position relates to the absolute position in the stripped code**Src**. Here Src is a string whose clean positions start at 1. Cursor positions are specified as TCodeXYPosition (Code,X,Y). A TCodeTool provides the functions**CaretToCleanPos**and**CleanPosToCaret''' to convert between them.
364337
365338# Inserting, deleting, replacing - the TSourceChangeCache
366339
367-When making changes to the source code of a unit (or its include files) you should use the CodetoolBoss.SourceChangeCache instead of altering the source directly.
340+When making changes to the source code of a unit (or its include files) you should use the CodetoolBoss.SourceChangeCache instead of altering the source directly.
368341
369- * Simple usage: Connect, Replace, Replace, ... Apply. See below.
370- * You can use cleanpos as given by the node tree OR you can use direct position in a file.
371- * You can use Replace to insert and delete, which automatically calls events, so connected editors are notified of changes.
372- * It can automatically insert needed spaces, line breaks or empty lines in front or behind each Replace. For example you define that there should be an empty line in front. The SourceChangeCache checks what is inserted and how much space there is already and will insert needed space.
373- * It checks if the replaced/deleted span is writable.
374- * You can do multiple Replaces and you control when they are applied. Keep in mind that inserting code means that the parsed tree becomes invalid and needs rebuilding.
375- * Multiple replaces are checked for intersection. For example an insert in the middle of deleted code gives an error.
376- * Mutiple insertions at the same place are added FIFO - first at the top.
377- * You can combine several functions altering code to one bigger function. See below.
342+- Simple usage: Connect, Replace, Replace, ... Apply. See below.
343+- You can use cleanpos as given by the node tree OR you can use direct position in a file.
344+- You can use Replace to insert and delete, which automatically calls events, so connected editors are notified of changes.
345+- It can automatically insert needed spaces, line breaks or empty lines in front or behind each Replace. For example you define that there should be an empty line in front. The SourceChangeCache checks what is inserted and how much space there is already and will insert needed space.
346+- It checks if the replaced/deleted span is writable.
347+- You can do multiple Replaces and you control when they are applied. Keep in mind that inserting code means that the parsed tree becomes invalid and needs rebuilding.
348+- Multiple replaces are checked for intersection. For example an insert in the middle of deleted code gives an error.
349+- Mutiple insertions at the same place are added FIFO - first at the top.
350+- You can combine several functions altering code to one bigger function. See below.
378351
379352## Usage
380353
381-The SourceChangeCache works on a unit, so you need to get a TCodeTool and scan a unit/include file. For example:
382-```
383-// Step 1: load the file and parse it
384- Code:=CodeToolBoss.LoadFile(Filename,false,false);
385- if Code=nil then
386- raise Exception.Create('loading failed '+Filename);
387- if not CodeToolBoss.Explore(Code,Tool,false) then
388- ...;// parse error ...
389-
390- // Step 2: connect the SourceChangeCache
391- CodeToolBoss.SourceChangeCache.MainScanner:=Tool.Scanner;
392-
393- // Step 3: use Replace to insert and/or delete code
394- // The first two parameters are the needed spaces in front and behind the insertion
395- // The FromPos,ToPos defines the deleted/replaced range in CleanPos positions.
396- // The NewCode is the string of new code. Use '' for a delete.
397- if not CodeToolBoss.SourceChangeCache.Replace(gtNone,gtNone,FromPos,ToPos,NewCode) then
398- exit; // e.g. source read only or a former Replace has deleted the place
399- ...do some more Replace...
400-
401- // Step 4: Apply the changes
402- if not CodeToolBoss.SourceChangeCache.Apply then
403- exit; // apply was aborted
354+The SourceChangeCache works on a unit, so you need to get a TCodeTool and scan a unit/include file. For example:
355+
356+``` pascal
357+ // Step 1: load the file and parse it
358+ Code:=CodeToolBoss.LoadFile(Filename,false,false);
359+ if Code=nil then
360+ raise Exception.Create('loading failed '+Filename);
361+ if not CodeToolBoss.Explore(Code,Tool,false) then
362+ ...;// parse error ...
363+
364+ // Step 2: connect the SourceChangeCache
365+ CodeToolBoss.SourceChangeCache.MainScanner:=Tool.Scanner;
366+
367+ // Step 3: use Replace to insert and/or delete code
368+ // The first two parameters are the needed spaces in front and behind the insertion
369+ // The FromPos,ToPos defines the deleted/replaced range in CleanPos positions.
370+ // The NewCode is the string of new code. Use '' for a delete.
371+ if not CodeToolBoss.SourceChangeCache.Replace(gtNone,gtNone,FromPos,ToPos,NewCode) then
372+ exit; // e.g. source read only or a former Replace has deleted the place
373+ ...do some more Replace...
374+
375+ // Step 4: Apply the changes
376+ if not CodeToolBoss.SourceChangeCache.Apply then
377+ exit; // apply was aborted
404378```
405379
406380## BeginUpdate/EndUpdate
407381
408-BeginUpdate/EndUpdate delays the Apply. This is useful when combining several code changing functions. For example:
382+BeginUpdate/EndUpdate delays the Apply. This is useful when combining several code changing functions. For example:
409383
410-You want to scan the unit, add a unit to the interface uses section, and remove the unit from the implementation uses section. The two functions AddUnitToMainUsesSection and RemoveUnitFromUsesSection use Apply, altering the source, so the second function would rescan the unit a second time. But since the two functions are independent of each other (they change different parts of the source) you can combine them and do it with one scan:
411-```
412-// Step 1: parse unit and connect SourceChangeCache
413- if not CodeToolBoss.Explore(Code,Tool,false) then
414- ...;// parse error ...
415- CodeToolBoss.SourceChangeCache.MainScanner:=Tool.Scanner;
416-
417- // Step 2: delay Apply
418- CodeToolBoss.SourceChangeCache.BeginUpdate;
419-
420- // Step 3: add unit to interface section
421- // AddUnitToMainUsesSection would apply and change the code
422- // Because of the BeginUpdate the change is not yet done, but stored in the SourceChangeCache
423- if not Tool.AddUnitToMainUsesSection('Classes','',CodeToolBoss.SourceChangeCache) then exit;
424-
425- // Step 4: remove unit from implementation section
426- // Without the BeginUpdate the RemoveUnitFromUsesSection would rescan the unit
427- if Tool.FindImplementationUsesSection<>nil then
428- if not Tool.RemoveUnitFromUsesSection(Tool.FindImplementationUsesSection,'Classes',CodeToolBoss.SourceChangeCache) then exit;
429-
430- // Step 5: apply all changes
431- if not CodeToolBoss.SourceChangeCache.EndUpdate then
432- exit; // apply was aborted
384+You want to scan the unit, add a unit to the interface uses section, and remove the unit from the implementation uses section. The two functions AddUnitToMainUsesSection and RemoveUnitFromUsesSection use Apply, altering the source, so the second function would rescan the unit a second time. But since the two functions are independent of each other (they change different parts of the source) you can combine them and do it with one scan:
385+
386+``` pascal
387+ // Step 1: parse unit and connect SourceChangeCache
388+ if not CodeToolBoss.Explore(Code,Tool,false) then
389+ ...;// parse error ...
390+ CodeToolBoss.SourceChangeCache.MainScanner:=Tool.Scanner;
391+
392+ // Step 2: delay Apply
393+ CodeToolBoss.SourceChangeCache.BeginUpdate;
394+
395+ // Step 3: add unit to interface section
396+ // AddUnitToMainUsesSection would apply and change the code
397+ // Because of the BeginUpdate the change is not yet done, but stored in the SourceChangeCache
398+ if not Tool.AddUnitToMainUsesSection('Classes','',CodeToolBoss.SourceChangeCache) then exit;
399+
400+ // Step 4: remove unit from implementation section
401+ // Without the BeginUpdate the RemoveUnitFromUsesSection would rescan the unit
402+ if Tool.FindImplementationUsesSection<>nil then
403+ if not Tool.RemoveUnitFromUsesSection(Tool.FindImplementationUsesSection,'Classes',CodeToolBoss.SourceChangeCache) then exit;
404+
405+ // Step 5: apply all changes
406+ if not CodeToolBoss.SourceChangeCache.EndUpdate then
407+ exit; // apply was aborted
433408```
434409
435-BeginUpdate/EndUpdate work with a counter, so if you call BeginUpdate twice you need to call EndUpdate twice. This means you can put the above example in a function and combine that with another function.
410+BeginUpdate/EndUpdate work with a counter, so if you call BeginUpdate twice you need to call EndUpdate twice. This means you can put the above example in a function and combine that with another function.
436411
437412## Saving changes to disk
438413
439-The above changes are made to the code buffers and the buffers are marked modified. To save the changes to disk, you have to call Save for each modified buffer.
414+The above changes are made to the code buffers and the buffers are marked modified. To save the changes to disk, you have to call Save for each modified buffer.
440415
441- * The buffers that will be modified in the next Apply/EndUpdate are in SourceChangeCache.BuffersToModify and BuffersToModifyCount.
442- * The events SourceChangeCache.OnBeforeApplyChanges/OnAfterApplyChanges are used by the CodeToolBoss, which connects it to its own OnBeforeApplyChanges/OnAfterApplyChanges. The Lazarus IDE sets these events and automatically opens modified files in the source editor, so all changes go into the undo list of synedit.
416+- The buffers that will be modified in the next Apply/EndUpdate are in SourceChangeCache.BuffersToModify and BuffersToModifyCount.
417+- The events SourceChangeCache.OnBeforeApplyChanges/OnAfterApplyChanges are used by the CodeToolBoss, which connects it to its own OnBeforeApplyChanges/OnAfterApplyChanges. The Lazarus IDE sets these events and automatically opens modified files in the source editor, so all changes go into the undo list of synedit.
443418
444419# Hints/Tips/Guide Lines
445420
446- * BuildTree checks the current state and will only parse if needed. If a former call has parsed the interface and you need the interface again, BuildTree will not do anything. If you need the full unit, only the implementation will be parsed. Nodes are only freed if some files have changed on disk or some settings have changed (initial macros). BuildTree does not check all files on every call. Instead it uses the directory cache of the codetools. So, if nothing has changed it will return very quickly. You should call it before any search operation.
447- * Do **not** call BuildTree **after** an operation. That is a waste of CPU.
448- * BuildTree raises an exception when there are missing include files or syntax errors. You should enclose your code into
421+- BuildTree checks the current state and will only parse if needed. If a former call has parsed the interface and you need the interface again, BuildTree will not do anything. If you need the full unit, only the implementation will be parsed. Nodes are only freed if some files have changed on disk or some settings have changed (initial macros). BuildTree does not check all files on every call. Instead it uses the directory cache of the codetools. So, if nothing has changed it will return very quickly. You should call it before any search operation.
422+- Do **not** call BuildTree **after** an operation. That is a waste of CPU.
423+- BuildTree raises an exception when there are missing include files or syntax errors. You should enclose your code into
449424
450-```
425+``` pascal
451426try
452- Tool.BuildTree(lsrEnd);
453- ... search ... replace
454- except
455- on E: Exception do
456- CodeToolBoss.HandleException(E);
457- end;
427+ Tool.BuildTree(lsrEnd);
428+ ... search ... replace
429+except
430+ on E: Exception do
431+ CodeToolBoss.HandleException(E);
432+end;
458433```
459434
460- * After calling SourceChangeCache.Replace (multiple times) the sources (TCodeBuffers) have not changed immediately. You must call SourceChangeCache.Apply to change the sources. This will not save the changes to file.
435+- After calling SourceChangeCache.Replace (multiple times) the sources (TCodeBuffers) have not changed immediately. You must call SourceChangeCache.Apply to change the sources. This will not save the changes to file.
461436
462437# Test suite
463438
464-The codetools test suite can be found here:
465-```
466-lazarus/components/codetools/tests/runtestscodetools
467-```
439+The codetools test suite can be found here:
468440
469-Compile it and run it:
470-```
471-cd lazarus/components/codetools/tests
472- ./runtestscodetools
473-```
441+`lazarus/components/codetools/tests/runtestscodetools`
474442
443+Compile it and run it:
444+
445+`cd lazarus/components/codetools/tests`\
446+`./runtestscodetools`
447+
475448# Links
476449
477- * [[Lazarus IDE Tools]] \- A tutorial about the built-in tools of the standard IDE
478- * [[Cody]] \- IDE package adding advanced code tools to the IDE
479- * [[Extending the IDE]] \- How to write your own codetools plugins for the IDE.
450+- [[Lazarus IDE Tools]] - A tutorial about the built-in tools of the standard IDE
451+- [[Cody]] - IDE package adding advanced code tools to the IDE
452+- [[Extending the IDE]] - How to write your own codetools plugins for the IDE.
480453
481454---
482-*From the Free Pascal wiki, page "Codetools", as the Internet Archive kept it on 2024-12-02. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
455+*From the Free Pascal wiki, page "Codetools", as it stood on 2020-12-31 after a change by Mattias2, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
456+Category: Components

Back to history