// kate: space-indent on; indent-width 3; replace-tabs on; remove-trailing-spaces all;
// kate: syntax pascal; indent-mode pascal;

// these variables are understood by the pascal indenter ...
// kate: cfgIndentCase true;          // indent elements in a case statement
// kate: cfgIndentBegin 0;            // indent 'begin' this many spaces
// kate: debugMode false;              // show how indent is determined
// kate: cfgAutoInsertStar true;      // auto insert '*' in (* ... *)-comments
// kate: cfgSnapParen true;           // snap ')' to '*)' in comments

(**********************************************   // check: indent OK?
 *                                            *
 *       Commment to test alignment           *
 *                                            *
 *                                            *
 **********************************************)

 (*************************************************************************
 Another Comment

 Relative alignment should be kept ...
       After indent, first character of this line should 
       still remain under the 'v' in relative

 *************************************************************************)

program fred;

uses bbb;

label fred001;
var   i: integer;

const const0 = 0;
   c33 = 12;
   const1 = 17;
   const2 = 18.4;

type x = record a: real; c : char end;

   // r = record ... vs unfinished typedef
   rType = record  // cr here ==> type def
              a: aType;       // this can be realigned manually
              b: bType;       // should follow line above
              c: cType
           end;

   colourType =
      { unfinished type declaration }
      ( red,    // CHECK: everything should line up below this
        orange, // this must follow line above
        green,
        blue,
        indigo,
        yellow,
        violet
        // CHECK: the comments should line up as well
        // closing paren should align to list when it's left shifted
        //                            to opening paren otherwise
      );

   otherTypeDef = integer;

// CHECK: next line should keep its relative alignment
  {ant}
   ant = RECORD CASE F: BOOLEAN OF
                   TRUE: ( fred : REAL;
                           joe  : INTEGER;
                         );  // parens should line up
                   FALSE: (  ted : ARRAY[
                                           1..16
                                        ] OF BOOLEAN;
                             moe: CHAR;
                          );
                END; // 'case' + 'record' share same 'end'



var a: real;

   RW:  ARRAY [AASY..ZZSY]
           OF   (*RESERVED WORDS*)   PACKED ARRAY [1..RWLENGTH,
                                                   2..66 ]     // CHECK: this line should be indented
                                               OF CHAR;    // CHECK: this line should be indented from array

   RW:  ARRAY [AASY..ZZSY] OF   (*RESERVED WORDS*)
           PACKED ARRAY [1..RWLENGTH] OF CHAR;

var
   sym : keysymbol;
   pos : hashIndex;
   len : charLenType;


type tR = record
             i: integer;   // CHECK: can be aligned manually, but default indented from record
             r: real;      // should align with line immediately above
             a: array[1..11] of char;

             case boolean of
                true: ( fred : real;
                        joe  : integer;
                      );  // parens should line up
                false: (  ted : array[
                                        1..16
                                     ] of boolean;
                          moe: char;
                       );
          end; // 'case' + 'record' share same 'end'

   tArray = array[0..17] of real; // should indent wrt 'type'

type    colourType = (
              red,    // CHECK: this line can be adjusted manually
              orange, // this must follow line above
              green,
              blue,
              indigo,
              yellow,
              violet
              // CHECK: the comments should line up as well
              // closing paren should align to list when it's left shifted
              //                            to opening paren otherwise
              );

   blah = char;  // should align after type

   optionset = set of options;

var
   r1: record
          i:    integer;
          r:    real;                   // should line up with first member
          a:    array[0..7] of char;
       end;  // CHECK: end is outdented relative to first member

   optionset : set of options;

   options : (    crsupp,crbefore,blinbefore,
                  dindonkey,dindent,spbef,
                  spaft,gobsym,
                  inbytab,   { indent current margin (was indent from symbol pos) }
                  crafter,
                  finl            { force symbol to follow on same line as previous symbol }
             );

   optionset = set of options;

   aa: array[   1..9, // should be indented after cr
                3..22 ]
          of ( crsupp,crbefore,blinbefore,
               dindonkey,dindent,spbef,
               spaft,gobsym,
               inbytab,   { indent current margin (was indent from symbol pos) }
               crafter,
               finl            { force symbol to follow on same line as previous symbol }
             );

   aaa: array[ 1..3,
               4..5,
               12..11 ]
           of record // cr after here should indent from record
                 a: array[1..6] of char;
                 i: integer;
              end;

               { CHECK: following text should keep indent relative to open/close brace
                        when annotating, behavior of "external", "end" and possibly other keywords
                        depends on whether we are in procedure declaration,
                        item (var/const/type) declaration, or statements
               }


procedure AVeryVeryLongFunctionName(const A : tRealArrayType;
                                    N : tIntegerType;
                                    var H : tRealArrayType); forward;

(*************************************************************************
CHECK:   comment is correctly aligned with precedinging statement

Input parameters:
A       -   description

N       -   longer description, but
            still preserving relative format

Output parameters:
H       - other meaningful description

Result:
   True, if successful
   False, otherwise
*************************************************************************)

var size : (small, medium, large);
   fred : real;

var   r : record i: integer; c: char end;

   a: array[ 1..9,    // should be indented after var
             'a'..'z'        // non-code, should line up with opening arg
           ] of integer;

begin (* AVeryVeryLongFunctionName *)

   if a then begin
      s1;
16:
      f(32);  //CHECK: label forced to margin, statement is on new line with comment
   end;

   for i := 0 to 100 do
   begin
      with p^ do
         begin s1; s2; s3 end
   end;

   with p^ do
      begin s1; s2; s3 end;

   for i := firstCh to lastCh do chtype[chr(i)] := none;
   value['0'] := 0; value['1'] := 1; value['2'] := 2;
   value['3'] := 3; value['4'] := 4; value['5'] := 5;
   value['6'] := 6; value['7'] := 7; value['8'] := 8;
   value['9'] := 9;
   value['A'] := 10; value['B'] := 11; value['C'] := 12;
   value['D'] := 13; value['E'] := 14; value['F'] := 15;
   value['a'] := 10; value['b'] := 11; value['c'] := 12;
   value['d'] := 13; value['e'] := 14; value['f'] := 15;

   IF NOT (CH IN ['{','}']) THEN
   // comment
   BEGIN  IF CH <= 'Z' THEN CMDCH := CH ELSE CMDCH := CHR(ORD(CH)-ORD('a')+ORD('A') );
      NEXTCH;
      IF CMDCH = 'L' THEN
         COMMAND(LISTON)
      ELSE IF CMDCH = 'T' THEN
         COMMAND(TRACEON)
      ELSE IF CMDCH = 'I' THEN
         COMMAND(INCLUDE)
      ELSE IF CMDCH = 'Z' THEN
         REPEAT
            BEGIN
               www.fred.com;
               REPEAT commandIn UNTIL numRem = 0;
               s1;
               s2;
            END;
         UNTIL False
      ELSE IF CMDCH = 'Q' THEN begin
         COMMAND(QUIET)
      end ELSE IF CMDCH = 'V' THEN
         COMMAND(VERBOSE)
      else if COMMAND.STRVAL = 'unknown' then
      begin
         IF
               (numStr[0] >= 0) AND
               (numStr[1] IN ['+', '-', '0' .. '9', '?']) // CHECK: indent
         THEN
            Power.Supply := '"AC' ELSE Power.Supply := '"DC'
      end else  if CommandResult.Str = 'helpIamLost' then begin
         Power.Supply := SetPowerSupplyCommands(Plus15V.Increase(Amps));
      end else if (line = 'SHORT') OR (line = 'OPEN') THEN  BEGIN
         OpenCircuit;
         {*smoke billows out*}
         IF SPARKS THEN
         BEGIN
            SPARKS := FALSE;
            ShutDown
         END
      END ELSE IF
         (line = 'OPEN') OR (line = 'CLOSED') THEN
      BEGIN;
         AddFuse(Low);
         IF SPARKS THEN
         BEGIN;
            SPARKS := False;
            CircuitBreaker(wishfulThinking)
         END else if cond then
            statement;
      END ELSE IF (line = 'PLUS') OR (line = 'MINUS') THEN Transform(RedPhase)
      ELSE IF (line = 'RED') OR (line = 'BLACK') THEN Transform(BluePhase)
      ELSE IF line = 'XX' THEN Transistor
      ELSE IF line = 'YYYY' THEN SetCurrent(FiveAmps)
      ELSE IF line = 'QQQQ' THEN SetPower(FiveWatts)
      ELSE IF line = 'AAAAA' THEN Power(FiveAmps)
      ELSE IF
         {* QWERTY COMMENT LLLLLLLLL ####### *}
         line = 'SSSSS' THEN
      BEGIN
         actualphase := YellowPhase;
         AdjustLinePhase(NewPhase);
      END
      ELSE IF
            line = 'Noisy' THEN Filter
      ELSE IF line = 'BLUE' THEN
      BEGIN
         AdjustLinePhase(XPhase);
         Erase := True
      END ELSE IF
         line = 'RED' THEN BEGIN Swap; Hope END
      ELSE IF
         line = '415' THEN iNumPut415
      ELSE IF
         // a statement like this has no chance of being correctly indented ...
         // otoh, it shouldn't turn out catastrophically wrong.
         line = 'REFL' THEN FOR i := 1 TO numLines DO
                                     WriteLn('level=', powerLevel[i], ' ', name[i]+'='+power[i])
      ELSE IF
         line = 'HIGH' THEN reduce
      ELSE IF
         line = 'LOW' THEN increase
      ELSE IF
         line = 'END' THEN
      BEGIN
         WHILE powerlevel[NumPowers] = level DO NumPowers := NumPowers-1;
         level := level-1;
      END
      ELSE IF
         line = 'WAIT' THEN
      BEGIN
         Z := ReActivate;
         Z := X*240.0 + i*Y*240;
         ROTATE(ABS(Z))
      END
      ELSE IF line = 'HILD' THEN motor(induction)
      ELSE IF (line = 'REV') THEN        BEGIN
         v := YellowPhase;
         IF (NOT(v IN [#14..#240])) THEN
            WriteLn(' POWER SUPPLY OUT OF SPEC') ELSE specValue := v;
         specValidate
      END
      ELSE IF (line = 'OK') THEN BEGIN
         IncomingSupply := True; specValidate END
      ELSE IF (line = 'NOK') THEN BEGIN IncomingSupply := False; specValidate END
      else    begin
         GeneratedPowerLine.IncreasePower(
                       'Unknown input power "%s"', [SwitchPower.Current]);    // CHECK: string should not cause problems
      end;
   END;


end (* AVeryVeryLongFunctionName *) ;  // check that only necessary work is done to align
