Fully automatic indentation

From Free Pascal wiki
Revision as of 14:26, 14 November 2009 by Mattias2 (talk | contribs) (→‎Examples)
Jump to navigationJump to search

Overview

Since 0.9.29 the lazarus source editor has a new algorithm for automatic indentation on pressing Enter or on pasting code from clipboard. This new algorithm works only for pascal and works different to many other editors you may know. Most other editors use either a fixed set of rules or a set of options to configure the rules. This is semi automatic indentation. These options are either too simple or too complex. And the other editors only allow one set of rules, so editing sources with different policies is difficult.

Fully automatic indentation tries to guess the rules from the surrounding code. It does that by searching for similar code and copying the indent.

Because it works fully automatic there are only a few options. You can disable it, you can setup the search scope and you can provide an example code: Codetools Options: Indentation. You do not need to learn rules, just write pascal.

How it works

For example you have the code: <Delphi> procedure TMainForm.Button1Click(Sender: TObject); begin | end; </Delphi>

You place the cursor at column 1 and paste the code <Delphi>

   if Visible then
   begin
   end;

</Delphi>

Note that the code on the clipboard is already indented by 4.

The indenter first scans the code, finds out, that the insertion position is in a begin..end block of a procedure. With the standard options it searches the code in front for other procedure begin..end blocks. If it does not find the code it searches behind the code, then in all units of the project (or package) and finally in the example code of the options. For instance it finds:

<Delphi> procedure TMainForm.FormPaint(Sender: TObject); begin

 with Canvas do FillRect(0,0,Width,Height);

end; </Delphi>

The indentation of the first token with is 2. The indentation of the first token of clipboard code is 4, so the indenter unindents the code by 2, resulting in:

<Delphi> procedure TMainForm.Button1Click(Sender: TObject); begin

 if Visible then
 begin
 end;|

end; </Delphi>

Examples

Sometimes record and classes are aligned to the keywords instead of start of last line.

<Delphi> type TMyRecord = record

                i: integer;
                end;

</Delphi>

begin end

<Delphi> procedure Do; var

 i: integer; // indent after var

begin // no indent after procedure, no indent before procedure-begin, unindent after var section

 if expr then
 begin       // no indent after then, no indent before then-begin
   Code;     // indent after begin
 end;        // unindent before end

end; </Delphi>

<Delphi> procedure Do; begin

 if expr then begin  
   Code;             // indent after begin
 end;                // unindent before end

end; </Delphi>

<Delphi> procedure Do; begin

 if expr then
   begin   // indent after then and unindent after then-statement
   Code;   // no indent after begin
   end;    // no unindent before end

end; </Delphi>

<Delphi> procedure Do; begin

 if expr then
   begin     // indent after then and unindent after then-statement
     Code;   // indent after begin
   end;      // unindent before end

end; </Delphi>

repeat until

I never saw code other than this:

<Delphi> repeat

 Code; // indent after repeat

until ; // unindent before until </Delphi>

try finally

I never saw code other than this:

<Delphi> try

 Code;     // indent after try

finally // unindent before finally

 on e do ; // indent after finally

end; // unindent before finally-end </Delphi>

case of end

<Delphi> case expr of 1: ; // no indent after case-of 2:

 Code;    // indent after case-colon

const:

 begin    // indent after case-colon
   Code;  // indent after case-colon-begin
 end;     // unindent before case-colon-end, unindent after case-colon-end

else // no indent case-else

 Code;    // indent after case-else

end; // unindent after case-else statements </Delphi>

<Delphi> case expr of

          // empty lines => not supported
 1: ; // indent after case-of
 2: 
 begin    // no indent after case-colon
 end;

else // no indent before case-else end; // no indent before case-end </Delphi>

if then else

<Delphi> if expr then

 Code

else

 Code;

</delphi>

<Delphi> if expr or

 expr or
 expr then
 Code

else

 Code;

</delphi>

<Delphi> if expr

 or expr

then

 Code

else

 Code;

</delphi>

<Delphi> if SrcEdit.SelectionAvailable and SrcEdit.CaretInSelection(CaretPos) then Expression := SrcEdit.GetText(True) else Expression := Identifier; if not DebugBoss.Evaluate(Expression, DebugEval) or (DebugEval = ) then DebugEval := '???'; </delphi>