Recent

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

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #105 on: December 14, 2015, 05:52:22 am »
well, before we continue further, I think let's review your modification.
You have broken the basic rule.


- The foldHL can't be collapsed/folded.
- My ColorFold-HighLighter  too.
- The MarkupWordGroup doesn't work any longer.
Do you miss something?

But, any of other HL (in my demo) works:
+ Pas HL work
+ LFM highligter work
+ XML HL work


I guess there are around ConfigFold (that I worried yesterday)


I am using Lazarus 1.7
« Last Edit: December 14, 2015, 06:03:41 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
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #106 on: December 14, 2015, 06:24:43 am »
Oh, it was easier than I thought.
It just need to add 'sfaFoldFold' and collapsible will be back again there.



Code: Pascal  [Select]
  1.   //Start
  2.   if not FinishingABlock then
  3.   begin
  4.     act := [sfaOpen, sfaOpenFold]; // todo deprecate sfaOpenFold
  5.     if BlockTypeEnabled then
  6.       act := act + FFoldConfig[PtrUInt(ABlockType)].FoldActions
  7.     else
  8.     if not BlockConfExists then
  9.       act := act + [sfaFold,sfaFoldFold, sfaMarkup]; //<<---------------here
  10.     DoInitNode(nd, FinishingABlock, ABlockType, act, True);
  11.   end
  12.   else
  13.   //Finish
  14.   begin
  15.     act := [sfaClose, sfaCloseFold]; // todo deprecate sfaCloseFold
  16.     if BlockTypeEnabled then
  17.       act := act + FFoldConfig[PtrUInt(ABlockType)].FoldActions
  18.     else
  19.     if not BlockConfExists then
  20.       act := act + [sfaFold, sfaMarkup]; //<<---------------------- and here. +markup?
  21.     act := act - [sfaFoldFold, sfaFoldHide]; // it is closing tag
  22.     DoInitNode(nd, FinishingABlock, ABlockType, act, LevelChanged);
  23.   end;                    
  24.  
                                     


Anyway, I agree to get rid the 'sfaMarkup' everywhere. It should be calculated automatically, right?
sfaMarkup seem as not that special case. Every opening~closing fold tag can be assumed as markupable by MarkupWordGroup (and other need if any).
When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5800
    • wiki
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #107 on: December 14, 2015, 08:12:52 am »
ups sorry, I missed that.

I am going to add sfafoldfold. (just need to test again, so in a couple of hours).

Basically "folding" (or sfaFold, sfaFoldFold) is the default for HL that do not specify what a they want.

sfaMarkup can only work if there is a foldconfig.

Sample from xml hl
Code: Pascal  [Select]
  1. function TSynXMLSyn.GetFoldConfigInstance(Index: Integer): TSynCustomFoldConfig;
  2. begin
  3.   Result := inherited GetFoldConfigInstance(Index);
  4.   Result.Enabled := True;
  5.   if TXmlCodeFoldBlockType(Index) in [cfbtXmlNode] then begin
  6.     Result.SupportedModes := Result.SupportedModes + [fmMarkup];
  7.     Result.Modes := Result.Modes + [fmMarkup];
  8.   end;
  9. end;
  10.  
  11. function TSynXMLSyn.GetFoldConfigCount: Integer;
  12. begin
  13.   Result := 1; // ord(high(TXmlCodeFoldBlockType)) - ord(low(TXmlCodeFoldBlockType));
  14. end;
  15.  

You can set the count to 1.

Then you can still pass nil (which translates to zero; and zero is the only element in a list with a count of 1)

or you define an enum
Code: Pascal  [Select]
  1.  TMyHlCodeFoldBlockType = (
  2.     cfbtFooBar
  3. // , optional more
  4.   );
  5.  
and call
Code: Pascal  [Select]
  1. StartCodeFoldBlock(Pointer(ptrUint(ord(cfbtFooBar))), true)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5800
    • wiki
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #108 on: December 14, 2015, 08:35:45 am »
foldconf:

for each node type (or actually for the amount returned by GetFoldConfigInternalCount) a config object will be created.

SupportedModes
The HL decides if a node can have a mode or not. E.g. the pas hl only allows "hide" for comments. (In this case its not a technical reason, just seemed sensible)

Modes
initialized with the default. This can be changed by user.

Enabled
must be true, or the node is entirely ignored (or at least should)


currently a node can have the following modes (set of)

fmFold: normal fold
fmHide: fold including hiding the line itself (comments in pas, can be configured)
fmMarkup: the word at caret matching node markup

and I suggest, that you add
fmMarkupOutline 
then the 2 markup modules (yours and the existing) can have different conf.

and use this in your markup, instead of sfMarkup

of course you dont use fmMarkup, but sfaMarkup
So you also need to create an new action sfaMarkupOutline.

Look at TSynCustomFoldConfig.SetModes  that should tell you how.

to make  them easier to remember:
fm = fold mode
sfa = syn fold action
cfbt = code fold block type


TODO in the code

GetFoldConfigInternalCount in the base class should probably default to GetFoldConfigCount, so a child class need only that one (but can have both)

SupportedModes should not be public. It could be set when calling the constructor. Or the TSynCustomFoldHighlighter (same unit, can access protected) could have itself a protected method to forward the data.

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #109 on: December 14, 2015, 12:12:39 pm »
OK, 2 bits of info.

1) foldconfig.

currently length is set in .Create. not good, maybe move.

GetFoldConfigInstance
gets the initial setting.

for each foldtype (cfbtBeginEnd,...) it indicates, if it can
Code: Pascal  [Select]
  1. TSynCustomFoldConfigMode = (fmFold, fmHide, fmMarkup);
- fold
- hide
- markup (word triplet at caret)

you could add fmMarkupOutline then this can be configured, and the HL can indicate which nodes are for your module.

the HL can set 2 flags (maybe more)
- sfaMarkupOutline
  visible outline
- sfaMarkupOutlineIndend
  not outlined, but increase color (e.g. a nested procedure block)

those would then be set in HL.InitNode() according to the language rules.

As for the "level" of intend. The HL levels are not correct, but when you go through Nest : TLazSynEditNestedFoldsList; you could keep count of nodes that have the flag (you need to start left to right then).

Or simply set them on the result FHighlights. But then you need to add dummy entries for the invisible sfaMarkupOutlineIndend. So that is not desirable.
....
Okay, I learn by doing. I am trying  to understand what you said.
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
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #110 on: December 15, 2015, 02:38:44 pm »
Okay, I did it! ;D

Further, after I know how to work with Node,
 I also found a bugfix of wrong triplet "if-then",  when there is no "else" and there is nor ';'
The bug is: the triplet will be paired with it's parent's 'end', which it should only 'if-then' highlighted.
Code: Pascal  [Select]
  1. function TSynPasSyn.Func23: TtkTokenKind;
  2. var
  3.   tfb: TPascalCodeFoldBlockType;
  4.   sl : integer;
  5. begin
  6.   if KeyComp('End') then begin
  7.     if ((fToIdent<2) or (fLine[fToIdent-1]<>'@'))
  8.     then begin
  9.       Result := tkKey;
  10.       fRange := fRange - [rsAsm, rsAfterClassMembers];
  11.       PasCodeFoldRange.BracketNestLevel := 0; // Reset in case of partial code
  12.       // there may be more than on block ending here
  13.       tfb := TopPascalCodeFoldBlockType;
  14.       while (tfb in [cfbtIfThen]) do begin // no semicolon before end
  15.         sl := fStringLen;
  16.         fStringLen:=0; // <--------------------------------- here bugfix
  17.         EndPascalCodeFoldBlock(True);
  18.         fStringLen := sl; // <------------------------------- here bugfix
  19.         tfb := TopPascalCodeFoldBlockType;
  20.       end;                  
see attachments



Now, my problem is: How to make if-then to not increase level?
I want the if-then---begin-end---else---begin-end all of them in similar color. I think it should be in similar level, isn't it?

edit:
see secondary attachment, if~then and it's begin~end has different color. How can I make them in one single color?
« Last Edit: December 16, 2015, 04:04:38 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: 5800
    • wiki
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #111 on: December 15, 2015, 11:35:07 pm »
In pas HL
Code: Pascal  [Select]
  1.    StartPascalCodeFoldBlock(cfbtIfThen, not( TopPascalCodeFoldBlockType in [cfbtCase, cfbtIfThen]));
  2.  

not tested, but that probably breaks case-else
Code: Pascal  [Select]
  1. case a of
  2.   1: foo;
  3.   2: if b then
  4.         if c then
  5.           foo1
  6.         else // NOT highlighted as case-label
  7.           foo2
  8.       else  // NOT highlighted as case-label
  9.         foo3
  10.   else  // highlighted as case-label
  11.     bar;
  12. end
  13.  

You probably want to look at initnode, and remove the sfaOutline for nested cases.

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #112 on: December 16, 2015, 03:28:26 am »
@Martin, in english, please?


Are you pointing to bugfix I show above,
or are you answering my question,
or you show me another bug?



About the code in your last post:
  • Surprisingly, it is valid code. So we should support it.
  • Surprisingly, CNPack has similar behavior of how take care the last "else".
  • If CNPack is okay, I think I am fine too. But I want to hear what you want to suggest ....
    Simply: What should be the correct color of the last "else"? should it be orange color?

When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5800
    • wiki
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #113 on: December 16, 2015, 04:43:40 am »
Quote
Are you pointing to bugfix I show above,
or are you answering my question,
or you show me another bug?

I saw that line of code when I diffed your latest commits.

I did not test, but suspect that it might interfere with existing features.



I was not talking of your color only

the pas dl has an option to highlight all case labels (in the IDE you can configure this / I use a frame around them).

Having nested "if" blocks means keeping track of where an else belongs.

I have not tested your change. But it may break this existing behaviour.



As for your colors. You do not highlight the case labels 1: or 2: so the "else" of the case should also be ignored.




There is a bigger problem:
Code: Pascal  [Select]
  1. ANode.FoldLvlEnd

1) ANode.FoldLvlEnd may be removed in future

2) never mind the future. In the IDE you can configure what folds, and what does not fold. You can disable folding for "begin" blocks.
If you do, then for a begin block the level will no longer increase. So if you have nested begin blocks (nested loops) then all begin will have the same color.

I said it before: the level is not intended for what you do. It only server finding opening and closing lines.

When you prepare FHighlights, then you know how many outer lines there are. So you can set the colors from the content of FHighlights.

However you have special cases.
1) "If" No increase in color wanted
add an action (to the inner) sfaOutlineMergeParent.

2) extra increase ("begin" in nested proc)
add an action sfaOutlineExtraLevel

those are just actions. there are no new modes.

The HL can add them in InitNode. (or somewhere like that)


« Last Edit: December 16, 2015, 04:46:00 am by Martin_fr »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5800
    • wiki
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #114 on: December 16, 2015, 05:40:49 am »
Quote
1) "If" No increase in color wanted
add an action (to the inner) sfaOutlineMergeParent.

2) extra increase ("begin" in nested proc)
add an action sfaOutlineExtraLevel

You may not even need 2.

If you make procedure and begin merge colors, so you have one long line from procedure, over begin to end, in one color, then nested procedures already have their own color.

Though if you prefer to start the line at begin, then add it.

It can later become an options

Code: Pascal  [Select]
  1. SynPasSyn.OutlineOptions = (
  2.    mergeProcBegin, // if both proc and begin have fmOutline
  3.    mergeIfBegin, // if both IF and begin have fmOutline
  4.    mergeNestedIf // only one color for all if
  5. )

x2nie

  • Sr. Member
  • ****
  • Posts: 478
  • Impossible=I don't know the way
    • impossible is nothing - www.x2nie.com
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #115 on: December 16, 2015, 08:20:15 am »
If you make procedure and begin merge colors, so you have one long line from procedure, over begin to end, in one color, ...
Excellent. That is what I really wanted.


I also would reapply that rule into the if-then make if the longest line, over the then,begin and else,begin. whooaa..... :-[
The reason is: I don't really want to fold/unfold at "then" (current rule), instead I want at "if". I believe other people want too.
* Was it a mistake to fold/unfold at "then". ? :P


If it was reached, I can work for another keywords: do~while, with~do, for~do ...etc.
but now the hardest part is to change the behavior of if~then~else. So, other keywords will follow.




About the pascal HL, I use both original and experimental (in case you aren't noticed, ) to compare side-by-side.
My experimental PAS Highlighter, is to reuse our modified base class. (but I seem failed to merge InitNode + DoInitNode).
The file is SynHighlighterMiniPas2.pas

So, if you worry about whether it will interferer with existing feature, you might right,
it may completely break many rules. But, this way is easier way I can do during learning.
We can discuss my modification PAS HL to back obey the IDE rules, maybe later.

What I should do with SynPasSyn.pas? I think I will replace it with mine when the experiment'r result is (someday) okay.

« Last Edit: December 16, 2015, 08:40:46 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
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #116 on: December 16, 2015, 08:31:30 am »
I said it before: the level is not intended for what you do. It only server finding opening and closing lines.
Okay, deal. It's clear that I was in wrong direction when depends on fold-level for nest-coloring, it should depends on other counter.
I may need to add that counter into PasRange.?

Quote
When you prepare FHighlights, then you know how many outer lines there are. So you can set the colors from the content of FHighlights.
:o You have said it several time, but sorry for my stupid, I don't understand yet either.  Maybe, I should just go forward, forgeting it for now.





I am still trying
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
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #117 on: December 16, 2015, 12:02:13 pm »
As for your colors. You do not highlight the case labels 1: or 2: so the "else" of the case should also be ignored.


Okay, it was a bug for my coloring markup over PAS hl bug too. So, if another SynEdit module working with it, they will found the same bug.
I've fixed.


Code: Pascal  [Select]
  1. function TSynPasSyn.Func41: TtkTokenKind;
  2. begin
  3.   if KeyComp('Else') then begin
  4.     Result := tkKey;
  5.     if (TopPascalCodeFoldBlockType = cfbtIfThen) then
  6.       EndPascalCodeFoldBlock
  7.     else
  8.     if TopPascalCodeFoldBlockType = cfbtCase then begin
  9.       StartPascalCodeFoldBlock(cfbtCaseElse);
  10.       FTokenIsCaseLabel := True; //<-------------------------------bug
  11.     end;



Code: Pascal  [Select]
  1.     if TopPascalCodeFoldBlockType = cfbtCase then begin
  2.       FTokenIsCaseLabel := True; // <--------- it should be there before calling StartBlock
  3.       StartPascalCodeFoldBlock(cfbtCaseElse, True);
  4.  



edit:
Fully configurable.
« Last Edit: December 16, 2015, 12:18:50 pm 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
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #118 on: December 16, 2015, 01:34:11 pm »
However you have special cases.
1) "If" No increase in color wanted
add an action (to the inner) sfaOutlineMergeParent.

OH! I know what you mean. I've modified original PAS HL a little bit.
The original is far worst (if & then is in different color).
But IMHO, My PAS (SynMiniPas2.pas) is also relevant to has sfaOutlineMergeParent. give me a try..

please compare this (original pas) screengrab with previous (my mod pas) one.
When you were logged in, you can see attachments.
Lazarus Trunk @ Windows7 64bit, XP 32bit, Debian under VirtualMachine

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5800
    • wiki
Re: Invite to Colorizing TSynEdit ! {Improving Editor for Editing Complex Codes}
« Reply #119 on: December 16, 2015, 04:55:03 pm »
Quote
When you prepare FHighlights, then you know how many outer lines there are. So you can set the colors from the content of FHighlights.
:o You have said it several time, but sorry for my stupid, I don't understand yet either.  Maybe, I should just go forward, forgeting it for now.

Lets start with this one.

If I read your code correctly:

Step 1:
you add all nodes to FHighlights.
First from the current line, then from TLazSynEditNestedFoldsList. As a result the innermost node is at index 0.
You will have to add duplicates at the same x pos, so you can NOT
    if FHighlights.X = x then    exit;
but instead add a flag to this node.

Then before you sort them (SortLeftMostFI), do something like
Code: Pascal  [Select]
  1. a := 0
  2. for i = high(FHighlights) downto 0 do begin// start at the outermost)
  3.   FHighlights[i].color = a mod lenght(colors).
  4.   inc(a)
  5. end
  6.  

And you got your colors. Of course if you want to join 2 lines, do not inc the color.

And that way you do not need any level from the HL at all.