From 42a27dba3d89afa96e160fc9932d1f7038080f5f Mon Sep 17 00:00:00 2001 From: martin Date: Sun, 25 Jan 2009 12:36:29 +0000 Subject: [PATCH] SynEdit: Highlight Begin/End pairs git-svn-id: trunk@18436 - --- .gitattributes | 1 + components/synedit/synedit.pp | 6 +- components/synedit/synedithighlighter.pp | 12 +- components/synedit/syneditmarkupwordgroup.pp | 255 +++++++++++++++++++ components/synedit/synhighlighterpas.pp | 220 +++++++++++++++- ide/editoroptions.pp | 23 +- 6 files changed, 504 insertions(+), 13 deletions(-) create mode 100644 components/synedit/syneditmarkupwordgroup.pp diff --git a/.gitattributes b/.gitattributes index 3b19846b26..949130ceba 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1430,6 +1430,7 @@ components/synedit/syneditmarkupctrlmouselink.pp svneol=native#text/plain components/synedit/syneditmarkuphighall.pp svneol=native#text/plain components/synedit/syneditmarkupselection.pp svneol=native#text/plain components/synedit/syneditmarkupspecialline.pp svneol=native#text/plain +components/synedit/syneditmarkupwordgroup.pp svneol=native#text/plain components/synedit/syneditmiscclasses.pp svneol=native#text/pascal components/synedit/syneditmiscprocs.pp svneol=native#text/pascal components/synedit/syneditplugins.pas svneol=native#text/pascal diff --git a/components/synedit/synedit.pp b/components/synedit/synedit.pp index db4d7908b9..e4e694845d 100644 --- a/components/synedit/synedit.pp +++ b/components/synedit/synedit.pp @@ -76,7 +76,7 @@ uses SynEditTypes, SynEditSearch, SynEditKeyCmds, SynEditMiscProcs, SynEditPointClasses, SynBeautifier, SynEditMarks, {$ifdef SYN_LAZARUS} - SynEditMarkup, SynEditMarkupHighAll, SynEditMarkupBracket, + SynEditMarkup, SynEditMarkupHighAll, SynEditMarkupBracket, SynEditMarkupWordGroup, SynEditMarkupCtrlMouseLink, SynEditMarkupSpecialLine, SynEditMarkupSelection, SynEditTextBase, SynEditTextTrimmer, SynEditFoldedView, SynEditTextTabExpander, SynGutterBase, SynGutter, SynGutterCodeFolding, SynGutterChanges, @@ -334,6 +334,7 @@ type fMarkupHighAll : TSynEditMarkupHighlightAll; fMarkupHighCaret : TSynEditMarkupHighlightAllCaret; fMarkupBracket : TSynEditMarkupBracket; + fMarkupWordGroup : TSynEditMarkupWordGroup; fMarkupCtrlMouse : TSynEditMarkupCtrlMouseLink; fMarkupSpecialLine : TSynEditMarkupSpecialLine; fMarkupSelection : TSynEditMarkupSelection; @@ -1465,6 +1466,7 @@ begin fMarkupHighCaret.Selection := FBlockSelection; fMarkupHighAll := TSynEditMarkupHighlightAll.Create(self); fMarkupBracket := TSynEditMarkupBracket.Create(self); + fMarkupWordGroup := TSynEditMarkupWordGroup.Create(self); fMarkupCtrlMouse := TSynEditMarkupCtrlMouseLink.Create(self); fMarkupSpecialLine := TSynEditMarkupSpecialLine.Create(self); fMarkupSelection := TSynEditMarkupSelection.Create(self, FBlockSelection); @@ -1475,6 +1477,7 @@ begin fMarkupManager.AddMarkUp(fMarkupHighAll); fMarkupManager.AddMarkUp(fMarkupCtrlMouse); fMarkupManager.AddMarkUp(fMarkupBracket); + fMarkupManager.AddMarkUp(fMarkupWordGroup); fMarkupManager.AddMarkUp(fMarkupSelection); fMarkupManager.Lines := TSynEditStrings(FTheLinesView); fMarkupManager.InvalidateLinesMethod := @InvalidateLines; @@ -6218,6 +6221,7 @@ begin end; fHighlighter := Value; fMarkupHighCaret.Highlighter := Value; + fMarkupWordGroup.Highlighter := Value; {$IFDEF SYN_LAZARUS} if fHighlighter<>nil then begin fHighlighter.ResetRange; diff --git a/components/synedit/synedithighlighter.pp b/components/synedit/synedithighlighter.pp index e48bac8595..27f6cb7b98 100644 --- a/components/synedit/synedithighlighter.pp +++ b/components/synedit/synedithighlighter.pp @@ -49,7 +49,7 @@ uses {$ENDIF} SynEditTypes, SynEditMiscClasses, - SynEditTextBuffer; + SynEditTextBuffer, SynEditTextBase; {$DEFINE _Gp_MustEnhanceRegistry} {$IFDEF SYN_COMPILER_4_UP} @@ -288,6 +288,8 @@ type function SaveToFile(AFileName: String): boolean; //DDH 10/16/01 procedure HookAttrChangeEvent(ANotifyEvent: TNotifyEvent); procedure UnhookAttrChangeEvent(ANotifyEvent: TNotifyEvent); + Function GetWordTriplet(LogicalCaret: TPoint; Lines: TSynEditStrings; + out Y1, XB1, XE1, Y2, XB2, XE2, Y3, XB3, XE3: Integer): Boolean; virtual; property IdentChars: TSynIdentChars read GetIdentChars; property WordBreakChars: TSynIdentChars read fWordBreakChars write SetWordBreakChars; property LanguageName: string read GetLanguageName; @@ -1259,6 +1261,13 @@ begin fAttrChangeHooks.Remove(ANotifyEvent); end; +function TSynCustomHighlighter.GetWordTriplet(LogicalCaret: TPoint; + Lines: TSynEditStrings; out Y1, XB1, XE1, Y2, XB2, XE2, Y3, XB3, XE3: Integer + ): Boolean; +begin + Result := False; +end; + procedure TSynCustomHighlighter.SetEnabled(const Value: boolean); begin if fEnabled <> Value then @@ -1525,6 +1534,7 @@ begin // add a copy Result:=TSynCustomHighlighterRangeClass(Range.ClassType).Create(Range); FItems.Add(Result); + if (FItems.Count mod 16) = 0 then DebugLn(['---------- TSynCustomHighlighterRanges Nodes.Count = ', FItems.Count]); end; //debugln('TSynCustomHighlighterRanges.GetEqual A ',dbgs(Node),' ',dbgs(Result.Compare(Range)),' ',dbgs(Result.CodeFoldStackSize)); end; diff --git a/components/synedit/syneditmarkupwordgroup.pp b/components/synedit/syneditmarkupwordgroup.pp new file mode 100644 index 0000000000..c349386fab --- /dev/null +++ b/components/synedit/syneditmarkupwordgroup.pp @@ -0,0 +1,255 @@ +{------------------------------------------------------------------------------- +The contents of this file are subject to the Mozilla Public License +Version 1.1 (the "License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for +the specific language governing rights and limitations under the License. + +Alternatively, the contents of this file may be used under the terms of the +GNU General Public License Version 2 or later (the "GPL"), in which case +the provisions of the GPL are applicable instead of those above. +If you wish to allow use of your version of this file only under the terms +of the GPL and not to allow others to use your version of this file +under the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the GPL. +If you do not delete the provisions above, a recipient may use your version +of this file under either the MPL or the GPL. + +-------------------------------------------------------------------------------} +unit SynEditMarkupWordGroup; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Graphics, SynEditMarkup, SynEditMiscClasses, Controls, + LCLProc, SynEditHighlighter; + +type + + TWordPoint = record + Y, X, X2: Integer; + end; + + + { TSynEditMarkupWordGroup } + + TSynEditMarkupWordGroup = class(TSynEditMarkup) + private + // Physical Position + FHighlightPos1: TWordPoint; + FHighlightPos2: TWordPoint; + FHighlightPos3: TWordPoint; + FHighlighter: TSynCustomHighlighter; + procedure SetHighlighter(const AValue: TSynCustomHighlighter); + protected + procedure FindMatchingWords(PhysCaret: TPoint; + out Word1, Word2, Word3: TWordPoint); + procedure DoCaretChanged(OldCaret : TPoint); override; + procedure DoTopLineChanged(OldTopLine : Integer); override; + procedure DoLinesInWindoChanged(OldLinesInWindow : Integer); override; + procedure DoTextChanged(StartLine, EndLine : Integer); override; + procedure DoMarkupChanged(AMarkup: TSynSelectedColor); override; + procedure InvalidateCurrentHighlight; + public + constructor Create(ASynEdit: TCustomControl); + + function GetMarkupAttributeAtRowCol(const aRow, aCol: Integer): TSynSelectedColor; override; + function GetNextMarkupColAfterRowCol(const aRow, aCol: Integer): Integer; override; + + property Highlighter: TSynCustomHighlighter + read FHighlighter write SetHighlighter; + end; + +implementation +uses + SynEdit; + +Function CompareWordPoints(P1, P2: TWordPoint): Integer; +begin + if P1.Y < P2.Y then Exit(-1); + if P1.Y > P2.Y then Exit(+1); + If P1.X < P2.X then Exit(-1); + If P1.X > P2.X then Exit(+1); + If P1.X2 < P2.X2 then Exit(-1); + If P1.X2 > P2.X2 then Exit(+1); + Result := 0; +end; + +Function PointToWordPoint(P1: TPoint): TWordPoint; +begin + Result.Y := P1.Y; + Result.X := P1.X; + Result.X2 := P1.X+1; +end; + + { TSynEditMarkupWordGroup } + +constructor TSynEditMarkupWordGroup.Create(ASynEdit : TCustomControl); +begin + inherited Create(ASynEdit); + FHighlightPos1.Y := -1; + FHighlightPos2.Y := -1; + MarkupInfo.Foreground := clNone;// clNone; + MarkupInfo.FrameColor := clred;// clNone; + MarkupInfo.Background := clNone; + MarkupInfo.Style := []; + MarkupInfo.StyleMask := []; +end; + +procedure TSynEditMarkupWordGroup.SetHighlighter(const AValue: TSynCustomHighlighter); +begin + FHighlighter := AValue; +end; + +procedure TSynEditMarkupWordGroup.FindMatchingWords(PhysCaret: TPoint; + out Word1, Word2, Word3: TWordPoint); +var + LogCaretXY: TPoint; +begin + Word1.Y := -1; + Word2.Y := -1; + Word3.Y := -1; + if (not assigned(Lines)) or (not MarkupInfo.IsEnabled) or + (PhysCaret.Y < 1) or (PhysCaret.Y > Lines.Count) or (PhysCaret.X < 1) + then + Exit; + + // Check for Begin-End like pairs + if not assigned(FHighlighter) then Exit; + LogCaretXY := TSynEdit(SynEdit).PhysicalToLogicalPos(PhysCaret); + if FHighlighter.GetWordTriplet(LogCaretXY, Lines, + Word1.Y, Word1.X, Word1.X2, + Word3.Y, Word3.X, Word3. X2, + Word2.Y, Word2.X, Word2. X2 + ) then + exit; + + // In Case GetWordTriplet did set them + Word1.Y := -1; + Word2.Y := -1; + Word3.Y := -1; +end; + +procedure TSynEditMarkupWordGroup.DoCaretChanged(OldCaret: TPoint); +begin + InvalidateCurrentHighlight; +end; + +procedure TSynEditMarkupWordGroup.DoTopLineChanged(OldTopLine: Integer); +begin + InvalidateCurrentHighlight; +end; + +procedure TSynEditMarkupWordGroup.DoLinesInWindoChanged(OldLinesInWindow: Integer); +begin + InvalidateCurrentHighlight; +end; + +procedure TSynEditMarkupWordGroup.DoTextChanged(StartLine, EndLine: Integer); +begin + InvalidateCurrentHighlight; +end; + +procedure TSynEditMarkupWordGroup.DoMarkupChanged(AMarkup: TSynSelectedColor); +begin + InvalidateCurrentHighlight; +end; + +procedure TSynEditMarkupWordGroup.InvalidateCurrentHighlight; +var + NewPos, NewAntiPos, NewMiddlePos : TWordPoint; +begin + FindMatchingWords(TSynEdit(SynEdit).CaretXY, NewPos, NewAntiPos, NewMiddlePos); + + // invalidate old highlighting, if changed + if (FHighlightPos1.Y > 0) + and (CompareWordPoints(FHighlightPos1, NewPos) <> 0) + then + InvalidateSynLines(FHighlightPos1.Y,FHighlightPos1.Y); + + if (FHighlightPos2.Y > 0) + and (CompareWordPoints(FHighlightPos2, NewAntiPos) <> 0) + then + InvalidateSynLines(FHighlightPos2.Y,FHighlightPos2.Y); + + if (FHighlightPos3.Y > 0) + and (CompareWordPoints(FHighlightPos3, NewMiddlePos) <> 0) + then + InvalidateSynLines(FHighlightPos3.Y,FHighlightPos3.Y); + + // invalidate new highlighting, if changed + if (NewPos.Y>0) + and (CompareWordPoints(FHighlightPos1, NewPos) <> 0) then + InvalidateSynLines(NewPos.Y, NewPos.Y); + + if (NewAntiPos.Y>0) + and (CompareWordPoints(FHighlightPos2, NewAntiPos) <> 0) then + InvalidateSynLines(NewAntiPos.Y, NewAntiPos.Y); + + if (NewMiddlePos.Y>0) + and (CompareWordPoints(FHighlightPos3, NewMiddlePos) <> 0) then + InvalidateSynLines(NewMiddlePos.Y, NewMiddlePos.Y); + + FHighlightPos1 := NewPos; + FHighlightPos2 := NewAntiPos; + FHighlightPos3 := NewMiddlePos; +// DebugLn('TCustomSynEdit.InvalidateCurrentHighlight C P=',dbgs(NewPos),' A=',dbgs(NewAntiPos), ' LP=',dbgs(fLogicalPos),' LA',dbgs(fLogicalAntiPos)); +end; + +function TSynEditMarkupWordGroup.GetMarkupAttributeAtRowCol(const aRow, aCol: Integer) : TSynSelectedColor; +begin + Result := nil; + if (FHighlightPos1.y = aRow) and + (aCol >= FHighlightPos1.x) and (aCol < FHighlightPos1.X2) then + begin + Result := MarkupInfo; + MarkupInfo.StartX := aCol; + MarkupInfo.EndX := FHighlightPos1.X2 - 1; + end + else + if (FHighlightPos3.y = aRow) and + (aCol >= FHighlightPos3.x) and (aCol < FHighlightPos3.X2) then + begin + Result := MarkupInfo; + MarkupInfo.StartX := aCol; + MarkupInfo.EndX := FHighlightPos3.X2 - 1; + end + else + if (FHighlightPos2.y = aRow) and + (aCol >= FHighlightPos2.x) and (aCol < FHighlightPos2.X2) then + begin + Result := MarkupInfo; + MarkupInfo.StartX := aCol; + MarkupInfo.EndX := FHighlightPos2.X2 - 1; + end; +end; + +function TSynEditMarkupWordGroup.GetNextMarkupColAfterRowCol(const aRow, aCol: Integer) : Integer; + Procedure CheckCol(Column: Integer; var Result: Integer); + begin + if (Column <= aCol) or ((Result >= 0) and (Result < Column)) then exit; + Result := Column; + end; +begin + Result := -1; + if (FHighlightPos1.y = aRow) then begin + CheckCol(FHighlightPos1.X, Result); + CheckCol(FHighlightPos1.X2, Result); + end; + if (FHighlightPos3.y = aRow) then begin + CheckCol(FHighlightPos3.X, Result); + CheckCol(FHighlightPos3.X2, Result); + end; + if (FHighlightPos2.y = aRow) then begin + CheckCol(FHighlightPos2.X, Result); + CheckCol(FHighlightPos2.X2, Result); + end; +end; + +end. + diff --git a/components/synedit/synhighlighterpas.pp b/components/synedit/synhighlighterpas.pp index e31457aff1..775f18a056 100644 --- a/components/synedit/synhighlighterpas.pp +++ b/components/synedit/synhighlighterpas.pp @@ -58,7 +58,7 @@ uses Windows, Messages, {$ENDIF} Classes, Registry, Controls, - SynEditTypes, SynEditHighlighter, SynEditTextBuffer; + SynEditTypes, SynEditHighlighter, SynEditTextBuffer, SynEditTextBase; type TtkTokenKind = (tkAsm, tkComment, tkIdentifier, tkKey, tkNull, tkNumber, @@ -103,6 +103,13 @@ type cfbtProgram, cfbtRecord ); + TPascalWordTrippletRanges = set of TPascalCodeFoldBlockType; + +const + PascalWordTrippletRanges: TPascalWordTrippletRanges = + [cfbtBeginEnd, cfbtProcedure, cfbtClass, cfbtProgram, cfbtRecord]; +type + TPascalCompilerMode = ( pcmObjFPC, pcmDelphi, @@ -119,6 +126,7 @@ type FMode: TPascalCompilerMode; FBracketNestLevel : Integer; FLastLineCodeFoldLevelFix: integer; + FMinimumCodeFoldBlockLevel: Integer; public procedure Clear; override; function Compare(Range: TSynCustomHighlighterRange): integer; override; @@ -128,8 +136,14 @@ type procedure DecLastLineCodeFoldLevelFix; property Mode: TPascalCompilerMode read FMode write FMode; property BracketNestLevel: integer read FBracketNestLevel write FBracketNestLevel; - property LastLineCodeFoldLevelFix: integer read FLastLineCodeFoldLevelFix - write FLastLineCodeFoldLevelFix; + // Refers To LastLine while scanning + // stored as begining of the next line, it will refer to 2nd last line + property LastLineCodeFoldLevelFix: integer + read FLastLineCodeFoldLevelFix write FLastLineCodeFoldLevelFix; + // Refers To this line while scanning + // stored as begining of the next line, it will refer to the last line + property MinimumCodeFoldBlockLevel: integer + read FMinimumCodeFoldBlockLevel write FMinimumCodeFoldBlockLevel; end; {$ENDIF} @@ -179,6 +193,7 @@ type {$ENDIF} fD4syntax: boolean; {$IFDEF SYN_LAZARUS} + function GetPasCodeFoldRange: TSynPasSynRange; procedure SetCompilerMode(const AValue: TPascalCompilerMode); function TextComp(aText: PChar): Boolean; function KeyHash: Integer; @@ -315,6 +330,7 @@ type {$ENDIF} procedure EndCodeFoldBlockLastLine; function GetLastLineCodeFoldLevelFix: integer; override; + property PasCodeFoldRange: TSynPasSynRange read GetPasCodeFoldRange; public {$IFNDEF SYN_CPPB_1} class {$ENDIF} function GetCapabilities: TSynHighlighterCapabilities; override; @@ -347,6 +363,8 @@ type {$IFDEF SYN_LAZARUS} function TopPascalCodeFoldBlockType: TPascalCodeFoldBlockType; {$ENDIF} + Function GetWordTriplet(LogicalCaret: TPoint; Lines: TSynEditStrings; + out Y1, XB1, XE1, Y2, XB2, XE2, Y3, XB3, XE3: Integer): Boolean; override; published property AsmAttri: TSynHighlighterAttributes read fAsmAttri write fAsmAttri; property CommentAttri: TSynHighlighterAttributes read fCommentAttri @@ -723,6 +741,11 @@ begin //DebugLn(['TSynPasSyn.SetCompilerMode FCompilerMode=',ord(FCompilerMode),' FNestedComments=',FNestedComments]); end; +function TSynPasSyn.GetPasCodeFoldRange: TSynPasSynRange; +begin + Result := TSynPasSynRange(CodeFoldRange); +end; + {$ENDIF} function TSynPasSyn.Func15: TtkTokenKind; @@ -2149,6 +2172,7 @@ begin // For speed reasons, we work with fRange instead of CodeFoldRange.RangeType // -> update now CodeFoldRange.RangeType:=Pointer(PtrUInt(Integer(fRange))); + PasCodeFoldRange.MinimumCodeFoldBlockLevel := MinimumCodeFoldBlockLevel; // return a fixed copy of the current CodeFoldRange instance Result := inherited GetRange; {$ELSE} @@ -2173,6 +2197,7 @@ procedure TSynPasSyn.ResetRange; begin fRange:= [rsAfterSemicolon]; // Begin of file = new Statement FStartCodeFoldBlockLevel:=0; + FMinimumCodeFoldBlockLevel := 0; {$IFDEF SYN_LAZARUS} Inherited ResetRange; CompilerMode:=pcmDelphi; @@ -2209,6 +2234,191 @@ begin Result:=TPascalCodeFoldBlockType(PtrUInt(inherited TopCodeFoldBlockType)); end; +// ToDO: pass in Max for the search lines (Begin must be found always) +function TSynPasSyn.GetWordTriplet(LogicalCaret: TPoint; Lines: TSynEditStrings; + out Y1, XB1, XE1, Y2, XB2, XE2, Y3, XB3, XE3: Integer): Boolean; + + function GetLevelBeforeCaret: Integer; + var + l: Integer; + begin + SetRange(Lines.Ranges[LogicalCaret.Y - 1]); + FMinimumCodeFoldBlockLevel := CurrentCodeFoldBlockLevel; + l := CurrentCodeFoldBlockLevel; + SetLine(Lines[LogicalCaret.Y - 1], LogicalCaret.Y - 1); + if (MinimumCodeFoldBlockLevel < CurrentCodeFoldBlockLevel) + then Result := MinimumCodeFoldBlockLevel + else Result := l; + while (Run <= LogicalCaret.x - 1) and not GetEol do begin + if (Run = LogicalCaret.x-1) and (Result <> CurrentCodeFoldBlockLevel) then + break; + FMinimumCodeFoldBlockLevel := CurrentCodeFoldBlockLevel; + l := CurrentCodeFoldBlockLevel; + Next; + if (MinimumCodeFoldBlockLevel < CurrentCodeFoldBlockLevel) + then Result := MinimumCodeFoldBlockLevel + else Result := l; + end; + end; + + function FindBegin(EndY, EndX, SeekLevel: Integer; out X1, X2: Integer; + out FoldType: TPascalCodeFoldBlockType): integer; // Returns Line + var + MinLvl: Integer; + begin + Result := EndY; + MinLvl := 0; // Search the current line always + repeat + SetRange(Lines.Ranges[Result - 1]); + //PasCodeFoldRange.MinimumCodeFoldBlockLevel; + if (EndX > 0) and (MinLvl <= SeekLevel) then begin + // Search in current Line + X1 := -1; + // Use MinimumCodefoldlevel to detect theimplicit end of "var"/"type" blocks at the next "begin" + FMinimumCodeFoldBlockLevel := CurrentCodeFoldBlockLevel; + MinLvl := PasCodeFoldRange.MinimumCodeFoldBlockLevel; // Before SetLine = LastLine's MinLvl + SetLine(Lines[Result - 1], Result - 1); + while (Run <= EndX) and not GetEol do begin + if (MinimumCodeFoldBlockLevel <= SeekLevel) then begin + X1 := fTokenPos; + X2 := Run; + FoldType := TopPascalCodeFoldBlockType; + end; + FMinimumCodeFoldBlockLevel := CurrentCodeFoldBlockLevel; + Next; + end; + if X1 >= 0 then exit; + end + else + MinLvl := PasCodeFoldRange.MinimumCodeFoldBlockLevel; // Before SetLine = LastLine's MinLvl + // Search previous lines + EndX := MaxInt; + dec(Result); + until Result = 0; // should always exit before + end; + + function FindEnd(BeginY, BeginX2, SeekLevel: Integer; + out X1, X2, LvlBefore: Integer): integer; // Returns Line + var + c, MinLvl : Integer; + begin + Result := BeginY; + c := Lines.Count; + MinLvl := 0; // CurrentLine always has samller Minlevel + repeat + SetRange(Lines.Ranges[Result-1]); + if (MinLvl < SeekLevel) then begin + // Search in current Line + LvlBefore := CurrentCodeFoldBlockLevel; + SetLine(Lines[Result - 1], Result - 1); + if (FTokenPos < BeginX2) then + begin + while (FTokenPos < BeginX2) and not GetEol do + Next; + FMinimumCodeFoldBlockLevel := CurrentCodeFoldBlockLevel; + end; + while not GetEol do + begin + if CurrentCodeFoldBlockLevel < SeekLevel then + begin + X1 := fTokenPos; + X2 := Run; + exit + end + else if (MinimumCodeFoldBlockLevel < SeekLevel) or + (CurrentCodeFoldBlockLevel + LastLineCodeFoldLevelFix < SeekLevel) + then + exit(-1); // This block ended in the previous line (implicit end) + LvlBefore := CurrentCodeFoldBlockLevel; + Next; + end; + end; + // Search previous lines + BeginX2 := 0; + inc(Result); + if Result < c-1 then begin + SetRange(Lines.Ranges[Result]); + MinLvl := PasCodeFoldRange.MinimumCodeFoldBlockLevel; + end else begin + MinLvl := 0; + end; + until Result = c; + Result := -1; + end; + +var + CurStartLevel, CurEndLevel, CurStartPosX, CurEndPosX, CurPosY: Integer; + EndStartLevel: Integer; + ft, ft2: TPascalCodeFoldBlockType; +begin + Result := False; + + CurPosY := LogicalCaret.Y; + CurStartLevel := GetLevelBeforeCaret; + CurEndLevel := CurrentCodeFoldBlockLevel; + CurStartPosX := fTokenPos; // 0 based + CurEndPosX := Run; // 0 based + + IF CurEndLevel > CurStartLevel then begin + // block open: begin or middle + if not (TopPascalCodeFoldBlockType in PascalWordTrippletRanges) then + exit; + + Y1 := CurPosY; + XB1 := CurStartPosX; + XE1 := CurEndPosX; + + Y3 := FindEnd(CurPosY, CurEndPosX, CurEndLevel, XB3, XE3, EndStartLevel); + if Y3 < 0 then exit(false); + + Result := true; + if (EndStartLevel - CurrentCodeFoldBlockLevel = 1) then begin; + Y2:=-2; + end else begin + if CurStartLevel = CurrentCodeFoldBlockLevel + then Y2 := FindBegin(Y3, XB3, CurrentCodeFoldBlockLevel+1, XB2, XE2, ft) + else Y2 := FindBegin(Y3, XB3, CurrentCodeFoldBlockLevel, XB2, XE2, ft); + if not (ft in PascalWordTrippletRanges) then + Y2 := -1; + end; + end + else + if CurStartLevel - CurEndLevel = 1 then begin + // block end, 1 lvl + Y1 := FindBegin(CurPosY, CurStartPosX, CurEndLevel, XB1, XE1, ft); + if not (ft in PascalWordTrippletRanges) then + exit; + Y2 := CurPosY; + XB2 := CurStartPosX; + XE2 := CurEndPosX; + Y3 := -2; + Result := true; + end + else + if CurEndLevel < CurStartLevel then begin + // block end, 2 lvl + Y2 := FindBegin(CurPosY, CurStartPosX, CurEndLevel+1, XB2, XE2, ft); + Y1 := FindBegin(Y2, XB2, CurEndLevel, XB1, XE1, ft2); + if not (ft in PascalWordTrippletRanges) then + Y2 := -1; + if not (ft2 in PascalWordTrippletRanges) then + Y1 := -1; + if (Y2 = -1) and (Y1 = -1) then + exit; + Y3 := CurPosY; + XB3 := CurStartPosX; + XE3 := CurEndPosX; + Result := true; + end; + + inc(XB1); + inc(XE1); + inc(XB2); + inc(XE2); + inc(XB3); + inc(XE3); +end; + function TSynPasSyn.StartPascalCodeFoldBlock( ABlockType: TPascalCodeFoldBlockType; SubBlock: boolean): TSynCustomCodeFoldBlock; @@ -2446,6 +2656,7 @@ begin inherited Clear; FBracketNestLevel := 0; FLastLineCodeFoldLevelFix := 0; + FMinimumCodeFoldBlockLevel := 0; end; function TSynPasSynRange.Compare(Range: TSynCustomHighlighterRange): integer; @@ -2456,6 +2667,8 @@ begin if Result<>0 then exit; Result := BracketNestLevel - TSynPasSynRange(Range).BracketNestLevel; if Result<>0 then exit; + Result := FMinimumCodeFoldBlockLevel - TSynPasSynRange(Range).FMinimumCodeFoldBlockLevel; + if Result<>0 then exit; Result := FLastLineCodeFoldLevelFix - TSynPasSynRange(Range).FLastLineCodeFoldLevelFix; end; @@ -2464,6 +2677,7 @@ begin inherited Assign(Src); FMode:=TSynPasSynRange(Src).FMode; FBracketNestLevel:=TSynPasSynRange(Src).FBracketNestLevel; + FMinimumCodeFoldBlockLevel := TSynPasSynRange(Src).FMinimumCodeFoldBlockLevel; FLastLineCodeFoldLevelFix := TSynPasSynRange(Src).FLastLineCodeFoldLevelFix; end; diff --git a/ide/editoroptions.pp b/ide/editoroptions.pp index 27817fdb0d..e9dba9cb07 100644 --- a/ide/editoroptions.pp +++ b/ide/editoroptions.pp @@ -40,7 +40,7 @@ uses Controls, Graphics, LCLProc, FileUtil, LResources, // synedit SynEdit, SynEditAutoComplete, SynEditHighlighter, SynEditKeyCmds, - SynEditStrConst, SynEditMarkupBracket, SynEditMarkupHighAll, + SynEditStrConst, SynEditMarkupBracket, SynEditMarkupHighAll, SynEditMarkupWordGroup, SynGutter, SynGutterBase, SynGutterCodeFolding, SynGutterLineNumber, SynGutterChanges, SynHighlighterCPP, SynHighlighterHTML, SynHighlighterJava, SynHighlighterLFM, SynHighlighterPas, SynHighlighterPerl, SynHighlighterPHP, SynHighlighterSQL, @@ -92,7 +92,7 @@ type ahaInvalidBreakpoint, ahaUnknownBreakpoint, ahaErrorLine, ahaIncrementalSearch, ahaHighlightAll, ahaBracketMatch, ahaMouseLink, ahaLineNumber, ahaLineHighlight, ahaModifiedLine, - ahaCodeFoldingTree, ahaHighlightWord, ahaFoldedCode); + ahaCodeFoldingTree, ahaHighlightWord, ahaFoldedCode, ahaWordGroup); TSingleColorAttribute = (scaGutter, scaRightMargin); @@ -116,7 +116,8 @@ const 'Modified line', 'Code folding tree', 'Highlight current word', - 'Folded code' + 'Folded code', + 'Word-Brackets' ); SingleColorAttributes: array[TSingleColorAttribute] of String = @@ -171,7 +172,8 @@ const { ahaModifiedLine } (BG: clNone; FG: clGreen; FC: $00E9FC; Styles: []; StylesMask: []), { ahaCodeFoldingTree } (BG: clWhite; FG: clSilver; FC: clNone; Styles: []; StylesMask: []), { ahaHighlightWord } (BG: $E6E6E6; FG: clDefault; FC: clSilver; Styles: []; StylesMask: []), - { ahaFoldedCode } (BG: clWhite; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []) + { ahaFoldedCode } (BG: clWhite; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []), + { ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: []) ); Single: ( { shaGutter } clBtnFace, @@ -209,7 +211,8 @@ const { ahaModifiedLine } (BG: clNone; FG: clGreen; FC: $00E9FC; Styles: []; StylesMask: []), { ahaCodeFoldingTree } (BG: clDefault; FG: clSilver; FC: clNone; Styles: []; StylesMask: []), { ahaHighlightWord } (BG: $303030; FG: clDefault; FC: clSilver; Styles: []; StylesMask: []), - { ahaFoldedCode } (BG: clDefault; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []) + { ahaFoldedCode } (BG: clDefault; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []), + { ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: []) ); Single: ( { shaGutter } clBtnFace, @@ -247,7 +250,8 @@ const { ahaModifiedLine } (BG: clNone; FG: clGreen; FC: $00E9FC; Styles: []; StylesMask: []), { ahaCodeFoldingTree } (BG: clDefault; FG: clSilver; FC: clNone; Styles: []; StylesMask: []), { ahaHighlightWord } (BG: clDefault; FG: clDefault; FC: clSilver; Styles: []; StylesMask: []), - { ahaFoldedCode } (BG: clDefault; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []) + { ahaFoldedCode } (BG: clDefault; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []), + { ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: []) ); Single: ( { shaGutter } clBtnFace, @@ -285,7 +289,8 @@ const { ahaModifiedLine } (BG: clNone; FG: clGreen; FC: $00E9FC; Styles: []; StylesMask: []), { ahaCodeFoldingTree } (BG: clDefault; FG: clSilver; FC: clNone; Styles: []; StylesMask: []), { ahaHighlightWord } (BG: clDefault; FG: clDefault; FC: clSilver; Styles: []; StylesMask: []), - { ahaFoldedCode } (BG: clDefault; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []) + { ahaFoldedCode } (BG: clDefault; FG: clSilver; FC: clSilver; Styles: []; StylesMask: []), + { ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: []) ); Single: ( { shaGutter } clBtnFace, @@ -323,7 +328,8 @@ const { ahaModifiedLine } (BG: $F4F4F4; FG: clLime; FC: clYellow;Styles: []; StylesMask: []), { ahaCodeFoldingTree } (BG: $F4F4F4; FG: $CC9999; FC: clNone; Styles: []; StylesMask: []), { ahaHighlightWord } (BG: clDefault; FG: clDefault; FC: $CCCCD6; Styles: []; StylesMask: []), - { ahaFoldedCode } (BG: clDefault; FG: $CC9999; FC: $CC9999; Styles: []; StylesMask: []) + { ahaFoldedCode } (BG: clDefault; FG: $CC9999; FC: $CC9999; Styles: []; StylesMask: []), + { ahaWordGroup } (BG: clNone; FG: clNone; FC: clRed; Styles: []; StylesMask: []) ); Single: ( { shaGutter } clBtnFace, @@ -2323,6 +2329,7 @@ begin SetMarkupColor(aSynEd.Highlighter, ahaFoldedCode, aSynEd.FoldedCodeColor); SetMarkupColor(aSynEd.Highlighter, ahaLineHighlight, aSynEd.LineHighlightColor); SetMarkupColorByClass(ahaHighlightWord, TSynEditMarkupHighlightAllCaret); + SetMarkupColorByClass(ahaWordGroup, TSynEditMarkupWordGroup); SetGutterColorByClass(ahaLineNumber, TSynGutterLineNumber); SetGutterColorByClass(ahaModifiedLine, TSynGutterChanges); SetGutterColorByClass(ahaCodeFoldingTree, TSynGutterCodeFolding);