View Issue Details

IDProjectCategoryView StatusLast Update
0012718LazarusIDEpublic2013-09-03 12:07
ReporterGraeme Geldenhuys Assigned ToMartin Friebe  
PrioritynormalSeverityfeatureReproducibilityN/A
Status closedResolutionfixed 
Platformx86OSUbuntu Linux 
Product Version0.9.27 (SVN) 
Target Version0.9.28Fixed in Version0.9.27 (SVN) 
Summary0012718: Code Folding with user defined {$REGION} comments
DescriptionAfter Delphi 7, Borland introduced code folding. They also introduced an option for the developer to create there own code folding regions. This is accomplished with the { $REGION } and { $ENDREGION } comment tags. Please note the space in front of the $REGION and $ENDREGION. This prevents FPC from thinking it's compiler directive and gets treated as a standard comment - this also allows any other editor that doesn't support $REGION to simply ignore this.

Syntax used in Delphi and that I think will be very handy in Lazarus IDE.

{ $REGION 'comment' }
  // you code goes here
{ $ENDREGION }

This is the basic syntax required. I also think it will be very handy if we can extend that syntax to include a default 'fold' option. For example: Say I want the editor to default show all code folding as collapsed (no folding by default), but a certain GUI initialization method I always want folded by default - because that code is normally auto generated and the developer 99.9% of the time doesn't need to scratch in there...

{ $REGION 'GUI initialization code' fold }
  // GUI initialization code goes here
{ $ENDREGION }

The $REGION now has a comment 'GUI Initialization' and trigger 'fold' that says by default this region must be folded when this unit is displayed for the first time.
If the region is folded, the editor must also display the user defined comment in the editor line next to the code folded (gutter) + (plus) sign.

See the following CodeGear web page showing the Code Folding and $REGION feature in action. It's about halfway down the page.
  http://dn.codegear.com/article/34323/


TagsNo tags attached.
Fixed in Revision19409
LazTarget1.4
Widgetset
Attached Files

Activities

Graeme Geldenhuys

2008-11-26 09:36

reporter   ~0023567

Alternatively, if the space between the opening bracket { and $ is annoying, maybe the $ sign could be changed to a @ sign.

{ $REGION 'some region comment' fold }

  vs

{@REGION 'some region comment' fold}

Paul Ishenin

2008-11-26 09:47

manager   ~0023568

Graeme, have you seen this page: http://wiki.lazarus.freepascal.org/User:Martin ?

2008-11-26 12:28

 

synedit_basic_region_fold.patch (4,402 bytes)   
Index: synhighlighterpas.pp
===================================================================
--- synhighlighterpas.pp	(revision 17598)
+++ synhighlighterpas.pp	(working copy)
@@ -62,7 +62,7 @@
 
 type
   TtkTokenKind = (tkAsm, tkComment, tkIdentifier, tkKey, tkNull, tkNumber,
-    tkSpace, tkString, tkSymbol, {$IFDEF SYN_LAZARUS}tkDirective, {$ENDIF}
+    tkSpace, tkString, tkSymbol, {$IFDEF SYN_LAZARUS}tkDirective, tkRegion, {$ENDIF}
     tkUnknown);
 
   TRangeState = (
@@ -83,7 +83,8 @@
   TPascalCodeFoldBlockType = (
     cfbtNone,
     cfbtBeginEnd,
-    cfbtNestedComment
+    cfbtNestedComment,
+    cfbtRegion
     );
   TPascalCompilerMode = (
     pcmObjFPC,
@@ -1440,45 +1441,74 @@
 procedure TSynPasSyn.DirectiveProc;
 begin
   fTokenID := tkDirective;
-  if TextComp('mode') then begin
-    // $mode directive
-    inc(Run,4);
-    // skip space
-    while (fLine[Run] in [' ',#9,#10,#13]) do inc(Run);
-    if TextComp('objfpc') then
-      CompilerMode:=pcmObjFPC
-    else if TextComp('delphi') then
-      CompilerMode:=pcmDelphi
-    else if TextComp('fpc') then
-      CompilerMode:=pcmFPC
-    else if TextComp('gpc') then
-      CompilerMode:=pcmGPC
-    else if TextComp('tp') then
-      CompilerMode:=pcmTP
-    else if TextComp('macpas') then
-      CompilerMode:=pcmMacPas;
-  end;
-  repeat
-    case fLine[Run] of
-    #0,#10,#13: break;
-    '}':
-      if TopPascalCodeFoldBlockType=cfbtNestedComment then
-        EndCodeFoldBlock
-      else begin
-        if fRange = rsDirectiveAsm then
-          fRange := rsAsm
-        else
-          fRange := rsUnKnown;
+  if TextComp('region') then
+  begin
+    inc(Run, 6);
+    while (fLine[Run] <> '}') and (Run<fLineLen) do inc(Run);
+    if fLine[Run]='}' then
+    begin
+      fTokenId := tkRegion;
+      StartPascalCodeFoldBlock(cfbtRegion);
+      fRange := rsUnKnown;
+    end;
+    Inc(Run);
+  end
+  else begin
+    if TextComp('endregion') then
+    begin
+      inc(Run, 9);
+      while (fLine[Run] in [' ',#9,#10,#13]) and (Run<fLineLen) do inc(Run);
+      if fLine[Run]='}' then
+      begin
+//        fTokenId := tkRegion;
+        if TopPascalCodeFoldBlockType=cfbtRegion then
+          EndCodeFoldBlock;
+        fRange := rsUnKnown;
+      end;
+      Inc(Run);
+    end
+    else begin
+      if TextComp('mode') then begin
+        // $mode directive
+        inc(Run,4);
+        // skip space
+        while (fLine[Run] in [' ',#9,#10,#13]) do inc(Run);
+        if TextComp('objfpc') then
+          CompilerMode:=pcmObjFPC
+        else if TextComp('delphi') then
+          CompilerMode:=pcmDelphi
+        else if TextComp('fpc') then
+          CompilerMode:=pcmFPC
+        else if TextComp('gpc') then
+          CompilerMode:=pcmGPC
+        else if TextComp('tp') then
+          CompilerMode:=pcmTP
+        else if TextComp('macpas') then
+          CompilerMode:=pcmMacPas;
+      end;
+      repeat
+        case fLine[Run] of
+        #0,#10,#13: break;
+        '}':
+          if TopPascalCodeFoldBlockType=cfbtNestedComment then
+            EndCodeFoldBlock
+          else begin
+            if fRange = rsDirectiveAsm then
+              fRange := rsAsm
+            else
+              fRange := rsUnKnown;
+            Inc(Run);
+            break;
+          end;
+        '{':
+          if NestedComments then
+            StartPascalCodeFoldBlock(cfbtNestedComment);
+        end;
         Inc(Run);
-        break;
-      end;
-    '{':
-      if NestedComments then
-        StartPascalCodeFoldBlock(cfbtNestedComment);
+      until (Run>=fLineLen);
+      //DebugLn(['TSynPasSyn.DirectiveProc Run=',Run,' fTokenPos=',fTokenPos,' fLineStr=',fLineStr,' Token=',GetToken]);
     end;
-    Inc(Run);
-  until (Run>=fLineLen);
-  //DebugLn(['TSynPasSyn.DirectiveProc Run=',Run,' fTokenPos=',fTokenPos,' fLineStr=',fLineStr,' Token=',GetToken]);
+  end;
 end;
 {$ENDIF}
 
@@ -1848,11 +1878,11 @@
     tkIdentifier: Result := fIdentifierAttri;
     tkKey: Result := fKeyAttri;
     tkNumber: Result := fNumberAttri;
-    tkSpace: Result := fSpaceAttri;
+    tkSpace: Result  := fSpaceAttri;
     tkString: Result := fStringAttri;
     tkSymbol: Result := fSymbolAttri;
     {$IFDEF SYN_LAZARUS}
-    tkDirective: Result := fDirectiveAttri;
+    tkRegion, tkDirective: Result := fDirectiveAttri;
     {$ENDIF}
     tkUnknown: Result := fSymbolAttri;
   else

Gerard V

2008-11-26 12:31

reporter   ~0023570

Last edited: 2008-11-26 12:51

Hi,

I uploaded a patch that allows basic {$REGION}{$ENDREGION} folding.
There is no special highlighting for the {$REGION} directive.
As it is now, it allows some text after the directive, but the syntax { $REGION 'comment' } would show the quotes around 'comment' as it doesn't process the comment.

HTH,

Gerard.

Martin Friebe

2008-11-26 13:44

manager   ~0023571

@Gerard:

Sorry your patch has several shortcomings:
1) {$REGION}

The original request had a space in front of the $REGION => so the compiler does not complain about an illegal directive

2) it doesn't work for part overlapping folds (and this is a *must*)

{$REGION}
  if foo then begin
     a:= 1;
{$ENDREGION}
     b:=2;
   end;

Never mind if it makes sense to write code like this. It can be done, so it must work.

And it must define behaviour for any combination of folded/unfolded of any involved block. That is the region fold, must work correct, independent of the begin being folded or not.

----
This means in order to add this, a new concept of storing fold-info must be found (FoldMinLevel, and FoldEndLevel can not do this.
Please feel free to discuss ideas on the mailing list.

Gerard V

2008-11-26 17:25

reporter   ~0023578

Last edited: 2008-11-26 17:48

Hi Martin,

1) The compiler issued only a warning, that's why I thought i compiled Ok. Not a big thing to fix.
2) I see your point, but that needs some rewriting of the folding logic.

Thaddy de Koning

2008-11-26 17:50

reporter   ~0023579

That "space" is bollocks. You don't need it in delphi. Since it's a preprocessor related thingy, you don't need it in freepascal either. I wonder how you came about that space in a production version of Delphi 2006 and over?

Paul Ishenin

2008-11-27 01:39

manager   ~0023591

I think we can request fpc team to skip this directives in the preprocessor. Martin, if you think to implement it better to ask fpc team now - then we have a chance to have it in the next year.

Graeme Geldenhuys

2008-11-27 08:24

reporter   ~0023593

@Thaddy
My thoughts regarding the space before $REGION is simply the following:
 
1. Yes it's not 100% Delphi compatible, but so are many other things.

2. Regions for code folding is purely a visual think for IDE's. So must we really bug the FPC developers and ask to add a work-around in FPC, just to we can have something for visual effect. I don't think so. $Region is simply a comment marker for some IDE editors to detect and handle. Does that mean if FPC core makes the change, that the text mode FP IDE must also be amened?

3. Due to the above, I thought maybe a @ sign could be used instead. It then gets treated as a standard comment {...} and any editor or code parsing tool will work as-is without fail.

Graeme Geldenhuys

2008-11-27 08:32

reporter   ~0023594

@Thaddy and @Paul
I suggest we handle user defined regions the same way Lazarus and Delphi IDE's handle TODO items. A standard comment with a special marker. This breaks no existing code like syntax highlighters or FPC comiler itself, any editors or ide's (MSEide for one). Hence the reason I suggest {#REGION '...'} or {@REGION '...'} instead of {$REGION '...'}

Standard comments with special tokens are often used already.
  * ToDo items
  * Pasdoc formatting
  * Many other API documentation programs.

Mattias Gaertner

2008-11-27 09:17

manager   ~0023597

Why not implement the Delphi syntax?
FPC will support it eventually anyway, because it is simple to do.
Is it too complicated or not flexible enough or patented?

What does Delphi do with

{$REGION}
  if foo then begin
     a:= 1;
{$ENDREGION}
     b:=2;
   end;

?

Gerard V

2008-11-27 09:42

reporter   ~0023598

+1 vote for the Delphi syntax. If it works in Delphi, some day FPC will have to compile Delphi code containing that directive, and as Mattias said, it's simple enough.

Marc Weustink

2009-02-21 19:35

administrator   ~0025619

For IDE directives we already use {%, so I propose to {%REGION}
I agree on not cluttering the compiler with visual ide directives

Alexander S. Klenin

2009-02-22 05:03

developer   ~0025623

BTW, regarding {$REGION} directives intersecting default folding --
Delphi does fold them, but I suggest to ignore such directives,
perhaps with some hint/warning.
The reason is that, even if CodeTools, after some complications,
will be able to make sense of the mess, the human still would be confused.

Graeme Geldenhuys

2009-02-23 08:43

reporter   ~0025650

@Marc
The {%REGION} will work just fine for me. As as I mentioned before, we shouldn't clutter the FPC compiler with purely "visual" enhancements for things like editors and IDE's. We already handle other IDE-only tags inside standard comments and the REGION tag should be handled in exactly the same way.

That way we break no existing Free Pascal code parses, syntax highlighters or other IDE's like MSEide etc..

Martin Friebe

2009-04-13 17:50

manager   ~0026734

Folding now regognizes:
{%Region} {%EndRegion}
{$Region} {$EndRegion}

Both "%" and "$ are treated the same, so a "{$Region}" can be closed by a "{%EndRegion}" and vice versa.

Opening and closing tag, are allowed further text/comment in the {} after the "Region"/"EndRegion". (e.g. {$Region fold me}).
Such comments are ignored by the folding engine. Now special behaviour.

----
Additionally the ability to fold at {$IfDef} has been added. see configuration, to enable it.

----
As with all other folds, folding at those keywords suffers the same problem described in 0012811

This means, if you have multiply folds starting at the same line, you can only fold the block, belonging to the *last* keyword in the line.

Graeme Geldenhuys

2009-04-14 15:41

reporter   ~0026761

Initial testing it seems to work perfectly. Thanks Martin for all your effort!
I'll create a separate feature request for the "fold at startup" for {%Region}'s.

Issue History

Date Modified Username Field Change
2008-11-26 09:14 Graeme Geldenhuys New Issue
2008-11-26 09:36 Graeme Geldenhuys Note Added: 0023567
2008-11-26 09:47 Paul Ishenin Note Added: 0023568
2008-11-26 12:08 Martin Friebe Status new => assigned
2008-11-26 12:08 Martin Friebe Assigned To => Martin Friebe
2008-11-26 12:10 Martin Friebe LazTarget => post 1.2
2008-11-26 12:28 Gerard V File Added: synedit_basic_region_fold.patch
2008-11-26 12:31 Gerard V Note Added: 0023570
2008-11-26 12:51 Gerard V Note Edited: 0023570
2008-11-26 13:44 Martin Friebe Note Added: 0023571
2008-11-26 17:25 Gerard V Note Added: 0023578
2008-11-26 17:48 Gerard V Note Edited: 0023578
2008-11-26 17:50 Thaddy de Koning Note Added: 0023579
2008-11-27 01:39 Paul Ishenin Note Added: 0023591
2008-11-27 08:24 Graeme Geldenhuys Note Added: 0023593
2008-11-27 08:32 Graeme Geldenhuys Note Added: 0023594
2008-11-27 09:17 Mattias Gaertner Note Added: 0023597
2008-11-27 09:42 Gerard V Note Added: 0023598
2009-02-21 19:35 Marc Weustink Note Added: 0025619
2009-02-22 05:03 Alexander S. Klenin Note Added: 0025623
2009-02-23 08:43 Graeme Geldenhuys Note Added: 0025650
2009-04-13 17:50 Martin Friebe Fixed in Revision => 19409
2009-04-13 17:50 Martin Friebe Status assigned => resolved
2009-04-13 17:50 Martin Friebe Fixed in Version => 0.9.27 (SVN)
2009-04-13 17:50 Martin Friebe Resolution open => fixed
2009-04-13 17:50 Martin Friebe Note Added: 0026734
2009-04-13 17:50 Martin Friebe Target Version => 0.9.28
2009-04-14 15:41 Graeme Geldenhuys Note Added: 0026761
2009-10-23 00:38 Marc Weustink Status resolved => closed
2013-09-03 12:07 Martin Friebe LazTarget post 1.2 => 1.4