Lazarus IDE Tools/sk
Nástroje IDE Lazarus
Úvod
IDE používa knižnicu analýzy zdrojového kódu Pascal a editačných nástrojov, zvanú "codetools". Tieto nástrojeposkytujú funkcie ako hľadanie deklarácie (find declaration), dokončovanie kódu (code completion), odstraňovanie, presúvanie, vkladanie a formátovanie zdrojového kódu Pascal. Tieto funkcie šetria mnoho času a dupľovanej roboty. Sú nastaviteľné a každá funkcia je dostupná pomocou klávesovej skratky (viz Editor Options).
Pretože ich práca záleží na zdrojovom kóde a pochopení FreePascal, Delphi a Kylix kódu, nevyžadujú preložené jednotky ani nainštalovaný prekladač Borland. Môžete naraz upravovať kód Delphi aj FreePascal. Môžete dokonca pracovať s rôznymi verziami Delphi a FreePascal naraz. Tým sa stáva prenos kódu Delphi ešte jednoduchší.
Zhrnutie klávesových skratiek IDE
Method Jumping | Ctrl+Shift+Up (toggle between definition and body) |
Code Templates | Ctrl+J |
Code Completion (Class Completion) | Ctrl+Shift+C |
Identifier Completion | Ctrl+Space |
Prepínanie metód
(Method Jumping) Na prepínanie medzi telom procedúry (begin..end) a jej definíciou (procedure Name;) použite Ctrl+Shift+Up.
Príklad:
interface procedure DoSomething; // procedure definition implementation procedure DoSomething; // procedure body begin end;
Ak je kurzor v tele provedúry a stlačíte Ctrl+Shift+Up, kurzor skočí na definíciu. Ak znova stlačíte Ctrl+Shift+Up preskočí do tela procedúry, za 'begin'. Funkcia pracuje aj s metódami (procedúrami v triedach).
Tipy: 'Method Jumping' presúva kurzor na rovnakú procedúru s rovnakým menom i zoznamom parametrov. Ak presná procedúra neexistuje, skočí na najpodobnejšiu a umiestni kurzor na prvý rozdiel. V Delphi táto funkcia neexistuje.
Príklad procedúry s rôznymi typmi parametrov:
interface procedure DoSomething(p: char); // procedure definition implementation procedure DoSomething(p: string); // procedure body begin end;
Preskočenie z definície do tela umiestni kurzor na kľúčové slovo 'string'. Túto vlastnosť môžete využiť na premenovanie metódy a/alebo zmenu jej parametrov.
Príklad: Premenovali ste 'DoSomething' na 'MakeIt':
interface procedure MakeIt; // procedure definition implementation procedure DoSomething; // procedure body begin end;
Potom urobte skok z definície MakeIt do tela. IDE hľadá vhodné telo, nenájde žiadne, preto začne hľadať kandidátov. Keďže stepremenovali len jednu procedúru, tak je len jedno telo bez definície (DoSomething) a tak skočí do DoSomething a umiestni kurzor vpravo od 'DoSomething'. Potomm ju môžete jednoducho premenovať tiež. Toto rovnako pracuje s parametrami.
Include súbory
(Include Files) Include súbory sú súbory vložené do zdrojového kódu pomocou direktív prekladača {$I filename} alebo {$INCLUDE filename}. Lazarus a FreePascal používajú veľa takýchto vecí na redukciu nadbytočnosti a vyhnuutie sa nečitateľnosti konštrukcií {$IFDEF} pri podpore rôznych platforiem. Narozdiel od Delphi, IDE Lazarus plne podporuje include súbory. Napríklad môžete skočiť z metódy v súbore .pas do tela metódy v include súbore. Všetky nástroje kódu, ako dokončovanie kódu, považuje include súbory za špeciálne hranice. Napríklad: keď dokončovanie kódu pridáva telo novej metódy za telom inej metódy, ponechá ich obe v rovnakom súbore. Týmto spôsobom môžete vložiť celú implementáciu triedy do include súborov, ako to robí LCL pre skoro všetky prvky. Ale je tu začiatočnícka chyba: Ak najprv otvoríte include súbor a skúsite prepínanie metód alebo hľadanie deklarácie, dostanete chybu. IDE nevie do ktorej jednotky include súbor patrí. Najprv musíte otvoriť jednotku. Hneď ako IDE zanalyzuje jednotku, zachytí v nej include direktívy a IDE si bude pamätať tento vzťah. Tieto informácie IDE ukladá pri skončení a pri uložení projektu do ~/.lazarus/includelinks.xml. Keď nabudúce otvoríte súbor include a urobíte skok do neho alebo hľadanie deklarácie, IDE interne otvorí jednotku a skoky budú fungovať. Tento mechanizmus má samozrejme obmedzenia, niektoré include súbory sú zahrnuté dva i viackrát. Napríklad: lcl/include/winapih.inc. Skákanie z definície procedúry/metódy v tomto include súbore do tela závisí na poslednej akcii. Ak ste pracovali v lcl/lclintf.pp, IDE skočí do winapi.inc. Ak ste pracovali v lcl/interfacebase.pp, potom skočíte do lcl/include/interfacebase.inc (alebo do jedného z ďalších include súborov). Ak pracujete s obomi, potom môže nastať zmätok. ;)
Šablóny kódu
(Code Templates) Šablóny kódu konvertujú identifikátor v texte alebo fragmente kódu. Šablóny kódu majú prednastavenú klávesovú skratku Ctrl+J. Môžete napísať identifikátor, stlačiť Ctrl+J a identifikátor je nahradený textom definovaným pre identifikátor. Šablóny kódu môžete definovať v Environment -> Editor Options -> CodeTools.
Príklad: Napíšte identifikátor 'classf', ponechajte kurzor vpravo za 'f' a stlačte Ctrl+J. Identifikátor 'classf' bude nahradený týmto:
T = class(T) private public constructor Create; destructor Destroy; override; end;
a kurzor bude za 'T'. Zoznam šablón získate tak, že kurzor ponecháte na medzere (nie ne identifikátore) a stlačíte Ctrl+J. Pomocou kurzorových klávesov alebon apísania niekoľkých znakov vyberte jeden. Enter vytvorí zvolenú šablónu a Esc zatvorí zoznam.
Dokončovanie kódu
(Code Completion) Dokončovanie kódu nájdete v menu IDE Edit -> Complete Code a má štandartnú klávespvú skratku Ctrl+Shift+C. V Delphi je dokončovaním kódu volaná funkcia zobrazujúca zoznam identifikátorov na aktuálnej pozícii v zdrojovom kóde (Ctrl+Space). V Lazarus je toto nazývané dokončovanie identifikátorov (Identifier completion). Dokončovanie kódu v sebe združuje niekoľko užitočných funkcií:
- Dokončovanie tried (Class Completion): dokončuje vlastnosti, pridáva telá metód, pridáva súkromné premenné a súkromné metódy;
- Dokončovanie forward procedúr (Forward Procedure Completion): pridáva telá forward procedúr;
- Dokončovanie priradenia udalostí (Event Assignment Completion): * dokončuje pridelenie udalostí a pridávanie tiel a definícií metód;
- * Dokončovanie lokálnych premenných (Local Variable Completion): pridáva definície lokálnych premenných.
Ktorá funkcia je použitá, závisí na pozícii kurzora v editore zdrojového kódu.
Class Completion
The most powerful code completion feature is "Class Completion". You write a class, add the methods and properties and Code Completion will add the method bodies, the property access methods/variables and the private variables.
For example: Create a class (see Code Templates to save you some type work):
TExample = class(TObject) public constructor Create; destructor Destroy; override; end;
Position the cursor somewhere in the class and press Ctrl+Shift+C. This will create the method missing bodies and move the cursor to the first created method body, so you can just start writing the class code:
{ TExample } constructor TExample.Create; begin | end; destructor TExample.Destroy; begin inherited Destroy; end;
Note: The '|' is the cursor and is not added.
Hint: You can jump between a method and its body with Ctrl+Shift+Up.
You can see, that the IDE added the 'inherited Destroy' call too. This is done, if there is an 'override' keyword in the class definition.
Now add a method DoSomething:
TExample = class(TObject) public constructor Create; procedure DoSomething(i: integer); destructor Destroy; override; end;
Then press Ctrl+Shift+C and the IDE will add
procedure TExample.DoSomething(i: integer); begin | end;
You can see, that the new method body is inserted between Create and Destroy, exactly as in the class definition. This way the bodies keep the same logical ordering as you define. You can define the insertion policy in Environment > Codetools Options -> Code Creation.
Complete Properties
Add a property AnInteger:
TExample = class(TObject) public constructor Create; procedure DoSomething(i: integer); destructor Destroy; override; property AnInteger; end;
Press Ctrl+Shift+C and you will get:
procedure TExample.SetAnInteger(const AValue: integer); begin |if FAnInteger=AValue then exit; FAnInteger:=AValue; end;
The code completion has added a Write access modifier and added some common code. Jump to the class with Ctrl+Shift+Up to see the new class:
TExample = class(TObject) private FAnInteger: integer; procedure SetAnInteger(const AValue: integer); public constructor Create; procedure DoSomething(i: integer); destructor Destroy; override; property AnInteger: integer read FAnInteger write SetAnInteger; end;
The property was extended by a Read and Write access modifier. The class got the new section 'private' with a Variable 'FAnInteger' and the method 'SetAnInteger'. It is a common Delphi style rule to prepend private variables with an 'F' and the write method with a 'Set'. If you don't like that, you can change this in Environment > Codetools Options -> Code Creation.
Creating a read only property:
property PropName: PropType read;
Will be expanded to
property PropName: PropType read FPropName;
Creating a write only property:
property PropName: PropType write;
Will be expanded to
property PropName: PropType write SetPropName;
Creating a read only property with a Read method:
property PropName: PropType read GetPropName;
Will be kept and a GetPropName function will be added:
function GetpropName: PropType;
Creating a property with a stored modifier:
property PropName: PropType stored;
Will be expanded to
property PropName: PropType read FPropName write SetPropName stored PropNameIsStored;
Because stored is used for streaming read and write modifiers are automatically added as well.
Hint: Identifier completion also recognizes incomplete properties and will suggest the default names. For example:
property PropName: PropType read |;
Place the cursor one space behind the 'read' keyword and press Ctrl+Space for the identifier completion. It will present you the variable 'FPropName' and the procedure 'SetPropName'.
Forward Procedure Completion
"Forward Procedure Completion" is part of the Code Completion and adds missing procedure bodies. It is invoked, when the cursor is on a forward defined procedure.
For example: Add a new procedure to the interface section:
procedure DoSomething;
Place the cursor on it and press Ctrl+Shift+C for code completion. It will create in the implementation section:
procedure DoSomething; begin | end;
Hint: You can jump between a procedure definition and its body with Ctrl+Shift+Up.
The new procedure body will be added in front of the class methods. If there are already some procedures in the interface the IDE tries to keep the ordering. For example:
procedure Proc1; procedure Proc2; // new proc procedure Proc3;
If the bodies of Proc1 and Proc3 already exists, then the Proc2 body will be inserted between the bodies of Proc1 and Proc3. This behaviour can be setup in Environment > Codetools Options -> Code Creation.
Multiple procedures:
procedure Proc1_Old; // body exists procedure Proc2_New; // body does not exists procedure Proc3_New; // " procedure Proc4_New; // " procedure Proc5_Old; // body exists
Code Completion will add all 3 procedure bodies (Proc2_New, Proc3_New, Proc4_New).
Why calling it "Forward Procedure Completion"?
Because it does not only work for procedures defined in the interface, but for procedures with the "forward" modifier as well.
Event Assignment Completion
"Event Assignment Completion" is part of the Code Completion and completes a single Event:=| statement. It is invoked, when the cursor is behind an assignment to an event.
For example: In a method, say the FormCreate event, add a line 'OnPaint:=':
procedure TForm1.Form1Create(Sender: TObject); begin OnPaint:=| end;
The '|' is the cursor and should not be typed. Then press Ctrl+Shift+C for code completion. The statement will be completed to
OnPaint:=@Form1Paint;
A new method Form1Paint will be added to the TForm1 class. Then class completion is started and you get:
procedure TForm1.Form1Paint(Sender: TObject); begin | end;
This works just like adding methods in the object inspector.
Note:
You must place the cursor behind the ':=' assignment operator. If you place the cursor on the identifier (e.g. OnPaint) code completion will invoke "Local Variable Completion", which fails, because OnPaint is already defined.
Hint:
You can define the new method name by yourself. For example:
OnPaint:=@ThePaintMethod;
Local Variable Completion
"Local Variable Completion" is part of the Code Completion and adds a local variable definition for a Identifier:=Term; statement. It is invoked, when the cursor is on the identifier of the assignment.
For example:
procedure TForm1.Form1Create(Sender: TObject); begin i:=3; end;
Place the cursor on the 'i' or just behind it. Then press Ctrl+Shift+C for code completion and you will get:
procedure TForm1.Form1Create(Sender: TObject); var i: Integer; begin i:=3; end;
The codetools first checks, if the identifier 'i' is already defined and if not it will add the declaration 'var i: integer;'. The type of the identifier is guessed from the term right to the assignment ':=' operator. Numbers like the 3 defaults to Integer.
Another example: type
TWhere = (Behind, Middle, InFront); procedure TForm1.Form1Create(Sender: TObject); var a: array[TWhere] of char; begin for Where:=Low(a) to High(a) do writeln(a[Where]); end;
Place the cursor on 'Where' and press Ctrl+Shift+C for code completion. You get:
procedure TForm1.Form1Create(Sender: TObject); var a: array[TWhere] of char; Where: TWhere; begin for Where:=Low(a) to High(a) do writeln(a[Where]); end;
Comments and Code Completion
Code completion tries to keep comments where they belong. For example:
FList: TList; // list of TComponent FInt: integer;
When inserting a new variable between FList and FInt, the comment is kept in the FList line. Same is true for
FList: TList; { list of TComponent This is a comment over several lines, starting in the FList line, so codetools assumes it belongs to the FLIst line and will not break this relationship. Code is inserted behind the comment. } FInt: integer;
If the comment starts in the next line:
FList: TList; // list of TComponent { This comment belongs to the statement below. New code is inserted above this comment and behind the comment of the FList line. } FInt: integer;
Refactoring
Invert Assignments
- Abstract
- : "Invert Assignments" takes some selected pascal statements and inverts all assignments from this code. This tool is usefull for transforming a "save" code to a "load" one and inverse operation.
Example:
procedure DoSomething; begin AValueStudio:= BValueStudio; AValueAppartment :=BValueAppartment; AValueHouse:=BValueHouse; end;
Select the lines with assignments (between begin and end) and do Invert Assignments. All assignments will be inverted and identation will be add automatically. For example:
Result:
procedure DoSomething; begin BValueStudio := AValueStudio; BValueAppartment := AValueAppartment; BValueHouse := AValueHouse; end;
Extract Procedure
- Abstract
- : "Export Procedure" takes some selected pascal statements and creates a new procedure/method from this code. This tool is useful to split big procedures or to easily create a new procedure from some code.
Basic example:
procedure DoSomething; begin CallSomething; end;
Select the line "CallSomething;" and do Extract Proc. A dialog pop ups and you can select the type and name of the procedure to create. For example: procedure, "NewProc". Result:
procedure NewProc; begin CallSomething; end; procedure DoSomething; begin NewProc; end;
You can see, that the new procedure "NewProc" was created with the selection as body and the old code was replaced by a call.
Local Variables and Parameters:
"Extract Proc" scans for used variables and automatically creates the
parameter list and local variables. Example:
procedure TForm1.DoSomething(var Erni, Bert: integer); var i: Integer; // Comment begin Erni:=Erni+Bert; for i:=Erni to 5 do begin | end; end;
Select the for loop and create a new Procedure "NewProc". The local variable i is only used in the selection, so it will be moved to the new procedure. Erni is also used in the remaining code, so it will become a parameter.
Result:
procedure NewProc(const Erni: integer); var i: Integer; // Comment begin for i:=Erni to 5 do begin | end; end; procedure TForm1.DoSomething(var Erni, Bert: integer); begin Erni:=Erni+Bert; NewProc(Erni); end;
You can see "i" was moved to the new procedure (Note: including its comment) and Erni.
Limitations:
Pascal is a very powerful language, so don't expect it will work with every code. Current limits/ToDos:
- check if selection bounds on statement bounds
- heuristic for parameter specifiers 'var'. At the moment all parameters are "const". If you need "var", you have to edit it manually.
- "with" statements
Find Declaration
Position the cursor on an identifier and do 'Find Declaration'. Then it will search the declaration of this identifier, open the file and jump to it.
Every find declaration sets a Jump Point. That means you jump with find declaration to the declaration and easily jump back with Search -> Jump back.
There are some differences to Delphi: The codetools work on sources following the normal pascal rules, instead of using the compiler output. The compiler returns the final type. The codetools see the sources and all steps in between. For example:
The 'Visible' property is first defined in TControl (controls.pp), then redefined in TCustomForm and finally redefined in TForm. Invoking find declaration on Visible will you first bring to Visible in TForm. Then you can invoke Find Declaration again to jump to Visible in TCustomForm and again to jump to Visible in TControl.
Same is true for types like TColor. For the compiler it is simply a 'longint'. But in the sources it is defined as
TGraphicsColor = -$7FFFFFFF-1..$7FFFFFFF; TColor = TGraphicsColor;
And the same for forward defined classes: For instance in TControl, there is a private variable
FHostDockSite: TWinControl;
Find declaration on TWinControl jumps to the forward definition
TWinControl = class;
And invoking it again jumps to the real implementation
TWinControl = class(TControl)
This way you can track down every identifier and find every overload.
Goto Include Directive
"Goto Include Directive" in the search menu of the IDE jumps to {$I filename} statement where the current include file is used.
Publish Project
Creates a copy of the whole project. If you want to send someone just the sources and compiler settings of your code, this function is your friend.
A normal project directory contains a lot of information. Most of it is not needed to be published: The .lpi file contains session information (like caret position and bookmarks of closed units) and the project directory contains a lot of .ppu, .o files and the executable. To create a lpi file with only the base information and only the sources, along with all sub directories use "Publish Project".
In the dialog you can setup the exclude and include filter, and with the command after you can compress the output into one archive.
Original contributors
This page has been converted from the epikwiki version.
- Created page and initial template - 4/6/2004 VlxAdmin
- Initial content posted - 4/10/2004 MattiasG
- Small wiki and formatting fixes - 4/11/2004 VlxAdmin
- Added a summary table for IdeTools shortcuts - 12 July 2004 User:Kirkpatc