Recent

Author Topic: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}  (Read 111298 times)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5695
    • wiki
Hi @x2nie. I have already designed a folding-highlighter: https://github.com/t-edson/SynFacilSyn
In it, the support for folding is not as good as I wanted, mainly because of some limitation I found in TSynCustomFoldHighlighter.
Summarizing, I wanted this class understood about block of syntax, but it only knows about showing folding marks on the gutter > >:(.

I am not exactly sure what you try to describe?

But the HL only provides what is foldable. It does not provide the GUI to fold it.
1) It is possible to fold code by clicking on the text (e.g. "begin"). Use advanced mouse settings.
2) you can write alternative gutter part code
3) you can write a markup to colorize fold keywords.

what you currently can not do, is to draw a [ + ] or other sign, in the middle of the text.

Edson

  • Hero Member
  • *****
  • Posts: 1055
Hi Martin,

I didn't worry, and I don't worry about the way the user interact with the folding or how it's shown in the gutter.

I was talking about some limitations (Maybe "features not implemented" sounds better) of TSynCustomFoldHighlighter:

1: There is not way to obtain the total of blocks opened (IIRC FoldIndex only count the opened with folding mark). I know Pascal HL do  :D.
2. There is not a way to know if a block was opened and closed at the same line. I know Pascal HL do  :-\.
3. (This is a new feature I wish) I would like to have some facilities to close a block before a token starts (http://forum.lazarus.freepascal.org/index.php/topic,23411.msg139608.html#msg139608). I know Pascal HL do  :o.

Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
I wanted this class understood about block of syntax, but it only knows about showing folding marks on the gutter .
I am not exactly sure what you try to describe?
... the HL only provides what is foldable. It does not provide the GUI to fold it.
I felt understood what Edson refer to.
That is, TSynCustomFoldHighlighter ("the HL") provides which "block" is foldable: by searching the fold level for each line.
Therefore, knowing the LineIndex is enough for TSynCustomFoldHighlighter it self to make foldable feature works.

But, for ancestor (like Edson own), it seem not enough. Because it also need to know the column index too for their internal work (such differentiate coloring per block-fold according to it's fold-dept).
(and another problem begun here!  :P )


Simply, the difference is about how to define of a "block".
Let make it simple, Suppose this code:
Code: Pascal  [Select]
  1. procedure Foo();
  2. begin
  3.     if Bar() then
  4.     begin                         // "inner-block" start
  5.         var_bean := const_nut;    // "inner block" inside
  6.         var_coffee := const_nut;    // "inner block" inside
  7.    end                           // "inner-block"  finish
  8.     else
  9.        var_bean := const_jar;
  10. end;
  11.  
  12. 0        1         2
  13. 12345678901234567890

All with excluding comment-statements will be :
  • TSynCustomFoldHighlighter recognizse the inner-block as ->> start=4, finish=7  // require Line Index only. column position are ignored
  • While another HL may defines inner block as ->> start = [4,5] ,finish= [7,6]      // require [LineIndex, ColumnIndex] = [Y,X]
  • But any other HL may also defines it as ->> start = [4,1] ,finish=[7,6]               // whole lines that will be hidden when folding
  • Again, more other HL may also defines as ->> start = [4,10]  ,finish=[7,3]          // Y,X ; the 'begin' and 'end' tags are excluded
  • Further, newer HL may recognize the "syntax block" in vary combination, up to the author needs.
  • My SynEditMarkupColor will define inner block as ->> start=[5,9,4] ->> finish=[4,6,7]  // format = [X1, X2, Y] ; the 'begin' and 'end' part only.
The new problem begun here! which problem?
when 'begin' is mixed with other block:
Code: Pascal  [Select]
  1. procedure Foo();
  2. begin
  3.     if Bar() then begin                      // "inner-block" start
  4.         var_bean := const_nut;    // "inner block" inside
  5.         var_coffee := const_nut;    // "inner block" inside
  6.     end                           // "inner-block"  finish
  7.     else       var_bean := const_jar;
  8. end;
  9. 0        1         2
  10. 12345678901234567890
.. the sum of combination of how to define the block exploded! TSynCustomFoldHighlighter souldn't care about it, right?

Summary:
  • Providing the "line index only" of each code-fold-block is not enough for some TSynCustomFoldHighlighter's ancestor.
  • By there are differences to define a start~finish of a block, so the TSynCustomFoldHighlighter is not the correct place to define this field.
  • Even if we could make TSynCustomFoldHighlighter as the right place to store this info, only the syntax-parser know where the exact "column" is, because the chance of calling StartCodeFoldBlock/EndCodeFoldBlock is finally up to the ancestor.
    FYI: This is the reason I reorder some lines of my SynHighlighterLFM2.pas : because Inc(Run); shall be called before StartCodeFoldBlock() / EndCodeFoldBlock()
  • But if everything is up to ancestor, it will be very hard job for ancestor (actually the author) to implement polymorphism of such automatic-fold-block (the columns) definition.
Feel contradiction, eh?
I think the compromised approach is to make TSynCustomFoldHighlighter holds everything, except the fold-block-definition. Wow, sexy right?
It is sexy because no matter columns definition, the TSynCustomFoldHighlighter it self doesn't need it, wouldn't change it, wouldn't be disturbed.
Meaning: we can  reuse all things implemented in current version, while those new fields added.
The ancestor (such TmySynLFMSyn2) is the who only take care about what data stored there and how to make them useful.


Enough of theory, give me the code (Linus said).
Code: Pascal  [Select]
  1. function TSynLFMSyn.StartLfmCodeFoldBlock(ABlockType: TLfmCodeFoldBlockType): TSynCustomCodeFoldBlock;
  2. var
  3.   FoldBlock: Boolean;
  4.   p: PtrInt;
  5. begin
  6.   FoldBlock :=  FFoldConfig[ord(ABlockType)].Enabled;
  7.   p := 0;
  8.   if not FoldBlock then
  9.     p := PtrInt(CountLfmCodeFoldBlockOffset);
  10.   //Result := StartCodeFoldBlock(p + Pointer(PtrInt(ABlockType)), FoldBlock);
  11.   Result := StartCodeFoldBlock(FTokenPos, Run, p + Pointer(PtrInt(ABlockType)), FoldBlock);
  12. end;
  13.  
  14.  
  15. procedure TSynLFMSyn.EndLfmCodeFoldBlock;
  16. var
  17.   DecreaseLevel: Boolean;
  18. begin
  19.   DecreaseLevel := TopCodeFoldBlockType < CountLfmCodeFoldBlockOffset;
  20.   //EndCodeFoldBlock(DecreaseLevel);
  21.   EndCodeFoldBlock(FTokenPos, Run, DecreaseLevel);
  22. end;
This is, the ancestor is given a chance by TSynCustomFoldHighlighter to tell the X and X2 (columns).
The Y (LineIndex) is already know by TSynCustomFoldHighlighter, so no need to ask as parameter.
But how to make X and X2 usefull, is completely up to ancestor since TSynCustomFoldHighlighter may ignore the columns value.


---
Conclusion:
The absent of columns info on TSynCustomFoldHighlighter is not a bug, nor it is "feature not implemented"
IMHO it was rather intended by design. see the above problem.
But, once we can generalized the need as "X1,X2,Y" values, we can add this new feature.
« Last Edit: December 10, 2015, 05:03:49 am by x2nie »
When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
...I have the feeling..,  the feature you are implementing need to know about the syntax of the language.
No, it wouldn't.


1. : I have satisfied with current progress of my coloring SynMarkup, which is the keywords doesn't colored. only 'begin' and 'end' is colored.
Anyway, The Markup doesn't scan/parse any programming syntax.
Nor it require of such knowledge of any specific programming language syntax to do markup (coloring)'s job.
Therefore, if/then/else/for/while/case/... is not colored here. But I am happy with this, since the keywords was already black+bold.


2. : Once I really need to color the pascal keyword according to depth of pascal statements,
 the synMarkup will only need to ask to HL about: at where coordinate should be painted with what color.
Hence "what color" is assumed by the Markup it self, HL only told some info such : its a opening-fold, it's the 2nd level of fold-dept, etc.

Quote
Maybe it's better open a new thread "Modernizing the TSynCustomFoldHighlighter class"  :-\ .
Yeah, good idea.
I am in beginning of collecting as much as possible ideas + many of conflicting requirement of new fold HL.
When it done, I will provide a patch / open new topic.
« Last Edit: December 10, 2015, 05:42:09 am by x2nie »
When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5695
    • wiki
very quick note / I go into more details (and all the other questions) later.
----------------------------

about the x position.

It is intentionally NOT stored. not even in the pas HL. The idea is to store less data. (yet each HL can decide to store added info, though the range is not a good place for it, as each range should by design apply to as many lines of code as possible, and should be re-used).

X can be calculated. Each HL can implement the same as the pas hl.

the procedure for getting the calculated x is in the TSynCustomFoldHighlighter , so if a HL overrides it, it will work.

Adding common code to TSynCustomFoldHighlighter, so it needn't be copied into each hl can be done, but it is not a show stopper.

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
Furthest progress: I have merged my middleware-HL into TSynCustomFoldHighlighter.


Known issue:
- FFoldConfig aren't yet supported. I don't have have idea when user gives nil as ABlockType.
- SingleLine still appears as foldable everywhere, but when is clicked the folded area is wrong (see LFM tab)
- TSynPasSyn is untouched.


- since pascal HL is kept unmodified, I keep both old way and the new way,
 the side effect of this keeping two gate, the old way call shall implement it's own NestFoldLevels.
For example:  FoldHL.pas (shipped with lazarus) doesn't work; see my FoldHL.pas for what is difference.
I reenabled the Fold tab, but now the error occured on XML tab. I wouldn't resolve it.
My priority is now going to pascal HL.

Code: Pascal  [Select]
  1. // Open/Close Folds
  2. //old gate:
  3. function StartCodeFoldBlock(ABlockType: Pointer;
  4.         IncreaseLevel: Boolean = true): TSynCustomCodeFoldBlock; virtual; overload;
  5. procedure EndCodeFoldBlock(DecreaseLevel: Boolean = True); virtual;
  6.  
  7.  
  8. //new gate:
  9. function StartCodeFoldBlock(LogX1,LogX2 : Integer; ABlockType: Pointer=nil;
  10.         IncreaseLevel: Boolean = true): TSynCustomCodeFoldBlock; virtual; overload;
  11. procedure EndCodeFoldBlock(LogX1,LogX2 : Integer;
  12.         DecreaseLevel: Boolean = True); virtual; overload;  
I think we should drop the old gate, and only accept the new one ?


-----

The code can be downloaded:
https://github.com/x2nie/syneditmarkupnestedcolors/blob/master/SynEdit-modified/synedithighlighterfoldbase.pas


svn: https://github.com/x2nie/syneditmarkupnestedcolors
git: https://github.com/x2nie/syneditmarkupnestedcolors
zip: https://github.com/x2nie/syneditmarkupnestedcolors/archive/master.zip

« Last Edit: December 10, 2015, 05:58:53 pm by x2nie »
When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5695
    • wiki
I was talking about some limitations (Maybe "features not implemented" sounds better) of TSynCustomFoldHighlighter:

1: There is not way to obtain the total of blocks opened (IIRC FoldIndex only count the opened with folding mark). I know Pascal HL do  :D.
You can add tracking them like pas-hl, but as I said maybe pas-hl can even get rid of it. Yet even then your hl can add it. It is not a feature that all HL need, so it still is open if or where to add it
Or simply walk up parent links and count.
Quote
2. There is not a way to know if a block was opened and closed at the same line. I know Pascal HL do  :-\.
then there is a way, isn't there?
If you are closing a fold, and after closing you are greater or equal to the MinFoldLevel, then it was opened on the same line.
MinFoldLevel must be maintained (after each of the above compare):
- it starts (at the start of line) with the current fold level.
- if you close a block and you get below it, then lower it too
That is assuming you process from left to right.
Quote
3. (This is a new feature I wish) I would like to have some facilities to close a block before a token starts (http://forum.lazarus.freepascal.org/index.php/topic,23411.msg139608.html#msg139608). I know Pascal HL do  :o.
like the "var" folding?
Code: Pascal  [Select]
  1. procedure a;
  2. var
  3.   i: boolean;
  4. begin
The "begin" closes the var block. But it is not part of it.
Search LastLinePasFoldLevelFix. But you can only go one line back (if there are empty lines they must be in the fold.
The importance is, that if a line (e.g. line 30) changes, the HL needs to tell the editor that the line above changed. See the comment in
  procedure TSynCustomHighlighter.ScanRanges;
that needs to be made optional.


Therefore, knowing the LineIndex is enough for TSynCustomFoldHighlighter it self to make foldable feature works.
But, for ancestor (like Edson own), it seem not enough. Because it also need to know the column index too for their internal work (such differentiate coloring per block-fold according to it's fold-dept).
(and then example code....)

This is about moving the CatchNodeInfo into the TSynCustomFoldHighlighter?

Because all x pos can be gotten with CatchNodeInfo, only currently each HL needs to implement from scratch.
Quote
Code: Pascal  [Select]
  1.   Result := StartCodeFoldBlock(FTokenPos, Run, p + Pointer(PtrInt(ABlockType)), FoldBlock);
Do not pass the data as param. It is only needed if CatchNodeInfo is on.

Define a virtual method that gets the boundaries, override it each HL (just a few lines of code), and TSynCustomFoldHighlighter can call it and get the info.


- SingleLine still appears as foldable everywhere, but when is clicked the folded area is wrong (see LFM tab)
still happening?
Quote
For example:  FoldHL.pas (shipped with lazarus) doesn't work; see my FoldHL.pas for what is difference.
ups then it needs to be fixed. Do you have a patch.
Please report a bug. (with or without patch)
Quote
Code: Pascal  [Select]
  1. //new gate:
  2. function StartCodeFoldBlock(LogX1,LogX2 : Integer; ABlockType: Pointer=nil;
  3.         IncreaseLevel: Boolean = true): TSynCustomCodeFoldBlock; virtual; overload;
  4. procedure EndCodeFoldBlock(LogX1,LogX2 : Integer;
  5.         DecreaseLevel: Boolean = True); virtual; overload;  
I think we should drop the old gate, and only accept the new one ?
see comment above. Keep old interface, and define a getter.
Quote
The code can be downloaded:
https://github.com/x2nie/syneditmarkupnestedcolors/blob/master/SynEdit-modified/synedithighlighterfoldbase.pas
Eventually a patch will be needed.

But for now you can keep it there.
« Last Edit: December 10, 2015, 10:47:30 pm by Martin_fr »

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
Therefore, knowing the LineIndex is enough for TSynCustomFoldHighlighter it self to make foldable feature works.
But, for ancestor (like Edson own), it seem not enough. Because it also need to know the column index too for their internal work (such differentiate coloring per block-fold according to it's fold-dept).
(and then example code....)

This is about moving the CatchNodeInfo into the TSynCustomFoldHighlighter?

Because all x pos can be gotten with CatchNodeInfo, only currently each HL needs to implement from scratch.
I think No, its not about the normal way of how to get x pos.
(normal = sample code = finding X,Y as such in TSynEditMarkupWordGroup.FindMatchingWords() ).


Rather, there is a need to find the pair of opening~closing fold tag in simplest way!
You know, in FindMatchingWords: FindEndNode / FindStartNode methods are too complicated for such this easy task: get opening~closing fold tag.
(simplest = storing that (opening+closing fold tag) info into whether a CodeFoldBlock or into each FoldRange?).


So, normal way is bad (or at least : not optimized) because this way is finding through too many lines (assumed 10000 lines) until it match.
Storing that info will save time and battery. :)p
Code: Pascal  [Select]
  1.   function FindEndNode(StartNode: TSynFoldNodeInfo;
  2.                        var YIndex, NIndex: Integer): TSynFoldNodeInfo;
  3.     function SearchLine(ALineIdx: Integer; var ANodeIdx: Integer): TSynFoldNodeInfo;
  4.     begin
  5.       NodeList.Line := ALineIdx;
  6.       repeat
  7.         inc(ANodeIdx);
  8.         Result := NodeList[ANodeIdx];
  9.       until (sfaInvalid in Result.FoldAction)
  10.          or (Result.NestLvlEnd <= StartNode.NestLvlStart);
  11.     end;
  12.   begin
  13.     Result := SearchLine(YIndex, NIndex);
  14.     if not (sfaInvalid in Result.FoldAction) then
  15.       exit;
  16.  
  17.  
  18.     inc(YIndex);
  19.     while (YIndex < LCnt) and
  20.           (HL.FoldBlockMinLevel(YIndex, StartNode.FoldGroup, [sfbIncludeDisabled])
  21.            > StartNode.NestLvlStart)
  22.     do
  23.       inc(YIndex);
  24.     if YIndex = LCnt then
  25.       exit;
  26.  
  27.  
  28.     NIndex := -1;
  29.     Result := SearchLine(YIndex, NIndex);
  30.  
  31.  
  32.     if (Result.LogXEnd = 0) or (sfaLastLineClose in Result.FoldAction) then
  33.       Result.FoldAction := [sfaInvalid]; // LastLine closed Node(maybe force-closed?)
  34.   end;      
The very bad code in #19..23
Even if there was no alternative way, we still need to do that searching/calculation easier, by such wrap it in a function maybe enough.


Quote
- SingleLine still appears as foldable everywhere, but when is clicked the folded area is wrong (see LFM tab)
still happening?
Quote
For example:  FoldHL.pas (shipped with lazarus) doesn't work; see my FoldHL.pas for what is difference.
ups, then it needs to be fixed. Do you have a patch.
Please report a bug. (with or without patch)
Sorry that is my fault. It's not happen in original/lazarus SynLFM. It occured only in my SynLFM2.pas


Quote
Keep old interface, and define a getter.
Nice idea!


Quote
Eventually a patch will be needed.
I forgot how to create a Svn patch?
But you can see all changes separated from original code here: https://github.com/x2nie/syneditmarkupnestedcolors/commit/2438a0298c73942e6545bc29be1bbeb194db4c7c
Or when you are visiting github, click the "38 commits', click a commit node (most top) and there will be file per file, changes are green.
« Last Edit: December 11, 2015, 04:01:25 am by x2nie »
When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5695
    • wiki
I think No, its not about the normal way of how to get x pos.
(normal = sample code = finding X,Y as such in TSynEditMarkupWordGroup.FindMatchingWords() ).

Rather, there is a need to find the pair of opening~closing fold tag in simplest way!
You know, in FindMatchingWords: FindEndNode / FindStartNode methods are too complicated for such this easy task: get opening~closing fold tag.
(simplest = storing that (opening+closing fold tag) info into whether a CodeFoldBlock or into each FoldRange?).

So, normal way is bad (or at least : not optimized) because this way is finding through too many lines (assumed 10000 lines) until it match.
Storing that info will save time and battery. :)p
Quote
The very bad code in #19..23
Even if there was no alternative way, we still need to do that searching/calculation easier, by such wrap it in a function maybe enough.
now we have to differentiate several things
1) the data itself (what is stored and how)
2) How to get other info from it, and what methods are provided.

(1)
I still think foldlevel is the correct data to store.

I see no need to store for example that a fold starting in line 190 has a length of 75 lines. (store 75)
a) you know the length only when you hit line 265, then you have to backtrack the same way as current search (just backward). Only in the HL you do so for every line, even if not visible / not needed.
b) you need extra storage, and since you can have 100 fold opening on the same line, you need more often to allocate/deallocate memory (not very fast).
c) if you store it in the range, or code foldblock (part of the range) then they become nearly impossible to re-use.
Example pascal: I tried loading several 100k lines (in many units) of code. There will only be about 1700 range objects. (Yes, you can write code that forces more, way more.)

One could (but later) discuss a cache for lines in the visible area (that would not be part of the HL)

(2)
TSynCustomFoldHighlighter.FoldEndLine ?

But it should be added to TLazSynEditNestedFoldsList, which could not only return the line but also the info node. And which, if nested folds are scanned can continue scanning from the last known line. And do other small caching tasks.

As for long folds (10000 lines), that is no problem. Well if you scan a 1000 folds of 10k lines then maybe it will be.
A simple loop with just one compare (as abort condition) can easily loop over a million lines.
Having said that: folding 100k lines takes about 1 to 2 sec on my 5 year old pc. But it might be something else that takes the time. Because the scrollbar is adjusted almost immediately, and that can only happen when it has the line count. So I think something else takes the time.

Quote
I forgot how to create a Svn patch?
But you can see all changes separated from original code here: https://github.com/x2nie/syneditmarkupnestedcolors/commit/2438a0298c73942e6545bc29be1bbeb194db4c7c
Or when you are visiting github, click the "38 commits', click a commit node (most top) and there will be file per file, changes are green.
We can create it from git.

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
I have good news and a question.


* a new virtual method has been introduced for getting X,X2 location of fold mark
Code: Pascal  [Select]
  1. procedure TSynCustomFoldHighlighter.GetTokenBounds(out LogX1, LogX2,
  2.   LogVertGuideX: Integer); //Vert Guide Line, used by nested color markup
  3. var p : pchar; L : integer;
  4. begin
  5.   GetTokenEx(p,L);
  6.   LogX1 := GetTokenPos;
  7.   LogX2 := LogX1 + L -1;
  8.   LogVertGuideX := LogX1;
  9. end;
By this, almost non of HL need to override, except the XML HL (see attachment)
Surprisingly, all of HL works like charms (fine).


But...
the MarkupWordGroup seem as wrong on Node.LogXEnd, mean conflict with my idea.
See the "food"~"/food"  vs  "repeat"~"until" screengrab.


* My idea is   : Node.LogXEnd = the last char.
* while MWG : Node.LogXEnd = the last char +1
In other word:
Code: Pascal  [Select]
  1.   object
  2. 012345678901234567890
  3. 0          1         2
above "object" keyword has Node values of
* My LogXEnd= 7, LogXStart=2
* MWG LogXEnd= 8, LogXStart=2


So, my question is: which one to keep? mine our MWG? by what reason?
My personal reason is in pascal, the width of string is the last char. NOt the width + 1
« Last Edit: December 11, 2015, 10:15:11 am by x2nie »
When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
please ignore my previous question. it was stupid question :-[
I have resolved it. of course reusing the known code (MarkupWordGroup) is the winner.
« Last Edit: December 11, 2015, 10:58:31 am by x2nie »
When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com

@martin,

Now, the problem is when text/line trailing with tab. The vertical lines drawn improperly.
I have no idea, what's problem? I have no clue :'(
When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
So, normal way is bad (or at least : not optimized) because this way is finding through too many lines (assumed 10000 lines) until it match.
Storing that info will save time and battery. :)p
...

I see no need to store for example that a fold starting in line 190 has a length of 75 lines. (store 75)

c) if you store it in the range, or code foldblock (part of the range) then they become nearly impossible to re-use.

As for long folds (10000 lines), that is no problem. Well if you scan a 1000 folds of 10k lines then maybe it will be.
Hey, I currently face a real problem ... >:D  !


coming is new bad news (and the same time is also good news too),
well, I integrated my MarkupColorFold into Lazarus  :-X :D :-*


The good news is there are no error, it was gracefully integrated (debug assert enabled).
The bad news is: it is not as what it was designed. Vertical lines are jerk here.
Rather helps programmer, it will confusing them.  %) 
Yeah, It need some finishing/touch-up to be looked as cool enough...
(see attachment)


This messy visual effect, can be solved by drawing all vertical lines,  straight to "end;" keyword vertically.
We can see how CnPack solves the same problem. (see attachment II )


-----
Using MarkupWordGroup as guidance, we can easily found the 'end' part of each fold block.
When the 'end' is founded, we can compare with the 'begin' positions, resulting which one is the left most.
this leftmost position will be used to draw the correct vertical lines.
This way, one vertical-line-mark is done.
But if a line is located in 3th dept of folds, this step should repeated 3 times.


But, because MarkupColorFold will operate per sourcecode's line basis,
the next sourcecode-line will repeat comparing the left most pair of that begin~end (that have already proir calculated)
... plus : if it still in 3th depth of folds, comparison will be repeated 3 times again.


see?


For honest, the longest procedure AFAIK would be only 200 lines including off-of-screen lines.  (sorry for 10K abuse).
But, couldn't we make this real solution more efficient?


MarkupWordGroup only finding pairs of begin~end once, or twice, or maximum 3 time, and her job done.
But MarkupColorFold is more expensive on looking for paired begin~end than MarkupWordGroup in this situation.


So, it is my assumption : storing both closing+opening tag of a fold-block will minimize allocate/deallocate memory,
which in turn will reduce your battery-laptop consumption.


How?


THere is a good idea that depends on the concept/fact that HL store states for each line.
Assumed that System.pas has 10K lines, it should have 10K states stored, right? because 1line = 1 states.
Hence, on file loading, when a 'begin' of procedure block founded, I can store that begin postion.
when 'end' of that procedure founded, I stored that in the shared-folding-block (whatever Range / CodeFoldBLock?).
Now, when SynEdit need to refresh the screen, MarkupFoldColorPascal wouldn't need to find the left most X of paired 'begin'~'end' for each dept of fold block.
She can directly read the data stored for each block, and when need to read the same info of .Parent block just read, without re-searching.

(similar situation was described here: http://forum.lazarus.freepascal.org/index.php/topic,30122.msg194828.html#msg194828
| |    | | | HorzEntry := EMPTY_ENTRY;
(see attachment for complete lines)


see?

You might say that we don't really want to store this specific pascal things in MarkupFold,
Well, For reason of general purpose use, let MarkupColorFold as is.
For pascal, we can inherit it into new class that able to store 3 x integer x 2(begin,end) = 6 integer length per block (not per line).


If this concept is negative, how can an HL rescan (reparsing) a line randomly?




But it most probably impossible, when range (or foldblock?) is reused rewriten unpredicably.  :(

Ranges (if they are an object) are re-used. And with that the same FoldBlock object is used to represent the state on many lines.
Code: Pascal  [Select]
  1. begin                   // range at the end of line has foldblock 0x0001
  2.   if a then begin    // range at the end of line has foldblock 0x0002
  3.   end;                  // range at the end of line has foldblock 0x0001 since the inner fold is closed
  4.   if longer_condition then begin // range at the end of line has foldblock 0x0002 again (re-used), even the X pos differs.
  5.   end;
  6. end;
  7.  
What do you think ? 8)
« Last Edit: December 11, 2015, 03:47:58 pm by x2nie »
When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5695
    • wiki
Still reading up....

But why: LogVertGuideX ? Shouldn't that be calculated in your markup?

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5695
    • wiki
Also, do you still change the "exit(-1)" to 0 in the nodelist (if not valid).

Some code currently relies on -1 (the example foldhl will not fold, if it is 0)

I agree the -1 is bad. So it is also possible to add a property IsValid and change all code that depends on it.

So one of 2 choices:
1) Make your code work with -1
2) add IsValid. This must be a standalone patch (or one separate commit of all involved changes in your git). Then it can be merged as a standalone svn commit.