View Issue Details

IDProjectCategoryView StatusLast Update
0034654LazarusIDEpublic2019-03-02 15:28
ReporterOndrej PokornyAssigned ToMartin Friebe 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product VersionProduct Build 
Target Version2.2Fixed in Version2.2 
Summary0034654: SynEdit: static keyword is not highlighted
DescriptionThe static keyword is not highlighted under special circumstances.
Steps To Reproduceprogram Project1;
{$mode objfpc}
{$modeswitch typehelpers}
type
  TTest = type helper for TObject
  private const
    B = 2;
  public
    class function A: Integer; static;
  end;
class function TTest.A: Integer;
begin
  Result := B;
end;
begin
end.
TagsNo tags attached.
Fixed in Revision60556
LazTarget2.2
Widgetset
Attached Files
  • static.png (5,295 bytes)
    static.png (5,295 bytes)
  • synhighlighterpas-typehelpers-01.patch (2,974 bytes)
    Index: components/synedit/synhighlighterpas.pp
    ===================================================================
    --- components/synedit/synhighlighterpas.pp	(revision 59711)
    +++ components/synedit/synhighlighterpas.pp	(working copy)
    @@ -317,6 +317,7 @@
         fAsmStart: Boolean;
         FExtendedKeywordsMode: Boolean;
         FNestedComments: boolean;
    +    FTypeHelpers: boolean;
         FProcedureHeaderNameAttr: TSynHighlighterAttributesModifier;
         FCurProcedureHeaderNameAttr: TSynSelectedColorMergeResult;
         FStartCodeFoldBlockLevel: integer; // TODO: rename FStartNestedFoldBlockLevel
    @@ -616,6 +617,7 @@
           write fDirectiveAttri;
         property CompilerMode: TPascalCompilerMode read FCompilerMode write SetCompilerMode;
         property NestedComments: boolean read FNestedComments write SetNestedComments;
    +    property TypeHelpers: boolean read FTypeHelpers write FTypeHelpers;
         property D4syntax: boolean read FD4syntax write SetD4syntax default true;
         property ExtendedKeywordsMode: Boolean
                  read FExtendedKeywordsMode write SetExtendedKeywordsMode default False;
    @@ -1449,17 +1451,23 @@
     function TSynPasSyn.Func66: TtkTokenKind;
     begin
       if KeyComp('Type') then begin
    -    if (PasCodeFoldRange.BracketNestLevel = 0)
    -       and (TopPascalCodeFoldBlockType in
    +    if (PasCodeFoldRange.BracketNestLevel = 0) then
    +    begin
    +      if (TopPascalCodeFoldBlockType in
             [cfbtVarType, cfbtLocalVarType, cfbtNone, cfbtProcedure, cfbtProgram,
              cfbtUnit, cfbtUnitSection]) and not(rsAfterEqualOrColon in fRange)
    -    then begin
    -      if TopPascalCodeFoldBlockType in [cfbtVarType, cfbtLocalVarType] then
    -        EndPascalCodeFoldBlockLastLine;
    -      if TopPascalCodeFoldBlockType in [cfbtProcedure]
    -      then StartPascalCodeFoldBlock(cfbtLocalVarType)
    -      else StartPascalCodeFoldBlock(cfbtVarType);
    -      fRange := fRange + [rsInTypeBlock];
    +      then begin
    +        if TopPascalCodeFoldBlockType in [cfbtVarType, cfbtLocalVarType] then
    +          EndPascalCodeFoldBlockLastLine;
    +        if TopPascalCodeFoldBlockType in [cfbtProcedure]
    +        then StartPascalCodeFoldBlock(cfbtLocalVarType)
    +        else StartPascalCodeFoldBlock(cfbtVarType);
    +        fRange := fRange + [rsInTypeBlock];
    +      end else
    +      if TypeHelpers and (rsAfterEqual in fRange) then begin
    +        fRange := fRange + [rsAtClass] - [rsVarTypeInSpecification, rsAfterEqual];
    +        StartPascalCodeFoldBlock(cfbtClass);
    +      end;
         end;
         Result := tkKey;
       end
    @@ -2590,6 +2598,17 @@
           if fLine[Run] = '-' then
             NestedComments:=False;
         end;
    +    if TextComp('typehelpers') then
    +    begin
    +      inc(Run,11);
    +      // skip space
    +      while (fLine[Run] in [' ',#9,#10,#13]) do inc(Run);
    +      if fLine[Run] in ['+', '}'] then
    +        TypeHelpers:=True
    +      else
    +      if fLine[Run] = '-' then
    +        TypeHelpers:=False;
    +    end;
       end;
       if TextComp('mode') then begin
         // $mode directive
    

Activities

Ondrej Pokorny

2018-12-06 12:48

developer  

static.png (5,295 bytes)
static.png (5,295 bytes)

Ondrej Pokorny

2018-12-06 13:24

developer  

synhighlighterpas-typehelpers-01.patch (2,974 bytes)
Index: components/synedit/synhighlighterpas.pp
===================================================================
--- components/synedit/synhighlighterpas.pp	(revision 59711)
+++ components/synedit/synhighlighterpas.pp	(working copy)
@@ -317,6 +317,7 @@
     fAsmStart: Boolean;
     FExtendedKeywordsMode: Boolean;
     FNestedComments: boolean;
+    FTypeHelpers: boolean;
     FProcedureHeaderNameAttr: TSynHighlighterAttributesModifier;
     FCurProcedureHeaderNameAttr: TSynSelectedColorMergeResult;
     FStartCodeFoldBlockLevel: integer; // TODO: rename FStartNestedFoldBlockLevel
@@ -616,6 +617,7 @@
       write fDirectiveAttri;
     property CompilerMode: TPascalCompilerMode read FCompilerMode write SetCompilerMode;
     property NestedComments: boolean read FNestedComments write SetNestedComments;
+    property TypeHelpers: boolean read FTypeHelpers write FTypeHelpers;
     property D4syntax: boolean read FD4syntax write SetD4syntax default true;
     property ExtendedKeywordsMode: Boolean
              read FExtendedKeywordsMode write SetExtendedKeywordsMode default False;
@@ -1449,17 +1451,23 @@
 function TSynPasSyn.Func66: TtkTokenKind;
 begin
   if KeyComp('Type') then begin
-    if (PasCodeFoldRange.BracketNestLevel = 0)
-       and (TopPascalCodeFoldBlockType in
+    if (PasCodeFoldRange.BracketNestLevel = 0) then
+    begin
+      if (TopPascalCodeFoldBlockType in
         [cfbtVarType, cfbtLocalVarType, cfbtNone, cfbtProcedure, cfbtProgram,
          cfbtUnit, cfbtUnitSection]) and not(rsAfterEqualOrColon in fRange)
-    then begin
-      if TopPascalCodeFoldBlockType in [cfbtVarType, cfbtLocalVarType] then
-        EndPascalCodeFoldBlockLastLine;
-      if TopPascalCodeFoldBlockType in [cfbtProcedure]
-      then StartPascalCodeFoldBlock(cfbtLocalVarType)
-      else StartPascalCodeFoldBlock(cfbtVarType);
-      fRange := fRange + [rsInTypeBlock];
+      then begin
+        if TopPascalCodeFoldBlockType in [cfbtVarType, cfbtLocalVarType] then
+          EndPascalCodeFoldBlockLastLine;
+        if TopPascalCodeFoldBlockType in [cfbtProcedure]
+        then StartPascalCodeFoldBlock(cfbtLocalVarType)
+        else StartPascalCodeFoldBlock(cfbtVarType);
+        fRange := fRange + [rsInTypeBlock];
+      end else
+      if TypeHelpers and (rsAfterEqual in fRange) then begin
+        fRange := fRange + [rsAtClass] - [rsVarTypeInSpecification, rsAfterEqual];
+        StartPascalCodeFoldBlock(cfbtClass);
+      end;
     end;
     Result := tkKey;
   end
@@ -2590,6 +2598,17 @@
       if fLine[Run] = '-' then
         NestedComments:=False;
     end;
+    if TextComp('typehelpers') then
+    begin
+      inc(Run,11);
+      // skip space
+      while (fLine[Run] in [' ',#9,#10,#13]) do inc(Run);
+      if fLine[Run] in ['+', '}'] then
+        TypeHelpers:=True
+      else
+      if fLine[Run] = '-' then
+        TypeHelpers:=False;
+    end;
   end;
   if TextComp('mode') then begin
     // $mode directive

Ondrej Pokorny

2018-12-06 13:24

developer   ~0112398

Patch attached

Martin Friebe

2018-12-06 17:37

manager   ~0112403

Needs a bit more work
Example below.

  Type a = type b;
This will open a block, and cannot be avoided (same like "class of TFoo").
But it must be prevented to have any other consequences. Such as "MyRec", which does not close at all.

Also the outline markup now colors the word type. I think it would be better to start the block on "helper". (Since outline can only do one word).

That would also solve the accidentally opened blocks.
Keeping it on "type" and trying to workaround like for "class of" would likely be to complex, because there can be other blocks inside.
Also (like "class of") it would lead to wrong fold and outline. For "class of" this will one day mean a bigger refactor...


And since there now is a flag, if typehelpers are active, could it be used for *not* marking "helper", if it is off.
See "MyBool", if the modeswitch is off.


--
Actually, if and only if it is on one line (with no comment in between) then both word could be a token together, and the start could be "type helper" (imho without the "for"). This would require to look ahead at the next word.
But if "type" is followed by either a comment or line end, then it would need to set a flag, so that "helper" can be found, if it happens to follow.

It is not possible to scan ahead to the next line(s). This will lead to later errors, when editing lines.

--
Let me know, if you want to work on a new patch. Otherwise I will look at it in a bit.

Testcase would also be welcome ;)




program Project1;
{$mode objfpc}
{$modeswitch typehelpers}
type

  helper = boolean;

  MyRec =
  type
   { foo bar }

   record
    o: integer;
   end
  ;

   MyInt =
    type
    { foo bar }
    integer
   ;

   //MyBool = // only if typehelpers are off
   // type
   // { foo bar }
   // helper
   //;

  TFoo =
  class
   of
   TObject
   ;


  TTest = type
  { abc } helper
  {def}
  for integer
  private const
    B = 2;
  public
    class function A: Integer; static;
  end;


class function TTest.A: Integer;
begin
  Result := B;
end;
begin
end.

Ondrej Pokorny

2018-12-06 19:52

developer   ~0112411

Huh I see now that the problem is more complex than I thought. Thank you for the detailed description. I assume I'd be able to limit the block to only "type helper" with some kind of flag, but I will rather leave it to you - you will do it better.

Martin Friebe

2019-03-02 15:28

manager   ~0114566

Please test and close if ok.

Note, there is a minor inconsistency.

TFoo = class helper for xxx // folds at class
TBar = type helper for xxx // folds at helper

This also affects how word-pairs (caret at class/end or helper/end) are shown.

Issue History

Date Modified Username Field Change
2018-12-06 12:48 Ondrej Pokorny New Issue
2018-12-06 12:48 Ondrej Pokorny File Added: static.png
2018-12-06 13:24 Ondrej Pokorny File Added: synhighlighterpas-typehelpers-01.patch
2018-12-06 13:24 Ondrej Pokorny Note Added: 0112398
2018-12-06 13:39 Martin Friebe Assigned To => Martin Friebe
2018-12-06 13:39 Martin Friebe Status new => assigned
2018-12-06 17:37 Martin Friebe Note Added: 0112403
2018-12-06 19:52 Ondrej Pokorny Note Added: 0112411
2019-03-02 15:28 Martin Friebe Fixed in Revision => 60556
2019-03-02 15:28 Martin Friebe LazTarget => 2.2
2019-03-02 15:28 Martin Friebe Note Added: 0114566
2019-03-02 15:28 Martin Friebe Status assigned => resolved
2019-03-02 15:28 Martin Friebe Fixed in Version => 2.2
2019-03-02 15:28 Martin Friebe Resolution open => fixed
2019-03-02 15:28 Martin Friebe Target Version => 2.2