From 8d681fd278e81499722019e56120c1741685246d Mon Sep 17 00:00:00 2001 From: martin Date: Sat, 28 Mar 2009 22:08:32 +0000 Subject: [PATCH] SynEdit Highlighter: Refactor; Highlighter now differs between Fold and Markup ranges; added Markup-Word-Pairs for repeat/try/case git-svn-id: trunk@19144 - --- components/synedit/synedit.pp | 120 +++---- components/synedit/syneditfoldedview.pp | 163 +++------ components/synedit/synedithighlighter.pp | 113 ++++-- .../synedit/synedithighlighterfoldbase.pas | 66 +++- components/synedit/synedittextbase.pas | 91 ++++- components/synedit/synedittextbuffer.pp | 145 ++++---- components/synedit/synhighlighterpas.pp | 340 ++++++++++++------ 7 files changed, 624 insertions(+), 414 deletions(-) diff --git a/components/synedit/synedit.pp b/components/synedit/synedit.pp index 69380706ec..82773007b5 100644 --- a/components/synedit/synedit.pp +++ b/components/synedit/synedit.pp @@ -312,6 +312,7 @@ type procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; procedure WMVScroll(var Msg: {$IFDEF SYN_LAZARUS}TLMScroll{$ELSE}TWMScroll{$ENDIF}); message WM_VSCROLL; private + FDividerDrawLevel: Integer; fFirstLine: integer; fBlockIndent: integer; FBlockSelection: TSynEditSelection; @@ -433,6 +434,7 @@ type procedure AquirePrimarySelection; function GetUndoList: TSynEditUndoList; + procedure SetDividerDrawLevel(const AValue: Integer); procedure SurrenderPrimarySelection; procedure BookMarkOptionsChanged(Sender: TObject); procedure ComputeCaret(X, Y: Integer); @@ -478,8 +480,6 @@ type {$IFDEF SYN_LAZARUS} function GetCharLen(const Line: string; CharStartPos: integer): integer; function GetLogicalCaretXY: TPoint; - procedure SetCFDividerDrawLevel(const AValue: Integer); - function GetCFDividerDrawLevel : Integer; procedure SetLogicalCaretXY(const NewLogCaretXY: TPoint); procedure SetBeautifier(NewBeautifier: TSynCustomBeautifier); {$ENDIF} @@ -619,7 +619,6 @@ type function GetTopView : Integer; procedure SetTopView(const AValue : Integer); {$ENDIF} - procedure ListScanRanges(Sender: TObject); procedure Loaded; override; procedure MarkListChange(Sender: TObject); {$IFDEF SYN_MBCSSUPPORT} @@ -929,10 +928,7 @@ type {$ENDIF} property SelectionMode: TSynSelectionMode read GetSelectionMode write SetSelectionMode default smNormal; - {$IFDEF SYN_LAZARUS} - property CFDividerDrawLevel: Integer - read GetCFDividerDrawLevel write SetCFDividerDrawLevel; - {$ENDIF} + property CFDividerDrawLevel: Integer read FDividerDrawLevel write SetDividerDrawLevel; property TabWidth: integer read fTabWidth write SetTabWidth default 8; property WantTabs: boolean read fWantTabs write SetWantTabs default FALSE; property OnChange: TNotifyEvent read FOnChange write FOnChange; @@ -1981,16 +1977,6 @@ begin Result:=PhysicalToLogicalPos(CaretXY); end; -procedure TCustomSynEdit.SetCFDividerDrawLevel(const AValue: Integer); -begin - FFoldedLinesView.CFDividerDrawLevel := AValue; -end; - -function TCustomSynEdit.GetCFDividerDrawLevel : Integer; -begin - Result := FFoldedLinesView.CFDividerDrawLevel; -end; - procedure TCustomSynEdit.SetLogicalCaretXY(const NewLogCaretXY: TPoint); begin CaretXY:=LogicalToPhysicalPos(NewLogCaretXY); @@ -2791,7 +2777,8 @@ var colEditorBG: TColor; // painting the background and the text rcLine, rcToken: TRect; - CurLine: integer; // line index for the loop + CurLine: integer; // Screen-line index for the loop + CurTextIndex: Integer; // Current Index in text CurPhysPos, CurLogIndex : Integer; // Physical Start Position of next token in current Line TokenAccu: record Len, MaxLen: integer; @@ -3314,6 +3301,7 @@ var CurLine := FirstLine-1; while CurLine>>> SynEdit Highlight-Ranges Error <<<< ', - ' AClip =', dbgs(AClip), - ' FirstLine=', FirstLine,' LastLine=',Lastline, - ' CurLine=',CurLine, - ' FirstCol=',FirstCol, ' LastCol=',LastCol, - ' CanvasRect=',dbgs(Canvas.ClipRect)]); - debugln([' Topline=', FTopLine, ' LineCount=', FLines.Count, - ' FoldedTopLine=', FFoldedLinesView.TopLine, - ' foldedCount=', FFoldedLinesView.Count, - ' TextHeight=', FTextHeight, - ' Range=', PtrInt(FFoldedLinesView.Ranges[CurLine]) - ]); - DrawHiLightMarkupToken(nil, PChar(Pointer(sLine)), Length(sLine)); - end - else begin - {$ENDIF} - fHighlighter.StartAtLineIndex(FFoldedLinesView.ScreenLineToTextIndex(CurLine)); - // Try to concatenate as many tokens as possible to minimize the count - // of ExtTextOut calls necessary. This depends on the selection state - // or the line having special colors. For spaces the foreground color - // is ignored as well. - //debugln('>>>> PaintLines Line=',dbgs(CurLine),' rect=',dbgs(rcToken)); - while not fHighlighter.GetEol do begin - fHighlighter.GetTokenEx(sToken,nTokenLen); - attr := fHighlighter.GetTokenAttribute; - // Add Markup to the token and append it to the TokenAccu - // record. This will paint any chars already stored if there is - // a (visible) change in the attributes. - DrawHiLightMarkupToken(attr,sToken,nTokenLen); - // Let the highlighter scan the next token. - fHighlighter.Next; - end; - {$IFDEF DEBUGSYNRANGE} + fHighlighter.StartAtLineIndex(CurTextIndex); + // Try to concatenate as many tokens as possible to minimize the count + // of ExtTextOut calls necessary. This depends on the selection state + // or the line having special colors. For spaces the foreground color + // is ignored as well. + //debugln('>>>> PaintLines Line=',dbgs(CurLine),' rect=',dbgs(rcToken)); + while not fHighlighter.GetEol do begin + fHighlighter.GetTokenEx(sToken,nTokenLen); + attr := fHighlighter.GetTokenAttribute; + // Add Markup to the token and append it to the TokenAccu + // record. This will paint any chars already stored if there is + // a (visible) change in the attributes. + DrawHiLightMarkupToken(attr,sToken,nTokenLen); + // Let the highlighter scan the next token. + fHighlighter.Next; end; - {$ENDIF} end; // Draw anything that's left in the TokenAccu record. Fill to the end // of the invalid area with the correct colors. @@ -3385,13 +3351,15 @@ var fMarkupManager.FinishMarkupForRow(FFoldedLinesView.TextIndex[CurLine]+1); - // codefold draw splitter line - if assigned(Gutter.CodeFoldPart) and Gutter.CodeFoldPart.Visible - and (FFoldedLinesView.DrawDivider[curLine]) then - begin - ypos := rcToken.Bottom - 1; - LCLIntf.MoveToEx(dc, nRightEdge, ypos, nil); - LCLIntf.LineTo(dc, fGutterWidth - 1, ypos); + // draw splitter line + if Assigned(fHighlighter) then begin + fHighlighter.DrawDividerLevel := FDividerDrawLevel; + if (fHighlighter.DrawDivider[CurTextIndex]) then + begin + ypos := rcToken.Bottom - 1; + LCLIntf.MoveToEx(dc, nRightEdge, ypos, nil); + LCLIntf.LineTo(dc, fGutterWidth - 1, ypos); + end; end; end; CurLine:=-1; @@ -4461,15 +4429,6 @@ begin end; {$ENDIF} -procedure TCustomSynEdit.ListScanRanges(Sender: TObject); -{$IFNDEF SYN_LAZARUS} -var - i: integer; -{$ENDIF} -begin - ScanFrom(0,FTheLinesView.Count-1); -end; - {$IFDEF SYN_MBCSSUPPORT} type TStringType = (stNone, stHalfNumAlpha, stHalfSymbol, stHalfKatakana, @@ -4967,6 +4926,12 @@ begin Result := fUndoList; end; +procedure TCustomSynEdit.SetDividerDrawLevel(const AValue: Integer); +begin + FDividerDrawLevel := AValue; + Invalidate; +end; + function TCustomSynEdit.GetLineState(ALine: Integer): TSynLineState; begin with TSynEditStringList(fLines) do @@ -5288,6 +5253,9 @@ begin if Operation = opRemove then begin if AComponent = fHighlighter then begin fHighlighter := nil; + if assigned(FLines.Ranges) then + FLines.Ranges.Free; + FLines.Ranges := nil; fMarkupHighCaret.Highlighter := nil; fMarkupWordGroup.Highlighter := nil; FFoldedLinesView.Highlighter := nil; @@ -5309,9 +5277,10 @@ end; procedure TCustomSynEdit.RemoveHooksFromHighlighter; begin - if Assigned(fHighlighter) then - fHighlighter.UnhookAttrChangeEvent - ({$IFDEF FPC}@{$ENDIF}HighlighterAttrChanged); + if not Assigned(fHighlighter) then + exit; + fHighlighter.UnhookAttrChangeEvent({$IFDEF FPC}@{$ENDIF}HighlighterAttrChanged); + fHighlighter.DetachFromLines(FLines); end; procedure TCustomSynEdit.SetHighlighter(const Value: TSynCustomHighlighter); @@ -5322,6 +5291,7 @@ begin Value.HookAttrChangeEvent( {$IFDEF FPC}@{$ENDIF}HighlighterAttrChanged); Value.FreeNotification(Self); + Value.AttachToLines(FLines); end; fHighlighter := Value; // Ensure to free all copies in SynEit.Notification too @@ -5338,7 +5308,7 @@ begin RecalcCharExtent; FTheLinesView.BeginUpdate; try - ListScanRanges(Self); + ScanFrom(0,FTheLinesView.Count-1); finally FTheLinesView.EndUpdate; end; diff --git a/components/synedit/syneditfoldedview.pp b/components/synedit/syneditfoldedview.pp index 8446cfeaa2..e59a67ce29 100644 --- a/components/synedit/syneditfoldedview.pp +++ b/components/synedit/syneditfoldedview.pp @@ -180,23 +180,16 @@ type fTextIndexList : Array of integer; (* Map each Screen line into a line in textbuffer *) fFoldTypeList : Array of TSynEditCodeFoldType; fOnFoldChanged : TFoldChangedEvent; - fCFDividerDrawLevel: Integer; fLockCount : Integer; fNeedFixFrom, fNeedFixMinEnd : Integer; fNeedCaretCheck : Boolean; function GetCount : integer; - function GetDrawDivider(Index : integer) : Boolean; - function GetFoldEndLevel(Index: integer): integer; - function GetFoldMinLevel(Index: integer): integer; - function GetFoldNestLevel(index : Integer): integer; function GetLines(index : Integer) : String; function GetDisplayNumber(index : Integer) : Integer; - function GetRange(Index : integer) : TSynEditRange; function GetTextIndex(index : Integer) : Integer; function GetFoldType(index : Integer) : TSynEditCodeFoldType; function IsFolded(index : integer) : Boolean; // TextIndex - procedure PutRange(Index : integer; const AValue : TSynEditRange); procedure SetTopLine(const ALine : integer); function GetTopTextIndex : integer; procedure SetTopTextIndex(const AIndex : integer); @@ -232,16 +225,10 @@ type // Attributes for Visible-Lines-On-screen property Lines[index : Integer] : String (* Lines on screen / 0 = TopLine *) read GetLines; default; - property Ranges[Index: integer]: TSynEditRange - read GetRange write PutRange; property DisplayNumber[index : Integer] : Integer (* LineNumber for display in Gutter / result is 1-based *) read GetDisplayNumber; property FoldType[index : Integer] : TSynEditCodeFoldType (* FoldIcon / State *) read GetFoldType; - property FoldNestLvl[index : Integer] : integer (* FoldIcon / Deep/Level of nesting; 1 for top-lvl *) - read GetFoldNestLevel; - property DrawDivider[Index: integer]: Boolean - read GetDrawDivider; property TextIndex[index : Integer] : Integer (* Position in SynTextBuffer / result is 0-based *) read GetTextIndex; // maybe writable @@ -255,7 +242,6 @@ type property Count : integer read GetCount; (* refers to visible (unfolded) lines *) - property CFDividerDrawLevel: Integer read fCFDividerDrawLevel write fCFDividerDrawLevel; property MarkupInfoFoldedCode: TSynSelectedColor read FMarkupInfoFoldedCode; public procedure Lock; @@ -283,10 +269,6 @@ type property OnFoldChanged: TFoldChangedEvent (* reports 1-based line *) {TODO: synedit expects 0 based } read fOnFoldChanged write fOnFoldChanged; - public - // TextIndex - property FoldMinLevel[Index: integer]: integer read GetFoldMinLevel; - property FoldEndLevel[Index: integer]: integer read GetFoldEndLevel; property HighLighter: TSynCustomHighlighter read FHighLighter write FHighLighter; end; @@ -1554,21 +1536,6 @@ begin Result := fLines.Count - fFoldTree.FindLastFold.FoldedBefore; end; -function TSynEditFoldedView.GetDrawDivider(Index : integer) : Boolean; -begin - result := (FoldType[Index] in [cfEnd]) - and (FoldEndLevel[TextIndex[index]] < CFDividerDrawLevel); -end; - -function TSynEditFoldedView.GetFoldNestLevel(index : Integer): integer; -begin - if (index < 0) or (index > fLinesInWindow) then exit(-1); - if (fFoldTypeList[index] = cfEnd) and (fTextIndexList[index] > 0) then - Result := FoldEndLevel[fTextIndexList[index]-1] - else - Result := FoldEndLevel[fTextIndexList[index]]; -end; - (* Topline *) procedure TSynEditFoldedView.SetTopLine(const ALine : integer); begin @@ -1601,7 +1568,19 @@ procedure TSynEditFoldedView.CalculateMaps; var i, tpos, cnt : Integer; node : TSynTextFoldAVLNode; + hl: TSynCustomFoldHighlighter; begin + if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter)) + then begin + for i := 0 to fLinesInWindow do begin + fTextIndexList[i] := fTopLine + i - 1; + fFoldTypeList[i] := cfNone; + end; + exit; + end; + + FHighLighter.CurrentLines := fLines; + hl := TSynCustomFoldHighlighter(FHighLighter); node := fFoldTree.FindFoldForFoldedLine(fTopLine, true); // ftopline is not a folded line // so node.FoldedBefore(next node after ftopl) does apply @@ -1617,13 +1596,13 @@ begin if (node.IsInFold) and (tpos+1 = node.StartLine) then fFoldTypeList[i] := cfCollapsed else - if FoldEndLevel[tpos-1] > FoldMinLevel[tpos-1] + if (hl.FoldOpenCount(tpos - 1) > 0) then fFoldTypeList[i] := cfExpanded else - if (tpos > 1) and (FoldEndLevel[tpos-2] > FoldMinLevel[tpos-1]) + if (tpos > 1) and (hl.FoldCloseCount(tpos - 1) > 0) then fFoldTypeList[i] := cfEnd else - if FoldEndLevel[tpos-1] > 0 + if hl.FoldNestCount(tpos - 1) > 0 then fFoldTypeList[i] := cfContinue else fFoldTypeList[i] := cfNone; @@ -1651,13 +1630,6 @@ begin Result := fTextIndexList[index]+1; end; -function TSynEditFoldedView.GetRange(Index : integer) : TSynEditRange; -begin - if (index < 0) or (index > fLinesInWindow) then - exit(fLines.Ranges[ScreenLineToTextIndex(Index)]); - Result := fLines.Ranges[fTextIndexList[index]]; -end; - function TSynEditFoldedView.GetTextIndex(index : Integer) : Integer; begin if (index < 0) or (index > fLinesInWindow) then @@ -1676,34 +1648,8 @@ begin Result := fFoldTree.FindFoldForLine(index+1).IsInFold; end; -procedure TSynEditFoldedView.PutRange(Index : integer; const AValue : TSynEditRange); -begin - if (index < 0) or (index > fLinesInWindow) then exit; - fLines.Ranges[fTextIndexList[index]] := AValue; -end; - (* Folding *) -function TSynEditFoldedView.GetFoldEndLevel(Index: integer): integer; -begin - if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter)) - then exit(0); - FHighLighter.CurrentLines := fLines; - Result := TSynCustomFoldHighlighter(FHighLighter).EndFoldLevel(Index) + - TSynCustomFoldHighlighter(FHighLighter).LastLineFoldLevelFix(Index + 1); -end; - -function TSynEditFoldedView.GetFoldMinLevel(Index: integer): integer; -begin - if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter)) - then exit(0); - FHighLighter.CurrentLines := fLines; - Result := TSynCustomFoldHighlighter(FHighLighter).EndFoldLevel(Index) + - TSynCustomFoldHighlighter(FHighLighter).LastLineFoldLevelFix(Index + 1); - Result := Min(Result, - TSynCustomFoldHighlighter(FHighLighter).MinimumFoldLevel(Index)); -end; - procedure TSynEditFoldedView.FoldAtLine(AStartLine : Integer); begin FoldAtViewPos(AStartLine + fTopLine); @@ -1715,17 +1661,11 @@ begin end; function TSynEditFoldedView.LengthForFoldAtTextIndex(ALine : Integer) : Integer; -var - i, lvl, cnt : Integer; begin - cnt := fLines.Count; - // AStartLine is 1-based // FoldEndLevel is 0-based - lvl := FoldEndLevel[ALine]; - i := ALine+1; - while (i < cnt) and (FoldMinLevel[i] >= lvl) do inc(i); - // check if fold last line of block (not mixed "end begin") - if (i < cnt) and (FoldEndLevel[i] <= FoldMinLevel[i]) then inc(i); - Result := i-ALine-1; + if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter)) + then exit(0); + Result := TSynCustomFoldHighlighter(FHighLighter).FoldLineLength(ALine, + TSynCustomFoldHighlighter(FHighLighter).FoldOpenCount(ALine) -1); end; procedure TSynEditFoldedView.FoldAtTextIndex(AStartIndex : Integer); @@ -1780,13 +1720,19 @@ end; procedure TSynEditFoldedView.FoldAll(StartLevel : Integer = 0; IgnoreNested : Boolean = False); var i, l, top: Integer; + hl: TSynCustomFoldHighlighter; begin + if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter)) + then exit; + FHighLighter.CurrentLines := fLines; + hl := TSynCustomFoldHighlighter(FHighLighter); + top := TopTextIndex; fFoldTree.Clear; i := 0; while i < fLines.Count do begin - if (FoldEndLevel[i] > FoldMinLevel[i]) - and (FoldEndLevel[i] > StartLevel) then begin + if (hl.FoldOpenCount(i) > 0) + and (hl.FoldNestCount(i) > StartLevel) then begin l := LengthForFoldAtTextIndex(i); // i is 0-based // FoldTree is 1-based AND first line remains visble @@ -1807,6 +1753,7 @@ var line, cnt, a: Integer; LastStart, LastCount: Integer; node, tmpnode: TSynTextFoldAVLNode; + hl: TSynCustomFoldHighlighter; begin Result := false; if fLockCount > 0 then begin @@ -1825,6 +1772,11 @@ begin end; If AMinEnd < node.StartLine then AMinEnd := node.StartLine; + if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter)) + then exit; + FHighLighter.CurrentLines := fLines; + hl := TSynCustomFoldHighlighter(FHighLighter); + // LineCount is allowed to be -1 while node.IsInFold and (node.StartLine + node.LineCount + 1 >= AStart) do begin tmpnode := node.Prev; @@ -1851,7 +1803,7 @@ begin LastCount := cnt; // look at the 0-based cfCollapsed (visible) Line - if not(FoldEndLevel[line -1] > FoldMinLevel[line - 1]) then begin + if not(hl.FoldOpenCount(line - 1) > 0) then begin // the Fold-Begin of this node has gone tmpnode := node.Prev; aFoldTree.RemoveFoldForNodeAtLine(node, -1); // Don't touch any nested node @@ -1917,36 +1869,35 @@ function TSynEditFoldedView.ExpandedLineForBlockAtLine(ALine : Integer) : Intege var i, l : Integer; node: TSynTextFoldAVLNode; + hl: TSynCustomFoldHighlighter; begin Result := -1; - i := ALine-1; + if not(assigned(FHighLighter) and (FHighLighter is TSynCustomFoldHighlighter)) + then exit; + FHighLighter.CurrentLines := fLines; + hl := TSynCustomFoldHighlighter(FHighLighter); - if (i>0) and (FoldMinLevel[i] < FoldEndLevel[i-1])then begin - if FoldMinLevel[i] < FoldEndLevel[i] then begin - // this is a combined "end begin" line - node := fFoldTree.FindFoldForLine(ALine, true); - if node.IsInFold and (node.StartLine = ALine +1) then - dec(i); - if i < 0 then exit; - end else begin - // this is a "end" line - dec(i); - end; - l := FoldEndLevel[i]; - end else if FoldEndLevel[i] = 0 then - exit - else begin - // check if current line is cfCollapsed + i := ALine; + if hl.FoldOpenCount(i - 1) > 0 then begin node := fFoldTree.FindFoldForLine(ALine, true); if node.IsInFold and (node.StartLine = ALine +1) then - dec(i); - if i < 0 then exit; - l := FoldEndLevel[i] - end; - - while (i > 0) and (FoldMinLevel[i] >= l) do + dec(i) + else + exit(ALine); + end + else if hl.FoldCloseCount(i - 1) > 0 then dec(i); - if (FoldEndLevel[i] > 0) then // TODO, check for collapsed at index = 0 + if (i < 0) or (hl.FoldNestCount(i-1) = 0) then + exit; + + l := 0; + while (i > 0) and (l >= 0) do begin // (FoldMinLevel[i] >= l) do + dec(i); + l := l - hl.FoldOpenCount(i); + if l >= 0 then + l := l + hl.FoldCloseCount(i); + end; + if (hl.FoldNestCount(i) > 0) then // TODO, check for collapsed at index = 0 Result := i + 1; end; diff --git a/components/synedit/synedithighlighter.pp b/components/synedit/synedithighlighter.pp index 9dd374e7af..427b3f56e3 100644 --- a/components/synedit/synedithighlighter.pp +++ b/components/synedit/synedithighlighter.pp @@ -59,6 +59,18 @@ type {$ENDIF} end; + { TSynHighlighterRangeList } + + TSynHighlighterRangeList = class(TSynEditStorageMem) + private + function GetRange(Index: Integer): Pointer; + procedure SetRange(Index: Integer; const AValue: Pointer); + protected + function ItemSize: Integer; override; + public + property Range[Index: Integer]: Pointer read GetRange write SetRange; default; + end; + { TSynHighlighterAttributes } TSynHighlighterAttributes = class(TPersistent) @@ -154,11 +166,15 @@ type {$IFDEF SYN_LAZARUS} FCapabilities: TSynHighlighterCapabilities; FCurrentLines: TSynEditStrings; + FCurrentRanges: TSynHighlighterRangeList; + FDrawDividerLevel: Integer; FLineIndex: Integer; {$ENDIF} fUpdateCount: integer; //mh 2001-09-13 fEnabled: Boolean; fWordBreakChars: TSynIdentChars; + procedure SetCurrentLines(const AValue: TSynEditStrings); + procedure SetDrawDividerLevel(const AValue: Integer); procedure SetEnabled(const Value: boolean); //DDH 2001-10-23 protected fDefaultFilter: string; @@ -177,8 +193,12 @@ type procedure SetAttributesOnChange(AEvent: TNotifyEvent); procedure SetDefaultFilter(Value: string); virtual; procedure SetSampleSource(Value: string); virtual; + function CreateRangeList: TSynHighlighterRangeList; virtual; + function UpdateRangeInfoAtLine(Index: Integer): Boolean; virtual; // Returns true if range changed // code fold - only valid if hcCodeFolding in Capabilities property LineIndex: Integer read FLineIndex; + property CurrentRanges: TSynHighlighterRangeList read FCurrentRanges; + function GetDrawDivider(Index: integer): Boolean; virtual; public procedure DefHighlightChange(Sender: TObject); {$IFNDEF SYN_CPPB_1} class {$ENDIF} @@ -194,6 +214,8 @@ type procedure Assign(Source: TPersistent); override; procedure BeginUpdate; procedure EndUpdate; + procedure AttachToLines(Lines: TSynEditStrings); + procedure DetachFromLines(Lines: TSynEditStrings); public function GetEol: Boolean; virtual; abstract; function GetRange: Pointer; virtual; @@ -206,13 +228,21 @@ type procedure Next; virtual; abstract; procedure NextToEol; + property DrawDivider[Index: integer]: Boolean read GetDrawDivider; + property DrawDividerLevel: Integer read FDrawDividerLevel write SetDrawDividerLevel; + public + property CurrentLines: TSynEditStrings read FCurrentLines write SetCurrentLines; + + procedure StartAtLineIndex(LineNumber:Integer); virtual; // 0 based + procedure ContinueNextLine; // To be called at EOL; does not read the range + + function ScanFrom(Index: integer; AtLeastTilIndex: integer = -1): integer; procedure SetRange(Value: Pointer); virtual; procedure ResetRange; virtual; procedure SetLine({$IFDEF FPC}const {$ENDIF}NewValue: String; LineNumber:Integer // 0 based ); virtual; - procedure StartAtLineIndex(LineNumber:Integer); // 0 based - procedure ContinueNextLine; // To be called at EOL; does not read the range + public function UseUserSettings(settingIndex: integer): boolean; virtual; procedure EnumUserSettings(Settings: TStrings); virtual; @@ -225,13 +255,6 @@ type property IdentChars: TSynIdentChars read GetIdentChars; property WordBreakChars: TSynIdentChars read fWordBreakChars write SetWordBreakChars; property LanguageName: string read GetLanguageName; - property CurrentLines: TSynEditStrings read FCurrentLines write FCurrentLines; - - function ScanFrom(Index: integer; AtLeastTilIndex: integer = -1): integer; - (* Methds for folding *) - function MinimumCodeFoldBlockLevel: integer; virtual; - function CurrentCodeFoldBlockLevel: integer; virtual; - function LastLineCodeFoldLevelFix: integer; virtual; public property AttrCount: integer read GetAttribCount; property Attribute[idx: integer]: TSynHighlighterAttributes @@ -833,6 +856,18 @@ begin end; end; +procedure TSynCustomHighlighter.AttachToLines(Lines: TSynEditStrings); +begin + Lines.Ranges := CreateRangeList; +end; + +procedure TSynCustomHighlighter.DetachFromLines(Lines: TSynEditStrings); +begin + if assigned(Lines.Ranges) then + Lines.Ranges.Free; + Lines.Ranges := nil; +end; + procedure TSynCustomHighlighter.FreeHighlighterAttributes; var i: integer; @@ -1067,7 +1102,7 @@ begin if LineNumber = 0 then ResetRange else - SetRange(CurrentLines.Ranges[LineNumber - 1]); + SetRange(FCurrentRanges[LineNumber - 1]); SetLine(CurrentLines[LineNumber], LineNumber); end; @@ -1106,11 +1141,26 @@ procedure TSynCustomHighlighter.SetSampleSource(Value: string); begin end; +function TSynCustomHighlighter.CreateRangeList: TSynHighlighterRangeList; +begin + Result := TSynHighlighterRangeList.Create; +end; + procedure TSynCustomHighlighter.UnhookAttrChangeEvent(ANotifyEvent: TNotifyEvent); begin fAttrChangeHooks.Remove(ANotifyEvent); end; +function TSynCustomHighlighter.UpdateRangeInfoAtLine(Index: Integer): Boolean; +var + r: Pointer; +begin + r := GetRange; + Result := r <> FCurrentRanges[Index]; + if Result then + FCurrentRanges[Index] := r; +end; + function TSynCustomHighlighter.ScanFrom(Index: integer; AtLeastTilIndex: integer): integer; var c: LongInt; @@ -1119,10 +1169,9 @@ begin c := CurrentLines.Count; StartAtLineIndex(Result); NextToEol; - while (GetRange <> CurrentLines.Ranges[Result]) or + while UpdateRangeInfoAtLine(Result) or (Result <= AtLeastTilIndex+1) do begin - CurrentLines.Ranges[Result] := GetRange; inc(Result); if Result = c then break; @@ -1131,11 +1180,6 @@ begin end; end; -function TSynCustomHighlighter.MinimumCodeFoldBlockLevel: integer; -begin - Result := 0; -end; - procedure TSynCustomHighlighter.SetEnabled(const Value: boolean); begin if fEnabled <> Value then @@ -1148,14 +1192,41 @@ begin end; end; -function TSynCustomHighlighter.LastLineCodeFoldLevelFix: integer; +procedure TSynCustomHighlighter.SetCurrentLines(const AValue: TSynEditStrings); begin - Result := 0; + if AValue = FCurrentLines then + exit; + FCurrentLines := AValue; + FCurrentRanges := TSynHighlighterRangeList(AValue.Ranges); end; -function TSynCustomHighlighter.CurrentCodeFoldBlockLevel: integer; +procedure TSynCustomHighlighter.SetDrawDividerLevel(const AValue: Integer); begin - Result := 0; + if FDrawDividerLevel = AValue then exit; + FDrawDividerLevel := AValue; + //DefHighlightChange(Self); +end; + +function TSynCustomHighlighter.GetDrawDivider(Index: integer): Boolean; +begin + result := false; +end; + +{ TSynHighlighterRangeList } + +function TSynHighlighterRangeList.GetRange(Index: Integer): Pointer; +begin + Result := Pointer(ItemPointer[Index]^); +end; + +procedure TSynHighlighterRangeList.SetRange(Index: Integer; const AValue: Pointer); +begin + Pointer(ItemPointer[Index]^) := AValue; +end; + +function TSynHighlighterRangeList.ItemSize: Integer; +begin + Result := SizeOf(Pointer); end; initialization diff --git a/components/synedit/synedithighlighterfoldbase.pas b/components/synedit/synedithighlighterfoldbase.pas index 3c0cb19397..62bb86f562 100644 --- a/components/synedit/synedithighlighterfoldbase.pas +++ b/components/synedit/synedithighlighterfoldbase.pas @@ -71,7 +71,8 @@ type TSynCustomHighlighterRange = class private - FCodeFoldStackSize: integer; + FCodeFoldStackSize: integer; // EndLevel + FMinimumCodeFoldBlockLevel: integer; FRangeType: Pointer; FTop: TSynCustomCodeFoldBlock; public @@ -79,8 +80,8 @@ type destructor Destroy; override; function Compare(Range: TSynCustomHighlighterRange): integer; virtual; function Add(ABlockType: Pointer = nil; IncreaseLevel: Boolean = True): - TSynCustomCodeFoldBlock; - procedure Pop(DecreaseLevel: Boolean = True); + TSynCustomCodeFoldBlock; virtual; + procedure Pop(DecreaseLevel: Boolean = True); virtual; procedure Clear; virtual; procedure Assign(Src: TSynCustomHighlighterRange); virtual; procedure WriteDebugReport; @@ -88,6 +89,8 @@ type public property RangeType: Pointer read FRangeType write FRangeType; property CodeFoldStackSize: integer read FCodeFoldStackSize; + property MinimumCodeFoldBlockLevel: integer + read FMinimumCodeFoldBlockLevel write FMinimumCodeFoldBlockLevel; property Top: TSynCustomCodeFoldBlock read FTop; end; TSynCustomHighlighterRangeClass = class of TSynCustomHighlighterRange; @@ -115,8 +118,6 @@ type FCodeFoldRange: TSynCustomHighlighterRange; fRanges: TSynCustomHighlighterRanges; FRootCodeFoldBlock: TSynCustomCodeFoldBlock; - protected - FMinimumCodeFoldBlockLevel: integer; protected function GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo; virtual; function GetFoldNodeInfoCount(Line: Integer): Integer; virtual; @@ -134,14 +135,21 @@ type destructor Destroy; override; function GetRange: Pointer; override; - function MinimumCodeFoldBlockLevel: integer; override; - function CurrentCodeFoldBlockLevel: integer; override; + function MinimumCodeFoldBlockLevel: integer; virtual; + function CurrentCodeFoldBlockLevel: integer; virtual; // requires CurrentLines; function MinimumFoldLevel(Index: Integer): integer; virtual; abstract; function EndFoldLevel(Index: Integer): integer; virtual; abstract; - function LastLineFoldLevelFix(Index: Integer): integer; virtual; abstract; + // fold-nodes that can be collapsed + // Highlighter can join several fold structures Or leave out some + function FoldOpenCount(ALineIndex: Integer): integer; virtual; + function FoldCloseCount(ALineIndex: Integer): integer; virtual; + function FoldNestCount(ALineIndex: Integer): integer; virtual; + function FoldLineLength(ALineIndex, FoldIndex: Integer): integer; virtual; + + // All fold-nodes property FoldNodeInfo[Line, Index: Integer]: TSynFoldNodeInfo read GetFoldNodeInfo; property FoldNodeInfoCount[Line: Integer]: Integer read GetFoldNodeInfoCount; @@ -258,7 +266,7 @@ end; function TSynCustomFoldHighlighter.MinimumCodeFoldBlockLevel: integer; begin - Result := FMinimumCodeFoldBlockLevel; + Result := FCodeFoldRange.MinimumCodeFoldBlockLevel; end; procedure TSynCustomFoldHighlighter.SetRange(Value: Pointer); @@ -267,14 +275,13 @@ begin // in case we asigned a null range if not assigned(FCodeFoldRange.FoldRoot) then FCodeFoldRange.FoldRoot := FRootCodeFoldBlock; - FMinimumCodeFoldBlockLevel:=FCodeFoldRange.CodeFoldStackSize; end; procedure TSynCustomFoldHighlighter.SetLine(const NewValue: String; LineNumber: Integer); begin inherited; - FMinimumCodeFoldBlockLevel:=CodeFoldRange.CodeFoldStackSize; + FCodeFoldRange.MinimumCodeFoldBlockLevel := FCodeFoldRange.FCodeFoldStackSize; end; function TSynCustomFoldHighlighter.CurrentCodeFoldBlockLevel: integer; @@ -285,6 +292,26 @@ begin Result:=0; end; +function TSynCustomFoldHighlighter.FoldOpenCount(ALineIndex: Integer): integer; +begin + result := 0; +end; + +function TSynCustomFoldHighlighter.FoldCloseCount(ALineIndex: Integer): integer; +begin + result := 0; +end; + +function TSynCustomFoldHighlighter.FoldNestCount(ALineIndex: Integer): integer; +begin + Result := 0; +end; + +function TSynCustomFoldHighlighter.FoldLineLength(ALineIndex, FoldIndex: Integer): integer; +begin + result := 0; +end; + function TSynCustomFoldHighlighter.GetFoldNodeInfoCount(Line: Integer): Integer; begin Result := 0; @@ -317,8 +344,6 @@ end; procedure TSynCustomFoldHighlighter.EndCodeFoldBlock(DecreaseLevel: Boolean = True); begin CodeFoldRange.Pop(DecreaseLevel); - if FMinimumCodeFoldBlockLevel>CodeFoldRange.CodeFoldStackSize then - FMinimumCodeFoldBlockLevel:=CodeFoldRange.CodeFoldStackSize; end; procedure TSynCustomFoldHighlighter.CreateRootCodeFoldBlock; @@ -538,16 +563,19 @@ end; function TSynCustomHighlighterRange.Compare(Range: TSynCustomHighlighterRange ): integer; begin - if RangeTypeRange.RangeType then + else if RangeType > Range.RangeType then Result:=-1 else if Pointer(FTop) < Pointer(Range.FTop) then Result:= -1 else if Pointer(FTop) > Pointer(Range.FTop) then Result:= 1 else - Result := 0; + Result := FMinimumCodeFoldBlockLevel - Range.FMinimumCodeFoldBlockLevel; + if Result <> 0 then + exit; + Result := FCodeFoldStackSize - Range.FCodeFoldStackSize; end; function TSynCustomHighlighterRange.Add(ABlockType: Pointer; @@ -568,6 +596,8 @@ begin FTop := FTop.Parent; if DecreaseLevel then dec(FCodeFoldStackSize); + if FMinimumCodeFoldBlockLevel > FCodeFoldStackSize then + FMinimumCodeFoldBlockLevel := FCodeFoldStackSize; end; end; @@ -575,6 +605,7 @@ procedure TSynCustomHighlighterRange.Clear; begin FRangeType:=nil; FCodeFoldStackSize := 0; + FMinimumCodeFoldBlockLevel := 0; FTop:=nil; end; @@ -583,11 +614,13 @@ begin if (Src<>nil) and (Src<>TSynCustomHighlighterRange(NullRange)) then begin FTop := Src.FTop; FCodeFoldStackSize := Src.FCodeFoldStackSize; + FMinimumCodeFoldBlockLevel := Src.FMinimumCodeFoldBlockLevel; FRangeType := Src.FRangeType; end else begin FTop := nil; FCodeFoldStackSize := 0; + FMinimumCodeFoldBlockLevel := 0; FRangeType := nil; end; end; @@ -634,6 +667,7 @@ begin // add a copy Result:=TSynCustomHighlighterRangeClass(Range.ClassType).Create(Range); FItems.Add(Result); + //if FItems.Count mod 32 = 0 then debugln(['FOLDRANGE Count=', FItems.Count]); end; //debugln('TSynCustomHighlighterRanges.GetEqual A ',dbgs(Node),' ',dbgs(Result.Compare(Range)),' ',dbgs(Result.CodeFoldStackSize)); end; diff --git a/components/synedit/synedittextbase.pas b/components/synedit/synedittextbase.pas index 2fd46b3cf8..9502aadaec 100644 --- a/components/synedit/synedittextbase.pas +++ b/components/synedit/synedittextbase.pas @@ -42,6 +42,30 @@ type type + + { TSynEditStorageMem } + + TSynEditStorageMem = class + private + FMem: PByte; + FCount, FCapacity: Integer; + function GetItemPointer(Index: Integer): Pointer; + protected + procedure SetCapacity(const AValue: Integer); virtual; + procedure SetCount(const AValue: Integer); virtual; + function ItemSize: Integer; virtual; abstract; + + property Mem: PByte read FMem; + property ItemPointer[Index: Integer]: Pointer read GetItemPointer; + public + constructor Create; + destructor Destroy; override; + procedure Move(AFrom, ATo, ALen: Integer); virtual; + property Capacity: Integer read FCapacity write SetCapacity; + // Count must be maintained by owner + property Count: Integer read FCount write SetCount; + end; + { TSynEditStrings } TSynEditStrings = class(TStrings) @@ -49,8 +73,8 @@ type FIsUtf8: Boolean; function GetIsUtf8 : Boolean; virtual; procedure SetIsUtf8(const AValue : Boolean); virtual; - function GetRange(Index: integer): TSynEditRange; virtual; abstract; - procedure PutRange(Index: integer; ARange: TSynEditRange); virtual; abstract; + function GetRange: TSynEditStorageMem; virtual; abstract; + procedure PutRange(ARange: TSynEditStorageMem); virtual; abstract; function GetAttribute(const Owner: TClass; const Index: Integer): Pointer; virtual; abstract; procedure SetAttribute(const Owner: TClass; const Index: Integer; const AValue: Pointer); virtual; abstract; @@ -103,7 +127,7 @@ type property ExpandedStrings[Index: integer]: string read GetExpandedString; property LengthOfLongestLine: integer read GetLengthOfLongestLine; property IsUtf8: Boolean read GetIsUtf8 write SetIsUtf8; - property Ranges[Index: integer]: TSynEditRange read GetRange write PutRange; + property Ranges: TSynEditStorageMem read GetRange write PutRange; end; { TSynEditStringsLinked } @@ -115,8 +139,8 @@ type function GetIsUtf8 : Boolean; override; procedure SetIsUtf8(const AValue : Boolean); override; - function GetRange(Index: integer): TSynEditRange; override; - procedure PutRange(Index: integer; ARange: TSynEditRange); override; + function GetRange: TSynEditStorageMem; override; + procedure PutRange(ARange: TSynEditStorageMem); override; function GetAttribute(const Owner: TClass; const Index: Integer): Pointer; override; procedure SetAttribute(const Owner: TClass; const Index: Integer; const AValue: Pointer); override; @@ -451,14 +475,14 @@ begin end; //Ranges -function TSynEditStringsLinked.GetRange(Index: integer): TSynEditRange; +function TSynEditStringsLinked.GetRange: TSynEditStorageMem; begin - Result:= fSynStrings.Ranges[Index]; + Result:= fSynStrings.Ranges; end; -procedure TSynEditStringsLinked.PutRange(Index: integer; ARange: TSynEditRange); +procedure TSynEditStringsLinked.PutRange(ARange: TSynEditStorageMem); begin - fSynStrings.Ranges[Index] := ARange; + fSynStrings.Ranges := ARange; end; function TSynEditStringsLinked.GetAttribute(const Owner: TClass; const Index: Integer): Pointer; @@ -985,5 +1009,54 @@ begin Result := FItems[FCount]; end; +{ TSynEditStorageMem } + +function TSynEditStorageMem.GetItemPointer(Index: Integer): Pointer; +begin + Result := Pointer(FMem + Index * ItemSize); +end; + +procedure TSynEditStorageMem.SetCapacity(const AValue: Integer); +begin + if FCapacity = AValue then exit; + FMem := ReallocMem(FMem, AValue * ItemSize); + if AValue > FCapacity then + FillChar((FMem+FCapacity*ItemSize)^, (AValue-FCapacity)*ItemSize, 0); + FCapacity := AValue; +end; + +procedure TSynEditStorageMem.SetCount(const AValue: Integer); +begin + FCount := AValue; +end; + +constructor TSynEditStorageMem.Create; +begin + FCapacity := 0; + FCount := 0; +end; + +destructor TSynEditStorageMem.Destroy; +begin + SetCount(0); + SetCapacity(0); + inherited Destroy; +end; + +procedure TSynEditStorageMem.Move(AFrom, ATo, ALen: Integer); +var + len: Integer; +begin + if ATo < AFrom then begin + Len := Min(ALen, AFrom-ATo); + System.Move((FMem+AFrom*ItemSize)^, (FMem+ATo*ItemSize)^, Alen*ItemSize); + FillChar((FMem+(AFrom+ALen-Len)*ItemSize)^, Len*ItemSize, 0); + end else begin + Len := Min(ALen, ATo-AFrom); + System.Move((FMem+AFrom*ItemSize)^, (FMem+ATo*ItemSize)^, Alen*ItemSize); + FillChar((FMem+AFrom*ItemSize)^, Len*ItemSize, 0); + end; +end; + end. diff --git a/components/synedit/synedittextbuffer.pp b/components/synedit/synedittextbuffer.pp index 36736eafa6..c4ea5cde89 100644 --- a/components/synedit/synedittextbuffer.pp +++ b/components/synedit/synedittextbuffer.pp @@ -50,7 +50,6 @@ const NullRange = TSynEditRange(-1); type - TSynEditRangeClass = class end; // For Register TSynEditFlagsClass = class end; // For Register TSynEditStringFlag = ( @@ -75,38 +74,36 @@ type Procedure CallRangeNotifyEvents(Sender: TSynEditStrings; aIndex, aCount: Integer); end; - { TSynEditStringMemory } - TSynEditStringMemory = class + TSynEditStringMemory = class(TSynEditStorageMem) private - FMem: ^Byte; - FCount, FCapacity: Integer; FAttributeSize: Integer; + FRangeList: TSynEditStorageMem; function GetAttribute(Index: Integer; Pos: Integer; Size: Word): Pointer; function GetAttributeSize: Integer; - function GetCapacity: Integer; function GetObject(Index: Integer): TObject; function GetString(Index: Integer): String; procedure SetAttribute(Index: Integer; Pos: Integer; Size: Word; const AValue: Pointer); procedure SetAttributeSize(const AValue: Integer); - procedure SetCapacity(const AValue: Integer); - procedure SetCount(const AValue: Integer); + procedure SetCount(const AValue: Integer); override; procedure SetObject(Index: Integer; const AValue: TObject); + procedure SetRangeList(const AValue: TSynEditStorageMem); procedure SetString(Index: Integer; const AValue: String); + protected + function ItemSize: Integer; override; + procedure SetCapacity(const AValue: Integer); override; public constructor Create; - destructor Destroy; override; - procedure Move(AFrom, ATo, ALen: Integer); + procedure Move(AFrom, ATo, ALen: Integer); override; property Strings[Index: Integer]: String read GetString write SetString; default; property Objects[Index: Integer]: TObject read GetObject write SetObject; property Attribute[Index: Integer; Pos: Integer; Size: Word]: Pointer read GetAttribute write SetAttribute; - property Capacity: Integer read GetCapacity write SetCapacity; - // Count must be maintained by owner - property Count: Integer read FCount write SetCount; property AttributeSize: Integer read GetAttributeSize write SetAttributeSize; + + property RangeList: TSynEditStorageMem read FRangeList write SetRangeList; end; { TSynEditStringList } @@ -144,8 +141,8 @@ type procedure SendNotification(AReason: TSynEditNotifyReason; ASender: TSynEditStrings; aIndex, aCount: Integer); override; - function GetRange(Index: integer): TSynEditRange; {$IFDEF SYN_LAZARUS}override;{$ENDIF} - procedure PutRange(Index: integer; ARange: TSynEditRange); {$IFDEF SYN_LAZARUS}override;{$ENDIF} + function GetRange: TSynEditStorageMem; override; + procedure PutRange(ARange: TSynEditStorageMem); override; function GetAttribute(const Owner: TClass; const Index: Integer): Pointer; override; procedure SetAttribute(const Owner: TClass; const Index: Integer; const AValue: Pointer); override; function Get(Index: integer): string; override; @@ -190,7 +187,6 @@ type public property DosFileFormat: boolean read fDosFileFormat write fDosFileFormat; property LengthOfLongestLine: integer read GetLengthOfLongestLine; - property Ranges[Index: integer]: TSynEditRange read GetRange write PutRange; property OnChange: TNotifyEvent read fOnChange write fOnChange; property OnChanging: TNotifyEvent read fOnChanging write fOnChanging; property OnCleared: TNotifyEvent read fOnCleared write fOnCleared; @@ -396,7 +392,6 @@ begin FLineChangeNotificationList := TLineRangeNotificationList.Create; inherited Create; SetAttributeSize(0); - RegisterAttribute(TSynEditRangeClass, SizeOf(Pointer)); RegisterAttribute(TSynEditFlagsClass, SizeOf(TSynEditStringFlag)); fDosFileFormat := TRUE; {begin} //mh 2000-10-19 @@ -445,7 +440,6 @@ begin Strings[Count-1] := AStrings[i]; Objects[Count-1] := AStrings.Objects[i]; end; - SetAttribute(TSynEditRangeClass, Count-1, NullRange); Flags[Count-1] := []; end; FLineRangeNotificationList.CallRangeNotifyEvents(self, FirstAdded, Count - FirstAdded); @@ -623,12 +617,9 @@ begin Result := nil; end; -function TSynEditStringList.GetRange(Index: integer): TSynEditRange; +function TSynEditStringList.GetRange: TSynEditStorageMem; begin - if (Index >= 0) and (Index < Count) then - Result := TSynEditRange(GetAttribute(TSynEditRangeClass, Index)) - else - Result := nil; + Result := FList.RangeList; end; procedure TSynEditStringList.Grow; @@ -670,7 +661,6 @@ begin SetCount(Count + 1); fList[Index] := S; FList.Objects[Index] := nil; - Ranges[Index] := NullRange; Flags[Index] := []; EndUpdate; end; @@ -739,17 +729,9 @@ begin EndUpdate; end; -procedure TSynEditStringList.PutRange(Index: integer; ARange: TSynEditRange); +procedure TSynEditStringList.PutRange(ARange: TSynEditStorageMem); begin - {$IFDEF SYN_LAZARUS} - // do not call BeginUpdate/EndUpdate. It would call the too generic OnChange - // events - SetAttribute(TSynEditRangeClass, Index, Pointer(PtrUInt(ARange))); - {$ELSE} - BeginUpdate; - SetAttribute(TSynEditRangeClass, Index, Pointer(PtrUInt(ARange))); - EndUpdate; - {$ENDIF} + FList.RangeList := ARange; end; function TSynEditStringList.GetAttribute(const Owner: TClass; const Index: Integer): Pointer; @@ -999,110 +981,111 @@ const constructor TSynEditStringMemory.Create; begin inherited Create; - FCapacity := 0; - FCount := 0; AttributeSize := 0; -end; - -destructor TSynEditStringMemory.Destroy; -begin - SetCount(0); - SetCapacity(0); - inherited Destroy; + FRangeList := nil; end; procedure TSynEditStringMemory.Move(AFrom, ATo, ALen: Integer); var - i, len: Integer; + Len, i: Integer; begin - //debugln(['TSynEditStringMemory.Move(',AFrom, ',', ATo, ', ',ALen,')']); if ATo < AFrom then begin Len := Min(ALen, AFrom-ATo); for i:=ATo to ATo + Len -1 do Strings[i]:=''; - System.Move((FMem+AFrom*FAttributeSize)^, (FMem+ATo*FAttributeSize)^, Alen*FAttributeSize); - FillChar((FMem+(AFrom+ALen-Len)*FAttributeSize)^, Len*FAttributeSize, 0); end else begin Len := Min(ALen, ATo-AFrom); for i:=ATo+Alen-Len to ATo+ALen -1 do Strings[i]:=''; - System.Move((FMem+AFrom*FAttributeSize)^, (FMem+ATo*FAttributeSize)^, Alen*FAttributeSize); - FillChar((FMem+AFrom*FAttributeSize)^, Len*FAttributeSize, 0); end; -end; - -function TSynEditStringMemory.GetCapacity: Integer; -begin - Result := FCapacity; -end; - -procedure TSynEditStringMemory.SetCapacity(const AValue: Integer); -begin - if FCapacity = AValue then exit;; - FMem := ReallocMem(FMem, AValue * FAttributeSize); - if AValue > FCapacity then - FillChar((FMem+FCapacity*FAttributeSize)^, (AValue-FCapacity)*FAttributeSize, 0); - FCapacity := AValue; + inherited Move(AFrom, ATo, ALen); + if assigned(FRangeList) then + FRangeList.Move(AFrom, ATo, ALen); end; procedure TSynEditStringMemory.SetCount(const AValue: Integer); var i : Integer; begin - If FCount = AValue then exit; - for i:= AValue to FCount-1 do Strings[i]:=''; - FCount := AValue; + If Count = AValue then exit; + for i:= AValue to Count-1 do Strings[i]:=''; + inherited SetCount(AValue); + if assigned(FRangeList) then + FRangeList.Count := AValue; end; - function TSynEditStringMemory.GetAttributeSize: Integer; begin Result := FAttributeSize - SizeOf(String) - SizeOf(TObject) end; procedure TSynEditStringMemory.SetAttributeSize(const AValue: Integer); +var + c: LongInt; begin if FAttributeSize = AValue + SizeOf(String) + SizeOf(TObject) then exit;; + c := Capacity; + Capacity := 0; FAttributeSize := AValue + SizeOf(String) + SizeOf(TObject); - SetCapacity(FCapacity); - // Todo: Move existing records + Capacity := c; end; function TSynEditStringMemory.GetString(Index: Integer): String; begin - Result := (PString(FMem + Index * FAttributeSize))^; + Result := (PString(Mem + Index * FAttributeSize))^; end; procedure TSynEditStringMemory.SetString(Index: Integer; const AValue: String); begin - (PString(FMem + Index * FAttributeSize))^ := AValue; + (PString(Mem + Index * FAttributeSize))^ := AValue; +end; + +function TSynEditStringMemory.ItemSize: Integer; +begin + Result := FAttributeSize; +end; + +procedure TSynEditStringMemory.SetCapacity(const AValue: Integer); +begin + inherited SetCapacity(AValue); + if assigned(FRangeList) then + FRangeList.Capacity := AValue; end; function TSynEditStringMemory.GetObject(Index: Integer): TObject; begin - Result := (PObject(FMem + Index * FAttributeSize + SizeOf(String)))^; + Result := (PObject(Mem + Index * FAttributeSize + SizeOf(String)))^; end; procedure TSynEditStringMemory.SetObject(Index: Integer; const AValue: TObject); begin - (PObject(FMem + Index * FAttributeSize + SizeOf(String)))^ := AValue; + (PObject(Mem + Index * FAttributeSize + SizeOf(String)))^ := AValue; +end; + +procedure TSynEditStringMemory.SetRangeList(const AValue: TSynEditStorageMem); +begin + FRangeList := AValue; + if FRangeList <> nil then begin + FRangeList.Capacity := Capacity; + FRangeList.Count := Count; + end; end; function TSynEditStringMemory.GetAttribute(Index: Integer; Pos: Integer; Size: Word): Pointer; begin case Size of - 1 : Result := Pointer(PtrUInt((PByte(FMem + Index * FAttributeSize + AttributeOfset + Pos))^)); - 2 : Result := Pointer(PtrUInt((PWord(FMem + Index * FAttributeSize + AttributeOfset + Pos))^)); - 4 : Result := Pointer(PtrUInt((PLongWord(FMem + Index * FAttributeSize + AttributeOfset + Pos))^)); - 8 : Result := Pointer(PtrUInt((PQWord(FMem + Index * FAttributeSize + AttributeOfset + Pos))^)); + 1 : Result := Pointer(PtrUInt((PByte(Mem + Index * FAttributeSize + AttributeOfset + Pos))^)); + 2 : Result := Pointer(PtrUInt((PWord(Mem + Index * FAttributeSize + AttributeOfset + Pos))^)); + 4 : Result := Pointer(PtrUInt((PLongWord(Mem + Index * FAttributeSize + AttributeOfset + Pos))^)); + 8 : Result := Pointer(PtrUInt((PQWord(Mem + Index * FAttributeSize + AttributeOfset + Pos))^)); end; end; procedure TSynEditStringMemory.SetAttribute(Index: Integer; Pos: Integer; Size: Word; const AValue: Pointer); begin case Size of - 1 : (PByte(FMem + Index * FAttributeSize + AttributeOfset + Pos))^ := Byte(PtrUInt(AValue)); - 2 : (PWord(FMem + Index * FAttributeSize + AttributeOfset + Pos))^ := Word(PtrUInt(AValue)); - 4 : (PLongWord(FMem + Index * FAttributeSize + AttributeOfset + Pos))^ := LongWord(PtrUInt(AValue)); - 8 : (PQWord(FMem + Index * FAttributeSize + AttributeOfset + Pos))^ := QWord(PtrUInt(AValue)); + 1 : (PByte(Mem + Index * FAttributeSize + AttributeOfset + Pos))^ := Byte(PtrUInt(AValue)); + 2 : (PWord(Mem + Index * FAttributeSize + AttributeOfset + Pos))^ := Word(PtrUInt(AValue)); + 4 : (PLongWord(Mem + Index * FAttributeSize + AttributeOfset + Pos))^ := LongWord(PtrUInt(AValue)); + 8 : (PQWord(Mem + Index * FAttributeSize + AttributeOfset + Pos))^ := QWord(PtrUInt(AValue)); end; end; diff --git a/components/synedit/synhighlighterpas.pp b/components/synedit/synhighlighterpas.pp index 08e728cc70..a94b248a1a 100644 --- a/components/synedit/synhighlighterpas.pp +++ b/components/synedit/synhighlighterpas.pp @@ -100,7 +100,9 @@ type cfbtUnitSection, cfbtProgram, cfbtUnit, - cfbtRecord + cfbtRecord, + cfbtExcept, + cfbtRepeat ); TPascalWordTrippletRanges = set of TPascalCodeFoldBlockType; @@ -108,7 +110,9 @@ const CountPascalCodeFoldBlockOffset: Pointer = Pointer(PtrInt(Integer(high(TPascalCodeFoldBlockType))+1)); PascalWordTrippletRanges: TPascalWordTrippletRanges = - [cfbtBeginEnd, cfbtProcedure, cfbtClass, cfbtProgram, cfbtRecord]; + [cfbtBeginEnd, cfbtProcedure, cfbtClass, cfbtProgram, cfbtRecord, + cfbtExcept, cfbtRepeat + ]; type @@ -128,24 +132,27 @@ type FMode: TPascalCompilerMode; FBracketNestLevel : Integer; FLastLineCodeFoldLevelFix: integer; - FMinimumCodeFoldBlockLevel: Integer; + FPasFoldEndLevel: Smallint; + FPasFoldFixLevel: Smallint; + FPasFoldMinLevel: Smallint; public procedure Clear; override; function Compare(Range: TSynCustomHighlighterRange): integer; override; procedure Assign(Src: TSynCustomHighlighterRange); override; + function Add(ABlockType: Pointer = nil; IncreaseLevel: Boolean = True): + TSynCustomCodeFoldBlock; override; + procedure Pop(DecreaseLevel: Boolean = True); override; procedure IncBracketNestLevel; procedure DecBracketNestLevel; procedure DecLastLineCodeFoldLevelFix; + procedure DecLastLinePasFoldFix; property Mode: TPascalCompilerMode read FMode write FMode; property BracketNestLevel: integer read FBracketNestLevel write FBracketNestLevel; - // 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; + property PasFoldEndLevel: Smallint read FPasFoldEndLevel write FPasFoldEndLevel; + property PasFoldFixLevel: Smallint read FPasFoldFixLevel write FPasFoldFixLevel; + property PasFoldMinLevel: Smallint read FPasFoldMinLevel write FPasFoldMinLevel; end; {$ENDIF} @@ -161,6 +168,7 @@ type fAsmStart: Boolean; FNestedComments: boolean; FStartCodeFoldBlockLevel: integer; + FPasStartLevel: Smallint; fRange: TRangeStates; FAtLineStart: Boolean; // Line had only spaces or comments sofar {$IFDEF SYN_LAZARUS} @@ -332,18 +340,27 @@ type protected function GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo; override; function GetFoldNodeInfoCount(Line: Integer): Integer; override; + function GetIdentChars: TSynIdentChars; override; function IsFilterStored: boolean; override; //mh 2000-10-08 + procedure CreateRootCodeFoldBlock; override; - {$IFDEF SYN_LAZARUS} function StartPascalCodeFoldBlock(ABlockType: TPascalCodeFoldBlockType; SubBlock: boolean = false): TSynCustomCodeFoldBlock; procedure EndCodeFoldBlock(DecreaseLevel: Boolean = True); override; procedure CloseBeginEndBlocks; - function GetRangeClass: TSynCustomHighlighterRangeClass; override; - {$ENDIF} procedure EndCodeFoldBlockLastLine; + function TopPascalCodeFoldBlockType: TPascalCodeFoldBlockType; + + function GetRangeClass: TSynCustomHighlighterRangeClass; override; property PasCodeFoldRange: TSynPasSynRange read GetPasCodeFoldRange; + + function MinimumPasFoldLevel(Index: Integer): integer; + function EndPasFoldLevel(Index: Integer): integer; + function LastLinePasFoldLevelFix(Index: Integer): integer; + + function LastLineFoldLevelFix(Index: Integer): integer; + function GetDrawDivider(Index: integer): Boolean; override; public {$IFNDEF SYN_CPPB_1} class {$ENDIF} function GetCapabilities: TSynHighlighterCapabilities; override; @@ -374,15 +391,14 @@ type function UseUserSettings(settingIndex: integer): boolean; override; procedure EnumUserSettings(settings: TStrings); override; - //code fold - function LastLineCodeFoldLevelFix: integer; override; - {$IFDEF SYN_LAZARUS} - function TopPascalCodeFoldBlockType: TPascalCodeFoldBlockType; - {$ENDIF} + // fold-nodes that can be collapsed + function FoldOpenCount(ALineIndex: Integer): integer; override; + function FoldCloseCount(ALineIndex: Integer): integer; override; + function FoldNestCount(ALineIndex: Integer): integer; override; + function FoldLineLength(ALineIndex, FoldIndex: Integer): integer; override; function MinimumFoldLevel(Index: Integer): integer; override; function EndFoldLevel(Index: Integer): integer; override; - function LastLineFoldLevelFix(Index: Integer): integer; override; published property AsmAttri: TSynHighlighterAttributes read fAsmAttri write fAsmAttri; property CommentAttri: TSynHighlighterAttributes read fCommentAttri @@ -755,7 +771,7 @@ begin if FCompilerMode=AValue then exit; FCompilerMode:=AValue; FNestedComments:=FCompilerMode in [pcmFPC,pcmObjFPC]; - TSynPasSynRange(CodeFoldRange).Mode:=FCompilerMode; + PasCodeFoldRange.Mode:=FCompilerMode; //DebugLn(['TSynPasSyn.SetCompilerMode FCompilerMode=',ord(FCompilerMode),' FNestedComments=',FNestedComments]); end; @@ -810,13 +826,17 @@ begin then begin Result := tkKey; fRange := fRange - [rsAsm]; - TSynPasSynRange(CodeFoldRange).BracketNestLevel := 0; // Reset in case of partial code + PasCodeFoldRange.BracketNestLevel := 0; // Reset in case of partial code {$IFDEF SYN_LAZARUS} // there may be more than on block ending here if TopPascalCodeFoldBlockType = cfbtRecord then begin EndCodeFoldBlock; end else if TopPascalCodeFoldBlockType = cfbtUnit then begin EndCodeFoldBlock; + end else if TopPascalCodeFoldBlockType = cfbtExcept then begin + EndCodeFoldBlock; + if TopPascalCodeFoldBlockType = cfbtBeginEnd then + EndCodeFoldBlock; end else if TopPascalCodeFoldBlockType = cfbtBeginEnd then begin EndCodeFoldBlock; if TopPascalCodeFoldBlockType = cfbtProcedure then @@ -910,7 +930,7 @@ begin // if we are in an include file, we may not know the state if (fRange * [rsImplementation, rsInterface] = []) then Include(fRange, rsImplementation); - TSynPasSynRange(CodeFoldRange).BracketNestLevel := 0; // Reset in case of partial code + PasCodeFoldRange.BracketNestLevel := 0; // Reset in case of partial code if TopPascalCodeFoldBlockType=cfbtVarType then EndCodeFoldBlockLastLine; Result := tkKey; {$IFDEF SYN_LAZARUS} @@ -942,7 +962,7 @@ begin if KeyComp('Else') then Result := tkKey else if KeyComp('Var') then begin - if (TSynPasSynRange(CodeFoldRange).BracketNestLevel = 0) and + if (PasCodeFoldRange.BracketNestLevel = 0) and (TopPascalCodeFoldBlockType in [cfbtVarType, cfbtNone, cfbtProcedure, cfbtProgram, cfbtUnit, cfbtUnitSection]) then begin if TopPascalCodeFoldBlockType=cfbtVarType then EndCodeFoldBlockLastLine; @@ -988,7 +1008,7 @@ function TSynPasSyn.Func54: TtkTokenKind; begin if KeyComp('Class') then begin Result := tkKey; - if (rsAfterEqual in fRange) and (TSynPasSynRange(CodeFoldRange).BracketNestLevel = 0) + if (rsAfterEqual in fRange) and (PasCodeFoldRange.BracketNestLevel = 0) then begin fRange := fRange + [rsAtClass]; StartPascalCodeFoldBlock(cfbtClass); @@ -1001,7 +1021,7 @@ function TSynPasSyn.Func55: TtkTokenKind; begin if KeyComp('Object') then begin Result := tkKey; - if (rsAfterEqual in fRange) and (TSynPasSynRange(CodeFoldRange).BracketNestLevel = 0) + if (rsAfterEqual in fRange) and (PasCodeFoldRange.BracketNestLevel = 0) then begin fRange := fRange + [rsAtClass]; StartPascalCodeFoldBlock(cfbtClass); @@ -1060,15 +1080,11 @@ begin end else if KeyComp('Array') then Result := tkKey else if KeyComp('Try') then - {$IFDEF SYN_LAZARUS} begin if TopPascalCodeFoldBlockType=cfbtBeginEnd then StartPascalCodeFoldBlock(cfbtBeginEnd,true); Result := tkKey; end - {$ELSE} - Result := tkKey - {$ENDIF} else if KeyComp('Inline') then Result := tkKey else Result := tkIdentifier; end; @@ -1091,13 +1107,17 @@ end; function TSynPasSyn.Func65: TtkTokenKind; begin - if KeyComp('Repeat') then Result := tkKey else Result := tkIdentifier; + if KeyComp('Repeat') then begin + Result := tkKey; + StartPascalCodeFoldBlock(cfbtRepeat, True); + end + else Result := tkIdentifier; end; function TSynPasSyn.Func66: TtkTokenKind; begin if KeyComp('Type') then begin - if (TSynPasSynRange(CodeFoldRange).BracketNestLevel = 0) + if (PasCodeFoldRange.BracketNestLevel = 0) and (TopPascalCodeFoldBlockType in [cfbtVarType, cfbtNone, cfbtProcedure, cfbtProgram, cfbtUnit, cfbtUnitSection]) and not(rsAfterEqual in fRange) @@ -1122,7 +1142,7 @@ begin if KeyComp('Stdcall') then Result := tkKey else if KeyComp('Const') then begin - if (TSynPasSynRange(CodeFoldRange).BracketNestLevel = 0) and + if (PasCodeFoldRange.BracketNestLevel = 0) and (TopPascalCodeFoldBlockType in [cfbtVarType, cfbtNone, cfbtProcedure, cfbtProgram, cfbtUnit, cfbtUnitSection]) then begin if TopPascalCodeFoldBlockType=cfbtVarType then EndCodeFoldBlockLastLine; @@ -1140,7 +1160,11 @@ end; function TSynPasSyn.Func73: TtkTokenKind; begin - if KeyComp('Except') then Result := tkKey else Result := tkIdentifier; + if KeyComp('Except') then begin + Result := tkKey; + StartPascalCodeFoldBlock(cfbtExcept, True); + end + else Result := tkIdentifier; end; function TSynPasSyn.Func75: TtkTokenKind; @@ -1153,12 +1177,20 @@ end; function TSynPasSyn.Func76: TtkTokenKind; begin - if KeyComp('Until') then Result := tkKey else Result := tkIdentifier; + if KeyComp('Until') then begin + Result := tkKey; + if TopPascalCodeFoldBlockType = cfbtRepeat then EndCodeFoldBlock; + end + else Result := tkIdentifier; end; function TSynPasSyn.Func79: TtkTokenKind; begin - if KeyComp('Finally') then Result := tkKey else Result := tkIdentifier; + if KeyComp('Finally') then begin + Result := tkKey; + StartPascalCodeFoldBlock(cfbtExcept, True); + end + else Result := tkIdentifier; end; function TSynPasSyn.Func81: TtkTokenKind; @@ -1308,7 +1340,7 @@ function TSynPasSyn.Func102: TtkTokenKind; begin if KeyComp('Function') then begin if not(rsAfterEqual in fRange) then begin - TSynPasSynRange(CodeFoldRange).BracketNestLevel := 0; // Reset in case of partial code + PasCodeFoldRange.BracketNestLevel := 0; // Reset in case of partial code CloseBeginEndBlocks; if TopPascalCodeFoldBlockType=cfbtVarType then EndCodeFoldBlockLastLine; if ((rsImplementation in fRange) and @@ -1330,7 +1362,7 @@ function TSynPasSyn.Func105: TtkTokenKind; begin if KeyComp('Procedure') then begin if not(rsAfterEqual in fRange) then begin - TSynPasSynRange(CodeFoldRange).BracketNestLevel := 0; // Reset in case of partial code + PasCodeFoldRange.BracketNestLevel := 0; // Reset in case of partial code CloseBeginEndBlocks; if TopPascalCodeFoldBlockType=cfbtVarType then EndCodeFoldBlockLastLine; if ((rsImplementation in fRange) and @@ -1429,7 +1461,7 @@ end; function TSynPasSyn.Func136: TtkTokenKind; begin if KeyComp('Finalization') then begin - TSynPasSynRange(CodeFoldRange).BracketNestLevel := 0; // Reset in case of partial code + PasCodeFoldRange.BracketNestLevel := 0; // Reset in case of partial code CloseBeginEndBlocks; if TopPascalCodeFoldBlockType=cfbtVarType then EndCodeFoldBlockLastLine; if TopPascalCodeFoldBlockType=cfbtUnitSection then EndCodeFoldBlockLastLine; @@ -1454,7 +1486,7 @@ begin begin if not(rsAfterEqual in fRange) then begin - TSynPasSynRange(CodeFoldRange).BracketNestLevel := 0; // Reset in case of partial code + PasCodeFoldRange.BracketNestLevel := 0; // Reset in case of partial code CloseBeginEndBlocks; if TopPascalCodeFoldBlockType = cfbtVarType then EndCodeFoldBlockLastLine; if ((rsImplementation in fRange) and @@ -1474,7 +1506,7 @@ function TSynPasSyn.Func166: TtkTokenKind; begin if KeyComp('Constructor') then begin if not(rsAfterEqual in fRange) then begin - TSynPasSynRange(CodeFoldRange).BracketNestLevel := 0; // Reset in case of partial code + PasCodeFoldRange.BracketNestLevel := 0; // Reset in case of partial code CloseBeginEndBlocks; if TopPascalCodeFoldBlockType=cfbtVarType then EndCodeFoldBlockLastLine; if ((rsImplementation in fRange) and @@ -1485,7 +1517,7 @@ begin Result := tkKey; end else if KeyComp('Implementation') then begin - TSynPasSynRange(CodeFoldRange).BracketNestLevel := 0; // Reset in case of partial code + PasCodeFoldRange.BracketNestLevel := 0; // Reset in case of partial code CloseBeginEndBlocks; if TopPascalCodeFoldBlockType=cfbtVarType then EndCodeFoldBlockLastLine; if TopPascalCodeFoldBlockType=cfbtUnitSection then EndCodeFoldBlockLastLine; @@ -1505,7 +1537,7 @@ end; function TSynPasSyn.Func168: TtkTokenKind; begin if KeyComp('Initialization') then begin - TSynPasSynRange(CodeFoldRange).BracketNestLevel := 0; // Reset in case of partial code + PasCodeFoldRange.BracketNestLevel := 0; // Reset in case of partial code CloseBeginEndBlocks; if TopPascalCodeFoldBlockType=cfbtVarType then EndCodeFoldBlockLastLine; if TopPascalCodeFoldBlockType=cfbtUnitSection then EndCodeFoldBlockLastLine; @@ -1672,18 +1704,17 @@ end; { Create } procedure TSynPasSyn.SetLine(const NewValue: string; LineNumber:Integer); begin //DebugLn(['TSynPasSyn.SetLine START LineNumber=',LineNumber,' Line="',NewValue,'"']); - {$IFDEF SYN_LAZARUS} fLineStr := NewValue; fLineLen:=length(fLineStr); fLine:=PChar(Pointer(fLineStr)); Run := 0; Inherited SetLine(NewValue,LineNumber); - FStartCodeFoldBlockLevel := FMinimumCodeFoldBlockLevel; - TSynPasSynRange(CodeFoldRange).LastLineCodeFoldLevelFix := 0; - {$ELSE} - fLine := PChar(NewValue); - Run := 0; - {$ENDIF} + FStartCodeFoldBlockLevel := MinimumCodeFoldBlockLevel; + PasCodeFoldRange.LastLineCodeFoldLevelFix := 0; + PasCodeFoldRange.PasFoldFixLevel := 0; + PasCodeFoldRange.PasFoldMinLevel := + PasCodeFoldRange.PasFoldEndLevel; + FPasStartLevel := PasCodeFoldRange.PasFoldMinLevel; FNodeInfoLine := -1; fLineNumber := LineNumber; FAtLineStart := True; @@ -1947,7 +1978,7 @@ begin {$IFDEF SYN_LAZARUS} if Run>=fLineLen then begin fTokenID:=tkSymbol; - TSynPasSynRange(CodeFoldRange).IncBracketNestLevel; + PasCodeFoldRange.IncBracketNestLevel; exit; end; {$ENDIF} @@ -1966,11 +1997,11 @@ begin begin inc(Run); fTokenID := tkSymbol; - TSynPasSynRange(CodeFoldRange).IncBracketNestLevel; + PasCodeFoldRange.IncBracketNestLevel; end; else fTokenID := tkSymbol; - TSynPasSynRange(CodeFoldRange).IncBracketNestLevel; + PasCodeFoldRange.IncBracketNestLevel; end; end; @@ -1978,7 +2009,7 @@ procedure TSynPasSyn.RoundCloseProc; begin inc(Run); fTokenID := tkSymbol; - TSynPasSynRange(CodeFoldRange).DecBracketNestLevel; + PasCodeFoldRange.DecBracketNestLevel; fRange := fRange + [rsAtClosingBracket]; end; @@ -1986,14 +2017,14 @@ procedure TSynPasSyn.SquareOpenProc; begin inc(Run); fTokenID := tkSymbol; - TSynPasSynRange(CodeFoldRange).IncBracketNestLevel; + PasCodeFoldRange.IncBracketNestLevel; end; procedure TSynPasSyn.SquareCloseProc; begin inc(Run); fTokenID := tkSymbol; - TSynPasSynRange(CodeFoldRange).DecBracketNestLevel; + PasCodeFoldRange.DecBracketNestLevel; end; procedure TSynPasSyn.EqualSignProc; @@ -2011,7 +2042,7 @@ begin EndCodeFoldBlock; if (TopPascalCodeFoldBlockType = cfbtClass) and (rsAfterClass in fRange) then EndCodeFoldBlock; - if (rsProperty in fRange) and (TSynPasSynRange(CodeFoldRange).BracketNestLevel = 0) then + if (rsProperty in fRange) and (PasCodeFoldRange.BracketNestLevel = 0) then fRange := fRange - [rsProperty]; end; @@ -2110,7 +2141,7 @@ begin fRange := fRange + [rsAfterClass] - [rsAtClass]; fProcTable[fLine[Run]]; if not (FTokenID in [tkSpace, tkComment, tkDirective]) then begin - if (TSynPasSynRange(CodeFoldRange).BracketNestLevel = 0) and + if (PasCodeFoldRange.BracketNestLevel = 0) and not(rsAtClosingBracket in fRange) then fRange := fRange - [rsAfterClass]; fRange := fRange - [rsAfterEqual, rsAtClosingBracket]; @@ -2214,41 +2245,29 @@ end; function TSynPasSyn.GetRange: Pointer; begin - {$IFDEF SYN_LAZARUS} // 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} - Result := Pointer(PtrInt(fRange)); - {$ENDIF} end; procedure TSynPasSyn.SetRange(Value: Pointer); begin - {$IFDEF SYN_LAZARUS} //DebugLn(['TSynPasSyn.SetRange START']); inherited SetRange(Value); - CompilerMode := TSynPasSynRange(CodeFoldRange).Mode; + CompilerMode := PasCodeFoldRange.Mode; fRange := TRangeStates(Integer(PtrUInt(CodeFoldRange.RangeType))); - {$ELSE} - fRange := TRangeStates(PtrUInt(Value)); - {$ENDIF} FNodeInfoLine := -1; - FStartCodeFoldBlockLevel := FMinimumCodeFoldBlockLevel; end; procedure TSynPasSyn.ResetRange; begin fRange := []; FStartCodeFoldBlockLevel:=0; - FMinimumCodeFoldBlockLevel := 0; - {$IFDEF SYN_LAZARUS} + FPasStartLevel := 0; Inherited ResetRange; CompilerMode:=pcmDelphi; - {$ENDIF} end; procedure TSynPasSyn.EnumUserSettings(settings: TStrings); @@ -2275,7 +2294,6 @@ begin end; end; -{$IFDEF SYN_LAZARUS} function TSynPasSyn.TopPascalCodeFoldBlockType: TPascalCodeFoldBlockType; var p: Pointer; @@ -2286,41 +2304,117 @@ begin Result := TPascalCodeFoldBlockType(PtrUInt(p)); end; -function TSynPasSyn.MinimumFoldLevel(Index: Integer): integer; +function TSynPasSyn.FoldOpenCount(ALineIndex: Integer): integer; +begin + Result := EndPasFoldLevel(ALineIndex) - MinimumPasFoldLevel(ALineIndex); +end; + +function TSynPasSyn.FoldCloseCount(ALineIndex: Integer): integer; +begin + Result := EndPasFoldLevel(ALineIndex - 1) - MinimumPasFoldLevel(ALineIndex); +end; + +function TSynPasSyn.FoldNestCount(ALineIndex: Integer): integer; +begin + Result := EndPasFoldLevel(ALineIndex); +end; + +function TSynPasSyn.FoldLineLength(ALineIndex, FoldIndex: Integer): integer; var - r: Pointer; + i, lvl, cnt : Integer; + e, m: Integer; +begin + cnt := CurrentLines.Count; + e := EndPasFoldLevel(ALineIndex); + m := MinimumPasFoldLevel(ALineIndex); + lvl := Min(m+1+FoldIndex, e); + i := ALineIndex + 1; + while (i < cnt) and (MinimumPasFoldLevel(i) >= lvl) do inc(i); + // check if fold last line of block (not mixed "end begin") + // and not lastlinefix + if (i < cnt) and (EndPasFoldLevel(i) > MinimumPasFoldLevel(i)) then + dec(i); + // Amount of lines, that will become invisible (excludes the cfCollapsed line) + Result := i - ALineIndex; +end; + +function TSynPasSyn.MinimumPasFoldLevel(Index: Integer): integer; +var + r: TSynPasSynRange; begin if (Index < 0) or (Index >= CurrentLines.Count) then exit(0); - r := CurrentLines.Ranges[Index]; - if (r <> nil) and (r <> NullRange) then - Result := TSynPasSynRange(r).MinimumCodeFoldBlockLevel + r := TSynPasSynRange(CurrentRanges[Index]); + if (r <> nil) and (Pointer(r) <> NullRange) then + Result := Min(r.PasFoldEndLevel + LastLinePasFoldLevelFix(Index + 1), + r.PasFoldMinLevel) + else + Result := 0; +end; + +function TSynPasSyn.EndPasFoldLevel(Index: Integer): integer; +var + r: TSynPasSynRange; +begin + if (Index < 0) or (Index >= CurrentLines.Count) then + exit(0); + r := TSynPasSynRange(CurrentRanges[Index]); + if (r <> nil) and (Pointer(r) <> NullRange) then + Result := r.PasFoldEndLevel + LastLinePasFoldLevelFix(Index + 1) + else + Result := 0; +end; + +function TSynPasSyn.LastLinePasFoldLevelFix(Index: Integer): integer; +var + r: TSynPasSynRange; +begin + if (Index < 0) or (Index >= CurrentLines.Count) then + exit(0); + r := TSynPasSynRange(CurrentRanges[Index]); + if (r <> nil) and (Pointer(r) <> NullRange) then + Result := r.PasFoldFixLevel + else + Result := 0; +end; + + +function TSynPasSyn.MinimumFoldLevel(Index: Integer): integer; +var + r: TSynPasSynRange; +begin + if (Index < 0) or (Index >= CurrentLines.Count) then + exit(0); + r := TSynPasSynRange(CurrentRanges[Index]); + if (r <> nil) and (Pointer(r) <> NullRange) then + Result := Min(r.CodeFoldStackSize + LastLineFoldLevelFix(Index + 1), + r.MinimumCodeFoldBlockLevel) else Result := 0; end; function TSynPasSyn.EndFoldLevel(Index: Integer): integer; var - r: Pointer; + r: TSynPasSynRange; begin if (Index < 0) or (Index >= CurrentLines.Count) then exit(0); - r := CurrentLines.Ranges[Index]; - if (r <> nil) and (r <> NullRange) then - Result := TSynPasSynRange(r).CodeFoldStackSize + r := TSynPasSynRange(CurrentRanges[Index]); + if (r <> nil) and (Pointer(r) <> NullRange) then + Result := r.CodeFoldStackSize + LastLineFoldLevelFix(Index + 1) else Result := 0; end; function TSynPasSyn.LastLineFoldLevelFix(Index: Integer): integer; var - r: Pointer; + r: TSynPasSynRange; begin if (Index < 0) or (Index >= CurrentLines.Count) then exit(0); - r := CurrentLines.Ranges[Index]; - if (r <> nil) and (r <> NullRange) then - Result := TSynPasSynRange(r).LastLineCodeFoldLevelFix + r := TSynPasSynRange(CurrentRanges[Index]); + if (r <> nil) and (Pointer(r) <> NullRange) then + Result := r.LastLineCodeFoldLevelFix else Result := 0; end; @@ -2347,10 +2441,10 @@ var p: PtrInt; begin p := 0; - if FCatchNodeInfo and not SubBlock then begin // exclude subblocks, because they do not increase the foldlevel yet + if FCatchNodeInfo then begin // exclude subblocks, because they do not increase the foldlevel yet GrowNodeInfoList; InitNode(FNodeInfoList[FNodeInfoCount], +1, ABlockType); - if not SubBlock then +// if not SubBlock then include(FNodeInfoList[FNodeInfoCount].FoldAction, sfaOpen); inc(FNodeInfoCount); end; @@ -2363,10 +2457,10 @@ end; procedure TSynPasSyn.EndCodeFoldBlock(DecreaseLevel: Boolean); begin DecreaseLevel := TopCodeFoldBlockType < CountPascalCodeFoldBlockOffset; - if FCatchNodeInfo and DecreaseLevel then begin // exclude subblocks, because they do not increase the foldlevel yet + if FCatchNodeInfo then begin // exclude subblocks, because they do not increase the foldlevel yet GrowNodeInfoList; InitNode(FNodeInfoList[FNodeInfoCount], -1, TopPascalCodeFoldBlockType); - if DecreaseLevel then +// if DecreaseLevel then include(FNodeInfoList[FNodeInfoCount].FoldAction, sfaClose); inc(FNodeInfoCount); end; @@ -2375,9 +2469,9 @@ end; procedure TSynPasSyn.CloseBeginEndBlocks; begin - if TopPascalCodeFoldBlockType <> cfbtBeginEnd then + if not(TopPascalCodeFoldBlockType in [cfbtBeginEnd, cfbtExcept, cfbtRepeat]) then exit; - while TopPascalCodeFoldBlockType = cfbtBeginEnd do + while TopPascalCodeFoldBlockType in [cfbtBeginEnd, cfbtExcept, cfbtRepeat] do EndCodeFoldBlockLastLine; if TopPascalCodeFoldBlockType = cfbtProcedure then EndCodeFoldBlockLastLine; // This procedure did have a begin/end block, so it must end too @@ -2390,13 +2484,19 @@ begin i := FNodeInfoCount; EndCodeFoldBlock; if FAtLineStart then begin - // If we are not at linestate, new folds could have been opened => handle as normal close + // If we are not at linestart, new folds could have been opened => handle as normal close if (CurrentCodeFoldBlockLevel < FStartCodeFoldBlockLevel) and (FStartCodeFoldBlockLevel > 0) then begin - TSynPasSynRange(CodeFoldRange).DecLastLineCodeFoldLevelFix; + PasCodeFoldRange.DecLastLineCodeFoldLevelFix; dec(FStartCodeFoldBlockLevel); - end + end; + if (PasCodeFoldRange.PasFoldEndLevel < FPasStartLevel) and + (FPasStartLevel > 0) + then begin + PasCodeFoldRange.DecLastLinePasFoldFix; + dec(FPasStartLevel); + end; end else if FNodeInfoCount > i then begin exclude(FNodeInfoList[FNodeInfoCount - 1].FoldAction, sfaMarkup); // not markup able @@ -2404,6 +2504,13 @@ begin end; end; +function TSynPasSyn.GetDrawDivider(Index: integer): Boolean; +begin + result := (EndFoldLevel(Index) < DrawDividerLevel) and + (EndFoldLevel(Index - 1) >= DrawDividerLevel) and + (MinimumFoldLevel(Index) = EndFoldLevel(Index)); // not amixed line +end; + function TSynPasSyn.GetFoldNodeInfo(Line, Index: Integer): TSynFoldNodeInfo; var i: LongInt; @@ -2441,13 +2548,6 @@ begin Result:=TSynPasSynRange; end; -function TSynPasSyn.LastLineCodeFoldLevelFix: integer; -begin - Result := TSynPasSynRange(CodeFoldRange).LastLineCodeFoldLevelFix; -end; - -{$endif} - function TSynPasSyn.UseUserSettings(settingIndex: integer): boolean; // Possible parameter values: // index into TStrings returned by EnumUserSettings @@ -2651,7 +2751,6 @@ begin CompilerMode:=pcmObjFPC; end; -{$IFDEF SYN_LAZARUS} { TSynPasSynRange } procedure TSynPasSynRange.Clear; @@ -2659,7 +2758,9 @@ begin inherited Clear; FBracketNestLevel := 0; FLastLineCodeFoldLevelFix := 0; - FMinimumCodeFoldBlockLevel := 0; + FPasFoldEndLevel := 0; + FPasFoldFixLevel := 0; + FPasFoldMinLevel := 0; end; function TSynPasSynRange.Compare(Range: TSynCustomHighlighterRange): integer; @@ -2671,9 +2772,13 @@ begin if Result<>0 then exit; Result := FBracketNestLevel - TSynPasSynRange(Range).FBracketNestLevel; if Result<>0 then exit; - Result := FMinimumCodeFoldBlockLevel - TSynPasSynRange(Range).FMinimumCodeFoldBlockLevel; - if Result<>0 then exit; Result := FLastLineCodeFoldLevelFix - TSynPasSynRange(Range).FLastLineCodeFoldLevelFix; + if Result<>0 then exit; + Result := FPasFoldEndLevel - TSynPasSynRange(Range).FPasFoldEndLevel; + if Result<>0 then exit; + Result := FPasFoldMinLevel - TSynPasSynRange(Range).FPasFoldMinLevel; + if Result<>0 then exit; + Result := FPasFoldFixLevel - TSynPasSynRange(Range).FPasFoldFixLevel; end; procedure TSynPasSynRange.Assign(Src: TSynCustomHighlighterRange); @@ -2682,11 +2787,31 @@ begin inherited Assign(Src); FMode:=TSynPasSynRange(Src).FMode; FBracketNestLevel:=TSynPasSynRange(Src).FBracketNestLevel; - FMinimumCodeFoldBlockLevel := TSynPasSynRange(Src).FMinimumCodeFoldBlockLevel; FLastLineCodeFoldLevelFix := TSynPasSynRange(Src).FLastLineCodeFoldLevelFix; + FPasFoldEndLevel := TSynPasSynRange(Src).FPasFoldEndLevel; + FPasFoldMinLevel := TSynPasSynRange(Src).FPasFoldMinLevel; + FPasFoldFixLevel := TSynPasSynRange(Src).FPasFoldFixLevel; end; end; +function TSynPasSynRange.Add(ABlockType: Pointer; IncreaseLevel: Boolean): TSynCustomCodeFoldBlock; +begin + if IncreaseLevel then + inc(FPasFoldEndLevel); + Result := inherited Add(ABlockType, True); +end; + +procedure TSynPasSynRange.Pop(DecreaseLevel: Boolean); +begin + if assigned(Top.Parent) then begin + if DecreaseLevel then + dec(FPasFoldEndLevel); + if FPasFoldMinLevel > FPasFoldEndLevel then + FPasFoldMinLevel := FPasFoldEndLevel; + end; + inherited Pop(True); +end; + procedure TSynPasSynRange.IncBracketNestLevel; begin inc(FBracketNestLevel); @@ -2702,7 +2827,10 @@ begin dec(FLastLineCodeFoldLevelFix) end; -{$ENDIF} +procedure TSynPasSynRange.DecLastLinePasFoldFix; +begin + dec(FPasFoldFixLevel); +end; initialization MakeIdentTable;