diff --git a/components/synedit/synhighlighterpas.pp b/components/synedit/synhighlighterpas.pp index f70f76822f..f13dbc2e83 100644 --- a/components/synedit/synhighlighterpas.pp +++ b/components/synedit/synhighlighterpas.pp @@ -917,6 +917,7 @@ end; function TSynPasSyn.Func15: TtkTokenKind; begin if KeyComp('If') then begin +//TODO: case a of 1: while x do if e then ... StartPascalCodeFoldBlock(cfbtIfThen, TopPascalCodeFoldBlockType in [cfbtCase, cfbtIfThen]); Result := tkKey end @@ -1289,9 +1290,9 @@ function TSynPasSyn.Func54: TtkTokenKind; begin if KeyComp('Class') then begin Result := tkKey; - if (rsAfterEqualOrColon in fRange) and (PasCodeFoldRange.BracketNestLevel = 0) + if (rsAfterEqual in fRange) and (PasCodeFoldRange.BracketNestLevel = 0) then begin - fRange := fRange + [rsAtClass] - [rsVarTypeInSpecification]; + fRange := fRange + [rsAtClass] - [rsVarTypeInSpecification, rsAfterEqual]; StartPascalCodeFoldBlock(cfbtClass); end; end @@ -1305,7 +1306,7 @@ begin Result := tkKey; if (rsAfterEqualOrColon in fRange) and (PasCodeFoldRange.BracketNestLevel = 0) then begin - fRange := fRange + [rsAtClass] - [rsVarTypeInSpecification]; + fRange := fRange + [rsAtClass] - [rsVarTypeInSpecification, rsAfterEqual]; StartPascalCodeFoldBlock(cfbtClass); end; end @@ -1384,7 +1385,7 @@ begin StartPascalCodeFoldBlock(cfbtRecord); fRange := fRange - [rsVarTypeInSpecification]; if CompilerMode = pcmDelphi then - fRange := fRange + [rsAtClass]; // highlight helper + fRange := fRange + [rsAtClass] - [rsAfterEqual]; // highlight helper Result := tkKey; end else if KeyComp('Array') then Result := tkKey diff --git a/components/synedit/test/testhighlightpas.pas b/components/synedit/test/testhighlightpas.pas index a9981cc3b2..8809126dc0 100644 --- a/components/synedit/test/testhighlightpas.pas +++ b/components/synedit/test/testhighlightpas.pas @@ -45,6 +45,7 @@ type function TestTextFoldInfo2: TStringArray; function TestTextFoldInfo3: TStringArray; function TestTextFoldInfo4(AIfCol: Integer): TStringArray; + function TestTextFoldInfo5: TStringArray; procedure CheckTokensForLine(Name: String; LineIdx: Integer; ExpTokens: Array of TtkTokenKind); published @@ -56,6 +57,7 @@ type procedure TestContextForDeprecated; procedure TestContextForClassModifier; // Sealed abstract procedure TestContextForClassHelper; + procedure TestContextForClassFunction; // in class,object,record procedure TestContextForRecordHelper; procedure TestContextForStatic; procedure TestCaretAsString; @@ -266,6 +268,24 @@ begin end; +function TTestHighlighterPas.TestTextFoldInfo5: TStringArray; +begin + SetLength(Result, 13); + Result[0] := 'Unit Foo;'; + Result[1] := 'Interface'; + Result[2] := 'type'; + Result[3] := 'TFoo = class(TBar)'; + Result[4] := 'class procedure Proc;'; + Result[5] := 'end;'; + Result[6] := 'TFoo = record'; + Result[7] := 'class procedure Proc;'; + Result[8] := 'end;'; + Result[9] := 'Implementation'; + Result[10] := '//'; + Result[11] := 'end.'; + Result[12] := ''; +end; + procedure TTestHighlighterPas.CheckTokensForLine(Name: String; LineIdx: Integer; ExpTokens: array of TtkTokenKind); var @@ -426,7 +446,28 @@ begin [1, 1, 3, 0, 0, 0, 1]); {%endregion} + {%region} + SetLines(TestTextFoldInfo5); + EnableFolds([cfbtBeginEnd..cfbtNone], [cfbtSlashComment]); + PushBaseName('Text 5 (class in generic type)'); + AssertEquals('Len Unit', 11, PasHighLighter.FoldLineLength( 0,0)); + AssertEquals('Len Intf', 7, PasHighLighter.FoldLineLength( 1,0)); + AssertEquals('Len type', 6, PasHighLighter.FoldLineLength( 2,0)); + AssertEquals('Len class', 2, PasHighLighter.FoldLineLength( 3,0)); + AssertEquals('Len record', 2, PasHighLighter.FoldLineLength( 6,0)); + AssertEquals('Len Impl', 1, PasHighLighter.FoldLineLength( 9,0)); + AssertEquals('Len //', 0, PasHighLighter.FoldLineLength(10,0)); + + // un in ty cl pr en re pr en im // en + CheckFoldOpenCounts('', [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0]); + CheckFoldInfoCounts('', [sfaOpenFold, sfaFold], + [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0]); + CheckFoldInfoCounts('', [sfaCloseFold, sfaFold, sfaLastLineClose], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + CheckFoldInfoCounts('', [sfaLastLineClose], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + {%endregion} end; procedure TTestHighlighterPas.TestExtendedKeywordsAndStrings; @@ -977,6 +1018,35 @@ begin end; +procedure TTestHighlighterPas.TestContextForClassFunction; +var + i: Integer; +const + t: array[0..2] of string = ('class', 'object', 'record'); +begin + for i:= 0 to 2 do begin + ReCreateEdit; + EnableFolds([cfbtBeginEnd..cfbtNone]); + + SetLines + ([ 'Unit A; interface', + 'type', + 'TFoo = '+t[i], + 'class function f1: boolean;', + 'class procedure p1(v: boolean);', + 'end;', + '' + ]); + // unit/iface, type, record, -,- + CheckFoldOpenCounts('', [2, 1, 1, 0, 0]); + CheckTokensForLine('class function', 3, + [ tkKey, tkSpace, tkKey, tkSpace, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol ]); + CheckTokensForLine('class procedure', 4, + [ tkKey, tkSpace, tkKey, tkSpace, tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSpace, tkIdentifier, tkSymbol, tkSymbol ]); + + end; +end; + procedure TTestHighlighterPas.TestContextForRecordHelper; begin ReCreateEdit; @@ -1087,24 +1157,26 @@ begin ([ 'Unit A; interface', // 0 'var', 'a:char=^o;', + 'a:somestring=^o^c;', 'b:^char=nil;', 'type', - 'c=^char;', // 5 + 'c=^char;', // 6 + 'c=type ^char;', // 6 'implementation', - 'function x(f:^char=^k):^v;', // actually the compiler does not allow ^ as pointer for result + 'function x(f:^char=^k^c):^v;', // actually the compiler does not allow ^ as pointer for result 'var', - 'a:char=^o;', - 'b:^char=nil;', // 10 + 'a:char=^o;', // 11 + 'b:^char=nil;', // 12 'type', 'c=^char;', 'begin', 'i:=^f;', - 'x:=GetTypeData(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF});', // 15 + 'x:=GetTypeData(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF});', // 17 'c:=p^;', 'c:=p ^;', 'c:=p(**)^;', - 'c:=p{} ^;', - 'i:=f(1)^;', // 20 + 'c:=p{} ^;', // 21 + 'i:=f(1)^;', // 22 'i:=f[1]^;', 'i:=f^^;', 'c:=p^+^i''e''^a#13^x;', @@ -1115,50 +1187,54 @@ begin CheckTokensForLine('a:char=^o;', 2, [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkString, tkSymbol]); - CheckTokensForLine('b:^char=nil;', 3, + CheckTokensForLine('a:char=^o^c;', 3, + [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkString, tkString, tkSymbol]); + CheckTokensForLine('b:^char=nil;', 4, [tkIdentifier, tkSymbol, tkSymbol, tkIdentifier, tkSymbol, tkKey, tkSymbol]); - CheckTokensForLine('c=^char;', 5, + CheckTokensForLine('c=^char;', 6, [tkIdentifier, tkSymbol, tkSymbol, tkIdentifier, tkSymbol]); + CheckTokensForLine('c=type ^char;', 7, + [tkIdentifier, tkSymbol, tkKey, tkSpace, tkSymbol, tkIdentifier, tkSymbol]); - CheckTokensForLine('function x(f:^char=^k):^v;', 7, + CheckTokensForLine('function x(f:^char=^k):^v;', 9, [tkKey, tkSpace, tkIdentifier, tkSymbol, tkIdentifier, // function x(f - tkSymbol, tkSymbol, tkIdentifier, tkSymbol, tkString, // :^char=^k + tkSymbol, tkSymbol, tkIdentifier, tkSymbol, tkString, tkString, // :^char=^k tkSymbol, tkSymbol, tkSymbol, tkIdentifier, tkSymbol]); // ):^v; - CheckTokensForLine('LOCAL a:char=^o;', 9, + CheckTokensForLine('LOCAL a:char=^o;', 11, [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkString, tkSymbol]); - CheckTokensForLine('LOCAL b:^char=nil;', 10, + CheckTokensForLine('LOCAL b:^char=nil;', 12, [tkIdentifier, tkSymbol, tkSymbol, tkIdentifier, tkSymbol, tkKey, tkSymbol]); - CheckTokensForLine('LOCAL c=^char;', 12, + CheckTokensForLine('LOCAL c=^char;', 14, [tkIdentifier, tkSymbol, tkSymbol, tkIdentifier, tkSymbol]); - CheckTokensForLine('i:=^f', 14, + CheckTokensForLine('i:=^f', 16, [tkIdentifier, tkSymbol, tkString, tkSymbol]); - CheckTokensForLine('x:=GetTypeData(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF});', 15, + CheckTokensForLine('x:=GetTypeData(PropInfo^.PropType{$IFNDEF FPC}^{$ENDIF});', 17, [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, // x:=GetTypeData( tkIdentifier, tkSymbol, tkSymbol, tkIdentifier, // PropInfo^.PropType tkDirective, tkSymbol, tkDirective, tkSymbol, tkSymbol]); // {$IFNDEF FPC}^{$ENDIF}); - CheckTokensForLine('c:=p^;', 16, + CheckTokensForLine('c:=p^;', 18, [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSymbol]); - CheckTokensForLine('c:=p ^;', 17, + CheckTokensForLine('c:=p ^;', 19, [tkIdentifier, tkSymbol, tkIdentifier, tkSpace, tkSymbol, tkSymbol]); - CheckTokensForLine('c:=p(**)^;', 18, + CheckTokensForLine('c:=p(**)^;', 20, [tkIdentifier, tkSymbol, tkIdentifier, tkComment, tkSymbol, tkSymbol]); - CheckTokensForLine('c:=p{} ^;', 19, + CheckTokensForLine('c:=p{} ^;', 21, [tkIdentifier, tkSymbol, tkIdentifier, tkComment, tkSpace, tkSymbol, tkSymbol]); - CheckTokensForLine('c:=p(1)^;', 20, + CheckTokensForLine('c:=p(1)^;', 22, [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkNumber, tkSymbol, tkSymbol]); - CheckTokensForLine('c:=p[1]^;', 21, + CheckTokensForLine('c:=p[1]^;', 23, [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkNumber, tkSymbol, tkSymbol]); - CheckTokensForLine('c:=p^^;', 22, + CheckTokensForLine('c:=p^^;', 24, [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSymbol, tkSymbol]); - CheckTokensForLine('c:=p^+^i''e''^a#13^x;', 23, + CheckTokensForLine('c:=p^+^i''e''^a#13^x;', 25, [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkSymbol, // c:=p^+ tkString, tkString, tkString, tkString, tkString, tkSymbol // ^i'e'^a#13^x; ]); - CheckTokensForLine('c:=x=^a and ^a=k and(^a^a=z);', 24, + CheckTokensForLine('c:=x=^a and ^a=k and(^a^a=z);', 26, [tkIdentifier, tkSymbol, tkIdentifier, tkSymbol, tkString, tkSpace, // c:=x=^a tkKey, tkSpace, tkString, tkSymbol, tkIdentifier, tkSpace, // and ^a=k tkKey, tkSymbol, tkString, tkString, tkSymbol, tkIdentifier, // and(^a^a=z @@ -1288,7 +1364,7 @@ begin PopPushBaseName('Text 1 -- [cfbtBeginEnd..cfbtNone], [], grp=1'); SetLines(TestTextFoldInfo1); EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []); - DebugFoldInfo([],1); + //DebugFoldInfo([],1); CheckFoldInfoCounts('', [], 1, [1, 1, 0, 1, 0, 1, 0, 1, 2, 1, 2, 2]); @@ -1878,6 +1954,78 @@ begin {%region TEXT 4} + {%region TEXT 5} + + {%region TEXT 5 -- [cfbtBeginEnd..cfbtNone], []} + PopPushBaseName('Text 5 -- [cfbtBeginEnd..cfbtNone], [], 0'); + SetLines(TestTextFoldInfo5); + EnableFolds([cfbtBeginEnd..cfbtNone]-[cfbtForDo,cfbtWhileDo,cfbtWithDo], []); + //DebugFoldInfo([]); + + CheckFoldInfoCounts('', [], 0, [1, 1, 1, 1, 0, 1, 1, 0, 3, 1, 3, 1]); + + // Line 0: unit foo; + CheckNode( 0, [], 0, 0, 0, 4, 0, 1, 0, 1, + cfbtUnit, cfbtUnit, FOLDGROUP_PASCAL, + [sfaOpen, sfaOpenFold, sfaFold, sfaFoldFold, sfaMultiLine]); + // Line 1: interface + CheckNode( 1, [], 0, 0, 0, 9, 1, 2, 1, 2, + cfbtUnitSection, cfbtUnitSection, FOLDGROUP_PASCAL, + [sfaOpen, sfaOpenFold, sfaFold, sfaFoldFold, sfaMultiLine]); + // Line 2: type + CheckNode( 2, [], 0, 0, 0, 4, 2, 3, 2, 3, + cfbtVarType, cfbtVarType, FOLDGROUP_PASCAL, + [sfaOpen, sfaFold, sfaFoldFold, sfaMultiLine, sfaOpenFold]); + // Line 3: TFoo = class(TBar) + CheckNode( 3, [], 0, 0, 17, 22, 3, 4, 3, 4, + cfbtClass, cfbtClass, FOLDGROUP_PASCAL, + [sfaOpen, sfaFold, sfaFoldFold, sfaMultiLine, sfaMarkup, sfaOpenFold]); + // Line 4: class procedure Proc; + CheckNode( 4, [], 0, -1, 0, 0, 4, 4, 4, 4, + cfbtNone, cfbtNone, FOLDGROUP_PASCAL, + [sfaInvalid]); + // Line 5: end. + CheckNode( 5, [], 0, 0, 0, 3, 4, 3, 4, 3, + cfbtClass, cfbtClass, FOLDGROUP_PASCAL, + [sfaClose, sfaFold, sfaMultiLine, sfaMarkup, sfaCloseFold]); + CheckNode( 6, [], 0, 0, 7, 13, 3, 4, 3, 4, + cfbtRecord, cfbtRecord, FOLDGROUP_PASCAL, + [sfaOpen, sfaFold, sfaFoldFold, sfaMultiLine, sfaMarkup, sfaOpenFold]); + // Line 7: class procedure Proc; + CheckNode( 7, [], 0, -1, 0, 0, 4, 4, 4, 4, + cfbtNone, cfbtNone, FOLDGROUP_PASCAL, + [sfaInvalid]); + // Line 8: end. + CheckNode( 8, [], 0, 0, 0, 3, 4, 3, 4, 3, + cfbtRecord, cfbtRecord, FOLDGROUP_PASCAL, + [sfaClose, sfaFold, sfaMultiLine, sfaMarkup, sfaCloseFold]); + CheckNode( 8, [], 0, 1, 4, 4, 3, 2, 3, 2, + cfbtVarType, cfbtVarType, FOLDGROUP_PASCAL, + [sfaClose, sfaFold, sfaMultiLine, sfaCloseForNextLine, sfaCloseFold]); + CheckNode( 8, [], 0, 2, 4, 4, 2, 1, 2, 1, + cfbtUnitSection, cfbtUnitSection, FOLDGROUP_PASCAL, + [sfaClose, sfaFold, sfaMultiLine, sfaCloseForNextLine, sfaCloseFold]); + // Line 9: implementation + CheckNode( 9, [], 0, 0, 0, 14, 1, 2, 1, 2, + cfbtUnitSection, cfbtUnitSection, FOLDGROUP_PASCAL, + [sfaOpen, sfaOpenFold,sfaFold, sfaFoldFold, sfaMultiLine]); + // Line 10: //, unit-section + CheckNode(10, [], 0, 0, 0, 2, 2, 3, 2, 3, + cfbtSlashComment, cfbtSlashComment, FOLDGROUP_PASCAL, + [sfaOpen, sfaOneLineOpen, sfaSingleLine]); + CheckNode(10, [], 0, 1, 2, 2, 3, 2, 3, 2, + cfbtSlashComment, cfbtSlashComment, FOLDGROUP_PASCAL, + [sfaClose, sfaOneLineClose, sfaCloseForNextLine, sfaSingleLine]); + CheckNode(10, [], 0, 2, 2, 2, 2, 1, 2, 1, + cfbtUnitSection, cfbtUnitSection, FOLDGROUP_PASCAL, + [sfaClose, sfaCloseFold,sfaFold, sfaCloseForNextLine, sfaMultiLine]); + // Line 11: end. + CheckNode(11, [], 0, 0, 0, 3, 1, 0, 1, 0, + cfbtUnit, cfbtUnit, FOLDGROUP_PASCAL, + [sfaClose, sfaCloseFold,sfaFold, sfaMultiLine]); + {%endregion TEXT 5 -- [cfbtBeginEnd..cfbtNone], []} + + {%region TEXT 5} end; initialization