Custom folding in a custom lexer with LEX_CONTAINER Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
User avatar
evstevemd
Part Of The Furniture
Part Of The Furniture
Posts: 2292
Joined: Wed Jan 28, 2009 11:57 am
Location: United Republic of Tanzania
Contact:

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by evstevemd » Tue Oct 31, 2017 4:30 pm

TobiasA wrote:This may be a noob question... But how do you create a new article? Is there a short howto on it?
Thank you!
You mean wa Wiki Article? You just register and then login there.
The editor is ugly IMHO but you can write nice article with it for sure!
Chief Justice: We have trouble dear citizens!
Citizens: What it is his honor?
Chief Justice:Our president is an atheist, who will he swear to?
[Ubuntu 19.04/Windows 10 Pro/MacOS 10.13 - GCC/MinGW/Clang, CodeLite IDE]

TobiasA
Knows some wx things
Knows some wx things
Posts: 38
Joined: Mon Aug 28, 2017 8:42 am

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by TobiasA » Tue Oct 31, 2017 4:54 pm

Yeah, exactly. I somehow can't find the button "create new article" or something like that.
Since I am registered I could edit an existing article but I don't know how to add a new one.

User avatar
evstevemd
Part Of The Furniture
Part Of The Furniture
Posts: 2292
Joined: Wed Jan 28, 2009 11:57 am
Location: United Republic of Tanzania
Contact:

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by evstevemd » Tue Oct 31, 2017 5:12 pm

TobiasA wrote:Yeah, exactly. I somehow can't find the button "create new article" or something like that.
Since I am registered I could edit an existing article but I don't know how to add a new one.
Seems there is no easy way to do it. Fortunately I found this help on how to do it.
Check it out and see if you still have problem!
Chief Justice: We have trouble dear citizens!
Citizens: What it is his honor?
Chief Justice:Our president is an atheist, who will he swear to?
[Ubuntu 19.04/Windows 10 Pro/MacOS 10.13 - GCC/MinGW/Clang, CodeLite IDE]

TobiasA
Knows some wx things
Knows some wx things
Posts: 38
Joined: Mon Aug 28, 2017 8:42 am

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by TobiasA » Tue Oct 31, 2017 7:54 pm

Finally I got it... I hope to have an article done by the end of the week.

User avatar
evstevemd
Part Of The Furniture
Part Of The Furniture
Posts: 2292
Joined: Wed Jan 28, 2009 11:57 am
Location: United Republic of Tanzania
Contact:

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by evstevemd » Tue Oct 31, 2017 8:04 pm

TobiasA wrote:Finally I got it... I hope to have an article done by the end of the week.
You can post how you got it just for reference.

And that Post will surely be helpful! =D>
Chief Justice: We have trouble dear citizens!
Citizens: What it is his honor?
Chief Justice:Our president is an atheist, who will he swear to?
[Ubuntu 19.04/Windows 10 Pro/MacOS 10.13 - GCC/MinGW/Clang, CodeLite IDE]

TobiasA
Knows some wx things
Knows some wx things
Posts: 38
Joined: Mon Aug 28, 2017 8:42 am

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by TobiasA » Tue Oct 31, 2017 8:54 pm

The fun thing is: I found the help function after I added the page...
You just enter a new link in the browser like
https://wiki.wxwidgets.org/TestPage
and then it offers you to edit this page... Which ultimately creates it. I was a bit frightened that I'd mess up the wiki and delete the internet, but it is really that easy. You just have to keep in mind that this is the (unchangeable) title of the page... So better write the full title in it. Not like I did, renaming the page afterwards because I didn't know.
I will continue to edit it over the week and hope to have the article finished within this week.

User avatar
evstevemd
Part Of The Furniture
Part Of The Furniture
Posts: 2292
Joined: Wed Jan 28, 2009 11:57 am
Location: United Republic of Tanzania
Contact:

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by evstevemd » Wed Nov 01, 2017 2:06 pm

TobiasA wrote:The fun thing is: I found the help function after I added the page...
You just enter a new link in the browser like
https://wiki.wxwidgets.org/TestPage
and then it offers you to edit this page... Which ultimately creates it. I was a bit frightened that I'd mess up the wiki and delete the internet, but it is really that easy. You just have to keep in mind that this is the (unchangeable) title of the page... So better write the full title in it. Not like I did, renaming the page afterwards because I didn't know.
I will continue to edit it over the week and hope to have the article finished within this week.
Great that you found a way ;)

Can you link the new page URL?
Chief Justice: We have trouble dear citizens!
Citizens: What it is his honor?
Chief Justice:Our president is an atheist, who will he swear to?
[Ubuntu 19.04/Windows 10 Pro/MacOS 10.13 - GCC/MinGW/Clang, CodeLite IDE]

TobiasA
Knows some wx things
Knows some wx things
Posts: 38
Joined: Mon Aug 28, 2017 8:42 am

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by TobiasA » Wed Nov 01, 2017 7:00 pm

https://wiki.wxwidgets.org/index.php?ti ... edTextCtrl

This wiki is driving me nuts... I finished formatting and stuff, explanation, all source additions including highlighting... And there comes the message "*** Forbidden. Browser seems to be spambot. ***" and "*** Forbidden. You submitted too quickly. You may try again in a few seconds. ***"
Yeah, cool. That's what life is giving you for being a fast writer :lol:

Hold on, it should be online within a few minutes. If you don't see the remark "under construction" and see code highlighting, you are looking on the somewhat finished version.

Edit: Nope, it's not gonna work. I'm not allowed to edit my article anymore. I could provide the raw text though just in case anyone else can fill it in.

TobiasA
Knows some wx things
Knows some wx things
Posts: 38
Joined: Mon Aug 28, 2017 8:42 am

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by TobiasA » Wed Nov 01, 2017 7:20 pm

Well, here comes the raw text... Maybe I can upload it tomorrow or something. I'd like to, but the wiki identifies me as a spambot.

Code: Select all

<h2>Introduction</h2>
This article describes how to write a custom "lexer" to a wxStyledTextCtrl (refered as "STC" in the article) including a sample for text folding.<br>
The STC is basically a 1:1 mapping of the scintilla editor (http://www.scintilla.org). The STC handles text and uses a lexer to add syntax highlighting to this text. There are a lot of internal lexers for the most common uses.Internally, as soon as you scroll a page or modify it, scintilla calls a style routine to style that text. The lexer than applies that style to the text.<br>
<h4>Implementing a lexer</h4>
You can set any of the included lexers by adding a lexer to the STC:
<source>wxSTC->SetLexer(wxSTC_LEX_xxxx);</source>
where xxxx stands for any of the compilers (like wxSTC_LEX_CPP for the C++ lexer). 
Now what if we want to highlight text with a different language? In this example we use CNC G-Code. In case you are not familiar with it, it is used on CNC machines (like a mill or lathe). To make it simple, we highlight everything that is a "G-Code" which is a command to execute a specific action like switching to another work offset (G54).
Also, we use folding- "IF" increases the fold level, "ENDIF" decreases it (just like { and } do in C++). This is a bit tricky since "ENDIF" contains "IF".<br>
The example is a bit shortened- keep in mind that in "real life" you would have to check if that "IF" is part of a comment or a string for example. But this doesn't matter for the example.<br>
Performance is not critical- you could also use RegEx since drawing the screen takes a lot longer than actually parsing the few lines you see. However, you should still keep it as small and fast as possible.<br>
So how do we do this? There is some "hook" that calls a custom style routine that you can set in your own part without modifying wxWidgets itself. It is the LEX_CONTAINER "lexer". If you set this, STC will call an event each time style is needed. So, set this:
<source>STC->SetLexer(wxSTC_LEX_CONTAINER);</source>
and then bind wxEVT_STC_STYLENEEDED to your own routine:
 m_activeSTC->Bind(wxEVT_STC_STYLENEEDED, &myFrame::OnStyleNeeded, this);
This way, every time the text in the container is modified or unstyled text comes into sight, myFrame::OnStyleNeeded(wxStyledTextEvent& event) is called which then styles the text. You should be able to understand what styles and folding levels are and how to use them. A lot of it is explained in the scintilla documentation- unfortunately, many open projects lack a good "beginners guide" so I'll explain the basics here:
<h4>Styles</h4>
A style is applied to a text with a number (more precisely, stylebits) and a color as well as other formatings like bold text, foreground and background.<br>
The number has to be lower than 32 (at least this has been the case in the documentation I have read). The lowest 3 styles seem to be used by extra stylings (like highlighting search occurences) so a number between 4 and 31 should be save.
The style is set with<br>
<source>STC->StyleSetForeground(19,wxcolor);</source>
for example which will set the foreground color for style 19 to the color specified in wxcolor. You should do this before styling text in the document (like when constructing the STC).<br>
<h4>Folding</h4>
Folding works by applying a fold level to each line. The lowest foldlevel is "0" (but: Since the fold bits don't start at bit 0, we need to add 1024 to this number). This means that this line will never be foldable. The first line that shall be visible when folding text (like the one containing the "IF") stays at that foldlevel, but is assigned a special flag, the wxSTC_FOLDLEVELHEADERFLAG. All following lines are assigned the higher fold level (1 until another IF comes -> increase or ENDIF -> decrease). When the folding ends by specifying ENDIF in a line, the line following that line receives the lower fold level (so the ENDIF line is folded as well). Folding always hides those lines containing the higher fold level when clicking the margin on the position of the header line (the one containing wxSTC_FOLDLEVELHEADERFLAG).
<h4>Margins</h4>
A margin is shown on the side of the document. It can hold markers, foldlines and similar items. In our case, we'll just add a margin, define the markers on it for folding and catch the event when someone clicks on it with
<source>STC->Bind(wxEVT_STC_MARGINCLICK, &myFrame::onMarginClick, this);</source>
to MyFrame::onMarginClick(wxStyledTextEvent& event) so this function is called whenever someone clicked the margin. This will toggle the fold level.
As with styles and folding, refer to the scintilla and/ or wxwidgets documentation to gather more information- it would be too long to explain it in detail here.
The below code for setting up the margin was provided by NewPagodi in the wxwidgets forum.

<h4>Writing your own "lexer"</h4>
Your own "lexer" consists of a style routine called by the wxEVT_STC_STYLENEEDED event. That's basically all. But we need some more things of course:
* A function for parsing your text and sorting out what color shall be applied (if any).
* A function for finding and calculating the fold levels.
* A function to finally apply styles and fold levels to the document.

A fast and dirty parser can be found in the example below- it is far from perfect, but should show the basics. Things you might have to consider:
* Keywords that are part of a comment should not be parsed or overridden by the comment style
* Keywords that are part of a string definition shouldn't affect folding levels
* Umlauts or other non-ascii signs can shift the found positions vs. real positions of a char since they are 2 bytes wide (you can possibly solve this by forcingly converting the search text to UTF8 for example in most cases).
All of those three might happen in the example below- but since we want to show the basics, we won't care about that for now.

<h4>Putting it all together in a small demo app</h4>
Define a small app:
<source>
 // For compilers that support precompilation, includes "wx/wx.h".
 #include "wx/wxprec.h"
 #ifdef __BORLANDC__
 #pragma hdrstop
 #endif
 // for all others, include the necessary headers (this file is usually all you
 // need because it includes almost all "standard" wxWidgets headers)
 #ifndef WX_PRECOMP
 #include "wx/wx.h"
 #endif
 //includes
 #include <wx/stc/stc.h>
 #include <vector>
 #include <utility>
 #include <algorithm>
 #define MY_FOLDMARGIN 2
 class myFrame : public wxFrame {
    //be sure to enable the C++11 standard for this example if you're using GCC !!
 public:
    myFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo"
             , wxPoint pos = wxDefaultPosition, wxSize size = wxSize(481,466)
                     , int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
 private:
    void onMarginClick(wxStyledTextEvent& event);
    void OnStyleNeeded(wxStyledTextEvent& event);
    void highlightSTCsyntax(size_t fromPos,size_t toPos,wxString &text);
    void setfoldlevels(size_t fromPos,int startfoldlevel,wxString &text);
    wxStyledTextCtrl* m_activeSTC;
    wxColor m_GCodecolor{255,130,0}; //color for highlighted parts
    //this is the mask for styling- just remember to set this to 0 with >3.1.0
    int m_stylemask=255; //for wxwidgets >3.1.0 set this to 0
 };
</source>
Define the frame, set up the STC and its margins:
<source>
 myFrame::myFrame( wxWindow* parent, int id, wxString title, wxPoint pos
                  , wxSize size, int style )
    :wxFrame( parent, id, title, pos, size, style ) {
    m_activeSTC = new wxStyledTextCtrl(this);
    //set Lexer to LEX_CONTAINER: This will trigger the styleneeded event so you can do your own highlighting
    m_activeSTC->SetLexer(wxSTC_LEX_CONTAINER);
    //folding example by New Pagodi copied from WxWidgets Forum
    //Set the fold marging to have a width of 14 pixels and give it a
    //distinctive background
    m_activeSTC->SetMarginWidth(MY_FOLDMARGIN,14);
    m_activeSTC->SetMarginMask(MY_FOLDMARGIN,wxSTC_MASK_FOLDERS);
    m_activeSTC->SetFoldMarginColour(true,wxColor(255,255,255));
    m_activeSTC->SetFoldMarginHiColour(true,wxColor(233,233,233));
    //Set up the markers that will be shown in the fold margin
    m_activeSTC->MarkerDefine(wxSTC_MARKNUM_FOLDEREND,wxSTC_MARK_BOXPLUSCONNECTED);
    m_activeSTC->MarkerSetForeground(wxSTC_MARKNUM_FOLDEREND,wxColor(243,243,243));
    m_activeSTC->MarkerSetBackground(wxSTC_MARKNUM_FOLDEREND,wxColor(128,128,128));
    m_activeSTC->MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID,wxSTC_MARK_BOXMINUSCONNECTED);
    m_activeSTC->MarkerSetForeground(wxSTC_MARKNUM_FOLDEROPENMID,wxColor(243,243,243));
    m_activeSTC->MarkerSetBackground(wxSTC_MARKNUM_FOLDEROPENMID,wxColor(128,128,128));
    m_activeSTC->MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_TCORNER);
    m_activeSTC->MarkerSetForeground(wxSTC_MARKNUM_FOLDERMIDTAIL,wxColor(243,243,243));
    m_activeSTC->MarkerSetBackground(wxSTC_MARKNUM_FOLDERMIDTAIL,wxColor(128,128,128));
    m_activeSTC->MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL,wxSTC_MARK_LCORNER);
    m_activeSTC->MarkerSetForeground(wxSTC_MARKNUM_FOLDERTAIL,wxColor(243,243,243));
    m_activeSTC->MarkerSetBackground(wxSTC_MARKNUM_FOLDERTAIL,wxColor(128,128,128));
    m_activeSTC->MarkerDefine(wxSTC_MARKNUM_FOLDERSUB,wxSTC_MARK_VLINE);
    m_activeSTC->MarkerSetForeground(wxSTC_MARKNUM_FOLDERSUB,wxColor(243,243,243));
    m_activeSTC->MarkerSetBackground(wxSTC_MARKNUM_FOLDERSUB,wxColor(128,128,128));
    m_activeSTC->MarkerDefine(wxSTC_MARKNUM_FOLDER,wxSTC_MARK_BOXPLUS);
    m_activeSTC->MarkerSetForeground(wxSTC_MARKNUM_FOLDER,wxColor(243,243,243));
    m_activeSTC->MarkerSetBackground(wxSTC_MARKNUM_FOLDER,wxColor(128,128,128));
    m_activeSTC->MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN,wxSTC_MARK_BOXMINUS);
    m_activeSTC->MarkerSetForeground(wxSTC_MARKNUM_FOLDEROPEN,wxColor(243,243,243));
    m_activeSTC->MarkerSetBackground(wxSTC_MARKNUM_FOLDEROPEN,wxColor(128,128,128));
    //Turn the fold markers red when the caret is a line in the group (optional)
    m_activeSTC->MarkerEnableHighlight(true);
    //The margin will only respond to clicks if it set sensitive.  Also, connect
    //the event handler that will do the collapsing/restoring
    m_activeSTC->SetMarginSensitive(MY_FOLDMARGIN,true);
    m_activeSTC->Bind(wxEVT_STC_MARGINCLICK, &myFrame::onMarginClick, this);
    m_activeSTC->Bind(wxEVT_STC_STYLENEEDED, &myFrame::OnStyleNeeded, this);
    //set color for G-Code highlighting
    m_activeSTC->StyleSetForeground(19,m_GCodecolor);
    //enter some text and set fold levels
    m_activeSTC->AppendText(";Foldtest\n");
    m_activeSTC->AppendText("DEF BOOL TESTVAR=FALSE\n");
    m_activeSTC->AppendText("IF (TESTVAR)\n");
    m_activeSTC->AppendText("  G0 G54 M0\n");
    m_activeSTC->AppendText("ENDIF\n");
    m_activeSTC->AppendText("M30\n");
    /*given the text above, folding should produce this output:
    m_activeSTC->SetFoldLevel(0, 1024);
    m_activeSTC->SetFoldLevel(1, 1024);
    m_activeSTC->SetFoldLevel(2, 1024|wxSTC_FOLDLEVELHEADERFLAG); //header flag: one item before increasing fold level!
    m_activeSTC->SetFoldLevel(3, 1025);  //here comes the new fold level in line G0 G54 M0
    m_activeSTC->SetFoldLevel(4, 1025);  //the ENDIF
    m_activeSTC->SetFoldLevel(5, 1024);  //and this has the lower fold level again
    m_activeSTC->SetFoldLevel(6, 1024|wxSTC_FOLDLEVELWHITEFLAG); //this is an empty line: set fold level white flag
    note: If you load text into the styled text control for example with file load or like we did above:
    style the whole document for once. If you don't, the document remains unstyled until you click some position below*/
    wxString text=m_activeSTC->GetText().Upper(); //Upper() makes it case insensitive
    this->highlightSTCsyntax(0,m_activeSTC->GetTextLength(),text);
    this->setfoldlevels(0,0,text);
 }
</source>
This is the function that toggles the fold levels. Basically we check if this is a header and the next line is hidden or not:
<source>
 void myFrame::onMarginClick(wxStyledTextEvent& event) {
    int margin   = event.GetMargin();
    int position = event.GetPosition();
    int  line        = m_activeSTC->LineFromPosition(position);
    int  foldLevel  = m_activeSTC->GetFoldLevel(line);
    bool headerFlag = (foldLevel & wxSTC_FOLDLEVELHEADERFLAG)!=0;
    if( margin==MY_FOLDMARGIN && headerFlag ) {
        m_activeSTC->ToggleFold(line);
    }
 }
</source>
This is the function called whenever scintilla needs a style:
<source>
 void myFrame::OnStyleNeeded(wxStyledTextEvent& event) {
    /*this is called every time the styler detects a line that needs style, so we style that range.
    This will save a lot of performance since we only style text when needed instead of parsing the whole file every time.*/
    size_t line_end=m_activeSTC->LineFromPosition(m_activeSTC->GetCurrentPos());
    size_t line_start=m_activeSTC->LineFromPosition(m_activeSTC->GetEndStyled());
    /*fold level: May need to include the two lines in front because of the fold level these lines have- the line above
    may be affected*/
    if(line_start>1) {
        line_start-=2;
    } else {
        line_start=0;
    }
    //if it is so small that all lines are visible, style the whole document
    if(m_activeSTC->GetLineCount()==m_activeSTC->LinesOnScreen()){
        line_start=0;
        line_end=m_activeSTC->GetLineCount()-1;
    }
    if(line_end<line_start) {
        //that happens when you select parts that are in front of the styled area
        size_t temp=line_end;
        line_end=line_start;
        line_start=temp;
    }
    //style the line following the style area too (if present) in case fold level decreases in that one
    if(line_end<m_activeSTC->GetLineCount()-1){
        line_end++;
    }
    //get exact start positions
    size_t startpos=m_activeSTC->PositionFromLine(line_start);
    size_t endpos=(m_activeSTC->GetLineEndPosition(line_end));
    int startfoldlevel=m_activeSTC->GetFoldLevel(line_start);
    startfoldlevel &= wxSTC_FOLDFLAG_LEVELNUMBERS; //mask out the flags and only use the fold level
    wxString text=m_activeSTC->GetTextRange(startpos,endpos).Upper();
    //call highlighting function
    this->highlightSTCsyntax(startpos,endpos,text);
    //calculate and apply foldings
    this->setfoldlevels(startpos,startfoldlevel,text);
 }
</source>
Highlighting function:
<source>
 void myFrame::highlightSTCsyntax(size_t fromPos,size_t toPos, wxString &text) {
    //this vector will hold the start and end position of each word to highlight
    //if you want to highlight more than one, you should pass a whole class or struct containing the offsets
    std::vector<std::pair<size_t,size_t>>GcodeVector;
    //the following example is a quick and dirty parser for G-Codes.
    //it just iterates through the Text Range and finds "Gxx" where xx is a digit.
    //you could also use regex, but one can build a pretty fast routine based on single char evaluation
    size_t actual_cursorpos = 0;
    size_t startpos = 0;
    size_t end_of_text = text.length();
    bool word_boundary = true; //check for word boundary
    char actualchar;
    while (actual_cursorpos<end_of_text) {
        actualchar= text[actual_cursorpos];
        //check if syntax matches "G" followed by a couple of numbers
        if((actualchar=='G')&&(word_boundary==true)) {
            //this is a new G-Code, store startposition
            startpos=actual_cursorpos;
            word_boundary=false;
            actual_cursorpos++;
            if(actual_cursorpos<end_of_text) {
                //refresh actual character
                actualchar= text[actual_cursorpos];
            }
            //add digits
            while((std::isdigit(actualchar)&&(actual_cursorpos<end_of_text))) {
                actual_cursorpos++;
                actualchar= text[actual_cursorpos];
            }
            //check if word boundary occurs at end of digits
            if((actualchar==' ')||(actualchar=='\n')||(actualchar=='\r')||(actualchar=='\t')||(actual_cursorpos==end_of_text)) {
                //success, append this one
                if((actual_cursorpos-startpos)>1) {
                    //success, append to vector. DO NOT FORGET THE OFFSET HERE! We start from fromPos, so we need to add this
                    GcodeVector.push_back(std::make_pair(startpos+fromPos, actual_cursorpos+fromPos));
                }
                word_boundary=true;
            }
        }
        if((actualchar==' ')||(actualchar=='\n')||(actualchar=='\r')||(actualchar=='\t')||(actual_cursorpos==end_of_text)) {
            word_boundary=true;
        }
        actual_cursorpos++;
    }
    //remove old styling
    m_activeSTC->StartStyling(fromPos,m_stylemask); //from here
    m_activeSTC->SetStyling(toPos-fromPos,0); //with that length and style -> cleared
    //now style the G-Codes
    for (int i=0; i<GcodeVector.size(); i++) {
        size_t startpos=GcodeVector[i].first;
        size_t endpos=GcodeVector[i].second;
        size_t length=(endpos-startpos);
        m_activeSTC->StartStyling(startpos,m_stylemask);
        m_activeSTC->SetStyling(length,19); //must match the style set above
    }
 }
</source>
Calculate and set fold levels:
<source>
 void myFrame::setfoldlevels(size_t fromPos, int startfoldlevel, wxString& text) {
    /*we'll increase the fold level with "IF" and decrease it with "ENDIF".
    First, find all "IF" included in the text. Then we check if this IF is actually an ENDIF.
    Keep in mind that you still need to check if this is actually commented out and so on.
    This is a pretty simple and not perfect example to demonstrate basic folding*/
    std::vector<size_t>if_positions;
    size_t actual_cursorpos=0;
    while ((actual_cursorpos<text.size())&&(actual_cursorpos!=wxNOT_FOUND)) {
        actual_cursorpos=text.find("IF",actual_cursorpos+1);
        if(actual_cursorpos!=wxNOT_FOUND) {
            if_positions.push_back(actual_cursorpos+fromPos);
        }
    }
    //build a vector to include line and folding level
    //also, check if this IF is actually an ENDIF
    std::vector<std::pair<size_t,int>>foldingvector;
    int actualfoldlevel=startfoldlevel;
    for(int i=0; i<if_positions.size(); i++) {
        size_t this_line=m_activeSTC->LineFromPosition(if_positions[i]);
        //check if that "IF" is an ENDIF
        wxString endif_string;
        if(if_positions[i]>3) { //if string is longer than 3
            endif_string=text.substr(if_positions[i]-3-fromPos,5);
        }
        //if it's an IF the fold level increases, if it's an ENDIF the foldlevel decreases
        if(endif_string=="ENDIF") {
            actualfoldlevel--;
            foldingvector.push_back(std::make_pair(this_line,actualfoldlevel));
        } else {
            actualfoldlevel++;
            foldingvector.push_back(std::make_pair(this_line,actualfoldlevel));
        }
    }
    //now that we know which lines shall influence folding, we can apply to folding level to the STC line for line
    int foldlevel=startfoldlevel; //this is a temporary marker containing the foldlevel of that position
    size_t vectorcount=0;
    //get positions from line from start and end
    size_t startline=m_activeSTC->LineFromPosition(fromPos);
    size_t endline=m_activeSTC->LineFromPosition(fromPos+text.size());
    //set folding for these lines
    for(size_t i=startline; i<=endline; i++) {
        int prevlevel=foldlevel; //previous foldlevel
        int foldflag=foldlevel; //this flag will be applied to the line
        if((foldingvector.size()>0)&&(vectorcount<foldingvector.size())) {
            if(i==foldingvector[vectorcount].first) { //if the fold level changes in that line
                //new foldlevel = foldlevel in that line
                foldlevel=foldingvector[vectorcount].second;
                vectorcount++;
                if(foldlevel>prevlevel) {
                    //when incremented, this line keeps the previous fold level (!) but is marked as a folder level header
                    foldflag= foldflag | wxSTC_FOLDLEVELHEADERFLAG; //incremented, set header flag
                }
            }
        }
        foldflag= foldflag | wxSTC_FOLDLEVELBASE; //add 1024 to the fold level
        if(m_activeSTC->GetLineLength(i)==0) { //if this does not contain any characters, set the white flag
            foldflag= foldflag | wxSTC_FOLDLEVELWHITEFLAG;
        }
        //finally, set fold level to line
        m_activeSTC->SetFoldLevel(i,foldflag);
    }
 }
</source>

Finally, call the app:
<source>
 class myApp : public wxApp {
 public:
    virtual bool OnInit() {
        myFrame* frame = new myFrame(NULL);
        frame->Show();
        return true;
    }
 };

 wxIMPLEMENT_APP(myApp);
</source>

Now, you can play around with entering a few "G1 G2 G3 this is a text IF this do that ENDIF" and so on to test it. There is a lot of details that will eat your time if you want it to work really flawless.
I wrote most of it offline. Maybe the wiki doesn't like that :? So either one of you guys upload it or I'll try again tomorrow.

TobiasA
Knows some wx things
Knows some wx things
Posts: 38
Joined: Mon Aug 28, 2017 8:42 am

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by TobiasA » Thu Nov 02, 2017 5:50 am

Nope. I am officially a spambot and I'm not allowed to edit the wiki anymore :cry:

TobiasA
Knows some wx things
Knows some wx things
Posts: 38
Joined: Mon Aug 28, 2017 8:42 am

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by TobiasA » Thu Nov 02, 2017 1:08 pm

Finally :) I wrote to the google group and got unlocked.

Would be cool if someone could proof-read this before linking it to some page.

User avatar
evstevemd
Part Of The Furniture
Part Of The Furniture
Posts: 2292
Joined: Wed Jan 28, 2009 11:57 am
Location: United Republic of Tanzania
Contact:

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by evstevemd » Fri Nov 03, 2017 6:23 am

TobiasA wrote:Finally :) I wrote to the google group and got unlocked.

Would be cool if someone could proof-read this before linking it to some page.
I definitely will do that. I would suggest at the end of tutorial you put a full working code one can copy and paste and compile and it will be nice to have compile commands though not necessary.
Chief Justice: We have trouble dear citizens!
Citizens: What it is his honor?
Chief Justice:Our president is an atheist, who will he swear to?
[Ubuntu 19.04/Windows 10 Pro/MacOS 10.13 - GCC/MinGW/Clang, CodeLite IDE]

TobiasA
Knows some wx things
Knows some wx things
Posts: 38
Joined: Mon Aug 28, 2017 8:42 am

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by TobiasA » Fri Nov 03, 2017 8:17 am

I added the complete code as copy & paste section at the end.

I am using Code::Blocks under Windows so I'm not sure about the build commands- I must admit I never took so much care about it since the IDE works great with wxWidgets. No hazzle, no long setup- just select wxwidgets and there you go.
Nothing fancy though, just be sure to enable C++11.
Libraries needed:
-lib_xx_core.a
-lib_xx_stc.a
-lib_xx_adv.a
-libwxbase_xx.a

That might be worth a note in the wiki as well.

User avatar
evstevemd
Part Of The Furniture
Part Of The Furniture
Posts: 2292
Joined: Wed Jan 28, 2009 11:57 am
Location: United Republic of Tanzania
Contact:

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by evstevemd » Sun Nov 05, 2017 6:31 pm

TobiasA wrote:I added the complete code as copy & paste section at the end.

I am using Code::Blocks under Windows so I'm not sure about the build commands- I must admit I never took so much care about it since the IDE works great with wxWidgets. No hazzle, no long setup- just select wxwidgets and there you go.
Nothing fancy though, just be sure to enable C++11.
Libraries needed:
-lib_xx_core.a
-lib_xx_stc.a
-lib_xx_adv.a
-libwxbase_xx.a

That might be worth a note in the wiki as well.
I will find time to add those details
Chief Justice: We have trouble dear citizens!
Citizens: What it is his honor?
Chief Justice:Our president is an atheist, who will he swear to?
[Ubuntu 19.04/Windows 10 Pro/MacOS 10.13 - GCC/MinGW/Clang, CodeLite IDE]

TobiasA
Knows some wx things
Knows some wx things
Posts: 38
Joined: Mon Aug 28, 2017 8:42 am

Re: Custom folding in a custom lexer with LEX_CONTAINER

Post by TobiasA » Mon Nov 06, 2017 8:21 am

I added some notes at the end of the document.

It is not linked to the main page yet- if you think it is worth it you may link it to the tutorials & guides page or I will do so later on.

Thank you very much for your kind help!

Post Reply