~ubuntu-branches/ubuntu/saucy/lazarus/saucy

« back to all changes in this revision

Viewing changes to components/synedit/syneditfoldedview.pp

  • Committer: Package Import Robot
  • Author(s): Paul Gevers, Abou Al Montacir, Bart Martens, Paul Gevers
  • Date: 2013-06-08 14:12:17 UTC
  • mfrom: (1.1.9)
  • Revision ID: package-import@ubuntu.com-20130608141217-7k0cy9id8ifcnutc
Tags: 1.0.8+dfsg-1
[ Abou Al Montacir ]
* New upstream major release and multiple maintenace release offering many
  fixes and new features marking a new milestone for the Lazarus development
  and its stability level.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_fixes_branch
* LCL changes:
  - LCL is now a normal package.
      + Platform independent parts of the LCL are now in the package LCLBase
      + LCL is automatically recompiled when switching the target platform,
        unless pre-compiled binaries for this target are already installed.
      + No impact on existing projects.
      + Linker options needed by LCL are no more added to projects that do
        not use the LCL package.
  - Minor changes in LCL basic classes behaviour
      + TCustomForm.Create raises an exception if a form resource is not
        found.
      + TNotebook and TPage: a new implementation of these classes was added.
      + TDBNavigator: It is now possible to have focusable buttons by setting
        Options = [navFocusableButtons] and TabStop = True, useful for
        accessibility and for devices with neither mouse nor touch screen.
      + Names of TControlBorderSpacing.GetSideSpace and GetSpace were swapped
        and are now consistent. GetSideSpace = Around + GetSpace.
      + TForm.WindowState=wsFullscreen was added
      + TCanvas.TextFitInfo was added to calculate how many characters will
        fit into a specified Width. Useful for word-wrapping calculations.
      + TControl.GetColorResolvingParent and
        TControl.GetRGBColorResolvingParent were added, simplifying the work
        to obtain the final color of the control while resolving clDefault
        and the ParentColor.
      + LCLIntf.GetTextExtentExPoint now has a good default implementation
        which works in any platform not providing a specific implementation.
        However, Widgetset specific implementation is better, when available.
      + TTabControl was reorganized. Now it has the correct class hierarchy
        and inherits from TCustomTabControl as it should.
  - New unit in the LCL:
      + lazdialogs.pas: adds non-native versions of various native dialogs,
        for example TLazOpenDialog, TLazSaveDialog, TLazSelectDirectoryDialog.
        It is used by widgetsets which either do not have a native dialog, or
        do not wish to use it because it is limited. These dialogs can also be
        used by user applications directly.
      + lazdeviceapis.pas: offers an interface to more hardware devices such
        as the accelerometer, GPS, etc. See LazDeviceAPIs
      + lazcanvas.pas: provides a TFPImageCanvas descendent implementing
        drawing in a LCL-compatible way, but 100% in Pascal.
      + lazregions.pas. LazRegions is a wholly Pascal implementation of
        regions for canvas clipping, event clipping, finding in which control
        of a region tree one an event should reach, for drawing polygons, etc.
      + customdrawncontrols.pas, customdrawndrawers.pas,
        customdrawn_common.pas, customdrawn_android.pas and
        customdrawn_winxp.pas: are the Lazarus Custom Drawn Controls -controls
        which imitate the standard LCL ones, but with the difference that they
        are non-native and support skinning.
  - New APIs added to the LCL to improve support of accessibility software
    such as screen readers.
* IDE changes:
  - Many improvments.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/New_IDE_features_since#v1.0_.282012-08-29.29
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes#IDE_Changes
* Debugger / Editor changes:
  - Added pascal sources and breakpoints to the disassembler
  - Added threads dialog.
* Components changes:
  - TAChart: many fixes and new features
  - CodeTool: support Delphi style generics and new syntax extensions.
  - AggPas: removed to honor free licencing. (Closes: Bug#708695)
[Bart Martens]
* New debian/watch file fixing issues with upstream RC release.
[Abou Al Montacir]
* Avoid changing files in .pc hidden directory, these are used by quilt for
  internal purpose and could lead to surprises during build.
[Paul Gevers]
* Updated get-orig-source target and it compinion script orig-tar.sh so that they
  repack the source file, allowing bug 708695 to be fixed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
{$coperators on}
28
28
{$IFDEF CPUPOWERPC} {$INLINE OFF} {$ENDIF} (* Workaround for bug 12576 (fpc) see bugs.freepascal.org/view.php?id=12576 *)
29
29
 
 
30
{$IFOPT C+}
 
31
  {$DEFINE SynAssertFold}
 
32
{$ENDIF}
 
33
{$IFDEF SynAssert}
 
34
  {$DEFINE SynAssertFold}
 
35
{$ENDIF}
 
36
 
30
37
{$IFDEF SynFoldDebug}
31
38
  {$DEFINE SynDebug}
32
39
  {$DEFINE SynFoldSaveDebug}
38
45
interface
39
46
 
40
47
uses
41
 
  LCLProc, Graphics,
42
 
  Classes, SysUtils, SynEditTextBase, SynEditTypes, SynEditMiscClasses,
 
48
  LCLProc, LazLoggerBase, Graphics,
 
49
  Classes, SysUtils, LazSynEditText, SynEditTypes, SynEditMiscClasses,
43
50
  SynEditMiscProcs, SynEditPointClasses,
44
51
  SynEditHighlighter, SynEditHighlighterFoldBase;
45
52
 
46
53
type
47
54
 
 
55
  TFoldNodeClassification = (fncInvalid, fncHighlighter, fncHighlighterEx, fncBlockSelection);
 
56
  TFoldNodeClassifications = set of TFoldNodeClassification;
 
57
 
48
58
  { TSynTextFoldAVLNodeData }
49
59
 
50
60
  TSynTextFoldAVLNodeData = class(TSynSizedDifferentialAVLNode)
75
85
 
76
86
    (* Source Info *)
77
87
    FoldIndex: Integer;    (* Index of fold in line; if a line has more than one fold starting *)
 
88
    FoldColumn, FoldColumnLen: Integer; (* The column (1-based) and len of the keywordm which starts this fold *)
 
89
    FoldTypeCompatible: Pointer; (* help identifying in FixFolding *)
 
90
    Classification: TFoldNodeClassification;
78
91
    VisibleLines: Integer; (* Visible Source lines, containing the "fold keyword"
79
92
                              0: Hiden block (the fold-keyword is inside the fold)
80
93
                              1: Normal fold (There is *1* visible line with the fold-keyword)
92
105
 
93
106
  TSynTextFoldAVLNode = object
94
107
  private
 
108
    function GetClassification: TFoldNodeClassification;
 
109
    function GetFoldColumn: Integer;
 
110
    function GetFoldColumnLen: Integer;
95
111
    function GetFoldIndex: Integer;
96
112
    function GetMergedLineCount : Integer;
97
113
    function GetFullCount : Integer;
98
114
    function GetSourceLine: integer;
99
115
    function GetSourceLineOffset: integer;
 
116
    procedure SetFoldColumn(const AValue: Integer);
100
117
  protected
101
118
    fData : TSynTextFoldAVLNodeData; // nil if unfolded
102
119
    fStartLine : Integer;            // start of folded
114
131
 
115
132
    function IsHide: Boolean;
116
133
    property FoldIndex: Integer read GetFoldIndex;
 
134
    property FoldColumn: Integer read GetFoldColumn write SetFoldColumn;
 
135
    property FoldColumnLen: Integer read GetFoldColumnLen;
117
136
    property SourceLine: integer read GetSourceLine;    // The SourceLine with the fold-keyword
118
137
    property SourceLineOffset: integer read GetSourceLineOffset;    // The SourceLine with the fold-keyword
 
138
    property Classification: TFoldNodeClassification read GetClassification;
119
139
  end;
120
140
 
121
141
  { TSynTextFoldAVLNodeNestedIterator:
169
189
    Function FindFoldForLine(ALine : Integer; FindNextNode : Boolean = False) : TSynTextFoldAVLNode;
170
190
    (* Find Fold by Line in Folded Text // always returns unfolded, unless next=true *)
171
191
    Function FindFoldForFoldedLine(ALine : Integer; FindNextNode: Boolean = False) : TSynTextFoldAVLNode;
172
 
    Function InsertNewFold(ALine, AColumn, ACount, AVisibleLines: Integer) : TSynTextFoldAVLNode;
 
192
    Function InsertNewFold(ALine, AFoldIndex, AColumn, AColumnLen, ACount, AVisibleLines: Integer;
 
193
                           AClassification: TFoldNodeClassification;
 
194
                           AFoldTypeCompatible: Pointer
 
195
                          ) : TSynTextFoldAVLNode;
173
196
    (* This will unfold the block which either contains tALine, or has Aline as its cgColapsed line
174
197
       If IgnoreFirst, the cfCollapsed will *not* unfold => Hint: IgnoreFirst = Make folded visible
175
198
       Returns the pos(1-based) of the cfCollapsed Line that was expanded; or ALine, if nothing was done
176
199
    *)
177
200
    Function RemoveFoldForLine(ALine : Integer; OnlyCol: Integer = -1) : Integer; overload;
178
 
    Procedure AdjustForLinesInserted(AStartLine, ALineCount : Integer);
179
 
    Procedure AdjustForLinesDeleted(AStartLine, ALineCount : Integer);
 
201
    Procedure AdjustForLinesInserted(AStartLine, ALineCount, ABytePos: Integer);
 
202
    Procedure AdjustForLinesDeleted(AStartLine, ALineCount, ABytePos: Integer);
 
203
    procedure AdjustColumn(ALine, ABytePos, ACount: Integer; InLineBreak: boolean = False);
180
204
    Function FindLastFold : TSynTextFoldAVLNode;
181
205
    Function FindFirstFold : TSynTextFoldAVLNode;
182
206
    Function LastFoldedLine : integer; // The actual line; LastNode.StartLine + LastNode.LineCount - 1
214
238
  end;
215
239
 
216
240
  TFoldChangedEvent = procedure(aLine: Integer) of object;
 
241
  TInvalidateLineProc = procedure(FirstLine, LastLine: integer) of object;
217
242
 
218
243
  TFoldViewNodeInfo = record
219
244
    HNode: TSynFoldNodeInfo;    // Highlighter Node
237
262
  );
238
263
  TSynEditFoldLineCapabilities = set of TSynEditFoldLineCapability;
239
264
  TSynEditFoldType = (scftOpen, scftFold, scftHide, scftAll, scftInvalid);
 
265
 
 
266
  TSynEditFoldLineMapInfo = record
 
267
    Capability: TSynEditFoldLineCapabilities;
 
268
    Classifications :TFoldNodeClassifications;
 
269
  end;
 
270
 
240
271
  {$IFDEF SynFoldSaveDebug}
241
272
const
242
273
  SynEditFoldTypeNames: Array [TSynEditFoldType] of string =
245
276
  {$ENDIF}
246
277
 
247
278
  { TSynEditFoldProvider }
 
279
  TSynEditFoldProviderNodeInfo = record
 
280
    LineCount: Integer;
 
281
    Column, ColumnLen: Integer;
 
282
    DefaultCollapsed: Boolean;
 
283
    FoldTypeCompatible: Pointer;  // eg begin, var, procedure
 
284
    FoldGroup: Integer; // eg.: pas, region, ifdef
 
285
    Classification: TFoldNodeClassification;
 
286
  end;
 
287
 
 
288
  TSynEditFoldProviderNodeInfoList = array of TSynEditFoldProviderNodeInfo;
 
289
  TSynEditFoldProvider = class;
 
290
 
 
291
  (* TLazSynEditNestedFoldsList
 
292
     Provides Info on all foldable-blocks containing a given line (0 based index).
 
293
     That are:
 
294
     - All foldable blocks opening on a previous line, that are still open
 
295
       at the start of the line. (May end on this line or later)
 
296
     - Foldable blocks opening on that line. (OpeningOnLineCount)
 
297
 
 
298
     The data is NOT automatically invalidated.
 
299
  *)
 
300
 
 
301
  TLazSynEditNestedFoldsListEntry = record
 
302
    HNode: TSynFoldNodeInfo;    // Highlighter Node
 
303
    //FNode: TSynTextFoldAVLNode; // AvlFoldNode
 
304
    //Text, Keyword: String;
 
305
    LineIdx: TLineIdx;
 
306
     //ColIndex: Integer;
 
307
    //OpenCount: Integer;
 
308
  end;
 
309
 
 
310
  TLazSynEditNestedFoldsList = class
 
311
  private
 
312
    FFoldProvider: TSynEditFoldProvider;
 
313
    FFoldGroup: Integer;
 
314
    FLine: TLineIdx;
 
315
    procedure SetFoldGroup(AValue: Integer);
 
316
    procedure SetLines(AValue: TLineIdx);
 
317
  private
 
318
    FFoldFlags: TSynFoldBlockFilterFlags;
 
319
    FGroupCount: Integer;
 
320
    FGroupEndLevels, FGroupEndLevelsAtEval: Array of integer;
 
321
    FCount, FOpeningOnLineCount: Integer;
 
322
    FIncludeOpeningOnLine: Boolean;
 
323
    FNestInfo: Array of TLazSynEditNestedFoldsListEntry;
 
324
    FEvaluationIndex: Integer;
 
325
    function GetHLNode(Index: Integer): TSynFoldNodeInfo;
 
326
    function GetNodeFoldGroup(Index: Integer): Integer;
 
327
    function GetNodeFoldType(Index: Integer): Pointer;
 
328
    procedure InitSubGroupEndLevels;
 
329
    procedure InitNestInfoForIndex(AnIndex: Integer);
 
330
    procedure SetFoldFlags(AValue: TSynFoldBlockFilterFlags);
 
331
    procedure SetIncludeOpeningOnLine(AValue: Boolean);
 
332
  public
 
333
    constructor Create(aFoldProvider: TSynEditFoldProvider);
 
334
    procedure Clear;
 
335
    procedure ResetFilter;
 
336
    function Count: Integer;
 
337
    function OpeningOnLineCount: Integer;  // ignores FFoldFlags
 
338
    property Line: TLineIdx read FLine write SetLines;
 
339
    property FoldGroup: Integer read FFoldGroup write SetFoldGroup;
 
340
    property FoldFlags: TSynFoldBlockFilterFlags read FFoldFlags write SetFoldFlags;
 
341
    property IncludeOpeningOnLine: Boolean read FIncludeOpeningOnLine write SetIncludeOpeningOnLine;
 
342
  public
 
343
    property HLNode[Index: Integer]: TSynFoldNodeInfo read GetHLNode;
 
344
    property NodeFoldType[Index: Integer]: Pointer read GetNodeFoldType;           // e.g.cfbtBeginEnd, cfbtcfbtProcedure ...
 
345
    property NodeFoldGroup[Index: Integer]: Integer read GetNodeFoldGroup;          // independend/overlapping folds, e.g begin/end; ifdef, region
 
346
 
 
347
  end;
248
348
 
249
349
  TSynEditFoldProvider = class
250
350
  private
251
351
    FHighlighter: TSynCustomFoldHighlighter;
 
352
    FLines : TSynEditStrings;
 
353
    FSelection: TSynEditSelection;
 
354
    FFoldTree : TSynTextFoldAVLTree;
 
355
    FNestedFoldsList: TLazSynEditNestedFoldsList;
 
356
    function GetFoldsAvailable: Boolean;
 
357
    function GetHighLighterWithLines: TSynCustomFoldHighlighter;
252
358
    function GetLineCapabilities(ALineIdx: Integer): TSynEditFoldLineCapabilities;
 
359
    function GetLineClassification(ALineIdx: Integer): TFoldNodeClassifications;
 
360
    function GetNestedFoldsList: TLazSynEditNestedFoldsList;
253
361
    procedure SetHighLighter(const AValue: TSynCustomFoldHighlighter);
 
362
  protected
 
363
    property HighLighterWithLines: TSynCustomFoldHighlighter read GetHighLighterWithLines;
254
364
  public
255
 
    function FoldOpenCount(ALineIdx: Integer; AType: Integer = 0): Integer;
256
 
    function FoldOpenInfo(ALineIdx, AFoldIdx: Integer; AType: Integer = 0): TSynFoldNodeInfo;
 
365
    constructor Create(aTextView : TSynEditStrings; AFoldTree : TSynTextFoldAVLTree);
 
366
    destructor Destroy; override;
 
367
 
 
368
    // Info about Folds opening on ALineIdx
 
369
    function  FoldOpenCount(ALineIdx: Integer; AType: Integer = 0): Integer;
 
370
    function  FoldOpenInfo(ALineIdx, AFoldIdx: Integer; AType: Integer = 0): TSynFoldNodeInfo;
257
371
    //property FoldOpenInfo[ALineIdx, AColumnIdx: Integer]: Integer read GetFoldOpenInfo;
258
 
    //property FoldInfoCount[ALineIdx: Integer]: Integer read GetFoldInfoCount;
259
 
    //property FoldInfo[ALineIdx, AColumnIdx: Integer]: Integer read GetFoldInfo;
 
372
 
 
373
    function  FoldLineLength(ALine, AFoldIndex: Integer): integer;
 
374
    function  InfoForFoldAtTextIndex(ALine, AFoldIndex : Integer;
 
375
                                     HideLen: Boolean = False;
 
376
                                     NeedLen: Boolean = True): TSynEditFoldProviderNodeInfo;
 
377
    function  InfoListForFoldsAtTextIndex(ALine: Integer; NeedLen: Boolean = False): TSynEditFoldProviderNodeInfoList;
 
378
 
260
379
    property LineCapabilities[ALineIdx: Integer]: TSynEditFoldLineCapabilities
261
380
             read GetLineCapabilities;
 
381
    property LineClassification[ALineIdx: Integer]: TFoldNodeClassifications
 
382
             read GetLineClassification;
 
383
    property Lines: TSynEditStrings read FLines write FLines;
262
384
    property HighLighter: TSynCustomFoldHighlighter read FHighlighter write SetHighLighter;
 
385
    property FoldsAvailable: Boolean read GetFoldsAvailable;
 
386
    property NestedFoldsList: TLazSynEditNestedFoldsList read GetNestedFoldsList;
 
387
  end;
 
388
 
 
389
  TSynEditFoldedView = class;
 
390
 
 
391
  { TLazSynDisplayFold }
 
392
 
 
393
  TLazSynDisplayFold = class(TLazSynDisplayViewEx)
 
394
  private
 
395
    FFoldView: TSynEditFoldedView;
 
396
    FLineState: integer;
 
397
    FTokenAttr: TSynHighlighterAttributes;
 
398
  public
 
399
    constructor Create(AFoldView: TSynEditFoldedView);
 
400
    destructor Destroy; override;
 
401
    procedure SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx); override;
 
402
    function GetNextHighlighterToken(out ATokenInfo: TLazSynDisplayTokenInfo): Boolean; override;
 
403
    function GetLinesCount: Integer; override;
 
404
 
 
405
    function TextToViewIndex(AIndex: TLineIdx): TLineRange; override;
 
406
    function ViewToTextIndex(AIndex: TLineIdx): TLineIdx; override;
263
407
  end;
264
408
 
265
409
  { TSynTextFoldedView
270
414
 
271
415
  { TSynEditFoldedView }
272
416
 
273
 
  TSynEditFoldedView = class // TODO: class(TSynEditStringsLinked)
 
417
  TSynEditFoldedView = class
274
418
  private
275
419
    fCaret: TSynEditCaret;
 
420
    FBlockSelection: TSynEditSelection;
276
421
    FFoldProvider: TSynEditFoldProvider;
277
 
    FHighLighter: TSynCustomFoldHighlighter;
278
422
    fLines : TSynEditStrings;
279
423
    fFoldTree : TSynTextFoldAVLTree;   // Folds are stored 1-based (the 1st line is 1)
280
424
    FMarkupInfoFoldedCode: TSynSelectedColor;
 
425
    FOnLineInvalidate: TInvalidateLineProc;
281
426
    fTopLine : Integer;
282
427
    fLinesInWindow : Integer;          // there may be an additional part visible line
283
428
    fTextIndexList : Array of integer;   (* Map each Screen line into a line in textbuffer *)
284
 
    fFoldTypeList : Array of TSynEditFoldLineCapabilities;
 
429
    fFoldTypeList : Array of TSynEditFoldLineMapInfo;
285
430
    fOnFoldChanged : TFoldChangedEvent;
286
431
    fLockCount : Integer;
287
432
    fNeedFixFrom, fNeedFixMinEnd : Integer;
288
433
    fNeedCaretCheck : Boolean;
 
434
    FInTopLineChanged: Boolean;
 
435
    FDisplayView: TLazSynDisplayFold;
289
436
 
290
437
    function GetCount : integer;
 
438
    function GetDisplayView: TLazSynDisplayView;
 
439
    function GetFoldClasifications(index : Integer): TFoldNodeClassifications;
291
440
    function GetHighLighter: TSynCustomHighlighter;
292
441
    function GetLines(index : Integer) : String;
293
442
    function GetDisplayNumber(index : Integer) : Integer;
294
443
    function GetTextIndex(index : Integer) : Integer;
295
444
    function GetFoldType(index : Integer) : TSynEditFoldLineCapabilities;
296
445
    function IsFolded(index : integer) : Boolean;  // TextIndex
 
446
    procedure SetBlockSelection(const AValue: TSynEditSelection);
297
447
    procedure SetHighLighter(AValue: TSynCustomHighlighter);
298
448
    procedure SetTopLine(const ALine : integer);
299
449
    function  GetTopTextIndex : integer;
300
450
    procedure SetTopTextIndex(const AIndex : integer);
301
451
    procedure SetLinesInWindow(const AValue : integer);
302
452
  protected
 
453
    procedure DoBlockSelChanged(Sender: TObject);
303
454
    Procedure CalculateMaps;
304
 
    function  LengthForFoldAtTextIndex(ALine, AFoldIndex : Integer; HideLen: Boolean = False) : Integer;
305
455
    function  FoldNodeAtTextIndex(AStartIndex, ColIndex: Integer): TSynTextFoldAVLNode; (* Returns xth Fold at nth TextIndex (all lines in buffer) / 1-based *)
306
456
    function  FixFolding(AStart : Integer; AMinEnd : Integer; aFoldTree : TSynTextFoldAVLTree) : Boolean;
307
457
 
308
458
    procedure DoCaretChanged(Sender : TObject);
309
459
    Procedure LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
310
 
    Procedure LinesInsertedAtTextIndex(AStartIndex, ALineCount : Integer;
 
460
    Procedure LinesCleared(Sender: TObject);
 
461
    Procedure LineEdited(Sender: TSynEditStrings; aLinePos, aBytePos, aCount,
 
462
                            aLineBrkCnt: Integer; aText: String);
 
463
    Procedure LinesInsertedAtTextIndex(AStartIndex, ALineCount, ABytePos: Integer;
311
464
                                       SkipFixFolding : Boolean = False);
312
 
    Procedure LinesInsertedAtViewPos(AStartPos, ALineCount : Integer;
313
 
                                     SkipFixFolding : Boolean = False);
314
 
    Procedure LinesDeletedAtTextIndex(AStartIndex, ALineCount : Integer;
 
465
    //Procedure LinesInsertedAtViewPos(AStartPos, ALineCount : Integer;
 
466
    //                                 SkipFixFolding : Boolean = False);
 
467
    Procedure LinesDeletedAtTextIndex(AStartIndex, ALineCount, ABytePos: Integer;
315
468
                                      SkipFixFolding : Boolean = False);
316
 
    Procedure LinesDeletedAtViewPos(AStartPos, ALineCount : Integer;
317
 
                                    SkipFixFolding : Boolean = False);
 
469
    //Procedure LinesDeletedAtViewPos(AStartPos, ALineCount : Integer;
 
470
    //                                SkipFixFolding : Boolean = False);
 
471
    property FoldTree: TSynTextFoldAVLTree read fFoldTree;
318
472
  public
319
473
    constructor Create(aTextView : TSynEditStrings; ACaret: TSynEditCaret);
320
474
    destructor Destroy; override;
328
482
    function TextIndexAddLines(aTextIndex, LineOffset : Integer) : Integer;     (* Add/Sub to/from TextIndex (0-based) skipping folded *)
329
483
    function TextPosAddLines(aTextpos, LineOffset : Integer) : Integer;     (* Add/Sub to/from TextPos (1-based) skipping folded *)
330
484
 
 
485
    property BlockSelection: TSynEditSelection write SetBlockSelection;
331
486
    // Attributes for Visible-Lines-On-screen
332
487
    property Lines[index : Integer] : String            (* Lines on screen / 0 = TopLine *)
333
488
      read GetLines; default;
335
490
      read GetDisplayNumber;
336
491
    property FoldType[index : Integer] : TSynEditFoldLineCapabilities (* FoldIcon / State *)
337
492
      read GetFoldType;
 
493
    property FoldClasifications[index : Integer] : TFoldNodeClassifications (* FoldIcon / State *)
 
494
      read GetFoldClasifications;
338
495
    property TextIndex[index : Integer] : Integer       (* Position in SynTextBuffer / result is 0-based *)
339
496
      read GetTextIndex; // maybe writable
340
497
 
402
559
    procedure FoldAll(StartLevel : Integer = 0; IgnoreNested : Boolean = False);
403
560
    procedure FixFoldingAtTextIndex(AStartIndex: Integer; AMinEndLine: Integer = 0); // Real/All lines
404
561
  public
405
 
    function OpenFoldCount(aStartIndex: Integer): Integer;
406
 
    function OpenFoldInfo(aStartIndex, ColIndex: Integer): TFoldViewNodeInfo;
 
562
    function OpenFoldCount(aStartIndex: Integer; AType: Integer = 0): Integer;
 
563
    function OpenFoldInfo(aStartIndex, ColIndex: Integer; AType: Integer = 0): TFoldViewNodeInfo;
407
564
 
408
565
  public
409
566
    // Find the visible first line of the fold at ALine. Returns -1 if Aline is not folded
417
574
 
418
575
    property OnFoldChanged: TFoldChangedEvent  (* reports 1-based line *) {TODO: synedit expects 0 based }
419
576
      read fOnFoldChanged write fOnFoldChanged;
 
577
    property OnLineInvalidate: TInvalidateLineProc(* reports 1-based line *) {TODO: synedit expects 0 based }
 
578
      read FOnLineInvalidate write FOnLineInvalidate;
420
579
    property HighLighter: TSynCustomHighlighter read GetHighLighter
421
580
                                                write SetHighLighter;
422
581
    property FoldProvider: TSynEditFoldProvider read FFoldProvider;
 
582
 
 
583
    property DisplayView: TLazSynDisplayView read GetDisplayView;
423
584
  end;
424
 
  
 
585
 
 
586
function dbgs(AClassification: TFoldNodeClassification): String; overload;
 
587
 
425
588
implementation
426
589
 
 
590
//var
 
591
//  SYN_FOLD_DEBUG: PLazLoggerLogGroup;
 
592
 
427
593
type
428
594
  TFoldExportEntry = Record
429
595
    // Lines and Pos (o 1st line) are relative to Scan-Start
558
724
    NumEncode86Values[NumEncode86Chars[i]] := i - 1;
559
725
end;
560
726
 
 
727
{ TLazSynDisplayFold }
 
728
 
 
729
constructor TLazSynDisplayFold.Create(AFoldView: TSynEditFoldedView);
 
730
begin
 
731
  inherited Create;
 
732
  FFoldView := AFoldView;
 
733
  FTokenAttr := TSynHighlighterAttributes.Create('');
 
734
end;
 
735
 
 
736
destructor TLazSynDisplayFold.Destroy;
 
737
begin
 
738
  FreeAndNil(FTokenAttr);
 
739
  inherited Destroy;
 
740
end;
 
741
 
 
742
procedure TLazSynDisplayFold.SetHighlighterTokensLine(ALine: TLineIdx; out ARealLine: TLineIdx);
 
743
begin
 
744
  FLineState := 0;
 
745
  CurrentTokenLine := ALine;
 
746
  inherited SetHighlighterTokensLine(FFoldView.ViewPosToTextIndex(ALine + 1), ARealLine);
 
747
end;
 
748
 
 
749
function TLazSynDisplayFold.GetNextHighlighterToken(out ATokenInfo: TLazSynDisplayTokenInfo): Boolean;
 
750
const
 
751
  MarkSpaces: string = '   ';
 
752
  MarkDots: string = '...';
 
753
var
 
754
  EolAttr: TSynHighlighterAttributes;
 
755
begin
 
756
  case FLineState of
 
757
    0: begin
 
758
        Result := inherited GetNextHighlighterToken(ATokenInfo);
 
759
        if (not Result) and
 
760
           (FFoldView.FoldType[CurrentTokenLine + 1 - FFoldView.TopLine] * [cfCollapsedFold, cfCollapsedHide] <> [])
 
761
        then begin
 
762
          inc(FLineState);
 
763
          ATokenInfo.TokenStart := PChar(MarkSpaces);
 
764
          ATokenInfo.TokenLength := 3;
 
765
          if Assigned(CurrentTokenHighlighter)
 
766
          then EolAttr := CurrentTokenHighlighter.GetEndOfLineAttribute
 
767
          else EolAttr := nil;
 
768
          if EolAttr <> nil then begin
 
769
            FTokenAttr.Assign(EolAttr);
 
770
            ATokenInfo.TokenAttr := FTokenAttr;
 
771
          end
 
772
          else
 
773
            ATokenInfo.TokenAttr := nil;
 
774
          Result := True;
 
775
        end;
 
776
      end;
 
777
    1: begin
 
778
        inc(FLineState);
 
779
        FTokenAttr.Assign(FFoldView.MarkupInfoFoldedCode);
 
780
        FTokenAttr.SetAllPriorities(MaxInt);
 
781
        ATokenInfo.TokenStart := PChar(MarkDots);
 
782
        ATokenInfo.TokenLength := 3;
 
783
        ATokenInfo.TokenAttr := FTokenAttr;
 
784
        Result := True;
 
785
      end;
 
786
    else
 
787
      Result := False;
 
788
  end;
 
789
end;
 
790
 
 
791
function TLazSynDisplayFold.GetLinesCount: Integer;
 
792
begin
 
793
  Result := FFoldView.Count;
 
794
end;
 
795
 
 
796
function TLazSynDisplayFold.TextToViewIndex(AIndex: TLineIdx): TLineRange;
 
797
begin
 
798
  Result := inherited TextToViewIndex(AIndex);
 
799
  if Result.Top = Result.Bottom then begin
 
800
    Result.Top    := FFoldView.TextIndexToViewPos(Result.Top) - 1;
 
801
    Result.Bottom := Result.Top;
 
802
  end
 
803
  else begin;
 
804
    Result.Top    := FFoldView.TextIndexToViewPos(Result.Top) - 1;
 
805
    Result.Bottom := FFoldView.TextIndexToViewPos(Result.Bottom) - 1;
 
806
  end;
 
807
end;
 
808
 
 
809
function TLazSynDisplayFold.ViewToTextIndex(AIndex: TLineIdx): TLineIdx;
 
810
begin
 
811
  Result := FFoldView.ViewPosToTextIndex(inherited ViewToTextIndex(AIndex)+1);
 
812
end;
 
813
 
561
814
{ TSynEditFoldExportStream }
562
815
 
563
816
constructor TSynEditFoldExportStream.Create;
699
952
     [NNXX[   (more then 21 bytes, from up to 64*64 back)
700
953
     ]X       (3 bytes from max 64 back)
701
954
     ]nx      ( reocurring space,x times, ever n pos)
702
 
*)
703
955
const
704
956
  max_single_len = 22 - 1;
 
957
  *)
705
958
var
706
959
  CurPos, EndPos, SearchPos: Integer;
707
960
  FndLen, FndPos, FndPos2: Integer;
1512
1765
 
1513
1766
{ TSynTextFoldAVLNode }
1514
1767
 
 
1768
function TSynTextFoldAVLNode.GetClassification: TFoldNodeClassification;
 
1769
begin
 
1770
  if fData = nil
 
1771
  then Result := fncInvalid
 
1772
  else Result := fData.Classification;
 
1773
end;
 
1774
 
 
1775
function TSynTextFoldAVLNode.GetFoldColumn: Integer;
 
1776
begin
 
1777
  if fData = nil
 
1778
  then Result := -1
 
1779
  else Result := fData.FoldColumn;
 
1780
end;
 
1781
 
 
1782
function TSynTextFoldAVLNode.GetFoldColumnLen: Integer;
 
1783
begin
 
1784
  if fData = nil
 
1785
  then Result := -1
 
1786
  else Result := fData.FoldColumnLen;
 
1787
end;
 
1788
 
1515
1789
function TSynTextFoldAVLNode.GetFoldIndex: Integer;
1516
1790
begin
1517
1791
  if fData = nil
1549
1823
    Result := fData.VisibleLines;
1550
1824
end;
1551
1825
 
 
1826
procedure TSynTextFoldAVLNode.SetFoldColumn(const AValue: Integer);
 
1827
begin
 
1828
  if fData <> nil then
 
1829
    fData.FoldColumn :=  AValue;
 
1830
end;
 
1831
 
1552
1832
procedure TSynTextFoldAVLNode.Init(aData: TSynTextFoldAVLNodeData; aStartLine,
1553
1833
  aFoldedBefore: Integer);
1554
1834
begin
1713
1993
begin
1714
1994
  Idx := FCurInfo.NodeIndex + 1;
1715
1995
  Line := FCurInfo.LineIndex;
1716
 
  Cnt := FHighlighter.FoldNodeInfoCount[Line, FActions];
 
1996
  Cnt := FHighlighter.FoldNodeInfo[Line].CountEx(FActions);
1717
1997
  if Idx >= Cnt then begin
1718
1998
    Idx := 0;
1719
1999
    inc(Line);
1720
2000
    while (Line < FHighlighter.CurrentLines.Count) and
1721
 
          (FHighlighter.FoldNodeInfoCount[Line, FActions] = 0)
 
2001
          (FHighlighter.FoldNodeInfo[Line].CountEx(FActions) = 0)
1722
2002
    do
1723
2003
      inc(Line);
1724
2004
  end;
1725
2005
  if (Line < FHighlighter.CurrentLines.Count) then
1726
 
    FCurInfo := FHighlighter.FoldNodeInfo[Line, Idx, FActions]
 
2006
    FCurInfo := FHighlighter.FoldNodeInfo[Line].NodeInfoEx(Idx, FActions)
1727
2007
  else
1728
2008
    Invalidate;
1729
2009
  Result := FCurInfo;
1738
2018
  if Idx < 0 then begin
1739
2019
    dec(Line);
1740
2020
    while (Line >= 0) and
1741
 
          (FHighlighter.FoldNodeInfoCount[Line, FActions] = 0)
 
2021
          (FHighlighter.FoldNodeInfo[Line].CountEx(FActions) = 0)
1742
2022
    do
1743
2023
      dec(Line);
1744
 
    Idx := FHighlighter.FoldNodeInfoCount[Line, FActions] - 1;
 
2024
    Idx := FHighlighter.FoldNodeInfo[Line].CountEx(FActions) - 1;
1745
2025
  end;
1746
2026
  if (Line >= 0) then
1747
 
    FCurInfo := FHighlighter.FoldNodeInfo[Line, Idx, FActions]
 
2027
    FCurInfo := FHighlighter.FoldNodeInfo[Line].NodeInfoEx(Idx, FActions)
1748
2028
  else
1749
2029
    Invalidate;
1750
2030
  Result := FCurInfo;
1758
2038
  Line := FCurInfo.LineIndex;
1759
2039
  EndLine := FHighlighter.FoldEndLine(Line, FCurInfo.NodeIndex);
1760
2040
  FActions := [sfaClose, sfaFold];
1761
 
  Cnt := FHighlighter.FoldNodeInfoCount[EndLine, FActions] - 1;
 
2041
  Cnt := FHighlighter.FoldNodeInfo[EndLine].CountEx(FActions) - 1;
1762
2042
  while Cnt >= 0 do begin
1763
 
    NdInfo := FHighlighter.FoldNodeInfo[EndLine, Cnt, FActions];
 
2043
    NdInfo := FHighlighter.FoldNodeInfo[EndLine].NodeInfoEx(Cnt, FActions);
1764
2044
    if (NdInfo.FoldLvlStart = FCurInfo.FoldLvlEnd) and
1765
2045
       (NdInfo.FoldType = FCurInfo.FoldType)
1766
2046
    then
1777
2057
function TSynFoldNodeInfoHelper.GotoOpenPos(aLineIdx, aNodeIdx: integer): TSynFoldNodeInfo;
1778
2058
begin
1779
2059
  FActions := [sfaOpen, sfaFold];
1780
 
  FCurInfo := FHighlighter.FoldNodeInfo[aLineIdx, aNodeIdx, FActions];
 
2060
  FCurInfo := FHighlighter.FoldNodeInfo[aLineIdx].NodeInfoEx(aNodeIdx, FActions);
1781
2061
  Result := FCurInfo;
1782
2062
end;
1783
2063
 
1786
2066
  Cnt: Integer;
1787
2067
begin
1788
2068
  FActions := [sfaOpen, sfaFold];
1789
 
  Cnt := FHighlighter.FoldNodeInfoCount[aLineIdx, FActions] - 1;
 
2069
  Cnt := FHighlighter.FoldNodeInfo[aLineIdx].CountEx(FActions) - 1;
1790
2070
  while Cnt >= 0 do begin
1791
 
    FCurInfo := FHighlighter.FoldNodeInfo[aLineIdx, Cnt, FActions];
 
2071
    FCurInfo := FHighlighter.FoldNodeInfo[aLineIdx].NodeInfoEx(Cnt, FActions);
1792
2072
    if FCurInfo.LogXStart = aXPos then break;
1793
2073
    dec(Cnt);
1794
2074
  end;
1800
2080
function TSynFoldNodeInfoHelper.GotoNodeOpenPos(ANode: TSynTextFoldAVLNode): TSynFoldNodeInfo;
1801
2081
begin
1802
2082
  FActions := [sfaOpen, sfaFold];
1803
 
  FCurInfo := FHighlighter.FoldNodeInfo[ANode.StartLine - ANode.SourceLineOffset - 1,
1804
 
                                        ANode.FoldIndex, FActions];
 
2083
  FCurInfo := FHighlighter.FoldNodeInfo[ANode.StartLine - ANode.SourceLineOffset - 1]
 
2084
              .NodeInfoEx(ANode.FoldIndex, FActions);
1805
2085
  Result := FCurInfo;
1806
2086
end;
1807
2087
 
1811
2091
  Cnt, EndCol, EndLineIdx: Integer;
1812
2092
begin
1813
2093
  FActions := [sfaClose, sfaFold];
1814
 
  NdInfo := FHighlighter.FoldNodeInfo[ANode.StartLine - ANode.SourceLineOffset - 1,
1815
 
                                      ANode.FoldIndex, [sfaOpen, sfaFold]];
 
2094
  NdInfo := FHighlighter.FoldNodeInfo[ANode.StartLine - ANode.SourceLineOffset - 1]
 
2095
            .NodeInfoEx(ANode.FoldIndex, [sfaOpen, sfaFold]);
 
2096
  if sfaInvalid in NdInfo.FoldAction then exit(NdInfo);
1816
2097
 
1817
2098
  EndLineIdx := FHighlighter.FoldEndLine(ANode.StartLine - ANode.SourceLineOffset - 1,
1818
2099
                                        ANode.FoldIndex);
1819
 
  Cnt := FHighlighter.FoldNodeInfoCount[EndLineIdx, [sfaClose, sfaFold]];
 
2100
  {$IFDEF SynAssertFold}
 
2101
  SynAssert(EndLineIdx >= 0, 'TSynFoldNodeInfoHelper.GotoNodeClosePos: Bad EndLineIdx=%d # Anode: StartLine=%d SrcLOffs=%d ColIdx=%d FoldCol=%d', [EndLineIdx, ANode.StartLine, ANode.SourceLineOffset, ANode.FoldIndex, ANode.FoldColumn]);
 
2102
  {$ENDIF}
 
2103
  Cnt := FHighlighter.FoldNodeInfo[EndLineIdx].CountEx([sfaClose, sfaFold]);
1820
2104
  EndCol := 0;
1821
2105
  while EndCol < Cnt do begin
1822
 
    NdInfo2 := FHighlighter.FoldNodeInfo[EndLineIdx, EndCol, [sfaClose, sfaFold]];
 
2106
    NdInfo2 := FHighlighter.FoldNodeInfo[EndLineIdx].NodeInfoEx(EndCol, [sfaClose, sfaFold]);
1823
2107
    if (NdInfo2.FoldLvlStart = NdInfo.FoldLvlEnd) and
1824
2108
       (NdInfo2.FoldType = NdInfo.FoldType) then break;
1825
2109
    inc(EndCol);
1938
2222
    r := r.Right; // rStartLine points to r, which now is the start of the previous fold;
1939
2223
  end;
1940
2224
 
1941
 
  Result.Init(r, rStartLine, rFoldedBefore);
 
2225
  Result{%H-}.Init(r, rStartLine, rFoldedBefore);
1942
2226
end;
1943
2227
 
1944
2228
(* Find Fold by Line in Folded Text // always returns unfolded, unless next=true *)
1974
2258
    r := r.Right; // rStartLine points to r, which now is the start of the previous fold;
1975
2259
  end;
1976
2260
 
1977
 
  Result.Init(r, rStartLine, rFoldedBefore);
 
2261
  Result{%H-}.Init(r, rStartLine, rFoldedBefore);
1978
2262
end;
1979
2263
 
1980
 
procedure TSynTextFoldAVLTree.AdjustForLinesInserted(AStartLine, ALineCount : Integer);
 
2264
procedure TSynTextFoldAVLTree.AdjustForLinesInserted(AStartLine, ALineCount, ABytePos: Integer);
1981
2265
  Procedure DoAdjustForLinesInserted(Current : TSynTextFoldAVLNodeData;
1982
2266
    CurrentLine : Integer);
1983
2267
  var
1986
2270
    while (Current <> nil) do begin
1987
2271
      CurrentLine := CurrentLine + Current.LineOffset;
1988
2272
 
1989
 
      if AStartLine < CurrentLine then begin
 
2273
      if (AStartLine <= CurrentLine - Current.VisibleLines) or
 
2274
         ( (AStartLine - 1 = CurrentLine - Current.VisibleLines) and
 
2275
           (ABytePos <= Current.FoldColumn) )
 
2276
      then begin
1990
2277
        // move current node
1991
2278
        Current.LineOffset := Current.LineOffset + ALineCount;
1992
2279
        CurrentLine := CurrentLine + ALineCount;
1999
2286
        Current := Current.Right;
2000
2287
      end
2001
2288
      else begin
2002
 
        // grow current node
 
2289
        // grow current node (there is only one node one the line, the others are nested)
2003
2290
        // CurrentLine <= AStartLine  <= CurrentLine + Current.FullCount - 1
2004
2291
        t := Current.FullCount;
2005
2292
        if AStartLine <= CurrentLine + t - 1 then
2006
2293
          Current.FullCount := t + ALineCount;
2007
2294
        Current.MergedLineCount:= Current.MergedLineCount+ ALineCount;
2008
2295
        Current.AdjustParentLeftCount(ALineCount);
2009
 
        TreeForNestedNode(Current, CurrentLine).AdjustForLinesInserted(AStartLine, ALineCount);
 
2296
        TreeForNestedNode(Current, CurrentLine).AdjustForLinesInserted(AStartLine, ALineCount, ABytePos);
2010
2297
 
2011
2298
        if Current.Right <> nil then // and move entire right
2012
2299
          Current.Right.LineOffset := Current.Right.LineOffset + ALineCount;
2016
2303
  end;
2017
2304
 
2018
2305
begin
 
2306
  {$IFDEF SynFoldDebug}debugln(['FOLD-- AdjustForLinesInsertedAStartLine:=', AStartLine, ' ALineCount=',ALineCount, '  ABytePos=',ABytePos ]); {$ENDIF}
2019
2307
  DoAdjustForLinesInserted(TSynTextFoldAVLNodeData(fRoot), fRootOffset);
 
2308
  AdjustColumn(AStartLine+ALineCount-1, ABytePos, -ABytePos+1, True);
2020
2309
end;
2021
2310
 
2022
2311
procedure TSynTextFoldAVLTree.AdjustForLinesDeleted(AStartLine,
2023
 
  ALineCount : Integer);
 
2312
  ALineCount, ABytePos: Integer);
2024
2313
  Procedure AdjustNodeForLinesDeleted(Current : TSynTextFoldAVLNodeData;
2025
2314
    CurrentLine, FirstLineToDelete, CountLinesToDelete : Integer);
2026
2315
  var
2031
2320
    while (Current <> nil) do begin
2032
2321
      CurrentLine := CurrentLine + Current.LineOffset;
2033
2322
 
2034
 
      if FirstLineToDelete < CurrentLine then begin
 
2323
      if FirstLineToDelete <= CurrentLine - Current.VisibleLines then begin
2035
2324
        // move current node
2036
 
        if LastLineToDelete >= CurrentLine then begin
 
2325
        if LastLineToDelete > CurrentLine  - Current.VisibleLines then begin
2037
2326
          // overlap => shrink
2038
2327
          LinesBefore := CurrentLine - FirstLineToDelete;
2039
2328
          LinesInside := CountLinesToDelete - LinesBefore;
2042
2331
          Current.FullCount := Max(Current.FullCount - LinesInside, -1);
2043
2332
          Current.MergedLineCount := Max(Current.MergedLineCount - LinesInside, 0);
2044
2333
          Current.AdjustParentLeftCount(Current.MergedLineCount - t); // If LineCount = -1; LeftCount will be correctd on delete node
2045
 
          TreeForNestedNode(Current, CurrentLine).AdjustForLinesDeleted(CurrentLine, LinesInside);
 
2334
          TreeForNestedNode(Current, CurrentLine).AdjustForLinesDeleted(CurrentLine, LinesInside, ABytePos);
2046
2335
 
2047
2336
          if (Current.Right <> nil) then begin
2048
2337
            // move right // Calculate from the new curent.LineOffset, as below
2055
2344
        // move current node (includes right subtree / left subtree needs eval)
2056
2345
        Current.LineOffset := Current.LineOffset - LinesBefore;
2057
2346
        CurrentLine := CurrentLine - LinesBefore;
 
2347
        //if AStartLine = CurrentLine then begin
 
2348
        //  Current.FoldColumn := Current.FoldColumn + ABytePos-1;
 
2349
        //  TreeForNestedNode(Current, CurrentLine).AdjustColumn(CurrentLine, 1, ABytePos-1);
 
2350
        //end;
2058
2351
        if Current.Left <> nil then
2059
2352
          Current.Left.LineOffset := Current.Left.LineOffset + LinesBefore;
2060
2353
        Current := Current.Left;
2076
2369
          Current.FullCount := Current.MergedLineCount;
2077
2370
        Current.AdjustParentLeftCount(Current.MergedLineCount - t); // If MergedLineCount = -1; LeftCount will be correctd on delete node
2078
2371
 
2079
 
        TreeForNestedNode(Current, CurrentLine).AdjustForLinesDeleted(FirstLineToDelete, LinesInside);
 
2372
        TreeForNestedNode(Current, CurrentLine).AdjustForLinesDeleted(FirstLineToDelete, LinesInside, ABytePos);
2080
2373
        Current := Current.Right;
2081
2374
      end;
2082
2375
 
2084
2377
  end;
2085
2378
 
2086
2379
begin
 
2380
  {$IFDEF SynFoldDebug}debugln(['FOLD-- AdjustForLinesDeleted AStartLine:=', AStartLine, ' ALineCount=',ALineCount, '  ABytePos=',ABytePos ]); {$ENDIF}
 
2381
  if ABytePos > 1 then
 
2382
    AdjustColumn(AStartLine+ALineCount-1, 1, ABytePos-1);
2087
2383
  AdjustNodeForLinesDeleted(TSynTextFoldAVLNodeData(fRoot), fRootOffset, AStartLine, ALineCount);
2088
2384
end;
2089
2385
 
 
2386
procedure TSynTextFoldAVLTree.AdjustColumn(ALine, ABytePos, ACount: Integer;
 
2387
  InLineBreak: boolean = False);
 
2388
var
 
2389
  Node: TSynTextFoldAVLNode;
 
2390
begin
 
2391
  Node := FindFoldForLine(ALine, True);
 
2392
  {$IFDEF SynFoldDebug}debugln(['FOLD-- AdjustColumn ALine:=', ALine, '  ABytePos=',ABytePos, ' ACount=',ACount, ' // node.srcline=',Node.SourceLine, '  StartLine=', node.StartLine, 'column=',Node.FoldColumn ]); {$ENDIF}
 
2393
  if (not Node.IsInFold) or (Node.SourceLine > ALine) then exit;
 
2394
  if (Node.SourceLine = ALine) and (node.FoldColumn >= ABytePos) then begin
 
2395
    node.FoldColumn := Node.FoldColumn + ACount;
 
2396
    if (not InLineBreak) and (node.FoldColumn < ABytePos) then node.FoldColumn := ABytePos;
 
2397
  end;
 
2398
  TreeForNestedNode(Node.fData, node.StartLine).AdjustColumn(ALine, ABytePos, ACount);
 
2399
end;
 
2400
 
2090
2401
function TSynTextFoldAVLTree.FindLastFold : TSynTextFoldAVLNode;
2091
2402
var
2092
2403
  r : TSynTextFoldAVLNodeData;
2103
2414
    r := r.Right; // rStartLine points to r, which now is the start of the previous fold;
2104
2415
  end;
2105
2416
 
2106
 
  Result.Init(r, rStartLine, rFoldedBefore);
 
2417
  Result{%H-}.Init(r, rStartLine, rFoldedBefore);
2107
2418
end;
2108
2419
 
2109
2420
function TSynTextFoldAVLTree.FindFirstFold : TSynTextFoldAVLNode;
2119
2430
    r := r.Left;
2120
2431
  end;
2121
2432
 
2122
 
  Result.Init(r, rStartLine, 0);
 
2433
  Result{%H-}.Init(r, rStartLine, 0);
2123
2434
end;
2124
2435
 
2125
2436
function TSynTextFoldAVLTree.LastFoldedLine: integer;
2138
2449
    result := 0;
2139
2450
    if ANode = nil then exit;
2140
2451
    with ANode do
2141
 
      DebugLn([Format('Lines=%3d-%3d (e=%3d / idx=%d):  Lcnt=%2d / Fcnt=%2d  | ',
 
2452
      DebugLn([Format('Lines=%3d-%3d (e=%3d / idx=%d) %2d:%d;  Lcnt=%2d / Fcnt=%2d  | ',
2142
2453
                      [offset + ANode.LineOffset, offset + ANode.LineOffset + ANode.FullCount -1,
2143
2454
                       offset + ANode.LineOffset + ANode.MergedLineCount-1, ANode.FoldIndex,
 
2455
                                           ANode.FoldColumn, ANode.FoldColumnLen,
2144
2456
                       MergedLineCount, FullCount]),
2145
2457
               ind, typ, ' (',LineOffset, ')  LeftCount: ', LeftCount,
2146
2458
               '     Balance: ',FBalance]);
2152
2464
    Result := Result + ANode.MergedLineCount;
2153
2465
  end;
2154
2466
begin
 
2467
  debugln('StartLine, EndLine (MergedEnd, FoldIndex) - Column:Len; MergedLineCnt / FullCCnt | .. (LineOffset) ...');
2155
2468
  debug2('', ' -', TSynTextFoldAVLNodeData(fRoot), nil, 0);
2156
2469
end;
2157
2470
{$ENDIF}
2158
2471
 
2159
 
function TSynTextFoldAVLTree.InsertNewFold(ALine, AColumn, ACount, AVisibleLines: Integer) : TSynTextFoldAVLNode;
 
2472
function TSynTextFoldAVLTree.InsertNewFold(ALine, AFoldIndex, AColumn, AColumnLen,
 
2473
   ACount, AVisibleLines: Integer; AClassification: TFoldNodeClassification;
 
2474
   AFoldTypeCompatible: Pointer) : TSynTextFoldAVLNode;
2160
2475
var
2161
2476
  r : TSynTextFoldAVLNodeData;
2162
2477
begin
2163
 
  {$IFDEF SynFoldDebug}debugln(['FOLD-- InsertNewFold ALine:=', ALine, '  AColumn=', AColumn]);{$ENDIF}
 
2478
  {$IFDEF SynFoldDebug}debugln(['FOLD-- InsertNewFold ALine:=', ALine, '  AFoldIndex=', AFoldIndex]);{$ENDIF}
2164
2479
  r := NewNode;
2165
2480
  r.LineOffset := ALine; // 1-based
2166
 
  r.FoldIndex := AColumn;
 
2481
  r.FoldIndex := AFoldIndex;
 
2482
  r.FoldColumn := AColumn;
 
2483
  r.FoldColumnLen := AColumnLen;
2167
2484
  r.MergedLineCount := ACount;
2168
2485
  r.FullCount  := ACount;
2169
2486
  r.LeftCount  := 0;
2170
2487
  r.VisibleLines := AVisibleLines;
 
2488
  r.Classification := AClassification;
 
2489
  r.FoldTypeCompatible := AFoldTypeCompatible;
2171
2490
 
2172
 
  Result.Init(r, ALine, 0);
 
2491
  Result{%H-}.Init(r, ALine, 0);
2173
2492
  Result.fFoldedBefore := InsertNode(r);
2174
2493
end;
2175
2494
 
2486
2805
  fNestedNodesTree := nil;
2487
2806
end;
2488
2807
 
 
2808
{ TLazSynEditNestedFoldsList }
 
2809
 
 
2810
procedure TLazSynEditNestedFoldsList.SetLines(AValue: TLineIdx);
 
2811
begin
 
2812
  if FLine = AValue then Exit;
 
2813
  FLine := AValue;
 
2814
  // Todo: might be able to re-use old data
 
2815
  Clear;
 
2816
end;
 
2817
 
 
2818
procedure TLazSynEditNestedFoldsList.Clear;
 
2819
begin
 
2820
  FGroupCount := -1;
 
2821
  FCount := -1;
 
2822
  FOpeningOnLineCount := -1;
 
2823
  FEvaluationIndex := -1;
 
2824
  SetLength(FNestInfo, 0);
 
2825
end;
 
2826
 
 
2827
procedure TLazSynEditNestedFoldsList.ResetFilter;
 
2828
begin
 
2829
  FIncludeOpeningOnLine := True;
 
2830
  FFoldFlags := [];
 
2831
  FFoldGroup := 0;
 
2832
  Clear;
 
2833
end;
 
2834
 
 
2835
procedure TLazSynEditNestedFoldsList.InitSubGroupEndLevels;
 
2836
var
 
2837
  hl: TSynCustomFoldHighlighter;
 
2838
  i: integer;
 
2839
begin
 
2840
  if FGroupCount > 0 then
 
2841
    exit;
 
2842
 
 
2843
  hl := FFoldProvider.HighLighterWithLines;
 
2844
  if hl = nil then exit;
 
2845
 
 
2846
  if FFoldGroup = 0 then begin
 
2847
    // special, join other groups (or some other...)
 
2848
    FGroupCount := hl.FoldTypeCount;
 
2849
    // start at 1, so FoldGroup can be used as index
 
2850
    SetLength(FGroupEndLevels, FGroupCount + 1);
 
2851
    SetLength(FGroupEndLevelsAtEval, FGroupCount + 1);
 
2852
    for i := 1 to FGroupCount do begin
 
2853
      FGroupEndLevels[i] := hl.FoldBlockEndLevel(FLine - 1, i, FFoldFlags);
 
2854
      if FIncludeOpeningOnLine then
 
2855
        FGroupEndLevels[i] := FGroupEndLevels[i] + FFoldProvider.FoldOpenCount(FLine, i);
 
2856
      FGroupEndLevelsAtEval[i] := FGroupEndLevels[i];
 
2857
    end;
 
2858
  end
 
2859
  else begin
 
2860
    FGroupCount := 1;
 
2861
    SetLength(FGroupEndLevels, 1);
 
2862
    SetLength(FGroupEndLevelsAtEval, 1);
 
2863
    FGroupEndLevels[0] := Count;  // includes OpeningOnLineCount
 
2864
    FGroupEndLevelsAtEval[0] := FGroupEndLevels[0];
 
2865
  end;
 
2866
end;
 
2867
 
 
2868
function TLazSynEditNestedFoldsList.GetHLNode(Index: Integer): TSynFoldNodeInfo;
 
2869
begin
 
2870
  if (Index < 0) or (Index >= Count) then begin
 
2871
    Result.FoldAction := [sfaInvalid];
 
2872
    exit;
 
2873
  end;
 
2874
  InitNestInfoForIndex(Index);
 
2875
  Result := FNestInfo[Index].HNode;
 
2876
end;
 
2877
 
 
2878
function TLazSynEditNestedFoldsList.GetNodeFoldGroup(Index: Integer): Integer;
 
2879
begin
 
2880
  if FoldGroup <> 0 then
 
2881
    Result := FoldGroup
 
2882
  else
 
2883
    Result := HLNode[Index].FoldGroup;
 
2884
end;
 
2885
 
 
2886
function TLazSynEditNestedFoldsList.GetNodeFoldType(Index: Integer): Pointer;
 
2887
var
 
2888
  hl: TSynCustomFoldHighlighter;
 
2889
begin
 
2890
  Result := nil;
 
2891
  hl := FFoldProvider.HighLighterWithLines;
 
2892
  if hl = nil then exit;
 
2893
 
 
2894
  if hl.FoldBlockNestedTypes(Line - 1, Index, Result, FFoldGroup, FFoldFlags) then
 
2895
    exit;
 
2896
 
 
2897
  Result := HLNode[Index].FoldType;
 
2898
end;
 
2899
 
 
2900
procedure TLazSynEditNestedFoldsList.InitNestInfoForIndex(AnIndex: Integer);
 
2901
var
 
2902
  CurLine: TLineIdx;
 
2903
  hl: TSynCustomFoldHighlighter;
 
2904
  i, c, t, l: Integer;
 
2905
  NFilter: TSynFoldActions;
 
2906
  nd: TSynFoldNodeInfo;
 
2907
begin
 
2908
  if (AnIndex >= Count) or (AnIndex >= FEvaluationIndex) then exit;
 
2909
  hl := FFoldProvider.HighLighterWithLines;
 
2910
  if hl = nil then exit;
 
2911
  InitSubGroupEndLevels;
 
2912
 
 
2913
  if FEvaluationIndex = Count then
 
2914
    CurLine := Line
 
2915
  else
 
2916
    CurLine := FNestInfo[FEvaluationIndex].LineIdx - 1;
 
2917
    // need index/column...
 
2918
 
 
2919
  inc(CurLine);
 
2920
  while CurLine > 0 do begin
 
2921
    dec(CurLine);
 
2922
 
 
2923
    if FFoldGroup = 0 then begin
 
2924
      i := FGroupCount;
 
2925
      while (i > 0) do begin
 
2926
        if hl.FoldBlockMinLevel(CurLine, i, FFoldFlags) < FGroupEndLevelsAtEval[i] then break;
 
2927
        dec(i);
 
2928
      end;
 
2929
      if i <= 0 then continue;
 
2930
    end
 
2931
    else begin
 
2932
      if hl.FoldBlockMinLevel(CurLine, FFoldGroup, FFoldFlags) >= FGroupEndLevelsAtEval[0] then continue;
 
2933
    end;
 
2934
 
 
2935
    // something of interest closes on this line
 
2936
    NFilter := [sfaOpen];
 
2937
    if not(sfbIncludeDisabled in FFoldFlags) then Include(NFilter, sfaFold);
 
2938
    c := hl.FoldNodeInfo[CurLine].CountEx(NFilter, FFoldGroup) - 1;
 
2939
    for i := c downto 0 do begin
 
2940
      nd := hl.FoldNodeInfo[CurLine].NodeInfoEx(i, NFilter, FFoldGroup);
 
2941
 
 
2942
      if FFoldGroup = 0 then
 
2943
        t := nd.FoldGroup
 
2944
      else
 
2945
        t := 0;
 
2946
 
 
2947
      if (sfbIncludeDisabled in FFoldFlags)
 
2948
      then l := nd.NestLvlStart
 
2949
      else l := nd.FoldLvlStart;
 
2950
      if l >= FGroupEndLevelsAtEval[t] then continue;
 
2951
 
 
2952
      dec(FGroupEndLevelsAtEval[t]);
 
2953
      dec(FEvaluationIndex);
 
2954
 
 
2955
      assert(FGroupEndLevelsAtEval[t] >= 0, 'TLazSynEditNestedFoldsList.InitNestInfoForIndex GroupEndLevel < 0');
 
2956
      assert(FEvaluationIndex >= 0, 'TLazSynEditNestedFoldsList.InitNestInfoForIndex FEvaluationIndex < 0');
 
2957
 
 
2958
      FNestInfo[FEvaluationIndex].LineIdx := CurLine;
 
2959
      FNestInfo[FEvaluationIndex].HNode := nd;
 
2960
    end;
 
2961
 
 
2962
    if (AnIndex >= FEvaluationIndex) then Break;
 
2963
  end;
 
2964
 
 
2965
 
 
2966
  assert(AnIndex >= FEvaluationIndex, 'TLazSynEditNestedFoldsList.InitNestInfoForIndex Index not found');
 
2967
end;
 
2968
 
 
2969
procedure TLazSynEditNestedFoldsList.SetFoldFlags(AValue: TSynFoldBlockFilterFlags);
 
2970
begin
 
2971
  if FFoldFlags = AValue then Exit;
 
2972
  FFoldFlags := AValue;
 
2973
  Clear;
 
2974
end;
 
2975
 
 
2976
procedure TLazSynEditNestedFoldsList.SetIncludeOpeningOnLine(AValue: Boolean);
 
2977
begin
 
2978
  if FIncludeOpeningOnLine = AValue then Exit;
 
2979
  FIncludeOpeningOnLine := AValue;
 
2980
  Clear;
 
2981
end;
 
2982
 
 
2983
procedure TLazSynEditNestedFoldsList.SetFoldGroup(AValue: Integer);
 
2984
begin
 
2985
  if FFoldGroup = AValue then Exit;
 
2986
  FFoldGroup := AValue;
 
2987
  Clear;
 
2988
end;
 
2989
 
 
2990
constructor TLazSynEditNestedFoldsList.Create(aFoldProvider: TSynEditFoldProvider);
 
2991
begin
 
2992
  FFoldProvider := aFoldProvider;
 
2993
  FIncludeOpeningOnLine := True;
 
2994
  FFoldFlags := [];
 
2995
  FFoldGroup := 0;
 
2996
end;
 
2997
 
 
2998
function TLazSynEditNestedFoldsList.Count: Integer;
 
2999
var
 
3000
  hl: TSynCustomFoldHighlighter;
 
3001
begin
 
3002
  Result := FCount;
 
3003
  if Result >= 0 then exit;
 
3004
  hl := FFoldProvider.HighLighterWithLines;
 
3005
  if hl = nil then exit(-1);
 
3006
 
 
3007
  FCount := hl.FoldBlockEndLevel(FLine - 1, FFoldGroup, FFoldFlags) + OpeningOnLineCount;
 
3008
  FEvaluationIndex := FCount;
 
3009
  SetLength(FNestInfo, FCount);
 
3010
  Result := FCount;
 
3011
end;
 
3012
 
 
3013
function TLazSynEditNestedFoldsList.OpeningOnLineCount: Integer;
 
3014
begin
 
3015
  if not FIncludeOpeningOnLine then
 
3016
    exit(0);
 
3017
 
 
3018
  Result := FOpeningOnLineCount;
 
3019
  if Result >= 0 then exit;
 
3020
 
 
3021
  FOpeningOnLineCount := FFoldProvider.FoldOpenCount(FLine, FFoldGroup);
 
3022
  Result := FOpeningOnLineCount;
 
3023
end;
 
3024
 
2489
3025
{ TSynEditFoldProvider }
2490
3026
 
2491
3027
function TSynEditFoldProvider.GetLineCapabilities(ALineIdx: Integer): TSynEditFoldLineCapabilities;
2493
3029
  c: Integer;
2494
3030
begin
2495
3031
  Result := [];
2496
 
  if (FHighlighter = nil) or (ALineIdx < 0) then exit;
2497
 
  if FHighlighter.FoldNestCount(ALineIdx - 1) > 0 then Result := Result + [cfFoldBody];
2498
 
  if FHighlighter.FoldCloseCount(ALineIdx) > 0    then Result := Result + [cfFoldEnd, cfFoldBody];
2499
 
 
2500
 
  c := FHighlighter.FoldNodeInfoCount[ALineIdx, []];
 
3032
  if (FSelection <> nil) and (FSelection.SelAvail) then begin
 
3033
    if (FSelection.FirstLineBytePos.Y < ALineIdx+1) and
 
3034
       (FSelection.LastLineBytePos.Y  > ALineIdx+1)
 
3035
    then Result := [cfFoldBody];
 
3036
    if (FSelection.LastLineBytePos.Y  = ALineIdx+1) then Result := [cfFoldEnd];
 
3037
    if (FSelection.FirstLineBytePos.Y = ALineIdx+1) then Result := [cfHideStart];
 
3038
    if (FSelection.FirstLineBytePos.Y = ALineIdx+1) and
 
3039
       (FSelection.LastLineBytePos.Y  = ALineIdx+1) then Result := [cfHideStart, cfSingleLineHide];
 
3040
  end;
 
3041
  if (FHighlighter = nil) or (ALineIdx < 0) then
 
3042
    exit;
 
3043
 
 
3044
  FHighlighter.CurrentLines := FLines;
 
3045
  if FHighlighter.FoldBlockEndLevel(ALineIdx - 1) > 0 then Result := Result + [cfFoldBody];
 
3046
  if FHighlighter.FoldBlockClosingCount(ALineIdx) > 0    then Result := Result + [cfFoldEnd, cfFoldBody];
 
3047
 
 
3048
  c := FHighlighter.FoldNodeInfo[ALineIdx].CountEx([]);
2501
3049
  if c > 0 then begin
2502
 
    c := FHighlighter.FoldNodeInfoCount[ALineIdx, [sfaOpen, sfaFoldFold]];
 
3050
    c := FHighlighter.FoldNodeInfo[ALineIdx].CountEx([sfaOpen, sfaFoldFold]);
2503
3051
    if c > 0 then
2504
3052
      include(Result, cfFoldStart);
2505
 
    c := FHighlighter.FoldNodeInfoCount[ALineIdx, [sfaOpen, sfaFoldHide]];
 
3053
    c := FHighlighter.FoldNodeInfo[ALineIdx].CountEx([sfaOpen, sfaFoldHide]);
2506
3054
    if c > 0 then
2507
3055
      include(Result, cfHideStart);
2508
 
    c := FHighlighter.FoldNodeInfoCount[ALineIdx, [sfaOneLineOpen, sfaFoldHide]]; // TODO: Include scftFoldEnd ?
 
3056
    c := FHighlighter.FoldNodeInfo[ALineIdx].CountEx([sfaOneLineOpen, sfaFoldHide]); // TODO: Include scftFoldEnd ?
2509
3057
    // Todo: cfSingleLineHide only, if there is no other hide
2510
3058
    if c > 0 then
2511
3059
      Result := Result + [cfHideStart, cfSingleLineHide];
2512
3060
  end
2513
3061
  else
2514
 
    if FHighlighter.FoldOpenCount(ALineIdx) > 0 then include(Result, cfFoldStart);
 
3062
    if FHighlighter.FoldBlockOpeningCount(ALineIdx) > 0 then include(Result, cfFoldStart);
 
3063
end;
 
3064
 
 
3065
function TSynEditFoldProvider.GetLineClassification(ALineIdx: Integer): TFoldNodeClassifications;
 
3066
begin
 
3067
  Result := [];
 
3068
  if (FSelection <> nil) and FSelection.SelAvail and (FSelection.FirstLineBytePos.Y = ALineIdx+1) then
 
3069
    Result := [fncBlockSelection];
 
3070
end;
 
3071
 
 
3072
function TSynEditFoldProvider.GetNestedFoldsList: TLazSynEditNestedFoldsList;
 
3073
begin
 
3074
  if FNestedFoldsList = nil then
 
3075
    FNestedFoldsList := TLazSynEditNestedFoldsList.Create(Self);
 
3076
  Result := FNestedFoldsList;
 
3077
end;
 
3078
 
 
3079
function TSynEditFoldProvider.GetFoldsAvailable: Boolean;
 
3080
begin
 
3081
  Result := (FHighlighter <> nil) or
 
3082
            ((FSelection <> nil) and FSelection.SelAvail);
 
3083
end;
 
3084
 
 
3085
function TSynEditFoldProvider.GetHighLighterWithLines: TSynCustomFoldHighlighter;
 
3086
begin
 
3087
  Result := FHighlighter;
 
3088
  if (Result = nil) then
 
3089
    exit;
 
3090
  Result.CurrentLines := FLines;
2515
3091
end;
2516
3092
 
2517
3093
procedure TSynEditFoldProvider.SetHighLighter(const AValue: TSynCustomFoldHighlighter);
2520
3096
  FHighlighter := AValue;
2521
3097
end;
2522
3098
 
 
3099
constructor TSynEditFoldProvider.Create(aTextView: TSynEditStrings; AFoldTree : TSynTextFoldAVLTree);
 
3100
begin
 
3101
  FLines := aTextView;
 
3102
  FFoldTree := AFoldTree;
 
3103
end;
 
3104
 
 
3105
destructor TSynEditFoldProvider.Destroy;
 
3106
begin
 
3107
  inherited Destroy;
 
3108
  FreeAndNil(FNestedFoldsList);
 
3109
end;
 
3110
 
2523
3111
function TSynEditFoldProvider.FoldOpenCount(ALineIdx: Integer; AType: Integer = 0): Integer;
2524
 
var
2525
 
  i: Integer;
2526
3112
begin
2527
 
  if (FHighlighter = nil) or (ALineIdx < 0) then exit(0);
2528
 
 
2529
 
  Result := FHighlighter.FoldNodeInfoCount[ALineIdx, [sfaOpen, sfaFold]];
2530
 
  if (result > 0) and (AType > 0) then begin
2531
 
    i := Result ;
2532
 
    Result := 0;
2533
 
    while i > 0 do begin
2534
 
      dec(i);
2535
 
      if FHighlighter.FoldNodeInfo[ALineIdx, i, [sfaOpen, sfaFold]].FoldGroup = AType then
2536
 
        inc(Result);
2537
 
    end;
2538
 
  end
2539
 
  //Result := Result + FHighlighter.FoldNodeInfoCount[ALineIdx, [sfaOpen, sfaFoldHide]];
2540
 
  //Result := Result + FHighlighter.FoldNodeInfoCount[ALineIdx, [sfaOneLineOpen, sfaFoldHide]];
2541
 
  else
 
3113
  if (FHighlighter = nil) or (ALineIdx < 0) then begin
 
3114
    if (AType=0) and (FSelection <> nil) and FSelection.SelAvail and (FSelection.FirstLineBytePos.Y=ALineIdx+1) then exit(1);
 
3115
    exit(0);
 
3116
  end;
 
3117
  // Need to check alll nodes with FoldNodeInfoCount
 
3118
  // Hide-able nodes can open and close on the same line "(* cmment *)"
 
3119
  FHighlighter.CurrentLines := FLines;
 
3120
  Result := FHighlighter.FoldNodeInfo[ALineIdx].CountEx([sfaOpen, sfaFold], AType);
 
3121
  // fallback for HL without GetFoldNodeInfoCountEx
2542
3122
  if Result < 0 then
2543
 
    Result := FHighlighter.FoldOpenCount(ALineIdx, AType);
 
3123
    Result := FHighlighter.FoldBlockOpeningCount(ALineIdx, AType);
 
3124
  if (AType=0) and (FSelection <> nil) and FSelection.SelAvail and (FSelection.FirstLineBytePos.Y=ALineIdx+1) then
 
3125
    inc(Result);
2544
3126
end;
2545
3127
 
2546
3128
function TSynEditFoldProvider.FoldOpenInfo(ALineIdx, AFoldIdx: Integer;
2547
3129
  AType: Integer = 0): TSynFoldNodeInfo;
2548
 
var
2549
 
  i, x: Integer;
 
3130
 
 
3131
  function BlockSelInfo(NIdx: Integer): TSynFoldNodeInfo;
 
3132
  begin
 
3133
    Result.LineIndex    := ALineIdx;
 
3134
    Result.NodeIndex    := NIdx;
 
3135
    Result.LogXStart    := FSelection.FirstLineBytePos.x;
 
3136
    Result.LogXEnd      := FSelection.FirstLineBytePos.x;
 
3137
    Result.FoldLvlStart := 0;
 
3138
    Result.NestLvlStart := 0;
 
3139
    Result.NestLvlEnd   := 1;
 
3140
    Result.FoldLvlEnd   := 1;
 
3141
    Result.FoldAction   := [sfaOpen, sfaFold, sfaFoldHide];
 
3142
    Result.FoldType           := nil;
 
3143
    Result.FoldTypeCompatible := nil;
 
3144
    Result.FoldGroup := -1;
 
3145
  end;
 
3146
 
2550
3147
begin
2551
3148
  Result.FoldAction := [sfaInvalid];
2552
 
  if (FHighlighter = nil) or (ALineIdx < 0) then exit;
2553
 
 
2554
 
  if AType = 0 then
2555
 
    Result := FHighlighter.FoldNodeInfo[ALineIdx, AFoldIdx, [sfaOpen, sfaFold]]
2556
 
  else begin
2557
 
    x := FHighlighter.FoldNodeInfoCount[ALineIdx, [sfaOpen, sfaFold]];
2558
 
    i := 0;
2559
 
    while i < x do begin
2560
 
      Result := FHighlighter.FoldNodeInfo[ALineIdx, i, [sfaOpen, sfaFold]];
2561
 
      if (Result.FoldGroup = AType) then begin
2562
 
        if AFoldIdx = 0 then
2563
 
          exit;
2564
 
        dec(AFoldIdx);
2565
 
      end;
2566
 
      inc(i);
2567
 
    end;
2568
 
    Result.FoldAction := [sfaInvalid];
 
3149
  if (FHighlighter = nil) or (ALineIdx < 0) then begin
 
3150
    if (AType=0) and (FSelection <> nil) and FSelection.SelAvail and (FSelection.FirstLineBytePos.Y=ALineIdx+1) then
 
3151
      exit(BlockSelInfo(0));
 
3152
    exit;
 
3153
  end;
 
3154
 
 
3155
  FHighlighter.CurrentLines := FLines;
 
3156
  if (AType = 0) and (FSelection <> nil) and FSelection.SelAvail and
 
3157
     (FSelection.FirstLineBytePos.Y=ALineIdx+1) and
 
3158
     (AFoldIdx = FoldOpenCount(ALineIdx, AType)-1)
 
3159
  then
 
3160
    Result := BlockSelInfo(AFoldIdx)
 
3161
  else
 
3162
    Result := FHighlighter.FoldNodeInfo[ALineIdx].NodeInfoEx(AFoldIdx, [sfaOpen, sfaFold], AType);
 
3163
end;
 
3164
 
 
3165
function TSynEditFoldProvider.FoldLineLength(ALine, AFoldIndex: Integer): integer;
 
3166
begin
 
3167
  if (FSelection <> nil) and FSelection.SelAvail and (FSelection.FirstLineBytePos.Y=ALine+1) and
 
3168
    (AFoldIndex = FoldOpenCount(ALine, 0)-1)
 
3169
  then
 
3170
    exit(FSelection.LastLineBytePos.y - FSelection.FirstLineBytePos.y);
 
3171
 
 
3172
  FHighlighter.CurrentLines := FLines;
 
3173
  Result := FHighlighter.FoldLineLength(ALine, AFoldIndex);
 
3174
end;
 
3175
 
 
3176
function TSynEditFoldProvider.InfoForFoldAtTextIndex(ALine, AFoldIndex: Integer;
 
3177
  HideLen: Boolean; NeedLen: Boolean = True): TSynEditFoldProviderNodeInfo;
 
3178
var
 
3179
  nd: TSynFoldNodeInfo;
 
3180
begin
 
3181
  Result.LineCount := 0;
 
3182
  Result.Column := 0;
 
3183
  Result.ColumnLen := 0;
 
3184
  Result.DefaultCollapsed := False;
 
3185
  Result.Classification := fncInvalid;
 
3186
  if not FoldsAvailable then
 
3187
    exit;
 
3188
 
 
3189
  if NeedLen then begin
 
3190
    Result.LineCount := FoldLineLength(ALine, AFoldIndex);
 
3191
    if HideLen then
 
3192
      inc(Result.LineCount);
 
3193
  end
 
3194
  else
 
3195
    Result.LineCount := -1;
 
3196
  nd := FoldOpenInfo(ALine, AFoldIndex, 0);
 
3197
  Result.Column := nd.LogXStart+1;
 
3198
  Result.ColumnLen := nd.LogXEnd - nd.LogXStart;
 
3199
  Result.DefaultCollapsed := (sfaDefaultCollapsed in nd.FoldAction);
 
3200
  Result.FoldTypeCompatible := nd.FoldTypeCompatible;
 
3201
  Result.FoldGroup := nd.FoldGroup;
 
3202
  if Result.FoldGroup = -1 then
 
3203
    Result.Classification := fncBlockSelection
 
3204
  else
 
3205
    Result.Classification := fncHighlighter;
 
3206
end;
 
3207
 
 
3208
function TSynEditFoldProvider.InfoListForFoldsAtTextIndex(ALine: Integer;
 
3209
  NeedLen: Boolean): TSynEditFoldProviderNodeInfoList;
 
3210
var
 
3211
  i: Integer;
 
3212
begin
 
3213
  i := FoldOpenCount(ALine);
 
3214
  SetLength(Result, i);
 
3215
  while i > 0 do begin
 
3216
    dec(i);
 
3217
    Result[i] := InfoForFoldAtTextIndex(ALine, i, False, NeedLen);
2569
3218
  end;
2570
3219
end;
2571
3220
 
2573
3222
 
2574
3223
constructor TSynEditFoldedView.Create(aTextView : TSynEditStrings; ACaret: TSynEditCaret);
2575
3224
begin
2576
 
  FFoldProvider := TSynEditFoldProvider.Create;
 
3225
  fTopLine := 0;
 
3226
  fLinesInWindow := -1;
2577
3227
  fLines := aTextView;
2578
3228
  fCaret := ACaret;
2579
3229
  fCaret.AddChangeHandler({$IFDEF FPC}@{$ENDIF}DoCaretChanged);
2580
3230
  fFoldTree := TSynTextFoldAVLTree.Create;
2581
 
  fTopLine := 0;
2582
 
  fLinesInWindow := -1;
 
3231
  FFoldProvider := TSynEditFoldProvider.Create(aTextView, fFoldTree);
 
3232
  FDisplayView := TLazSynDisplayFold.Create(Self);
2583
3233
 
2584
3234
  FMarkupInfoFoldedCode := TSynSelectedColor.Create;
2585
3235
  FMarkupInfoFoldedCode.Background := clNone;
2587
3237
  FMarkupInfoFoldedCode.FrameColor := clDkGray;
2588
3238
 
2589
3239
  fLines.AddChangeHandler(senrLineCount, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
 
3240
  fLines.AddNotifyHandler(senrCleared, {$IFDEF FPC}@{$ENDIF}LinesCleared);
 
3241
  fLines.AddEditHandler({$IFDEF FPC}@{$ENDIF}LineEdited);
2590
3242
end;
2591
3243
 
2592
3244
destructor TSynEditFoldedView.Destroy;
2593
3245
begin
2594
3246
  fLines.RemoveChangeHandler(senrLineCount, {$IFDEF FPC}@{$ENDIF}LineCountChanged);
 
3247
  fLines.RemoveNotifyHandler(senrCleared, {$IFDEF FPC}@{$ENDIF}LinesCleared);
 
3248
  fLines.RemoveEditHandler({$IFDEF FPC}@{$ENDIF}LineEdited);
2595
3249
  fCaret.RemoveChangeHandler({$IFDEF FPC}@{$ENDIF}DoCaretChanged);
 
3250
  FreeAndNil(FDisplayView);
2596
3251
  fFoldTree.Free;
2597
3252
  fTextIndexList := nil;
2598
3253
  fFoldTypeList := nil;
2601
3256
  inherited Destroy;
2602
3257
end;
2603
3258
 
2604
 
procedure TSynEditFoldedView.LinesInsertedAtTextIndex(AStartIndex, ALineCount : Integer; SkipFixFolding : Boolean);
 
3259
procedure TSynEditFoldedView.LinesInsertedAtTextIndex(AStartIndex, ALineCount, ABytePos: Integer; SkipFixFolding : Boolean);
2605
3260
var top : Integer;
2606
3261
begin
2607
3262
  if ALineCount = 0 then exit;
2608
3263
  top := TopTextIndex;
2609
 
  fFoldTree.AdjustForLinesInserted(AStartIndex+1, ALineCount);
 
3264
  fFoldTree.AdjustForLinesInserted(AStartIndex+1, ALineCount, ABytePos);
2610
3265
  if AStartIndex < top then
2611
3266
    TopTextIndex := top + ALineCount;
2612
3267
  if not(SkipFixFolding) then FixFoldingAtTextIndex(AStartIndex, AStartIndex+ALineCount+1)
2614
3269
  if AStartIndex < top + ALineCount then CalculateMaps;
2615
3270
end;
2616
3271
 
2617
 
procedure TSynEditFoldedView.LinesInsertedAtViewPos(AStartPos, ALineCount : Integer; SkipFixFolding : Boolean);
2618
 
begin
2619
 
  LinesInsertedAtTextIndex(ViewPosToTextIndex(AStartPos), ALineCount, SkipFixFolding);
2620
 
end;
 
3272
//procedure TSynEditFoldedView.LinesInsertedAtViewPos(AStartPos, ALineCount : Integer; SkipFixFolding : Boolean);
 
3273
//begin
 
3274
//  LinesInsertedAtTextIndex(ViewPosToTextIndex(AStartPos), ALineCount, SkipFixFolding);
 
3275
//end;
2621
3276
 
2622
 
procedure TSynEditFoldedView.LinesDeletedAtTextIndex(AStartIndex, ALineCount : Integer; SkipFixFolding : Boolean);
 
3277
procedure TSynEditFoldedView.LinesDeletedAtTextIndex(AStartIndex, ALineCount, ABytePos: Integer; SkipFixFolding : Boolean);
2623
3278
var top : Integer;
2624
3279
begin
2625
3280
  top := TopTextIndex;
2626
3281
  // topline may get out of sync => synedit is always going to change it back
2627
 
  fFoldTree.AdjustForLinesDeleted(AStartIndex+1, ALineCount);
 
3282
  fFoldTree.AdjustForLinesDeleted(AStartIndex+1, ALineCount, ABytePos);
2628
3283
  if not(SkipFixFolding) then
2629
3284
    FixFoldingAtTextIndex(AStartIndex, AStartIndex+ALineCount+1)
2630
3285
  else
2631
3286
  if AStartIndex < top - ALineCount then CalculateMaps;
2632
3287
end;
2633
3288
 
2634
 
procedure TSynEditFoldedView.LinesDeletedAtViewPos(AStartPos, ALineCount : Integer; SkipFixFolding : Boolean);
2635
 
begin
2636
 
  LinesDeletedAtTextIndex(ViewPosToTextIndex(AStartPos), ALineCount, SkipFixFolding);
2637
 
end;
 
3289
//procedure TSynEditFoldedView.LinesDeletedAtViewPos(AStartPos, ALineCount : Integer; SkipFixFolding : Boolean);
 
3290
//begin
 
3291
//  LinesDeletedAtTextIndex(ViewPosToTextIndex(AStartPos), ALineCount, SkipFixFolding);
 
3292
//end;
2638
3293
 
2639
3294
function TSynEditFoldedView.TextIndexToViewPos(aTextIndex : Integer) : Integer;
2640
3295
var
2654
3309
 
2655
3310
function TSynEditFoldedView.ViewPosToTextIndex(aViewPos : Integer) : Integer;
2656
3311
begin
2657
 
  if aViewPos > Count then
2658
 
    aViewPos := Count;
2659
3312
  result := aViewPos - 1 + fFoldTree.FindFoldForFoldedLine(aViewPos).FoldedBefore;
2660
3313
end;
2661
3314
 
2677
3330
    then node := node.Prev
2678
3331
    else node := fFoldTree.FindLastFold;
2679
3332
    while LineOffset < 0 do begin
 
3333
      dec(Result);
2680
3334
      if Result <= boundary then exit(boundary);
2681
 
      dec(Result);
2682
 
      if node.IsInFold and (Result+1 < node.StartLine + node.MergedLineCount) then begin
 
3335
      while node.IsInFold and (Result+1 < node.StartLine + node.MergedLineCount) do begin
2683
3336
        Result := Result - node.MergedLineCount;
 
3337
        if Result <= boundary then exit(boundary);
2684
3338
        node := node.Prev;
2685
3339
      end;
2686
3340
      inc(LineOffset);
2690
3344
    while LineOffset > 0 do begin
2691
3345
      if Result >= boundary then exit(boundary);
2692
3346
      inc(Result);
2693
 
      if node.IsInFold and (Result+1 >= node.StartLine) then begin
 
3347
      while node.IsInFold and (Result+1 >= node.StartLine) do begin
2694
3348
        Result := Result + node.MergedLineCount;
 
3349
        if Result >= boundary then exit(boundary);
2695
3350
        if Result >= boundary then exit(boundary-node.MergedLineCount-1);
2696
3351
        node := node.Next;
2697
3352
      end;
2732
3387
  Result := fLines.Count - fFoldTree.FindLastFold.FoldedBefore;
2733
3388
end;
2734
3389
 
 
3390
function TSynEditFoldedView.GetDisplayView: TLazSynDisplayView;
 
3391
begin
 
3392
  Result := FDisplayView;
 
3393
end;
 
3394
 
 
3395
function TSynEditFoldedView.GetFoldClasifications(index : Integer): TFoldNodeClassifications;
 
3396
begin
 
3397
  if (index < -1) or (index > fLinesInWindow + 1) then exit([]);
 
3398
  Result := fFoldTypeList[index+1].Classifications;
 
3399
end;
 
3400
 
2735
3401
function TSynEditFoldedView.GetHighLighter: TSynCustomHighlighter;
2736
3402
begin
2737
 
  Result := FHighLighter;
 
3403
  Result := FFoldProvider.HighLighter;
2738
3404
  if assigned(Result) then
2739
3405
    Result.CurrentLines := fLines;
2740
3406
end;
2743
3409
procedure TSynEditFoldedView.SetTopLine(const ALine : integer);
2744
3410
begin
2745
3411
  if fTopLine = ALine then exit;
 
3412
  FInTopLineChanged := True;
2746
3413
  fTopLine := ALine;
2747
3414
  CalculateMaps;
 
3415
  FInTopLineChanged := False;
2748
3416
end;
2749
3417
 
2750
3418
function TSynEditFoldedView.GetTopTextIndex : integer;
2767
3435
  CalculateMaps;
2768
3436
end;
2769
3437
 
 
3438
procedure TSynEditFoldedView.DoBlockSelChanged(Sender: TObject);
 
3439
begin
 
3440
  CalculateMaps;
 
3441
end;
 
3442
 
2770
3443
procedure TSynEditFoldedView.CalculateMaps;
2771
3444
var
2772
3445
  i, tpos, cnt  : Integer;
2773
3446
  node, tmpnode: TSynTextFoldAVLNode;
2774
 
  hl: TSynCustomFoldHighlighter;
 
3447
  FirstChanged, LastChanged: Integer;
 
3448
  NewCapability: TSynEditFoldLineCapabilities;
 
3449
  NewClassifications :TFoldNodeClassifications;
2775
3450
begin
2776
3451
  if fLinesInWindow < 0 then exit;
2777
 
  hl := TSynCustomFoldHighlighter(HighLighter);
2778
 
  if not assigned(hl) then begin
2779
 
    for i := 0 to fLinesInWindow+2 do begin
2780
 
      fTextIndexList[i] := fTopLine + i - 2;
2781
 
      fFoldTypeList[i] := [];
2782
 
    end;
2783
 
    exit;
2784
 
  end;
2785
3452
 
2786
3453
  node := fFoldTree.FindFoldForFoldedLine(fTopLine, true);
2787
3454
  // ftopline is not a folded line
2797
3464
  end;
2798
3465
  {$IFDEF SynFoldDebug}debugln(['FOLD-- CalculateMaps fTopLine:=', fTopLine, '  tpos=',tpos]);{$ENDIF}
2799
3466
  cnt := fLines.Count;
 
3467
  FirstChanged := -1;
 
3468
  LastChanged := -1;
2800
3469
  for i := 0 to fLinesInWindow + 2 do begin
2801
3470
    if (tpos > cnt) or (tpos < 0) then begin
2802
3471
      // Past end of Text
2803
3472
      fTextIndexList[i] := -1;
2804
 
      fFoldTypeList[i] := [];
 
3473
      NewCapability := [];
 
3474
      NewClassifications := [];
2805
3475
    end else begin
2806
3476
      fTextIndexList[i] := tpos - 1; // TextIndex is 0-based
2807
 
      fFoldTypeList[i] := FFoldProvider.LineCapabilities[tpos - 1];
 
3477
      NewCapability := FFoldProvider.LineCapabilities[tpos - 1];
 
3478
      NewClassifications := FFoldProvider.LineClassification[tpos - 1];
2808
3479
      if (node.IsInFold) then begin
2809
 
        if (tpos = node.SourceLine) then
2810
 
          include(fFoldTypeList[i], cfCollapsedFold)
2811
 
        else if node.IsHide and (tpos + 1 = node.SourceLine) then
2812
 
          include(fFoldTypeList[i], cfCollapsedHide);
 
3480
        if (tpos = node.SourceLine) then begin
 
3481
          include(NewCapability, cfCollapsedFold);
 
3482
          include(NewClassifications, node.fData.Classification);
 
3483
        end
 
3484
        else if node.IsHide and (tpos + 1 = node.SourceLine) then begin
 
3485
          include(NewCapability, cfCollapsedHide);
 
3486
          include(NewClassifications, node.fData.Classification);
 
3487
        end;
2813
3488
      end;
2814
3489
 
2815
3490
      inc(tpos);
2818
3493
        node := node.Next;
2819
3494
      end;
2820
3495
    end;
 
3496
 
 
3497
    if (fFoldTypeList[i].Capability <> NewCapability) or
 
3498
       (fFoldTypeList[i].Classifications <> NewClassifications)
 
3499
    then begin
 
3500
      if FirstChanged < 0 then FirstChanged := tpos - 1;
 
3501
      LastChanged := tpos;
 
3502
    end;
 
3503
    fFoldTypeList[i].Capability := NewCapability;
 
3504
    fFoldTypeList[i].Classifications := NewClassifications;
2821
3505
  end;
 
3506
  if (not FInTopLineChanged) and assigned(FOnLineInvalidate) and (FirstChanged > 0) then
 
3507
    FOnLineInvalidate(FirstChanged, LastChanged + 1);
2822
3508
end;
2823
3509
 
2824
3510
(* Lines *)
2846
3532
function TSynEditFoldedView.GetFoldType(index : Integer) : TSynEditFoldLineCapabilities;
2847
3533
begin
2848
3534
  if (index < -1) or (index > fLinesInWindow + 1) then exit([]);
2849
 
  Result := fFoldTypeList[index+1];
 
3535
  Result := fFoldTypeList[index+1].Capability;
2850
3536
end;
2851
3537
 
2852
3538
function TSynEditFoldedView.IsFolded(index : integer) : Boolean;
2854
3540
  Result := fFoldTree.FindFoldForLine(index+1).IsInFold;
2855
3541
end;
2856
3542
 
2857
 
procedure TSynEditFoldedView.SetHighLighter(AValue: TSynCustomHighlighter
2858
 
  );
 
3543
procedure TSynEditFoldedView.SetBlockSelection(const AValue: TSynEditSelection);
 
3544
begin
 
3545
  if FBlockSelection <> nil then
 
3546
    FBlockSelection.RemoveChangeHandler(@DoBlockSelChanged);
 
3547
  FBlockSelection := AValue;
 
3548
  if FBlockSelection <> nil then
 
3549
    FBlockSelection.AddChangeHandler(@DoBlockSelChanged);
 
3550
  FoldProvider.FSelection := AValue;
 
3551
end;
 
3552
 
 
3553
procedure TSynEditFoldedView.SetHighLighter(AValue: TSynCustomHighlighter);
2859
3554
begin
2860
3555
  if not(AValue is TSynCustomFoldHighlighter) then
2861
3556
    AValue := nil;
2862
 
  if FHighLighter = AValue then exit;
2863
 
  FHighLighter := TSynCustomFoldHighlighter(AValue);
2864
 
  FFoldProvider.HighLighter := FHighLighter;
 
3557
  FFoldProvider.HighLighter := TSynCustomFoldHighlighter(AValue);
2865
3558
  UnfoldAll;
2866
3559
end;
2867
3560
 
2882
3575
                  ColIndex, ColCount, Skip, AVisibleLines);
2883
3576
end;
2884
3577
 
2885
 
function TSynEditFoldedView.LengthForFoldAtTextIndex(ALine, AFoldIndex: Integer;
2886
 
  HideLen: Boolean = False) : Integer;
2887
 
var
2888
 
  hl: TSynCustomFoldHighlighter;
2889
 
begin
2890
 
  hl := TSynCustomFoldHighlighter(HighLighter);
2891
 
  if not assigned(hl) then
2892
 
    exit(0);
2893
 
  Result := hl.FoldLineLength(ALine, AFoldIndex);
2894
 
  if HideLen then
2895
 
    inc(Result);
2896
 
end;
2897
 
 
2898
3578
function TSynEditFoldedView.FoldNodeAtTextIndex(AStartIndex,
2899
3579
  ColIndex: Integer): TSynTextFoldAVLNode;
2900
3580
var
2947
3627
    exit(0);
2948
3628
  // AStartIndex is 0-based
2949
3629
  // FoldTree is 1-based AND first line remains visble
2950
 
  c := hl.FoldNodeInfoCount[AStartIndex, [sfaOpen, sfaFold]];
 
3630
  c := hl.FoldNodeInfo[AStartIndex].CountEx([sfaOpen, sfaFold]);
2951
3631
  if c = 0 then
2952
3632
    exit(-1);
2953
3633
  i := 0;
2954
3634
  while i < c do begin
2955
 
    nd := hl.FoldNodeInfo[aStartIndex, i, [sfaOpen, sfaFold]];
 
3635
    nd := hl.FoldNodeInfo[aStartIndex].NodeInfoEx(i, [sfaOpen, sfaFold]);
2956
3636
    if (nd.LogXStart >= LogX) then begin
2957
3637
      dec(i);
2958
3638
      if not Previous then
2970
3650
var
2971
3651
  i, j, c: Integer;
2972
3652
  hl: TSynCustomFoldHighlighter;
2973
 
  nd: TSynFoldNodeInfo;
 
3653
  fldinf: TSynEditFoldProviderNodeInfo;
2974
3654
begin
2975
3655
  hl := TSynCustomFoldHighlighter(HighLighter);
2976
3656
  if not assigned(hl) then
2980
3660
  while i < fLines.Count do begin
2981
3661
     // Todo: Highlighter should return a list of types that can return default folded
2982
3662
     // Currently PascalHl Type 2 = Region
2983
 
    c := hl.FoldOpenCount(i, 2);
 
3663
    c := hl.FoldBlockOpeningCount(i, 2);
2984
3664
    if c > 0 then begin
2985
 
      c := hl.FoldNodeInfoCount[i, [sfaOpen, sfaFold]];
 
3665
      c := hl.FoldNodeInfo[i].CountEx([sfaOpen, sfaFold]);
2986
3666
      j := 0;
2987
3667
      while j < c do begin
2988
 
        nd := hl.FoldNodeInfo[i, j, [sfaOpen, sfaFold]];
2989
 
        if (sfaDefaultCollapsed in nd.FoldAction) and
2990
 
           (not IsFoldedAtTextIndex(i, j))
 
3668
        fldinf := FoldProvider.InfoForFoldAtTextIndex(i, j);
 
3669
        if (fldinf.DefaultCollapsed) and (not IsFoldedAtTextIndex(i, j))
2991
3670
        then begin
2992
3671
          // TODO: detect default hide too
2993
3672
          // currently always VisibleLines=1 => since region only folds
2994
 
          fFoldTree.InsertNewFold(i+2, j, LengthForFoldAtTextIndex(i, j), 1);
 
3673
          fFoldTree.InsertNewFold(i+2, j, fldinf.Column, fldinf.ColumnLen, fldinf.LineCount, 1,
 
3674
                                  fldinf.Classification, fldinf.FoldTypeCompatible);
2995
3675
          if Assigned(fOnFoldChanged) then
2996
3676
            fOnFoldChanged(i);
2997
3677
        end;
3065
3745
      {$IFDEF SynFoldSaveDebug}
3066
3746
      DebugLnEnter(['TSynEditFoldedView.GetFoldDescription as Text']);
3067
3747
      {$ENDIF}
 
3748
      while Node.IsInFold and (Node.fData.Classification <> fncHighlighter) do
 
3749
        Node := NodeIterator.Next;
 
3750
      if not node.IsInFold then
 
3751
        exit;
 
3752
 
3068
3753
      NdInfo := NdiHelper1.GotoNodeOpenPos(Node);
3069
3754
      while Node.IsInFold and (Node.StartLine-2 <= AEndIndex) do
3070
3755
      begin
3073
3758
        NodeFoldType := scftFold;
3074
3759
        if Node.SourceLineOffset = 0 then
3075
3760
          NodeFoldType := scftHide;
3076
 
        if not(sfaDefaultCollapsed in NdInfo.FoldAction) then // Currently skip default nodes
 
3761
        if (NdInfo.FoldAction * [sfaInvalid, sfaDefaultCollapsed] = []) then // Currently skip default nodes
3077
3762
          FoldCoderForType(NdInfo.FoldType).AddNode
3078
3763
                     (NdInfo.LogXStart, NdInfo.LineIndex, Node.FullCount, NodeFoldType);
 
3764
 
3079
3765
        Node := NodeIterator.Next;
 
3766
        while Node.IsInFold and (Node.fData.Classification <> fncHighlighter) do
 
3767
          Node := NodeIterator.Next;
3080
3768
        if not Node.IsInFold then
3081
3769
          break;
3082
3770
 
3083
3771
        NdInfo := NdiHelper1.Next;
3084
3772
        while NdiHelper1.IsValid and (not NdiHelper1.IsAtNodeOpenPos(Node)) do begin
3085
3773
          // Add unfolded nodes
3086
 
          if not(sfaDefaultCollapsed in NdInfo.FoldAction) then // Currently skip default nodes
 
3774
          if (NdInfo.FoldAction * [sfaInvalid, sfaDefaultCollapsed] = []) then // Currently skip default nodes
3087
3775
            FoldCoderForType(NdInfo.FoldType).AddNode
3088
3776
                                 (NdInfo.LogXStart, NdInfo.LineIndex, 0, scftOpen);
3089
3777
          NdInfo := NdiHelper1.Next;
3224
3912
        end;
3225
3913
        Coder := FoldCoderForType(NdInfo.FoldType);
3226
3914
        if coder <> nil then begin
3227
 
          i := LengthForFoldAtTextIndex(NdInfo.LineIndex, NdInfo.NodeIndex);
 
3915
          i := FoldProvider.InfoForFoldAtTextIndex(NdInfo.LineIndex, NdInfo.NodeIndex).LineCount;
3228
3916
          case coder.ReadNode(NdInfo.LogXStart, NdInfo.LineIndex, i) of
3229
3917
            scftFold:  FoldAtTextIndex(NdInfo.LineIndex, NdInfo.NodeIndex);
3230
3918
            scftHide:  FoldAtTextIndex(NdInfo.LineIndex, NdInfo.NodeIndex, 1, False, 0);
3249
3937
          continue;
3250
3938
 
3251
3939
        ndinfo :=NdiHelper1.GotoOpenAtChar(Line, entry.LogX);
3252
 
        Fl := LengthForFoldAtTextIndex(Line, ndinfo.NodeIndex);
 
3940
        Fl := FoldProvider.InfoForFoldAtTextIndex(Line, ndinfo.NodeIndex).LineCount;
3253
3941
        IsFold := (sfaFoldFold in NdInfo.FoldAction) and (entry.LinesFolded = FL);
3254
3942
        IsHide := (sfaFoldHide in NdInfo.FoldAction) and (entry.LinesFolded = FL + 1);
3255
3943
        if (sfaInvalid in ndinfo.FoldAction) or
3285
3973
  AVisibleLines: Integer = 1);
3286
3974
var
3287
3975
  NodeCount, top: Integer;
3288
 
  hl: TSynCustomFoldHighlighter;
3289
3976
  down: Boolean;
3290
3977
  NFolded: TSynTextFoldAVLNode;
3291
3978
  IsHide: Boolean;
 
3979
  fldinf: TSynEditFoldProviderNodeInfo;
3292
3980
begin
3293
 
  hl := TSynCustomFoldHighlighter(HighLighter);
3294
 
  if not assigned(hl) then
3295
 
    exit;
 
3981
  if not FoldProvider.FoldsAvailable then exit;
3296
3982
  top := TopTextIndex;
3297
3983
 
3298
3984
  // AStartIndex is 0-based
3320
4006
      continue;
3321
4007
    end;
3322
4008
 
 
4009
    // TODO: missing check, that hl-node is hideable
 
4010
    fldinf := FoldProvider.InfoForFoldAtTextIndex(AStartIndex, ColIndex, IsHide);
3323
4011
    if not NFolded.IsInFold then
3324
4012
      fFoldTree.InsertNewFold(AStartIndex+1+AVisibleLines, ColIndex,
3325
 
                              LengthForFoldAtTextIndex(AStartIndex, ColIndex, IsHide),
3326
 
                              AVisibleLines)
 
4013
                              fldinf.Column, fldinf.ColumnLen, fldinf.LineCount,
 
4014
                              AVisibleLines,
 
4015
                              fldinf.Classification, fldinf.FoldTypeCompatible)
3327
4016
    else
3328
4017
    if (AVisibleLines=0) and (not NFolded.IsHide) then begin
3329
4018
      // upgrade to hide
3330
4019
      fFoldTree.RemoveFoldForNodeAtLine(NFolded, -1);
3331
4020
      fFoldTree.InsertNewFold(AStartIndex+1, ColIndex,
3332
 
                              LengthForFoldAtTextIndex(AStartIndex, ColIndex, IsHide),
3333
 
                              AVisibleLines);
 
4021
                              fldinf.Column, fldinf.ColumnLen, fldinf.LineCount,
 
4022
                              AVisibleLines,
 
4023
                              fldinf.Classification, fldinf.FoldTypeCompatible);
3334
4024
    end;
3335
4025
    if down
3336
4026
    then dec(ColIndex)
3364
4054
  AVisibleLines: Integer = 1);
3365
4055
var
3366
4056
  top, c, r, r2 : Integer;
3367
 
  hl: TSynCustomFoldHighlighter;
3368
4057
  down: Boolean;
3369
4058
  NFolded: TSynTextFoldAVLNode;
3370
4059
begin
3371
 
  hl := TSynCustomFoldHighlighter(HighLighter);
3372
 
  if not assigned(hl) then
3373
 
    exit;
3374
4060
  top := TopTextIndex;
3375
4061
  c := FoldProvider.FoldOpenCount(AStartIndex);
3376
4062
 
 
4063
  //TODO move to FoldProvider
 
4064
  NFolded := fFoldTree.FindFoldForLine(AStartIndex+1, True);
 
4065
  while NFolded.IsInFold and (NFolded.StartLine = AStartIndex+1) do begin
 
4066
    if NFolded.FoldIndex + 1 > c then c := NFolded.FoldIndex + 1;
 
4067
    NFolded := fFoldTree.TreeForNestedNode(NFolded.fData, NFolded.StartLine).FindFoldForLine(AStartIndex, True);
 
4068
  end;
 
4069
 
 
4070
  if c < 1 then begin
 
4071
    // TODO: foldprovider to return all folded nodes, for hte line
 
4072
    ColCount := 0;
 
4073
  end;
 
4074
 
3377
4075
  r := -1;
3378
4076
  if ColCount = 0 then begin
3379
4077
    r := fFoldTree.RemoveFoldForLine(AStartIndex+AVisibleLines+1); // r is 1-based num of first (ex-)hidden line
3435
4133
 
3436
4134
procedure TSynEditFoldedView.FoldAll(StartLevel : Integer = 0; IgnoreNested : Boolean = False);
3437
4135
var
3438
 
  c, i, l, top, t: Integer;
 
4136
  c, i, top, t: Integer;
3439
4137
  hl: TSynCustomFoldHighlighter;
 
4138
  fldinf: TSynEditFoldProviderNodeInfo;
3440
4139
begin
3441
4140
  hl := TSynCustomFoldHighlighter(HighLighter);
3442
4141
  if not assigned(hl) then
3447
4146
  fFoldTree.Clear;
3448
4147
  i := 0;
3449
4148
  while i < fLines.Count do begin
3450
 
    if (hl.FoldOpenCount(i, t) > 0)
3451
 
    and (hl.FoldNestCount(i, t) > StartLevel) then begin
3452
 
      c := hl.FoldOpenCount(i) -1;
3453
 
      l := LengthForFoldAtTextIndex(i, c);
 
4149
    if (hl.FoldBlockOpeningCount(i, t) > 0)
 
4150
    and (hl.FoldBlockEndLevel(i, t) > StartLevel) then begin
 
4151
      c := hl.FoldBlockOpeningCount(i) -1;
 
4152
      fldinf := FoldProvider.InfoForFoldAtTextIndex(i, c);
3454
4153
      // i is 0-based
3455
4154
      // FoldTree is 1-based AND first line remains visble
3456
 
      fFoldTree.InsertNewFold(i+2, c, l, 1); // TODO: hide too? currently VisibleLines=1
 
4155
      fFoldTree.InsertNewFold(i+2, c, fldinf.Column, fldinf.ColumnLen, fldinf.LineCount, 1,
 
4156
                              fldinf.Classification, fldinf.FoldTypeCompatible); // TODO: hide too? currently VisibleLines=1
3457
4157
      if IgnoreNested then
3458
 
        i := i + l;
 
4158
        i := i + fldinf.LineCount;
3459
4159
    end;
3460
4160
    inc(i);
3461
4161
  end;
3468
4168
function TSynEditFoldedView.FixFolding(AStart: Integer; AMinEnd: Integer;
3469
4169
  aFoldTree: TSynTextFoldAVLTree): Boolean;
3470
4170
var
3471
 
  hl: TSynCustomFoldHighlighter;
3472
 
  FirstchangedLine: Integer;
 
4171
  FirstchangedLine, MaxCol: Integer;
 
4172
  SrcLineForFldInfos: Integer;
 
4173
  FldInfos: TSynEditFoldProviderNodeInfoList;
3473
4174
 
3474
4175
  function DoFixFolding(doStart: Integer; doMinEnd, AtColumn: Integer;
3475
4176
    doFoldTree: TSynTextFoldAVLTree; node: TSynTextFoldAVLNode) : Boolean;
3490
4191
    end;
3491
4192
 
3492
4193
  var
3493
 
    FldLine, FldIndex, FldLen, FldCol: Integer;
3494
 
    MaxCol, CurLen: Integer;
3495
 
    PrevFldLine: Integer;
 
4194
    FldSrcLine, FldSrcIndex, FLdNodeLine, FldLen, FndLen: Integer;
 
4195
    i, j, CurLen: Integer;
3496
4196
    SubTree: TSynTextFoldAVLTree;
3497
 
    IsHide: Boolean;
3498
4197
  begin
 
4198
    {$IFDEF SynFoldDebug}try DebugLnEnter(['>>FOLD-- DoFixFolding: doStart=', doStart, '  AMinEnd=',AMinEnd]);{$ENDIF}
 
4199
    {$IFDEF SynFoldDebug}aFoldTree.Debug;{$ENDIF}
3499
4200
    Result := False;
3500
 
    FldLine := doStart;
 
4201
    FldSrcLine := doStart;
3501
4202
    while node.IsInFold do begin
3502
 
      PrevFldLine := FldLine;
3503
 
      FldLine := node.SourceLine; // the 1-based cfCollapsed (last visible) Line (or 1st hidden)
3504
 
      FldIndex := FldLine - 1;
 
4203
      {$IFDEF SynFoldDebug}debugln(['>>FOLD-- Node StartLine=', node.StartLine, ' FoldColumn=', node.FoldColumn, ' FoldIndex=', node.FoldIndex, ' FullCount=', node.FullCount, ' Classification=', dbgs(node.Classification)]);{$ENDIF}
 
4204
      FldSrcLine := node.SourceLine; // the 1-based cfCollapsed (last visible) Line (or 1st hidden)
 
4205
      FLdNodeLine := node.StartLine; // the 1 based, first hidden line
 
4206
      FldSrcIndex := FldSrcLine - 1;
3505
4207
      FldLen := node.FullCount;
3506
4208
      if (FldLen <= 0) then begin
3507
 
        {$IFDEF SynFoldDebug}debugln(['>>FOLD-- FixFolding: Remove node with len<0 FldLine=', FldLine]);{$ENDIF}
 
4209
        {$IFDEF SynFoldDebug}debugln(['>>FOLD-- FixFolding: Remove node with len<0 FldSrcLine=', FldSrcLine]);{$ENDIF}
3508
4210
        DoRemoveNode(node);
3509
4211
        continue;
3510
4212
      end;
3511
4213
 
3512
 
      if (FldLine > PrevFldLine) then
 
4214
      //{$IFDEF SynAssertFold}
 
4215
      //With mixed fold/hide => line goes up/down
 
4216
      //SynAssert(FldSrcLine >= SrcLineForFldInfos, 'TSynEditFoldedView.FixFolding: FoldLine went backwards now %d was %d', [FldSrcLine, SrcLineForFldInfos]);
 
4217
      //{$ENDIF}
 
4218
      if (FldSrcLine <> SrcLineForFldInfos) then begin
 
4219
        // Next Line
 
4220
        SrcLineForFldInfos := FldSrcLine;
3513
4221
        AtColumn := 0;
3514
 
      // check the fold-length
3515
 
      MaxCol := FoldProvider.FoldOpenCount(FldIndex) - 1;
3516
 
      FldCol := node.FoldIndex;
3517
 
      IsHide := node.SourceLineOffset = 0;
3518
 
      if (FldCol < AtColumn) then FldCol := AtColumn;
3519
 
      if (FldCol <= MaxCol) and (FldCol >= AtColumn) and
3520
 
         (FldLen = LengthForFoldAtTextIndex(FldIndex, FldCol, IsHide)) then begin
3521
 
        CurLen := FldLen;
3522
 
      end
3523
 
      else if (FldCol - 1 <= MaxCol) and (FldCol > AtColumn) and (FldCol > 0) and
3524
 
         (FldLen = LengthForFoldAtTextIndex(FldIndex, FldCol - 1, IsHide)) then begin
3525
 
        CurLen := FldLen;
3526
 
        dec(FldCol);
3527
 
      end
3528
 
      else if (FldCol + 1 <= MaxCol) and (FldCol + 1 >= AtColumn) and
3529
 
         (FldLen = LengthForFoldAtTextIndex(FldIndex, FldCol + 1, IsHide)) then begin
3530
 
        CurLen := FldLen;
3531
 
        inc(FldCol);
3532
 
      end
3533
 
      else
3534
 
        CurLen := -1;
 
4222
                  // AtColumn is used for nodes, behing the HLs index-range (fncHighlighterEx, fncBlockSelection)
 
4223
                  // TODO: At Colum may be wrong for mixed fold/hide
 
4224
        FldInfos := FoldProvider.InfoListForFoldsAtTextIndex(FldSrcIndex, False);
 
4225
        MaxCol := length(FldInfos)-1;
 
4226
        {$IFDEF SynFoldDebug}debugln(['>>FOLD-- Got FldInfos for FldSrcIndex=', FldSrcIndex, ' MaxCol=', MaxCol]);{$ENDIF}
 
4227
      end;
3535
4228
 
3536
 
      if CurLen <> FldLen then begin
3537
 
        {$IFDEF SynFoldDebug}debugln(['>>FOLD-- FixFolding: Remove node with len<>len FldLine=', FldLine, ' curlen=',CurLen, ' FldLen=',FldLen]);{$ENDIF}
3538
 
        DoRemoveNode(node);
3539
 
        continue;
 
4229
      if node.fData.Classification in [fncHighlighter, fncHighlighterEx] then begin
 
4230
        // find node in list
 
4231
        i := -1;
 
4232
        while (i < MaxCol) do begin
 
4233
          inc(i);
 
4234
          if (FldInfos[i].Classification <> fncHighlighter) or
 
4235
             (FldInfos[i].FoldTypeCompatible <> node.fData.FoldTypeCompatible)
 
4236
          then
 
4237
            continue;
 
4238
          FndLen := -1;
 
4239
          j := abs(FldInfos[i].Column - node.FoldColumn);
 
4240
          if (j > 0) and (j < node.FoldColumnLen) then begin
 
4241
            //maybe
 
4242
            FndLen := FoldProvider.FoldLineLength(FldSrcIndex, i);
 
4243
            if node.IsHide then inc(FndLen);
 
4244
            if FndLen <> node.FullCount then Continue;
 
4245
            {$IFDEF SynFoldDebug}debugln('******** FixFolding: Adjusting x pos');{$ENDIF}
 
4246
            //FldInfos[i].Column := node.FoldColumn;
 
4247
          end;
 
4248
          if (FndLen > 0) or (FldInfos[i].Column = node.FoldColumn) then begin
 
4249
            if FndLen < 0 then begin
 
4250
              FndLen := FoldProvider.FoldLineLength(FldSrcIndex, i);
 
4251
              if node.IsHide then inc(FndLen);
 
4252
            end;
 
4253
            if abs(FndLen - node.FullCount) > 1 then continue;
 
4254
            if (node.fData.Classification <> fncHighlighter) or
 
4255
               (node.FoldColumn <> FldInfos[i].Column) or
 
4256
               (node.FoldIndex <> i)
 
4257
            then
 
4258
              Result := true;
 
4259
            {$IFDEF SynFoldDebug}if (node.fData.Classification <> fncHighlighter) then debugln(['>>FOLD-- FixFolding: set Node to fncHighlighter (FOUND) FldSrcLine=', FldSrcLine]);{$ENDIF}
 
4260
            node.fData.Classification :=  fncHighlighter;
 
4261
            node.FoldColumn := FldInfos[i].Column;
 
4262
            node.fData.FoldIndex := i;
 
4263
            i := -1;
 
4264
            break;
 
4265
          end;
 
4266
        end;
 
4267
        if i = MaxCol then begin
 
4268
          {$IFDEF SynFoldDebug}debugln(['>>FOLD-- FixFolding: set Node to fncHighlighterEx (NOT FOUND) FldSrcLine=', FldSrcLine]);{$ENDIF}
 
4269
          node.fData.Classification :=  fncHighlighterEx;
 
4270
          node.fData.FoldIndex := MaxCol + AtColumn;
 
4271
          inc(AtColumn);
 
4272
          Result := True;
 
4273
        end;
 
4274
      end
 
4275
      else begin
 
4276
        if node.fData.FoldIndex <> MaxCol + AtColumn then
 
4277
          Result := True;
 
4278
        node.fData.FoldIndex := MaxCol + AtColumn;
 
4279
        inc(AtColumn);
3540
4280
      end;
3541
 
      node.fData.FoldIndex := FldCol;
3542
 
      AtColumn := FldCol + 1;
3543
4281
 
3544
4282
      if (node.fData.Nested <> nil) then begin
3545
 
        SubTree := doFoldTree.TreeForNestedNode(node.fData, FldLine+1);
 
4283
        SubTree := doFoldTree.TreeForNestedNode(node.fData, FLdNodeLine);
3546
4284
        CurLen := node.MergedLineCount;
3547
 
        if DoFixFolding(FldLine, FldLine + CurLen + 1, AtColumn, SubTree, SubTree.FindFirstFold)
 
4285
        if DoFixFolding(FldSrcLine, FLdNodeLine + CurLen, AtColumn, SubTree, SubTree.FindFirstFold)
3548
4286
        then begin
3549
4287
          if CurLen > FldLen then begin
3550
4288
            node.fData.MergedLineCount:= max(node.FullCount,
3552
4290
            if CurLen <> node.MergedLineCount then
3553
4291
              node.fData.AdjustParentLeftCount(node.MergedLineCount - CurLen);
3554
4292
          end;
3555
 
          continue;
3556
4293
        end;
3557
4294
      end;
3558
4295
 
3560
4297
      if node.StartLine >= doMinEnd then break;
3561
4298
      node := node.Next;
3562
4299
    end;
 
4300
    {$IFDEF SynFoldDebug}finally DebugLnExit(['<<FOLD-- DoFixFolding: DONE=', Result]); end{$ENDIF}
3563
4301
  end;
3564
4302
 
3565
4303
var
3566
4304
  node, tmpnode: TSynTextFoldAVLNode;
3567
4305
begin
3568
 
  {$IFDEF SynFoldDebug}debugln(['>>FOLD-- FixFolding: Start=', AStart, '  AMinEnd=',AMinEnd]);{$ENDIF}
 
4306
  {$IFDEF SynFoldDebug}try DebugLnEnter(['>>FOLD-- FixFolding: Start=', AStart, '  AMinEnd=',AMinEnd]);{$ENDIF}
3569
4307
  Result := false;
3570
4308
  if fLockCount > 0 then begin
3571
4309
    fNeedCaretCheck := true; // We may be here as a result of lines deleted/inserted
3575
4313
    exit;
3576
4314
  end;
3577
4315
 
3578
 
  hl := TSynCustomFoldHighlighter(HighLighter);
3579
 
  if not assigned(hl) then begin
3580
 
    CalculateMaps;
3581
 
    exit;
3582
 
  end;
3583
 
 
3584
4316
  node := aFoldTree.FindFoldForLine(aStart, true);
3585
4317
  if not node.IsInFold then node:= aFoldTree.FindLastFold;
3586
4318
  if not node.IsInFold then begin
3598
4330
  end;
3599
4331
 
3600
4332
  FirstchangedLine := -1;
 
4333
  FldInfos := nil;
 
4334
  MaxCol := -1;
 
4335
  SrcLineForFldInfos := -1;
3601
4336
  Result := DoFixFolding(-1, AMinEnd, 0, aFoldTree, node);
3602
4337
  CalculateMaps;
3603
4338
  if Assigned(fOnFoldChanged) and (FirstchangedLine >= 0) then
3604
4339
    fOnFoldChanged(FirstchangedLine);
3605
 
  {$IFDEF SynFoldDebug}debugln(['<<FOLD-- FixFolding: DONE=', Result]);{$ENDIF}
 
4340
  {$IFDEF SynFoldDebug}finally DebugLnExit(['<<FOLD-- FixFolding: DONE=', Result]); end{$ENDIF}
3606
4341
end;
3607
4342
 
3608
4343
procedure TSynEditFoldedView.DoCaretChanged(Sender : TObject);
3621
4356
 
3622
4357
procedure TSynEditFoldedView.LineCountChanged(Sender: TSynEditStrings; AIndex, ACount : Integer);
3623
4358
begin
3624
 
  {$IFDEF SynFoldDebug}debugln(['FOLD-- LineCountChanged AIndex=', AIndex, '  Acount=',ACount]);{$ENDIF}
 
4359
  {$IFDEF SynFoldDebug}try DebugLnEnter(['>> FOLD-- LineCountChanged AIndex=', AIndex, '  Acount=',ACount]);{$ENDIF}
3625
4360
  // no need for fix folding => synedit will be called, and scanlines will call fixfolding
3626
4361
  {TODO: a "need fix folding" flag => to ensure it will be called if synedit doesnt
3627
4362
         SynEdit.ScanRanges, calls Fixfolding as workaroound => review
3631
4366
    if (ACount < 0) and (AIndex < fNeedFixFrom) then inc(fNeedFixFrom, ACount);
3632
4367
    if (ACount > 0) and (AIndex < fNeedFixMinEnd) then inc(fNeedFixMinEnd, ACount);
3633
4368
  end;
 
4369
  if fLines.IsInEditAction then exit;
3634
4370
  if ACount<0
3635
 
  then LinesDeletedAtTextIndex(AIndex, -ACount, true)
3636
 
  else LinesInsertedAtTextIndex(AIndex, ACount, true);
 
4371
  then LinesDeletedAtTextIndex(AIndex+1, -ACount, 1, true)
 
4372
  else LinesInsertedAtTextIndex(AIndex+1, ACount, 1, true);
 
4373
  {$IFDEF SynFoldDebug}finally DebugLnExit(['<< FOLD-- LineCountChanged']); end;{$ENDIF}
 
4374
end;
 
4375
 
 
4376
procedure TSynEditFoldedView.LinesCleared(Sender: TObject);
 
4377
begin
 
4378
  UnfoldAll;
 
4379
end;
 
4380
 
 
4381
procedure TSynEditFoldedView.LineEdited(Sender: TSynEditStrings; aLinePos, aBytePos, aCount,
 
4382
  aLineBrkCnt: Integer; aText: String);
 
4383
begin
 
4384
  {$IFDEF SynFoldDebug}try DebugLnEnter(['>> FOLD-- LineEditied aLinePos=', aLinePos, ' aBytePos=', aBytePos, '  Acount=',ACount, ' aLineBrkCnt=',aLineBrkCnt]);{$ENDIF}
 
4385
  if aLineBrkCnt<0
 
4386
  then LinesDeletedAtTextIndex(aLinePos, -aLineBrkCnt, ABytePos, true)
 
4387
  else if aLineBrkCnt > 0
 
4388
  then LinesInsertedAtTextIndex(aLinePos, aLineBrkCnt, ABytePos, true)
 
4389
  else begin
 
4390
    fFoldTree.AdjustColumn(aLinePos, aBytePos, aCount);
 
4391
    //if not(SkipFixFolding) then FixFoldingAtTextIndex(AStartIndex, AStartIndex+ALineCount+1)
 
4392
    //else
 
4393
    //if aLinePos < top + ALineCount then CalculateMaps;
 
4394
  end;
 
4395
  {$IFDEF SynFoldDebug}finally DebugLnExit(['<< FOLD-- LineEditied']); end;{$ENDIF}
3637
4396
end;
3638
4397
 
3639
4398
procedure TSynEditFoldedView.FixFoldingAtTextIndex(AStartIndex: Integer; AMinEndLine : Integer);
3641
4400
  FixFolding(AStartIndex + 1, AMinEndLine, fFoldTree);
3642
4401
end;
3643
4402
 
3644
 
function TSynEditFoldedView.OpenFoldCount(aStartIndex: Integer): Integer;
 
4403
function TSynEditFoldedView.OpenFoldCount(aStartIndex: Integer; AType: Integer = 0): Integer;
3645
4404
// Todo: move entirely to FoldProvider
3646
4405
var
3647
4406
  hl: TSynCustomFoldHighlighter;
3649
4408
  hl := TSynCustomFoldHighlighter(HighLighter);
3650
4409
  if not assigned(hl) then
3651
4410
    exit(-1);
3652
 
  Result := hl.FoldNestCount(AStartIndex-1) + FoldProvider.FoldOpenCount(AStartIndex);
 
4411
  Result := hl.FoldBlockEndLevel(AStartIndex-1, AType) + FoldProvider.FoldOpenCount(AStartIndex);
3653
4412
end;
3654
4413
 
3655
 
function TSynEditFoldedView.OpenFoldInfo(aStartIndex, ColIndex: Integer): TFoldViewNodeInfo;
 
4414
function TSynEditFoldedView.OpenFoldInfo(aStartIndex, ColIndex: Integer; AType: Integer = 0): TFoldViewNodeInfo;
3656
4415
var
3657
4416
  hl: TSynCustomFoldHighlighter;
3658
4417
  TypeCnt, Lvl: Integer;
3659
4418
  EndLvl, CurLvl: Array of integer;
3660
 
  i, t, n, o: Integer;
 
4419
  i, c, t, n, o: Integer;
3661
4420
  nd: TSynFoldNodeInfo;
3662
4421
  procedure GetEndLvl(l: Integer);
3663
4422
  var i: integer;
3664
4423
  begin
3665
 
    for i := 1 to TypeCnt do begin
3666
 
      EndLvl[i] := hl.FoldNestCount(l-1, i);
3667
 
      EndLvl[i] := EndLvl[i] + FoldProvider.FoldOpenCount(l, i);
3668
 
      CurLvl[i] := EndLvl[i];
 
4424
    if AType = 0 then begin;
 
4425
      for i := 1 to TypeCnt do begin
 
4426
        EndLvl[i] := hl.FoldBlockEndLevel(l-1, i);
 
4427
        EndLvl[i] := EndLvl[i] + FoldProvider.FoldOpenCount(l, i);
 
4428
        CurLvl[i] := EndLvl[i];
 
4429
      end;
3669
4430
    end
 
4431
    else begin
 
4432
      EndLvl[0] := hl.FoldBlockEndLevel(l-1, AType);
 
4433
      EndLvl[0] := EndLvl[0] + FoldProvider.FoldOpenCount(l, AType);
 
4434
      CurLvl[0] := EndLvl[0];
 
4435
    end;
3670
4436
  end;
3671
4437
begin
3672
4438
  hl := TSynCustomFoldHighlighter(HighLighter);
3673
4439
  if not assigned(hl) then
3674
4440
    exit;
3675
4441
 
3676
 
  TypeCnt := hl.FoldTypeCount;
3677
 
  Lvl := hl.FoldNestCount(AStartIndex-1);
3678
 
  i := 0;
 
4442
  if AType <> 0 then
 
4443
    TypeCnt := 1
 
4444
  else
 
4445
    TypeCnt := hl.FoldTypeCount;
 
4446
  Lvl := hl.FoldBlockEndLevel(AStartIndex-1, AType);
3679
4447
  if ColIndex >= Lvl then begin
3680
4448
    n := ColIndex - Lvl;
3681
 
    o :=  hl.FoldNodeInfoCount[aStartIndex, [sfaOpen, sfaFold]];
3682
 
    nd := hl.FoldNodeInfo[aStartIndex, n, [sfaOpen, sfaFold]];
 
4449
    if AType = 0 then begin
 
4450
      o :=  hl.FoldNodeInfo[aStartIndex].CountEx([sfaOpen, sfaFold]);
 
4451
      nd := hl.FoldNodeInfo[aStartIndex].NodeInfoEx(n, [sfaOpen, sfaFold]);
 
4452
    end else begin
 
4453
      // no sfaFold
 
4454
      o :=  hl.FoldNodeInfo[aStartIndex].CountEx([sfaOpen],AType);
 
4455
      nd := hl.FoldNodeInfo[aStartIndex].NodeInfoEx(n, [sfaOpen], AType);
 
4456
    end;
3683
4457
  end
3684
4458
  else begin
3685
4459
    SetLength(EndLvl, TypeCnt+1);
3686
4460
    SetLength(CurLvl, TypeCnt+1);
3687
4461
    GetEndLvl(aStartIndex);
3688
 
    aStartIndex := aStartIndex + i;
 
4462
    aStartIndex := aStartIndex;
3689
4463
    while (ColIndex < Lvl) and (aStartIndex > 0) do begin
3690
4464
      dec(aStartIndex);
3691
 
      o := hl.FoldOpenCount(AStartIndex);
3692
 
      if (o > 0) or (hl.FoldCloseCount(aStartIndex) > 0) then begin
 
4465
      o := hl.FoldBlockOpeningCount(AStartIndex, AType);
 
4466
      if (o > 0) or (hl.FoldBlockClosingCount(aStartIndex, AType) > 0) then begin
3693
4467
        n := o;
3694
 
        for i := hl.FoldNodeInfoCount[aStartIndex, []] - 1 downto 0 do begin
3695
 
          nd := hl.FoldNodeInfo[aStartIndex, i, []];
3696
 
          if not(sfaFold in nd.FoldAction) then
 
4468
        c := hl.FoldNodeInfo[aStartIndex].CountEx([], AType) - 1;
 
4469
        for i := c downto 0 do begin
 
4470
          nd := hl.FoldNodeInfo[aStartIndex].NodeInfoEx(i, [], AType);
 
4471
          if (AType = 0) and not(sfaFold in nd.FoldAction) then
3697
4472
            continue;
3698
 
          t := nd.FoldGroup;
 
4473
          if AType = 0 then
 
4474
            t := nd.FoldGroup
 
4475
          else
 
4476
            t := 0;
3699
4477
          if sfaOpen in nd.FoldAction then begin
3700
4478
            dec(n);
3701
4479
            dec(CurLvl[t]);
3713
4491
        end;
3714
4492
      end
3715
4493
      else
3716
 
      if hl.FoldNestCount(AStartIndex-1) = 0 then break;
 
4494
      if hl.FoldBlockEndLevel(AStartIndex-1, AType) = 0 then break;
3717
4495
    end;
3718
4496
  end;
3719
4497
  Result.HNode := nd;
3739
4517
    exit;
3740
4518
 
3741
4519
  i := ALine;
3742
 
  l := hl.FoldOpenCount(i - 1);
 
4520
  l := hl.FoldBlockOpeningCount(i - 1);
3743
4521
  if l > 0 then begin
3744
4522
    node := fFoldTree.FindFoldForLine(ALine, true);
3745
4523
    if node.IsInFold and (node.StartLine = ALine +1) then begin
3753
4531
    else
3754
4532
      exit(ALine);
3755
4533
  end
3756
 
  else if hl.FoldCloseCount(i - 1) > 0 then
 
4534
  else if hl.FoldBlockClosingCount(i - 1) > 0 then
3757
4535
    dec(i);
3758
 
  if (i < 0) or (hl.FoldNestCount(i-1) = 0) then
 
4536
  if (i < 0) or (hl.FoldBlockEndLevel(i-1) = 0) then
3759
4537
    exit;
3760
4538
 
3761
4539
  l := 0;
3762
4540
  while (i > 0) and (l >= 0) do begin // (FoldMinLevel[i] >= l) do
3763
4541
    dec(i);
3764
 
    l := l - hl.FoldOpenCount(i);
 
4542
    l := l - hl.FoldBlockOpeningCount(i);
3765
4543
    if l >= 0 then
3766
 
      l := l + hl.FoldCloseCount(i);
 
4544
      l := l + hl.FoldBlockClosingCount(i);
3767
4545
  end;
3768
 
  if (hl.FoldNestCount(i) > 0) then // TODO, check for collapsed at index = 0
 
4546
  if (hl.FoldBlockEndLevel(i) > 0) then // TODO, check for collapsed at index = 0
3769
4547
    Result := i + 1;
3770
4548
end;
3771
4549
 
3794
4572
  end;
3795
4573
end;
3796
4574
 
 
4575
function dbgs(AClassification: TFoldNodeClassification): String;
 
4576
begin
 
4577
  WriteStr(Result{%H-}, AClassification);
 
4578
end;
 
4579
 
3797
4580
{$IFDEF SynDebug}
3798
4581
procedure TSynEditFoldedView.debug;
3799
4582
begin
3803
4586
 
3804
4587
initialization
3805
4588
  InitNumEncodeValues;
 
4589
  //SYN_FOLD_DEBUG := DebugLogger.RegisterLogGroup('SynFoldDebug' {$IFDEF SynFoldDebug} , True {$ENDIF} );
3806
4590
 
3807
4591
end.
3808
4592