1 /*
2  * This file is part of the FortranProject plugin for Code::Blocks IDE
3  * and licensed under the GNU General Public License, version 3
4  * http://www.gnu.org/licenses/gpl-3.0.html
5  *
6  * Author: Darius Markauskas
7  *
8  */
9 #include "constrhighlighter.h"
10 
11 #include <sdk.h>
12 #ifndef CB_PRECOMP
13     #include <configmanager.h>
14     #include <editormanager.h>
15     #include <logmanager.h>
16     #include <cbstyledtextctrl.h>
17 #endif
18 #include <algorithm>
19 
ConstrHighlighter()20 ConstrHighlighter::ConstrHighlighter():
21     m_MakeHighlight(true),
22     m_FullColour(100, 100, 255),
23     m_UnfinColour(255, 165, 0),
24     m_CurrentPosition(0),
25     m_IndicFound(24),
26     m_IndicNotFound(25),
27     m_WasCleared(true)
28 {
29     m_KeywordSet.insert(_T("if"));
30     m_KeywordSet.insert(_T("elseif"));
31     m_KeywordSet.insert(_T("then"));
32     m_KeywordSet.insert(_T("else"));
33     m_KeywordSet.insert(_T("endif"));
34     m_KeywordSet.insert(_T("do"));
35     m_KeywordSet.insert(_T("enddo"));
36     m_KeywordSet.insert(_T("while"));
37     m_KeywordSet.insert(_T("concurrent"));
38     m_KeywordSet.insert(_T("subroutine"));
39     m_KeywordSet.insert(_T("endsubroutine"));
40     m_KeywordSet.insert(_T("function"));
41     m_KeywordSet.insert(_T("endfunction"));
42     m_KeywordSet.insert(_T("abstract"));
43     m_KeywordSet.insert(_T("interface"));
44     m_KeywordSet.insert(_T("endinterface"));
45     m_KeywordSet.insert(_T("associate"));
46     m_KeywordSet.insert(_T("endassociate"));
47     m_KeywordSet.insert(_T("block"));
48     m_KeywordSet.insert(_T("endblock"));
49     m_KeywordSet.insert(_T("blockdata"));
50     m_KeywordSet.insert(_T("data"));
51     m_KeywordSet.insert(_T("endblockdata"));
52     m_KeywordSet.insert(_T("critical"));
53     m_KeywordSet.insert(_T("endcritical"));
54     m_KeywordSet.insert(_T("module"));
55     m_KeywordSet.insert(_T("endmodule"));
56     m_KeywordSet.insert(_T("program"));
57     m_KeywordSet.insert(_T("endprogram"));
58     m_KeywordSet.insert(_T("select"));
59     m_KeywordSet.insert(_T("case"));
60     m_KeywordSet.insert(_T("selectcase"));
61     m_KeywordSet.insert(_T("default"));
62     m_KeywordSet.insert(_T("is"));
63     m_KeywordSet.insert(_T("class"));
64     m_KeywordSet.insert(_T("selecttype"));
65     m_KeywordSet.insert(_T("endselect"));
66     m_KeywordSet.insert(_T("type"));
67     m_KeywordSet.insert(_T("endtype"));
68     m_KeywordSet.insert(_T("where"));
69     m_KeywordSet.insert(_T("elsewhere"));
70     m_KeywordSet.insert(_T("endwhere"));
71     m_KeywordSet.insert(_T("enum"));
72     m_KeywordSet.insert(_T("endenum"));
73     m_KeywordSet.insert(_T("forall"));
74     m_KeywordSet.insert(_T("endforall"));
75     m_KeywordSet.insert(_T("submodule"));
76     m_KeywordSet.insert(_T("endsubmodule"));
77     m_KeywordSet.insert(_T("end"));
78     m_KeywordSet.insert(_T("change"));
79     m_KeywordSet.insert(_T("team"));
80     m_KeywordSet.insert(_T("endteam"));
81     m_KeywordSet.insert(_T("procedure"));
82     m_KeywordSet.insert(_T("endprocedure"));
83 
84     MakeFConstructTypeMap();
85     FConstruct::MakeFCLReMap();
86     FConstruct::MakeFCLWordMap();
87     FConstruct::MakeWordFCLidMap();
88     m_TimeMax = 100;
89 }
90 
~ConstrHighlighter()91 ConstrHighlighter::~ConstrHighlighter()
92 {
93     FConstruct::DelFCLReMap();
94 }
95 
ReadOptions()96 void ConstrHighlighter::ReadOptions()
97 {
98     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("fortran_project"));
99     m_MakeHighlight = cfg->ReadBool(_T("/do_construct_highlighting"), true);
100     m_FullColour = cfg->ReadColour(_T("/chighlighter_full_colour"),wxColour(165, 165, 255));
101     m_UnfinColour = cfg->ReadColour(_T("/chighlighter_unfinished_colour"),wxColour(255, 165, 0));
102 }
103 
MakeFConstructTypeMap()104 void ConstrHighlighter::MakeFConstructTypeMap()
105 {
106     m_FConstructTypeMap[_T("end")] = FConstruct::ctProgramGroup;
107 
108     m_FConstructTypeMap[_T("subroutine")] = FConstruct::ctProgramGroup;
109     m_FConstructTypeMap[_T("endsubroutine")] = FConstruct::ctProgramGroup;
110 
111     m_FConstructTypeMap[_T("function")] = FConstruct::ctProgramGroup;
112     m_FConstructTypeMap[_T("endfunction")] = FConstruct::ctProgramGroup;
113 
114     m_FConstructTypeMap[_T("program")] = FConstruct::ctProgramGroup;
115     m_FConstructTypeMap[_T("endprogram")] = FConstruct::ctProgramGroup;
116 
117     m_FConstructTypeMap[_T("module")] = FConstruct::ctProgramGroup;
118     m_FConstructTypeMap[_T("endmodule")] = FConstruct::ctProgramGroup;
119 
120     m_FConstructTypeMap[_T("submodule")] = FConstruct::ctProgramGroup;
121     m_FConstructTypeMap[_T("endsubmodule")] = FConstruct::ctProgramGroup;
122 
123     m_FConstructTypeMap[_T("moduleprocedure")] = FConstruct::ctProgramGroup;
124     m_FConstructTypeMap[_T("endprocedure")] = FConstruct::ctProgramGroup;
125 
126     m_FConstructTypeMap[_T("blockdata")] = FConstruct::ctProgramGroup;
127     m_FConstructTypeMap[_T("endblockdata")] = FConstruct::ctProgramGroup;
128 
129     m_FConstructTypeMap[_T("interface")] = FConstruct::ctInterface;
130     m_FConstructTypeMap[_T("abstractinterface")] = FConstruct::ctInterface;
131     m_FConstructTypeMap[_T("endinterface")] = FConstruct::ctInterface;
132 
133     m_FConstructTypeMap[_T("ifthen")] = FConstruct::ctIf;
134     m_FConstructTypeMap[_T("elseifthen")] = FConstruct::ctIf;
135     m_FConstructTypeMap[_T("else")] = FConstruct::ctIf;
136     m_FConstructTypeMap[_T("endif")] = FConstruct::ctIf;
137 
138     m_FConstructTypeMap[_T("do")] = FConstruct::ctDo;
139     m_FConstructTypeMap[_T("dowhile")] = FConstruct::ctDo;
140     m_FConstructTypeMap[_T("doconcurrent")] = FConstruct::ctDo;
141     m_FConstructTypeMap[_T("enddo")] = FConstruct::ctDo;
142 
143     m_FConstructTypeMap[_T("associate")] = FConstruct::ctAssiciate;
144     m_FConstructTypeMap[_T("endassociate")] = FConstruct::ctAssiciate;
145 
146     m_FConstructTypeMap[_T("block")] = FConstruct::ctBlock;
147     m_FConstructTypeMap[_T("endblock")] = FConstruct::ctBlock;
148 
149     m_FConstructTypeMap[_T("selectcase")] = FConstruct::ctSelectGroup;
150     m_FConstructTypeMap[_T("case")] = FConstruct::ctSelectGroup;
151     m_FConstructTypeMap[_T("casedefault")] = FConstruct::ctSelectGroup;
152     m_FConstructTypeMap[_T("endselect")] = FConstruct::ctSelectGroup;
153 
154     m_FConstructTypeMap[_T("selecttype")] = FConstruct::ctSelectGroup;
155     m_FConstructTypeMap[_T("typeis")] = FConstruct::ctSelectGroup;
156     m_FConstructTypeMap[_T("classis")] = FConstruct::ctSelectGroup;
157     m_FConstructTypeMap[_T("classdefault")] = FConstruct::ctSelectGroup;
158 
159     m_FConstructTypeMap[_T("type")] = FConstruct::ctType;
160     m_FConstructTypeMap[_T("endtype")] = FConstruct::ctType;
161 
162     m_FConstructTypeMap[_T("critical")] = FConstruct::ctCritical;
163     m_FConstructTypeMap[_T("endcritical")] = FConstruct::ctCritical;
164 
165     m_FConstructTypeMap[_T("where")] = FConstruct::ctWhere;
166     m_FConstructTypeMap[_T("elsewhere")] = FConstruct::ctWhere;
167     m_FConstructTypeMap[_T("endwhere")] = FConstruct::ctWhere;
168 
169     m_FConstructTypeMap[_T("enum")] = FConstruct::ctEnum;
170     m_FConstructTypeMap[_T("endenum")] = FConstruct::ctEnum;
171 
172     m_FConstructTypeMap[_T("forall")] = FConstruct::ctForall;
173     m_FConstructTypeMap[_T("endforall")] = FConstruct::ctForall;
174 
175     m_FConstructTypeMap[_T("changeteam")] = FConstruct::ctTeam;
176     m_FConstructTypeMap[_T("endteam")] = FConstruct::ctTeam;
177 }
178 
ClearHighlighting(cbStyledTextCtrl * control,bool forceAction)179 void ConstrHighlighter::ClearHighlighting(cbStyledTextCtrl* control, bool forceAction)
180 {
181     if (!control)
182         return;
183 
184     if (!m_WasCleared || forceAction)
185     {
186         const int old_indic = control->GetIndicatorCurrent();
187         control->SetIndicatorCurrent(m_IndicFound);
188         control->IndicatorClearRange(0, control->GetLength());
189         control->SetIndicatorCurrent(m_IndicNotFound);
190         control->IndicatorClearRange(0, control->GetLength());
191         m_WasCleared = true;
192         control->SetIndicatorCurrent(old_indic);
193         if (forceAction)
194             m_CurrentPosition = 0;
195     }
196 }
197 
DoWork(cbEditor * editor,FortranSourceForm fsForm)198 void ConstrHighlighter::DoWork(cbEditor* editor, FortranSourceForm fsForm)
199 {
200     cbStyledTextCtrl* control = editor->GetControl();
201 
202     if (!m_MakeHighlight || !control->GetSelectionEmpty())
203     {
204         ClearHighlighting(control);
205         return;
206     }
207 
208     m_Watch.Start();
209 
210     int cpos = control->GetCurrentPos();
211     if (cpos == m_CurrentPosition)
212         return; // nothing is changed
213     m_CurrentPosition = cpos;
214     m_CurrentSForm = fsForm;
215 
216     const int old_indic = control->GetIndicatorCurrent();
217     if (!m_WasCleared)
218     {
219         control->SetIndicatorCurrent(m_IndicFound);
220         control->IndicatorClearRange(0, control->GetLength());
221         m_WasCleared = true;
222         control->SetIndicatorCurrent(old_indic);
223     }
224 
225     int style = control->GetStyleAt(cpos);
226     if (style != wxSCI_F_WORD)
227         return;
228 
229     int wstart = control->WordStartPosition(cpos, true);
230     if (wstart == cpos)
231         return; // do not highlight if the cursor is on the start of keyword
232     int wend = control->WordEndPosition(cpos, true);
233     wxString cword = control->GetTextRange(wstart,wend).Lower();
234     if (cword.IsEmpty())
235         return;
236     else if (m_KeywordSet.count(cword) == 0)
237         return;
238 
239     Keyword word1;
240     Keyword word2;
241     Keyword word3;
242     FConstruct::FCLid flid;
243     KeywordList myPairs;
244     bool foundFull;
245 
246     std::vector<FConstruct::FCLid> flidAll;
247     flidAll = FConstruct::WordFCLidMap[cword];
248     if (flidAll.empty())
249         return;
250     bool containsK = false;
251     int flineStartPos;
252     int flineEndPos;
253     wxString fLine;
254     GetFortranLine(control, wstart, fLine, flineStartPos, flineEndPos);
255     for (size_t i=0; i<flidAll.size(); i++)
256     {
257         if (FConstruct::FCLReMap.count(flidAll[i]) == 0)
258             continue;
259 
260         bool match = false;
261         if (flidAll[i] == FConstruct::fclIf_else)
262         {
263             if ( FConstruct::FCLReMap[FConstruct::fclIf_else]->Matches(fLine) &&
264                 !FConstruct::FCLReMap[FConstruct::fclWhere_else_where]->Matches(fLine))
265                     match = true;
266         }
267         else if (flidAll[i] == FConstruct::fclBlock_end_block)
268         {
269             if ( FConstruct::FCLReMap[FConstruct::fclBlock_end_block]->Matches(fLine) &&
270                 !FConstruct::FCLReMap[FConstruct::fclBlockdata_end_blockdata]->Matches(fLine))
271                     match = true;
272         }
273         else if (FConstruct::FCLReMap[flidAll[i]]->Matches(fLine))
274         {
275             match = true;
276         }
277 
278         if (match)
279         {
280             wxString wstr1, wstr2, wstr3;
281             FConstruct::GetWordsFromFCLid(flidAll[i], wstr1, wstr2, wstr3);
282 
283             wxString str1, str2, str3;
284             int str1Pos, str2Pos, str3Pos;
285             int pos = FindFKeyword(control, flineStartPos, control->GetLength(), flidAll[i], wstr1, wstr2, wstr3,
286                                    str1, str1Pos, str2, str2Pos, str3, str3Pos);
287             word1.word = str1;
288             word1.posStart = str1Pos;
289             word2.word = str2;
290             word2.posStart = str2Pos;
291             word3.word = str3;
292             word3.posStart = str3Pos;
293 
294             if ((str1 + str2 + str3) == _T("end"))
295                 flid = FConstruct::fclProgGroup_end;
296             else
297                 flid = flidAll[i];
298 
299             if (pos == wxSCI_INVALID_POSITION)
300                 containsK = false;
301             else
302                 containsK = true;
303             break;
304         }
305     }
306     if (!containsK)
307         return;
308 
309     FindMyPairs(control, word1, word2, word3, flid, myPairs, foundFull);
310 
311     if (m_Watch.Time() > m_TimeMax)
312         return;
313 
314     if (foundFull)
315         control->IndicatorSetForeground(m_IndicFound, m_FullColour);
316     else
317         control->IndicatorSetForeground(m_IndicFound, m_UnfinColour);
318     control->IndicatorSetStyle(m_IndicFound, wxSCI_INDIC_ROUNDBOX);
319     control->IndicatorSetAlpha(m_IndicFound, 100);
320     control->IndicatorSetOutlineAlpha(m_IndicFound, 255);
321     control->IndicatorSetUnder(m_IndicFound,true);
322     control->SetIndicatorCurrent(m_IndicFound);
323 
324     m_WasCleared = false;
325 
326     for (KeywordList::iterator it = myPairs.begin(); it != myPairs.end(); ++it)
327     {
328         control->IndicatorFillRange(it->posStart, it->word.length());
329     }
330     control->SetIndicatorCurrent(old_indic);
331 }
332 
333 
FindMyPairs(cbStyledTextCtrl * control,Keyword & word1,Keyword & word2,Keyword & word3,FConstruct::FCLid flid,KeywordList & myPairs,bool & foundFull)334 void ConstrHighlighter::FindMyPairs(cbStyledTextCtrl* control, Keyword &word1, Keyword &word2, Keyword &word3, FConstruct::FCLid flid,
335                                     KeywordList &myPairs, bool &foundFull)
336 {
337     foundFull = false;
338     // Get Fortran construct to search for
339     FConstruct fcon;       // full construct
340     FConstruct unFconBack; // unfinished construct we should search
341     FConstruct unFconForth;
342     GetFortranConstruct(word1, word2, word3, fcon);
343     if (fcon.GetType() != FConstruct::ctProgramGroup && fcon.GetType() != FConstruct::ctSelectGroup && fcon.Size() == 0)
344         return;
345 
346     SearchDirection sdir;
347     GetSearchDirection(word1, word2, word3, sdir, unFconBack, unFconForth);
348     if (sdir == sdirUnknown)
349         return;
350 
351     myPairs.push_back(word1);
352     int wordsEndPos = word1.posStart + word1.word.size();
353     if (!word2.word.IsEmpty())
354     {
355         myPairs.push_back(word2);
356         wordsEndPos = word2.posStart + word2.word.size();
357         if (!word3.word.IsEmpty())
358         {
359             myPairs.push_back(word3);
360             wordsEndPos = word3.posStart + word3.word.size();
361         }
362     }
363 
364     bool foundBack = true;
365     if (sdir == sdirBack || sdir == sdirBackForth)
366     {
367         // Search backward
368         int pLimitBack = FindLimitPos(control, fcon, word1.posStart, sdirBack);
369         if (m_Watch.Time() > m_TimeMax)
370             return;
371         if (fcon.GetType() == FConstruct::ctProgramGroup || fcon.GetType() == FConstruct::ctSelectGroup)
372             SearchUnConGroup(control, word1.posStart, pLimitBack, fcon.GetType(), unFconBack, flid, foundBack, myPairs);
373         else
374             SearchUnCon(control, word1.posStart, pLimitBack, fcon, unFconBack, foundBack, myPairs);
375     }
376 
377     bool foundForth = true;
378     if (sdir == sdirForth || sdir == sdirBackForth)
379     {
380         // Search forth
381         int pLimitForth = FindLimitPos(control, fcon, wordsEndPos, sdirForth);
382         if (m_Watch.Time() > m_TimeMax)
383             return;
384         if (fcon.GetType() == FConstruct::ctProgramGroup || fcon.GetType() == FConstruct::ctSelectGroup)
385             SearchUnConGroup(control, wordsEndPos, pLimitForth, fcon.GetType(), unFconForth, flid, foundForth, myPairs);
386         else
387             SearchUnCon(control, wordsEndPos, pLimitForth, fcon, unFconForth, foundForth, myPairs);
388     }
389     foundFull = (foundBack && foundForth);
390 }
391 
SearchUnCon(cbStyledTextCtrl * control,int pStartC,int pEndC,const FConstruct & fcon,const FConstruct & unFcon,bool & foundEnd,KeywordList & myPairs)392 void ConstrHighlighter::SearchUnCon(cbStyledTextCtrl* control, int pStartC, int pEndC, const FConstruct& fcon, const FConstruct& unFcon,
393                                        bool& foundEnd, KeywordList& myPairs)
394 {
395     foundEnd = false;
396     wxString word1;
397     wxString word2;
398     wxString word3;
399     FConstruct::FCLid flid;
400     fcon.GetWords(0, word1, word2, word3, flid);
401 
402     wxString wordE1;
403     wxString wordE2;
404     wxString wordE3;
405     FConstruct::FCLid flidE;
406     fcon.GetWords(fcon.Size()-1, wordE1, wordE2, wordE3, flidE);
407 
408     bool searchBack = pStartC > pEndC;
409     int pStart   = pStartC;
410     int pEnd     = pEndC;
411     int level    = 0;
412     int cutEnd   = -1;
413     int cutStart = -1;
414     std::vector<int> cutEndVec;
415     std::vector<int> cutStartVec;
416 
417     wxString str1, str2, str3;
418     int str1Pos, str2Pos, str3Pos;
419 
420     wxString strE1, strE2, strE3;
421     int strE1Pos, strE2Pos, strE3Pos;
422     bool haveStart = false;
423     bool haveEnd   = false;
424 
425     while (true)
426     {
427         if (m_Watch.Time() > m_TimeMax)
428             return;
429         int posFCstart;
430         int posFCend;
431         if (!haveStart)
432             posFCstart = FindFKeyword(control, pStart, pEnd, flid, word1, word2, word3,
433                                       str1, str1Pos, str2, str2Pos, str3, str3Pos);
434         if (!haveEnd)
435             posFCend = FindFKeyword(control, pStart, pEnd, flidE, wordE1, wordE2, wordE3,
436                                       strE1, strE1Pos, strE2, strE2Pos, strE3, strE3Pos);
437 
438         if (searchBack)
439         {
440             if (posFCstart == wxSCI_INVALID_POSITION && posFCend != wxSCI_INVALID_POSITION)
441             {
442                 pEnd = GetWordsEnd(strE1, strE1Pos, strE2, strE2Pos, strE3, strE3Pos);
443                 break; // try to search intermediate keywords
444             }
445             else if (posFCstart == wxSCI_INVALID_POSITION && posFCend == wxSCI_INVALID_POSITION)
446             {
447                 pEnd = pEndC;
448                 break; // try to search intermediate keywords
449             }
450             else if (posFCstart != wxSCI_INVALID_POSITION && posFCend == wxSCI_INVALID_POSITION)
451                 posFCend = -1;
452         }
453         else
454         {
455             if (posFCstart != wxSCI_INVALID_POSITION && posFCend == wxSCI_INVALID_POSITION)
456             {
457                 pEnd = posFCstart;
458                 break; // try to search intermediate keywords
459             }
460             else if (posFCstart == wxSCI_INVALID_POSITION && posFCend == wxSCI_INVALID_POSITION)
461             {
462                 pEnd = pEndC;
463                 break; // try to search intermediate keywords
464             }
465             else if (posFCstart == wxSCI_INVALID_POSITION && posFCend != wxSCI_INVALID_POSITION)
466                 posFCstart = control->GetLength();
467         }
468 
469         if (searchBack)
470         {
471             if (posFCstart < posFCend)
472             {
473                 // Starts another level of construct
474                 if (level == 0)
475                     cutEnd = GetWordsEnd(strE1, strE1Pos, strE2, strE2Pos, strE3, strE3Pos);
476                 level += 1;
477                 pStart = posFCend;
478                 haveStart = true;
479                 haveEnd   = false;
480             }
481             else // (posFCstart > posFCend)
482             {
483                 if (level == 0)
484                 {
485                     PutToKeywordList(str1, str2, str3, str1Pos, str2Pos, str3Pos, myPairs);
486                     foundEnd = true;
487                     pEnd = GetWordsEnd(str1, str1Pos, str2, str2Pos, str3, str3Pos);
488                     break;
489                 }
490                 else if (level == 1)
491                 {
492                     cutStart = posFCstart;
493                     cutEndVec.push_back(cutEnd);
494                     cutStartVec.push_back(cutStart);
495                 }
496                 level -= 1;
497                 pStart = posFCstart;
498                 haveStart = false;
499                 haveEnd   = true;
500             }
501         }
502         else // search forth
503         {
504             if (posFCstart < posFCend)
505             {
506                 // Starts another level of construct
507                 if (level == 0)
508                     cutStart = posFCstart;
509                 level += 1;
510                 pStart = GetWordsEnd(str1, str1Pos, str2, str2Pos, str3, str3Pos);
511                 haveStart = false;
512                 haveEnd   = true;
513             }
514             else // (posFCstart > posFCend)
515             {
516                 if (level == 0)
517                 {
518                     PutToKeywordList(strE1, strE2, strE3, strE1Pos, strE2Pos, strE3Pos, myPairs);
519                     foundEnd = true;
520                     pEnd = strE1Pos;
521                     break;
522                 }
523                 else if (level == 1)
524                 {
525                     cutEnd = GetWordsEnd(strE1, strE1Pos, strE2, strE2Pos, strE3, strE3Pos);
526                     cutEndVec.push_back(cutEnd);
527                     cutStartVec.push_back(cutStart);
528                 }
529                 level -= 1;
530                 pStart = GetWordsEnd(strE1, strE1Pos, strE2, strE2Pos, strE3, strE3Pos);
531                 haveStart = true;
532                 haveEnd   = false;
533             }
534         }
535     }
536 
537     // Find intermediate keywords
538     SearchUnConIntermediate(control, pStartC, pEnd, unFcon, cutEndVec, cutStartVec, myPairs);
539 }
540 
SearchUnConGroup(cbStyledTextCtrl * control,int pStartC,int pEndC,FConstruct::FConstructType fct,const FConstruct & unFcon,FConstruct::FCLid fcl,bool & foundEnd,KeywordList & myPairs)541 void ConstrHighlighter::SearchUnConGroup(cbStyledTextCtrl* control, int pStartC, int pEndC, FConstruct::FConstructType fct,
542                                        const FConstruct& unFcon, FConstruct::FCLid fcl, bool& foundEnd, KeywordList& myPairs)
543 {
544     foundEnd = false;
545 
546     bool searchBack = pStartC > pEndC;
547     int pStart = pStartC;
548     int pEnd   = pEndC;
549     int level  = 0;
550     int cutEnd   = -1;
551     int cutStart = -1;
552     std::vector<int> cutEndVec;
553     std::vector<int> cutStartVec;
554 
555     wxString str1, str2, str3;
556     int str1Pos, str2Pos, str3Pos;
557 
558     wxString strE1, strE2, strE3;
559     int strE1Pos, strE2Pos, strE3Pos;
560 
561     FConstruct::FCLid flid;
562     FConstruct::FCLid flidE;
563     if (fct == FConstruct::ctProgramGroup)
564     {
565         flid = FConstruct::fclProgGroup_start;
566         flidE = FConstruct::fclProgGroup_end;
567     }
568     else if (fct == FConstruct::ctSelectGroup)
569     {
570         flid = FConstruct::fclSelGroup_start;
571         flidE = FConstruct::fclSelGroup_end;
572     }
573     else
574         return; // this should not happen
575 
576     bool haveStart = false;
577     bool haveEnd = false;
578     int posFCstart;
579     int posFCend;
580 
581     while (true)
582     {
583         if (m_Watch.Time() > m_TimeMax)
584             return;
585         int lineStartPos;
586         int lineEndPos;
587         FConstruct::FCLid flidFound;
588         if (!haveStart)
589             posFCstart = FindGroupKeyword(control, pStart, pEnd, flid,
590                                       str1, str1Pos, str2, str2Pos, str3, str3Pos);
591 
592         bool oneWord;
593         if (!haveEnd)
594         {
595             if (fct == FConstruct::ctProgramGroup)
596                 posFCend = FindProgGroupEndKeywordPos(control, pStart, pEnd, lineStartPos, lineEndPos, flidFound, oneWord);
597             else
598                 posFCend = FindGroupKeyword(control, pStart, pEnd, flidE, strE1, strE1Pos, strE2, strE2Pos, strE3, strE3Pos);
599         }
600 
601         if (searchBack)
602         {
603             if (posFCstart == wxSCI_INVALID_POSITION)
604                 break;
605             else if (posFCend == wxSCI_INVALID_POSITION)
606                 posFCend = -1;
607         }
608         else
609         {
610             if (posFCend == wxSCI_INVALID_POSITION)
611                 break;
612             else if (posFCstart == wxSCI_INVALID_POSITION)
613                 posFCstart = control->GetLength();
614         }
615 
616         if (searchBack)
617         {
618             if (posFCstart < posFCend)
619             {
620                 // Starts another level of construct
621                 if (level == 0)
622                     cutEnd = GetWordsEnd(strE1, strE1Pos, strE2, strE2Pos, strE3, strE3Pos);
623                 level += 1;
624                 pStart = posFCend;
625                 haveStart = true;
626                 haveEnd = false;
627                 continue;
628             }
629             else if (posFCstart > posFCend)
630             {
631                 if (level == 0)
632                 {
633                     wxString strFound = str1 + str2 + str3;
634                     if ( fcl == FConstruct::fclProgGroup_end ||
635                         (fcl == FConstruct::fclSub_end_sub && strFound.IsSameAs(_T("subroutine"))) ||
636                         (fcl == FConstruct::fclFun_end_fun && strFound.IsSameAs(_T("function"))) ||
637                         (fcl == FConstruct::fclMod_end_module && strFound.IsSameAs(_T("module"))) ||
638                         (fcl == FConstruct::fclSubmod_end_submod && strFound.IsSameAs(_T("submodule"))) ||
639                         (fcl == FConstruct::fclProg_end_prog && strFound.IsSameAs(_T("program"))) ||
640                         (fcl == FConstruct::fclBlockdata_end_blockdata && strFound.IsSameAs(_T("blockdata"))) ||
641                         (fcl == FConstruct::fclProc_end_proc && strFound.IsSameAs(_T("moduleprocedure"))) ||
642 
643                          fcl == FConstruct::fclSelect_end ||
644                         (fcl == FConstruct::fclSelectCase_case && strFound.IsSameAs(_T("selectcase"))) ||
645                         (fcl == FConstruct::fclSelectType_type_is && strFound.IsSameAs(_T("selecttype"))) ||
646                         (fcl == FConstruct::fclSelectType_class_is && strFound.IsSameAs(_T("selecttype"))) ||
647                         (fcl == FConstruct::fclSelectType_class_default && strFound.IsSameAs(_T("selecttype"))) )
648                     {
649                         PutToKeywordList(str1, str2, str3, str1Pos, str2Pos, str3Pos, myPairs);
650                         foundEnd = true;
651                         pEnd = GetWordsEnd(str1, str1Pos, str2, str2Pos, str3, str3Pos);
652                     }
653                     break;
654                 }
655                 else if (fct == FConstruct::ctSelectGroup && level == 1)
656                 {
657                     cutStart = posFCstart;
658                     cutEndVec.push_back(cutEnd);
659                     cutStartVec.push_back(cutStart);
660                 }
661                 level -= 1;
662                 pStart = posFCstart;
663                 haveStart = false;
664                 haveEnd = true;
665             }
666         }
667         else // search forth
668         {
669             if (posFCstart < posFCend)
670             {
671                 // Starts another level of construct
672                 if (level == 0)
673                     cutStart = posFCstart;
674                 level += 1;
675                 pStart = GetWordsEnd(str1, str1Pos, str2, str2Pos, str3, str3Pos);
676                 haveStart = false;
677                 haveEnd = true;
678                 continue;
679             }
680             else if (posFCstart > posFCend)
681             {
682                 if (level == 0)
683                 {
684                     if (fct == FConstruct::ctProgramGroup)
685                     {
686                         if ( oneWord ||
687                             (fcl == FConstruct::fclBlockdata_blockdata && flidFound == FConstruct::fclBlockdata_end_blockdata))
688                         {
689                             GetKeyworsFromLine(control, flidFound, lineStartPos, lineEndPos, strE1, strE2, strE3, strE1Pos, strE2Pos, strE3Pos);
690 
691                             wxString strFound = strE1 + strE2 + strE3;
692                             if ( strFound.IsSameAs(_T("end")) ||
693                                  (fcl == FConstruct::fclSub_sub && strFound.IsSameAs(_T("endsubroutine"))) ||
694                                  (fcl == FConstruct::fclFun_fun && strFound.IsSameAs(_T("endfunction"))) ||
695                                  (fcl == FConstruct::fclMod_module && strFound.IsSameAs(_T("endmodule"))) ||
696                                  (fcl == FConstruct::fclSubmod_submod && strFound.IsSameAs(_T("endsubmodule"))) ||
697                                  (fcl == FConstruct::fclProg_prog && strFound.IsSameAs(_T("endprogram"))) ||
698                                  (fcl == FConstruct::fclProc_mod_proc && strFound.IsSameAs(_T("endprocedure"))) )
699                             {
700                                 PutToKeywordList(strE1, strE2, strE3, strE1Pos, strE2Pos, strE3Pos, myPairs);
701                                 foundEnd = true;
702                             }
703                         }
704                         else if ((fcl == FConstruct::fclSub_sub && flidFound == FConstruct::fclSub_end_sub) ||
705                                  (fcl == FConstruct::fclFun_fun && flidFound == FConstruct::fclFun_end_fun) ||
706                                  (fcl == FConstruct::fclMod_module && flidFound == FConstruct::fclMod_end_module) ||
707                                  (fcl == FConstruct::fclSubmod_submod && flidFound == FConstruct::fclSubmod_end_submod) ||
708                                  (fcl == FConstruct::fclProg_prog && flidFound == FConstruct::fclProg_end_prog) ||
709                                  (fcl == FConstruct::fclProc_mod_proc && flidFound == FConstruct::fclProc_end_proc))
710                         {
711                             std::vector<wxString> sWords = FConstruct::FCLWordMap[flidFound];
712                             strE1 = sWords[0]+sWords[1];
713                             strE2 = wxEmptyString;
714                             strE3 = wxEmptyString;
715                             PutToKeywordList(strE1, strE2, strE3, posFCend, 0, 0, myPairs);
716                             foundEnd = true;
717                         }
718                     }
719                     else
720                     {
721                         wxString strFound = strE1 + strE2 + strE3;
722                         if (strFound.IsSameAs(_T("endselect")))
723                         {
724                             PutToKeywordList(strE1, strE2, strE3, strE1Pos, strE2Pos, strE3Pos, myPairs);
725                             foundEnd = true;
726                             pEnd = strE1Pos;
727                         }
728                     }
729                     break;
730                 }
731                 else if (fct == FConstruct::ctSelectGroup && level == 1)
732                 {
733                     cutEndVec.push_back(GetWordsEnd(strE1, strE1Pos, strE2, strE2Pos, strE3, strE3Pos));
734                     cutStartVec.push_back(cutStart);
735                 }
736                 level -= 1;
737                 if (fct == FConstruct::ctProgramGroup)
738                     pStart = lineEndPos;
739                 else
740                     pStart = GetWordsEnd(strE1, strE1Pos, strE2, strE2Pos, strE3, strE3Pos);
741                 haveStart = true;
742                 haveEnd = false;
743             }
744         }
745     }
746 
747     if (fct == FConstruct::ctSelectGroup)
748     {
749         // Find intermediate keywords
750         SearchUnConIntermediate(control, pStartC, pEnd, unFcon, cutEndVec, cutStartVec, myPairs);
751     }
752 }
753 
SearchUnConIntermediate(cbStyledTextCtrl * control,int pStartC,int pEndC,const FConstruct & unFcon,std::vector<int> & cutEndVec,std::vector<int> & cutStartVec,KeywordList & myPairs)754 void ConstrHighlighter::SearchUnConIntermediate(cbStyledTextCtrl* control, int pStartC, int pEndC, const FConstruct& unFcon,
755                                               std::vector<int>& cutEndVec, std::vector<int>& cutStartVec, KeywordList& myPairs)
756 {
757     // Find intermediate keywords
758     bool searchBack = pStartC > pEndC;
759     FConstruct::FCLid flid;
760     wxString str1, str2, str3;
761     int str1Pos, str2Pos, str3Pos;
762 
763     for (size_t i=1; i<unFcon.Size(); i++)
764     {
765         int ik = searchBack? i : i-1;
766         wxString word1, word2, word3;
767         unFcon.GetWords(ik, word1, word2, word3, flid);
768         if (flid == FConstruct::fclUnknown)
769             return; // something wrong
770         int pInterStart = pStartC;
771         int pInterEnd = pEndC;
772 
773         while (true)
774         {
775             int pos = FindFKeyword(control, pInterStart, pInterEnd, flid, word1, word2, word3,
776                                       str1, str1Pos, str2, str2Pos, str3, str3Pos);
777             if (pos == wxSCI_INVALID_POSITION)
778                 break;
779 
780             bool wasCut = false;
781             for (size_t j=0; j<cutStartVec.size(); j++)
782             {
783                 if (pos > cutStartVec[j] && pos < cutEndVec[j])
784                 {
785                     wasCut = true;
786                     break;
787                 }
788             }
789 
790             if (!wasCut)
791                 PutToKeywordList(str1, str2, str3, str1Pos, str2Pos, str3Pos, myPairs);
792 
793             if (searchBack)
794                 pInterStart = pos;
795             else
796                 pInterStart = GetWordsEnd(str1, str1Pos, str2, str2Pos, str3, str3Pos);
797         }
798     }
799 }
800 
GetWordsEnd(wxString & str1,int str1Pos,wxString & str2,int str2Pos,wxString & str3,int str3Pos)801 int ConstrHighlighter::GetWordsEnd(wxString& str1, int str1Pos, wxString& str2, int str2Pos, wxString& str3, int str3Pos)
802 {
803     int wend = -1;
804     if (!str3.IsEmpty())
805         wend = str3Pos + str3.Length();
806     else if (!str2.IsEmpty())
807         wend = str2Pos + str2.Length();
808     else if (!str1.IsEmpty())
809         wend = str1Pos + str1.Length();
810     return wend;
811 }
812 
PutToKeywordList(wxString & str1,wxString & str2,wxString & str3,int str1Pos,int str2Pos,int str3Pos,KeywordList & kList)813 void ConstrHighlighter::PutToKeywordList(wxString& str1, wxString& str2, wxString& str3,
814                                        int str1Pos, int str2Pos, int str3Pos, KeywordList& kList)
815 {
816     Keyword sk = {str1, str1Pos};
817     kList.push_back(sk);
818     if (str2Pos != wxSCI_INVALID_POSITION)
819     {
820         sk.word = str2;
821         sk.posStart = str2Pos;
822         kList.push_back(sk);
823         if (str3Pos != wxSCI_INVALID_POSITION)
824         {
825             sk.word = str3;
826             sk.posStart = str3Pos;
827             kList.push_back(sk);
828         }
829     }
830 }
831 
FindFKeywordFull(cbStyledTextCtrl * control,int pStart,int pEnd,FConstruct::FCLid flid,const wxString & sWord1,const wxString & sWord2,const wxString & sWord3,wxString & str1,int & str1Pos,wxString & str2,int & str2Pos,wxString & str3,int & str3Pos)832 int ConstrHighlighter::FindFKeywordFull(cbStyledTextCtrl* control, int pStart, int pEnd, FConstruct::FCLid flid, const wxString& sWord1, const wxString& sWord2, const wxString& sWord3,
833                                       wxString& str1, int& str1Pos, wxString& str2, int& str2Pos, wxString& str3, int& str3Pos)
834 {
835     if (FConstruct::FCLReMap.count(flid) == 0)
836         return wxSCI_INVALID_POSITION;
837 
838     bool searchBack = pStart > pEnd;
839     int flag;
840     wxString sw1;
841     int cStart = pStart;
842     if (sWord2.IsEmpty())
843     {
844         sw1 = sWord1;
845         flag = wxSCI_FIND_WORDSTART;
846     }
847     else
848     {
849         sw1 = sWord2;
850         flag = 0;
851     }
852 
853     while (true)
854     {
855         int pos = FindText(control, cStart, pEnd, sw1, flag);
856         if (pos == wxSCI_INVALID_POSITION)
857             return wxSCI_INVALID_POSITION;
858 
859         wxString fLine;
860         int lineStartPos;
861         int lineEndPos;
862         GetFortranLine(control, pos, fLine, lineStartPos, lineEndPos);
863 
864         if (FConstruct::FCLReMap[flid]->Matches(fLine))
865         {
866             int nfilled = 0;
867             pos = FindText(control, lineStartPos, lineEndPos, sWord1, wxSCI_FIND_WHOLEWORD);
868             if (pos != wxSCI_INVALID_POSITION)
869             {
870                 str1 = sWord1;
871                 str1Pos = pos;
872                 if (sWord2.IsEmpty())
873                     return pos;
874                 sw1 = sWord2;
875                 nfilled++;
876             }
877             else
878                 sw1 = sWord1 + sWord2;
879 
880             pos = FindText(control, lineStartPos, lineEndPos, sw1, wxSCI_FIND_WHOLEWORD);
881             if (pos != wxSCI_INVALID_POSITION)
882             {
883                 if (nfilled == 0)
884                 {
885                     str1 = sWord1;
886                     str1Pos = pos;
887                 }
888                 else
889                 {
890                     str2 = sWord2;
891                     str2Pos = pos;
892                 }
893 
894                 if (sWord3.IsEmpty())
895                     return pos;
896                 sw1 = sWord3;
897                 nfilled++;
898             }
899             else
900                 return wxSCI_INVALID_POSITION;
901 
902             pos = FindText(control, lineStartPos, lineEndPos, sw1, wxSCI_FIND_WHOLEWORD);
903             if (pos != wxSCI_INVALID_POSITION)
904             {
905                 if (nfilled == 1)
906                 {
907                     str2 = sw1;
908                     str2Pos = pos;
909                 }
910                 else
911                 {
912                     str3 = sw1;
913                     str3Pos = pos;
914                 }
915             }
916             else
917                 return wxSCI_INVALID_POSITION;
918         }
919         else
920         {
921             if(searchBack)
922             {
923                 cStart = lineStartPos;
924                 if (cStart <= pEnd)
925                     return wxSCI_INVALID_POSITION;
926             }
927             else
928             {
929                 cStart = lineEndPos;
930                 if (cStart >= pEnd)
931                     return wxSCI_INVALID_POSITION;
932             }
933         }
934     }
935 }
936 
FindProgGroupEndKeywordPos(cbStyledTextCtrl * control,int pStart,int pEnd,int & lineStartPos,int & lineEndPos,FConstruct::FCLid & flid,bool & oneWord)937 int ConstrHighlighter::FindProgGroupEndKeywordPos(cbStyledTextCtrl* control, int pStart, int pEnd, int& lineStartPos, int& lineEndPos,
938                                                   FConstruct::FCLid& flid, bool& oneWord)
939 {
940     int nUsed = 0;
941     bool searchBack = pStart > pEnd;
942 
943     flid = FConstruct::fclUnknown;
944     oneWord = false;
945 
946     std::vector<FConstruct::FCLid> flidAll;
947     flidAll.push_back(FConstruct::fclFun_end_fun);
948     flidAll.push_back(FConstruct::fclSub_end_sub);
949     flidAll.push_back(FConstruct::fclProg_end_prog);
950     flidAll.push_back(FConstruct::fclMod_end_module);
951     flidAll.push_back(FConstruct::fclSubmod_end_submod);
952     flidAll.push_back(FConstruct::fclBlockdata_end_blockdata);
953     flidAll.push_back(FConstruct::fclProc_end_proc);
954 
955     wxString sW = _T("end");
956     while (true)
957     {
958         int pos = FindText(control, pStart, pEnd, sW, wxSCI_FIND_WORDSTART);
959 
960         if (pos == wxSCI_INVALID_POSITION)
961             break;
962 
963         int wordendpos = control->WordEndPosition(pos, true);
964         wxString foundWord = control->GetTextRange(pos, wordendpos).Lower();
965         if (foundWord.IsSameAs(sW))
966         {
967             nUsed = 1;
968         }
969         else if (foundWord.IsSameAs(_T("endsubroutine")))
970         {
971             flid = FConstruct::fclSub_end_sub;
972             nUsed = 2;
973         }
974         else if (foundWord.IsSameAs(_T("endfunction")))
975         {
976             flid = FConstruct::fclFun_end_fun;
977             nUsed = 2;
978         }
979         else if (foundWord.IsSameAs(_T("endprogram")))
980         {
981             flid = FConstruct::fclProg_end_prog;
982             nUsed = 2;
983         }
984         else if (foundWord.IsSameAs(_T("endmodule")))
985         {
986             flid = FConstruct::fclMod_end_module;
987             nUsed = 2;
988         }
989         else if (foundWord.IsSameAs(_T("endsubmodule")))
990         {
991             flid = FConstruct::fclSubmod_end_submod;
992             nUsed = 2;
993         }
994         else if (foundWord.IsSameAs(_T("endblock")))
995         {
996             flid = FConstruct::fclBlockdata_end_blockdata;
997             nUsed = 2;
998         }
999         else if (foundWord.IsSameAs(_T("endblockdata")))
1000         {
1001             flid = FConstruct::fclBlockdata_end_blockdata;
1002             nUsed = 3;
1003         }
1004         else if (foundWord.IsSameAs(_T("endprocedure")))
1005         {
1006             flid = FConstruct::fclProc_end_proc;
1007             nUsed = 2;
1008         }
1009         else
1010         {
1011             pStart = searchBack? pos : pos+foundWord.Length();
1012             continue;
1013         }
1014 
1015         wxString fLine;
1016         GetFortranLine(control, pos, fLine, lineStartPos, lineEndPos);
1017 
1018         if (nUsed == 1)
1019         {
1020             for (size_t i=0; i<flidAll.size(); i++)
1021             {
1022                 if (FConstruct::FCLReMap[flidAll[i]]->Matches(fLine))
1023                 {
1024                     oneWord = true;
1025                     flid = flidAll[i];
1026                     return pos;
1027                 }
1028             }
1029         }
1030         else
1031         {
1032             if (FConstruct::FCLReMap[flid]->Matches(fLine))
1033                 return pos;
1034         }
1035 
1036         pStart = searchBack? pos : pos+foundWord.Length();
1037     }
1038     return wxSCI_INVALID_POSITION;
1039 }
1040 
FindGroupKeyword(cbStyledTextCtrl * control,int pStart,int pEnd,FConstruct::FCLid flid,wxString & rstr1,int & rstr1Pos,wxString & rstr2,int & rstr2Pos,wxString & rstr3,int & rstr3Pos)1041 int ConstrHighlighter::FindGroupKeyword(cbStyledTextCtrl* control, int pStart, int pEnd, FConstruct::FCLid flid,
1042                                       wxString& rstr1, int& rstr1Pos, wxString& rstr2, int& rstr2Pos, wxString& rstr3, int& rstr3Pos)
1043 {
1044     int posGK = wxSCI_INVALID_POSITION;
1045     rstr1 = wxEmptyString;
1046     rstr1Pos = wxSCI_INVALID_POSITION;
1047     rstr2 = wxEmptyString;
1048     rstr2Pos = wxSCI_INVALID_POSITION;
1049     rstr3 = wxEmptyString;
1050     rstr3Pos = wxSCI_INVALID_POSITION;
1051 
1052     std::vector<FConstruct::FCLid> flidAll;
1053     if (flid == FConstruct::fclProgGroup_end)
1054     {
1055         flidAll.push_back(FConstruct::fclFun_end_fun);
1056         flidAll.push_back(FConstruct::fclSub_end_sub);
1057         flidAll.push_back(FConstruct::fclProg_end_prog);
1058         flidAll.push_back(FConstruct::fclMod_end_module);
1059         flidAll.push_back(FConstruct::fclSubmod_end_submod);
1060         flidAll.push_back(FConstruct::fclBlockdata_end_blockdata);
1061         flidAll.push_back(FConstruct::fclProc_end_proc);
1062     }
1063     else if (flid == FConstruct::fclProgGroup_start)
1064     {
1065         flidAll.push_back(FConstruct::fclFun_fun);
1066         flidAll.push_back(FConstruct::fclSub_sub);
1067         flidAll.push_back(FConstruct::fclProg_prog);
1068         flidAll.push_back(FConstruct::fclMod_module);
1069         flidAll.push_back(FConstruct::fclSubmod_submod);
1070         flidAll.push_back(FConstruct::fclBlockdata_blockdata);
1071         flidAll.push_back(FConstruct::fclProc_mod_proc);
1072     }
1073     else if (flid == FConstruct::fclSelGroup_end)
1074     {
1075         flidAll.push_back(FConstruct::fclSelect_end);
1076     }
1077     else if (flid == FConstruct::fclSelGroup_start)
1078     {
1079         flidAll.push_back(FConstruct::fclSelectCase_start);
1080         flidAll.push_back(FConstruct::fclSelectType_start);
1081     }
1082     else
1083         return posGK;
1084 
1085     wxString str1, str2, str3;
1086     int str1Pos, str2Pos, str3Pos;
1087     bool searchBack = pStart > pEnd;
1088 
1089     for (size_t i=0; i<flidAll.size(); i++)
1090     {
1091         std::vector<wxString> sWords;
1092         if (FConstruct::FCLWordMap.count(flidAll[i]) == 0)
1093             continue;
1094         sWords = FConstruct::FCLWordMap[flidAll[i]];
1095 
1096         int pos = FindFKeyword(control, pStart, pEnd, flidAll[i], sWords[0], sWords[1], sWords[2],
1097                                str1, str1Pos, str2, str2Pos, str3, str3Pos);
1098         if (pos != wxSCI_INVALID_POSITION)
1099         {
1100             if ((posGK == wxSCI_INVALID_POSITION) ||
1101                 (posGK != wxSCI_INVALID_POSITION && searchBack && pos > posGK) ||
1102                 (posGK != wxSCI_INVALID_POSITION && !searchBack && pos < posGK))
1103             {
1104                 posGK = pos;
1105                 rstr1 = str1;
1106                 rstr1Pos = str1Pos;
1107                 rstr2 = str2;
1108                 rstr2Pos = str2Pos;
1109                 rstr3 = str3;
1110                 rstr3Pos = str3Pos;
1111                 if (searchBack)
1112                     pEnd = pos + 2;
1113                 else
1114                     pEnd = pos - 2;
1115             }
1116         }
1117     }
1118     return posGK;
1119 }
1120 
FindFKeyword(cbStyledTextCtrl * control,int pStart,int pEnd,FConstruct::FCLid flid,const wxString & sWord1,const wxString & sWord2,const wxString & sWord3,wxString & str1,int & str1Pos,wxString & str2,int & str2Pos,wxString & str3,int & str3Pos)1121 int ConstrHighlighter::FindFKeyword(cbStyledTextCtrl* control, int pStart, int pEnd, FConstruct::FCLid flid, const wxString& sWord1, const wxString& sWord2, const wxString& sWord3,
1122                                   wxString& str1, int& str1Pos, wxString& str2, int& str2Pos, wxString& str3, int& str3Pos)
1123 {
1124     const int flag = wxSCI_FIND_WORDSTART; // wxSCI_FIND_WHOLEWORD;
1125     int nUsed;
1126     str1 = wxEmptyString;
1127     str1Pos = wxSCI_INVALID_POSITION;
1128     str2 = wxEmptyString;
1129     str2Pos = wxSCI_INVALID_POSITION;
1130     str3 = wxEmptyString;
1131     str3Pos = wxSCI_INVALID_POSITION;
1132     bool searchBack = pStart > pEnd;
1133 
1134     while (true)
1135     {
1136         wxString sW = sWord1;
1137         int pos = FindText(control, pStart, pEnd, sW, flag);
1138 
1139         if (pos == wxSCI_INVALID_POSITION)
1140             return wxSCI_INVALID_POSITION;
1141 
1142         int wordendpos = control->WordEndPosition(pos, true);
1143         wxString foundWord = control->GetTextRange(pos, wordendpos).Lower();
1144         if (foundWord.IsSameAs(sWord1))
1145             nUsed = 1;
1146         else if (!sWord2.IsEmpty() && foundWord.IsSameAs(sWord1+sWord2))
1147             nUsed = 2;
1148         else if (flid == FConstruct::fclBlockdata_end_blockdata && foundWord.IsSameAs(_T("endblockdata")))
1149             nUsed = 3;
1150         else
1151         {
1152             pStart = searchBack? pos : pos+foundWord.Length();
1153             continue;
1154         }
1155 
1156         str1 = foundWord;
1157         str1Pos = pos;
1158         wxString fLine;
1159         int lineStartPos;
1160         int lineEndPos;
1161         GetFortranLine(control, pos, fLine, lineStartPos, lineEndPos);
1162 
1163         if (FConstruct::FCLReMap.count(flid) == 0)
1164             return wxSCI_INVALID_POSITION;
1165 
1166         bool match = false;
1167         if (flid == FConstruct::fclIf_else)
1168         {
1169             if ( FConstruct::FCLReMap[FConstruct::fclIf_else]->Matches(fLine) &&
1170                 !FConstruct::FCLReMap[FConstruct::fclWhere_else_where]->Matches(fLine))
1171                     match = true;
1172         }
1173         else if (flid == FConstruct::fclBlock_end_block)
1174         {
1175             if ( FConstruct::FCLReMap[FConstruct::fclBlock_end_block]->Matches(fLine) &&
1176                 !FConstruct::FCLReMap[FConstruct::fclBlockdata_end_blockdata]->Matches(fLine))
1177                     match = true;
1178         }
1179         else if (FConstruct::FCLReMap[flid]->Matches(fLine))
1180             match = true;
1181 
1182         if (match)
1183         {
1184             // We already found keyword.
1185             // Now find positions of sWord2 and sWord3
1186             if (nUsed == 1 && sWord2.IsEmpty())
1187             {
1188                 if (flid == FConstruct::fclInterf_interf)
1189                 {
1190                     // check "abstract interface"
1191                     pos = FindText(control, pos-16, pos-1, _T("abstract"), wxSCI_FIND_WHOLEWORD);
1192                     if (pos != wxSCI_INVALID_POSITION)
1193                     {
1194                         str2Pos = str1Pos;
1195                         str2 = str1;
1196                         str1Pos = pos;
1197                         str1 = _T("abstract");
1198                     }
1199                 }
1200                 else if (flid == FConstruct::fclDo_do)
1201                 {
1202                     pos = FindText(control, str1Pos+3, str1Pos+10, _T("while"), wxSCI_FIND_WHOLEWORD);
1203                     if (pos != wxSCI_INVALID_POSITION)
1204                     {
1205                         str2Pos = pos;
1206                         str2 = _T("while");
1207                     }
1208                     else
1209                     {
1210                         pos = FindText(control, str1Pos+3, str1Pos+15, _T("concurrent"), wxSCI_FIND_WHOLEWORD);
1211                         if (pos != wxSCI_INVALID_POSITION)
1212                         {
1213                             str2Pos = pos;
1214                             str2 = _T("concurrent");
1215                         }
1216                     }
1217                 }
1218                 return str1Pos;
1219             }
1220             else if (nUsed == 1)
1221             {
1222                 sW = sWord2;
1223                 nUsed = 2;
1224             }
1225             else if ((nUsed == 2) && sWord3.IsEmpty())
1226                 return str1Pos;
1227             else if (nUsed == 3)
1228                 return str1Pos;
1229             else
1230             {
1231                 sW = sWord3;
1232                 nUsed = 3;
1233             }
1234 
1235             if (nUsed == 2 && flid == FConstruct::fclBlockdata_end_blockdata)
1236             {
1237                 pos = FindText(control, pos+1, lineEndPos, sW, wxSCI_FIND_WORDSTART);
1238                 wordendpos = control->WordEndPosition(pos, true);
1239                 foundWord = control->GetTextRange(pos, wordendpos).Lower();
1240                 if (foundWord.IsSameAs(_T("block")))
1241                 {
1242                     str2 = foundWord;
1243                     str2Pos = pos;
1244                     sW = sWord3;
1245                     pos = FindText(control, pos+1, lineEndPos, sW, wxSCI_FIND_WHOLEWORD);
1246                     if (pos == wxSCI_INVALID_POSITION)
1247                         return str1Pos;
1248                     else
1249                     {
1250                         str3 = sW;
1251                         str3Pos = pos;
1252                         return str1Pos;
1253                     }
1254                 }
1255                 else if (foundWord.IsSameAs(_T("blockdata")))
1256                 {
1257                     str2 = foundWord;
1258                     str2Pos = pos;
1259                     return str1Pos;
1260                 }
1261                 else
1262                     return wxSCI_INVALID_POSITION;
1263             }
1264             else
1265                 pos = FindText(control, pos+1, lineEndPos, sW, wxSCI_FIND_WHOLEWORD);
1266 
1267             if (pos == wxSCI_INVALID_POSITION)
1268                 return str1Pos; // Second word was not found.
1269             if (nUsed == 2)
1270             {
1271                 str2 = sW;
1272                 str2Pos = pos;
1273                 if (!sWord3.IsEmpty())
1274                 {
1275                     pos = FindText(control, pos+1, lineEndPos, sWord3, wxSCI_FIND_WHOLEWORD);
1276                     if (pos != wxSCI_INVALID_POSITION)
1277                     {
1278                         str3 = sWord3;
1279                         str3Pos = pos;
1280                     }
1281                 }
1282             }
1283             else // (nUsed == 3)
1284             {
1285                 str2 = sW;
1286                 str2Pos = pos;
1287             }
1288 
1289             return str1Pos;
1290         }
1291         else
1292         {
1293             pStart = searchBack? pos : pos+foundWord.Length();
1294         }
1295     }
1296     return wxSCI_INVALID_POSITION;
1297 }
1298 
GetKeyworsFromLine(cbStyledTextCtrl * control,FConstruct::FCLid flid,int lineStartPos,int lineEndPos,wxString & str1,wxString & str2,wxString & str3,int & str1Pos,int & str2Pos,int & str3Pos)1299 void ConstrHighlighter::GetKeyworsFromLine(cbStyledTextCtrl* control, FConstruct::FCLid flid, int lineStartPos, int lineEndPos,
1300                                            wxString& str1, wxString& str2, wxString& str3, int& str1Pos, int& str2Pos, int& str3Pos)
1301 {
1302     str1 = wxEmptyString;
1303     str2 = wxEmptyString;
1304     str3 = wxEmptyString;
1305 
1306     if (FConstruct::FCLWordMap.count(flid) == 0)
1307         return;
1308 
1309     std::vector<wxString> sWords = FConstruct::FCLWordMap[flid];
1310     wxString sw;
1311     int nFilled = 0;
1312     for (size_t i=0; i<3; i++)
1313     {
1314         if (sWords[i].IsEmpty())
1315             break;
1316         sw.Append(sWords[i]);
1317 
1318         int pos = FindText(control, lineStartPos, lineEndPos, sw, wxSCI_FIND_WHOLEWORD);
1319         if (pos != wxSCI_INVALID_POSITION)
1320         {
1321             if (nFilled == 0)
1322             {
1323                 str1 = sw;
1324                 str1Pos = pos;
1325             }
1326             else if (nFilled == 1)
1327             {
1328                 str2 = sw;
1329                 str2Pos = pos;
1330             }
1331             else
1332             {
1333                 str3 = sw;
1334                 str3Pos = pos;
1335             }
1336             sw = wxEmptyString;
1337             nFilled++;
1338         }
1339     }
1340 }
1341 
FindText(cbStyledTextCtrl * control,int pStart,int pEnd,const wxString & sWord,int flag)1342 int ConstrHighlighter::FindText(cbStyledTextCtrl* control, int pStart, int pEnd, const wxString& sWord, int flag)
1343 {
1344     int pos;
1345     int pS = pStart;
1346     while (true)
1347     {
1348         pos = control->FindText(pS, pEnd, sWord, flag);
1349         if (pos == wxSCI_INVALID_POSITION)
1350             return pos;
1351         else if (IsCommentOrString(control, pos))
1352             pS = pos + 1;
1353         else
1354             return pos;
1355     }
1356 }
1357 
IsCommentOrString(cbStyledTextCtrl * control,int pos)1358 bool ConstrHighlighter::IsCommentOrString(cbStyledTextCtrl* control, int pos)
1359 {
1360     int line = control->LineFromPosition(pos);
1361     int lineStartPos = control->PositionFromLine(line);
1362     bool inStr1 = false;
1363     bool inStr2 = false;
1364     bool inCom = false;
1365 
1366     if (m_CurrentSForm == fsfFixed && lineStartPos <= pos)
1367     {
1368             const wxChar cch = control->GetCharAt(lineStartPos);
1369             if (cch == 'C' || cch == 'c' || cch == '*' || cch == '!')
1370                 return true; // comment line in fixed format file
1371     }
1372 
1373     for (int i=lineStartPos; i<pos; i++)
1374     {
1375         const wxChar cch = control->GetCharAt(i);
1376         if (cch == '!' && !inStr1 && !inStr2)
1377         {
1378             inCom = true;
1379             break;
1380         }
1381         else if (cch == '\'' && !inStr2)
1382         {
1383             if (inStr1)
1384                 inStr1 = false;
1385             else
1386                 inStr1 = true;
1387         }
1388         else if (cch == '"' && !inStr1)
1389         {
1390             if (inStr2)
1391                 inStr2 = false;
1392             else
1393                 inStr2 = true;
1394         }
1395     }
1396 
1397     if (inCom || inStr1 || inStr2)
1398         return true;
1399     else
1400         return false;
1401 }
1402 
GetFortranConstruct(const Keyword & word1,const Keyword & word2,const Keyword & word3,FConstruct & fcon)1403 void ConstrHighlighter::GetFortranConstruct(const Keyword &word1, const Keyword &word2, const Keyword &word3, FConstruct &fcon)
1404 {
1405     fcon.Clear();
1406     wxString str = word1.word + word2.word + word3.word;
1407     if (m_FConstructTypeMap.count(str) == 0)
1408         return;
1409 
1410     wxString estr;
1411     FConstruct::FConstructType fct = m_FConstructTypeMap[str];
1412     if (fct == FConstruct::ctProgramGroup || fct == FConstruct::ctSelectGroup)
1413         fcon.SetType(fct);
1414     else if (fct == FConstruct::ctIf)
1415     {
1416         fcon.AddPart(_T("if"), _T("then"), estr);
1417         fcon.AddPart(_T("else"), _T("if"), _T("then"));
1418         fcon.AddPart(_T("else"), estr, estr);
1419         fcon.AddPart(_T("end"), _T("if"), estr);
1420         fcon.SetType(FConstruct::ctIf);
1421     }
1422     else if (fct == FConstruct::ctDo)
1423     {
1424         fcon.AddPart(_T("do"), estr, estr);
1425         fcon.AddPart(_T("end"), _T("do"), estr);
1426         fcon.SetType(FConstruct::ctDo);
1427     }
1428     else if (fct == FConstruct::ctInterface)
1429     {
1430         fcon.AddPart(_T("interface"), estr, estr);
1431         fcon.AddPart(_T("end"), _T("interface"), estr);
1432         fcon.SetType(FConstruct::ctInterface);
1433     }
1434     else if (fct == FConstruct::ctFunction)
1435     {
1436         fcon.AddPart(_T("function"), estr, estr);
1437         fcon.AddPart(_T("end"), _T("function"), estr);
1438         fcon.SetType(FConstruct::ctFunction);
1439     }
1440     else if (fct == FConstruct::ctSubroutine)
1441     {
1442         fcon.AddPart(_T("subroutine"), estr, estr);
1443         fcon.AddPart(_T("end"), _T("subroutine"), estr);
1444         fcon.SetType(FConstruct::ctSubroutine);
1445     }
1446     else if (fct == FConstruct::ctProgram)
1447     {
1448         fcon.AddPart(_T("program"), estr, estr);
1449         fcon.AddPart(_T("end"), _T("program"), estr);
1450         fcon.SetType(FConstruct::ctProgram);
1451     }
1452     else if (fct == FConstruct::ctModule)
1453     {
1454         fcon.AddPart(_T("module"), estr, estr);
1455         fcon.AddPart(_T("end"), _T("module"), estr);
1456         fcon.SetType(FConstruct::ctModule);
1457     }
1458     else if (fct == FConstruct::ctSubmodule)
1459     {
1460         fcon.AddPart(_T("submodule"), estr, estr);
1461         fcon.AddPart(_T("end"), _T("submodule"), estr);
1462         fcon.SetType(FConstruct::ctSubmodule);
1463     }
1464     else if (fct == FConstruct::ctType)
1465     {
1466         fcon.AddPart(_T("type"), estr, estr);
1467         fcon.AddPart(_T("end"), _T("type"), estr);
1468         fcon.SetType(FConstruct::ctType);
1469     }
1470     else if (fct == FConstruct::ctEnum)
1471     {
1472         fcon.AddPart(_T("enum"), estr, estr);
1473         fcon.AddPart(_T("end"), _T("enum"), estr);
1474         fcon.SetType(FConstruct::ctEnum);
1475     }
1476     else if (fct == FConstruct::ctCritical)
1477     {
1478         fcon.AddPart(_T("critical"), estr, estr);
1479         fcon.AddPart(_T("end"), _T("critical"), estr);
1480         fcon.SetType(FConstruct::ctCritical);
1481     }
1482     else if (fct == FConstruct::ctForall)
1483     {
1484         fcon.AddPart(_T("forall"), estr, estr);
1485         fcon.AddPart(_T("end"), _T("forall"), estr);
1486         fcon.SetType(FConstruct::ctForall);
1487     }
1488     else if (fct == FConstruct::ctAssiciate)
1489     {
1490         fcon.AddPart(_T("associate"), estr, estr);
1491         fcon.AddPart(_T("end"), _T("associate"), estr);
1492         fcon.SetType(FConstruct::ctAssiciate);
1493     }
1494     else if (fct == FConstruct::ctBlock)
1495     {
1496         fcon.AddPart(_T("block"), estr, estr);
1497         fcon.AddPart(_T("end"), _T("block"), estr);
1498         fcon.SetType(FConstruct::ctBlock);
1499     }
1500     else if (fct == FConstruct::ctTeam)
1501     {
1502         fcon.AddPart(_T("change"), _T("team"), estr);
1503         fcon.AddPart(_T("end"), _T("team"), estr);
1504         fcon.SetType(FConstruct::ctTeam);
1505     }
1506     else if (fct == FConstruct::ctWhere)
1507     {
1508         fcon.AddPart(_T("where"), estr, estr);
1509         fcon.AddPart(_T("else"), _T("where"), estr);
1510         fcon.AddPart(_T("end"), _T("where"), estr);
1511         fcon.SetType(FConstruct::ctWhere);
1512     }
1513     else if (fct == FConstruct::ctBlockdata)
1514     {
1515         fcon.AddPart(_T("block"), _T("data"), estr);
1516         fcon.AddPart(_T("end"), _T("block"), _T("data"));
1517         fcon.SetType(FConstruct::ctBlockdata);
1518     }
1519     else if (fct == FConstruct::ctProcedure)
1520     {
1521         fcon.AddPart(_T("module"), _T("procedure"), estr);
1522         fcon.AddPart(_T("end"), _T("procedure"), estr);
1523         fcon.SetType(FConstruct::ctProcedure);
1524     }
1525 }
1526 
GetSearchDirection(const Keyword & word1,const Keyword & word2,const Keyword & word3,SearchDirection & sdir,FConstruct & unFconBack,FConstruct & unFconForth)1527 void ConstrHighlighter::GetSearchDirection(const Keyword &word1, const Keyword &word2, const Keyword &word3,
1528                                          SearchDirection& sdir, FConstruct& unFconBack, FConstruct& unFconForth)
1529 {
1530     sdir = sdirUnknown;
1531     unFconBack.Clear();
1532     unFconForth.Clear();
1533     wxString str = word1.word + word2.word + word3.word;
1534     if (m_FConstructTypeMap.count(str) == 0)
1535         return;
1536 
1537     FConstruct::FConstructType fct = m_FConstructTypeMap[str];
1538     wxString estr;
1539 
1540     if (fct == FConstruct::ctProgramGroup)
1541     {
1542         if (str.IsSameAs(_T("end")) || str.IsSameAs(_T("endfunction")) || str.IsSameAs(_T("endsubroutine")) ||
1543             str.IsSameAs(_T("endprogram")) || str.IsSameAs(_T("endmodule")) || str.IsSameAs(_T("endsubmodule")) ||
1544             str.IsSameAs(_T("endblockdata")) || str.IsSameAs(_T("endprocedure")))
1545         {
1546             sdir = sdirBack;
1547         }
1548         else if (str.IsSameAs(_T("function")) || str.IsSameAs(_T("subroutine")) || str.IsSameAs(_T("program")) ||
1549                  str.IsSameAs(_T("module")) || str.IsSameAs(_T("submodule")) || str.IsSameAs(_T("blockdata")) ||
1550                  str.IsSameAs(_T("moduleprocedure")))
1551         {
1552             sdir = sdirForth;
1553         }
1554     }
1555     else if (fct== FConstruct::ctSelectGroup)
1556     {
1557         if (str.IsSameAs(_T("selectcase")) || str.IsSameAs(_T("selecttype")))
1558         {
1559             sdir = sdirForth;
1560             unFconForth.AddPart(_T("case"), estr, estr);
1561             unFconForth.AddPart(_T("case"), _T("default"), estr);
1562             unFconForth.AddPart(_T("type"), _T("is"), estr);
1563             unFconForth.AddPart(_T("class"), _T("is"), estr);
1564             unFconForth.AddPart(_T("class"), _T("default"), estr);
1565             unFconForth.AddPart(_T("end"), _T("select"), estr);
1566         }
1567         else if (str.IsSameAs(_T("endselect")))
1568         {
1569             sdir = sdirBack;
1570             unFconBack.AddPart(_T("select"), _T("case"), estr);
1571             unFconBack.AddPart(_T("case"), estr, estr);
1572             unFconBack.AddPart(_T("case"), _T("default"), estr);
1573             unFconBack.AddPart(_T("type"), _T("is"), estr);
1574             unFconBack.AddPart(_T("class"), _T("is"), estr);
1575             unFconBack.AddPart(_T("class"), _T("default"), estr);
1576         }
1577         else if (str.IsSameAs(_T("case")) || str.IsSameAs(_T("casedefault")))
1578         {
1579             sdir = sdirBackForth;
1580             unFconForth.AddPart(_T("case"), estr, estr);
1581             unFconForth.AddPart(_T("case"), _T("default"), estr);
1582             unFconForth.AddPart(_T("end"), _T("select"), estr);
1583 
1584             unFconBack.AddPart(_T("select"), _T("case"), estr);
1585             unFconBack.AddPart(_T("case"), estr, estr);
1586         }
1587         else if (str.IsSameAs(_T("typeis")) || str.IsSameAs(_T("classis")) || str.IsSameAs(_T("classdefault")))
1588         {
1589             sdir = sdirBackForth;
1590             unFconForth.AddPart(_T("type"), _T("is"), estr);
1591             unFconForth.AddPart(_T("class"), _T("is"), estr);
1592             unFconForth.AddPart(_T("class"), _T("default"), estr);
1593             unFconForth.AddPart(_T("end"), _T("select"), estr);
1594 
1595             unFconBack.AddPart(_T("select"), _T("type"), estr);
1596             unFconBack.AddPart(_T("type"), _T("is"), estr);
1597             unFconBack.AddPart(_T("class"), _T("is"), estr);
1598             unFconBack.AddPart(_T("class"), _T("default"), estr);
1599         }
1600     }
1601     else if (fct == FConstruct::ctIf)
1602     {
1603         if (str == _T("ifthen") || str == _T("elseifthen"))
1604         {
1605             sdir = sdirForth;
1606             unFconForth.AddPart(_T("else"), _T("if"), _T("then"));
1607             unFconForth.AddPart(_T("else"), estr, estr);
1608             unFconForth.AddPart(_T("end"), _T("if"), estr);
1609 
1610             if (str == _T("elseifthen"))
1611             {
1612                 sdir = sdirBackForth;
1613                 unFconBack.AddPart(_T("if"), _T("then"), estr);
1614                 unFconBack.AddPart(_T("else"), _T("if"), _T("then"));
1615             }
1616         }
1617         else if (str == _T("else"))
1618         {
1619             sdir = sdirBackForth;
1620             unFconForth.AddPart(_T("end"), _T("if"), estr);
1621 
1622             unFconBack.AddPart(_T("if"), _T("then"), estr);
1623             unFconBack.AddPart(_T("else"), _T("if"), _T("then"));
1624         }
1625         else if (str == _T("endif"))
1626         {
1627             sdir = sdirBack;
1628             unFconBack.AddPart(_T("if"), _T("then"), estr);
1629             unFconBack.AddPart(_T("else"), _T("if"), _T("then"));
1630             unFconBack.AddPart(_T("else"), estr, estr);
1631         }
1632     }
1633     else if (fct == FConstruct::ctDo)
1634     {
1635         if (str.StartsWith(_T("do")))
1636         {
1637             sdir = sdirForth;
1638             unFconForth.AddPart(_T("end"), _T("do"), estr);
1639         }
1640         else if (str == _T("enddo"))
1641         {
1642             sdir = sdirBack;
1643             unFconBack.AddPart(_T("do"), estr, estr);
1644         }
1645     }
1646     else if (fct == FConstruct::ctInterface)
1647     {
1648         if (str == _T("interface") || str == _T("abstractinterface"))
1649         {
1650             sdir = sdirForth;
1651             unFconForth.AddPart(_T("end"), _T("interface"), estr);
1652         }
1653         else if (str == _T("endinterface"))
1654         {
1655             sdir = sdirBack;
1656             unFconBack.AddPart(_T("interface"), estr, estr);
1657         }
1658     }
1659     else if (fct == FConstruct::ctType)
1660     {
1661         if (str == _T("type"))
1662         {
1663             sdir = sdirForth;
1664             unFconForth.AddPart(_T("end"), _T("type"), estr);
1665         }
1666         else if (str == _T("endtype"))
1667         {
1668             sdir = sdirBack;
1669             unFconBack.AddPart(_T("type"), estr, estr);
1670         }
1671     }
1672     else if (fct == FConstruct::ctEnum)
1673     {
1674         if (str == _T("enum"))
1675         {
1676             sdir = sdirForth;
1677             unFconForth.AddPart(_T("end"), _T("enum"), estr);
1678         }
1679         else if (str == _T("endenum"))
1680         {
1681             sdir = sdirBack;
1682             unFconBack.AddPart(_T("enum"), estr, estr);
1683         }
1684     }
1685     else if (fct == FConstruct::ctCritical)
1686     {
1687         if (str == _T("critical"))
1688         {
1689             sdir = sdirForth;
1690             unFconForth.AddPart(_T("end"), _T("critical"), estr);
1691         }
1692         else if (str == _T("endcritical"))
1693         {
1694             sdir = sdirBack;
1695             unFconBack.AddPart(_T("critical"), estr, estr);
1696         }
1697     }
1698     else if (fct == FConstruct::ctForall)
1699     {
1700         if (str == _T("forall"))
1701         {
1702             sdir = sdirForth;
1703             unFconForth.AddPart(_T("end"), _T("forall"), estr);
1704         }
1705         else if (str == _T("endforall"))
1706         {
1707             sdir = sdirBack;
1708             unFconBack.AddPart(_T("forall"), estr, estr);
1709         }
1710     }
1711     else if (fct == FConstruct::ctAssiciate)
1712     {
1713         if (str == _T("associate"))
1714         {
1715             sdir = sdirForth;
1716             unFconForth.AddPart(_T("end"), _T("associate"), estr);
1717         }
1718         else if (str == _T("endassociate"))
1719         {
1720             sdir = sdirBack;
1721             unFconBack.AddPart(_T("associate"), estr, estr);
1722         }
1723     }
1724     else if (fct == FConstruct::ctBlock)
1725     {
1726         if (str == _T("block"))
1727         {
1728             sdir = sdirForth;
1729             unFconForth.AddPart(_T("end"), _T("block"), estr);
1730         }
1731         else if (str == _T("endblock"))
1732         {
1733             sdir = sdirBack;
1734             unFconBack.AddPart(_T("block"), estr, estr);
1735         }
1736     }
1737     else if (fct == FConstruct::ctTeam)
1738     {
1739         if (str == _T("changeteam"))
1740         {
1741             sdir = sdirForth;
1742             unFconForth.AddPart(_T("end"), _T("team"), estr);
1743         }
1744         else if (str == _T("endteam"))
1745         {
1746             sdir = sdirBack;
1747             unFconBack.AddPart(_T("change"), _T("team"), estr);
1748         }
1749     }
1750     else if (fct == FConstruct::ctWhere)
1751     {
1752         if (str == _T("where"))
1753         {
1754             sdir = sdirForth;
1755             unFconForth.AddPart(_T("else"), _T("where"), estr);
1756             unFconForth.AddPart(_T("end"), _T("where"), estr);
1757         }
1758         else if (str == _T("endwhere"))
1759         {
1760             sdir = sdirBack;
1761             unFconBack.AddPart(_T("where"), estr, estr);
1762             unFconBack.AddPart(_T("else"), _T("where"), estr);
1763         }
1764         else if (str == _T("elsewhere"))
1765         {
1766             sdir = sdirBackForth;
1767             unFconBack.AddPart(_T("where"), estr, estr);
1768             unFconBack.AddPart(_T("else"), _T("where"), estr);
1769 
1770             unFconForth.AddPart(_T("else"), _T("where"), estr);
1771             unFconForth.AddPart(_T("end"), _T("where"), estr);
1772         }
1773     }
1774 }
1775 
GetFortranLine(cbStyledTextCtrl * control,int pos,wxString & fLine,int & lineStartPos,int & lineEndPos)1776 void ConstrHighlighter::GetFortranLine(cbStyledTextCtrl* control, int pos, wxString& fLine, int& lineStartPos, int& lineEndPos)
1777 {
1778     bool tryBack;
1779     bool withContinuation;
1780     fLine = GetFortranLine2(control, pos, lineStartPos, lineEndPos, tryBack, withContinuation, true);
1781     if (m_CurrentSForm == fsfFree)
1782     {
1783         while (tryBack)
1784         {
1785             if (control->LineFromPosition(lineStartPos) == 0)
1786                 break;
1787             pos = lineStartPos - 1;
1788             int lep;
1789             int lsBackPos;
1790             wxString lineBack = GetFortranLine2(control, pos, lsBackPos, lep, tryBack, withContinuation, false);
1791             if (withContinuation)
1792             {
1793                 lineStartPos = lsBackPos;
1794                 fLine.Prepend(lineBack);
1795             }
1796             else
1797                 break;
1798         }
1799     }
1800     else // (m_CurrentSForm == fsfFixed)
1801     {
1802         while (tryBack && withContinuation)
1803         {
1804             if (control->LineFromPosition(lineStartPos) == 0)
1805                 break;
1806             pos = lineStartPos - 1;
1807             int lep;
1808             int lsBackPos;
1809             wxString lineBack = GetFortranLine2(control, pos, lsBackPos, lep, tryBack, withContinuation, false);
1810             lineStartPos = lsBackPos;
1811             fLine.Prepend(lineBack);
1812         }
1813     }
1814     fLine = CutBracketsLevel2(fLine);
1815     fLine.Replace(_T("\t"), _T(" "));
1816     fLine.Trim();
1817 }
1818 
GetFortranLine2(cbStyledTextCtrl * control,int posC,int & posStart,int & posEnd,bool & tryBack,bool & withContinuation,bool goForth)1819 wxString ConstrHighlighter::GetFortranLine2(cbStyledTextCtrl* control, int posC, int& posStart, int& posEnd, bool& tryBack,
1820                                             bool& withContinuation, bool goForth)
1821 {
1822     int line = control->LineFromPosition(posC);
1823     wxString lineStr = control->GetLine(line);
1824     posStart = control->PositionFromLine(line);
1825     posEnd   = control->PositionFromLine(line+1);
1826     tryBack = true;
1827     withContinuation = false;
1828     bool inStr1 = false;
1829     bool inStr2 = false;
1830     bool spaceOnly = true;
1831     int lsl = lineStr.length();
1832     if (m_CurrentSForm == fsfFixed)
1833     {
1834         if (lsl <= 6)
1835             return wxEmptyString;
1836         const wxChar cch = lineStr.GetChar(0);
1837         if (cch == 'C' || cch == 'c' || cch == '*' || cch == '!')
1838             return wxEmptyString; // comment line in fixed format file
1839         if (lineStr.GetChar(5) != ' ' && lineStr.GetChar(5) != '0')
1840             withContinuation = true;
1841     }
1842     int i = 0;
1843     while (i < lsl)
1844     {
1845         if (inStr1 && lineStr.GetChar(i) == '\'')
1846             inStr1 = false;
1847         else if (inStr2 && lineStr.GetChar(i) == '"')
1848             inStr2 = false;
1849         else if (inStr1 || inStr2)
1850             lineStr.SetChar(i, ' ');
1851         else if (lineStr.GetChar(i) == '\'')
1852         {
1853             inStr1 = true;
1854             spaceOnly = false;
1855         }
1856         else if (lineStr.GetChar(i) == '"')
1857         {
1858             inStr2 = true;
1859             spaceOnly = false;
1860         }
1861         else if (lineStr.GetChar(i) == '!')
1862         {
1863             if (posStart + i >= posC)
1864             {
1865                 lineStr = lineStr.Mid(0, i);
1866                 posEnd = posStart + i;
1867                 break;
1868             }
1869             else
1870             {
1871                 lineStr = _T("");
1872                 break;
1873             }
1874         }
1875         else if (lineStr.GetChar(i) == '&')
1876         {
1877             lineStr.SetChar(i, ' ');
1878             if (!spaceOnly && (m_CurrentSForm == fsfFree))
1879             {
1880                 lineStr = lineStr.Mid(0, i+1);
1881 
1882                 if (goForth && line+1 < control->GetLineCount())
1883                 {
1884                     int posStart2;
1885                     bool tback, econ;
1886                     lineStr.Append(GetFortranLine2(control, control->PositionFromLine(line+1), posStart2, posEnd, tback, econ, true));
1887                 }
1888                 else
1889                     withContinuation = true;
1890                 break;
1891             }
1892         }
1893         else if (lineStr.GetChar(i) == ';')
1894         {
1895             if (posStart + i >= posC)
1896             {
1897                 lineStr = lineStr.Mid(0, i);
1898                 posEnd = posStart + i;
1899                 break;
1900             }
1901             else
1902             {
1903                 posStart = posStart + i + 1;
1904                 lineStr = lineStr.Mid(i+1);
1905                 lsl = lineStr.length();
1906                 i = -1;
1907                 tryBack = false;
1908                 spaceOnly = false;
1909             }
1910         }
1911         else if (spaceOnly)
1912             spaceOnly = false;
1913         i++;
1914     }
1915 
1916     if (m_CurrentSForm == fsfFixed)
1917     {
1918         if (goForth && line+1 < control->GetLineCount())
1919         {
1920             int posStart2;
1921             bool tback;
1922             bool wCon;
1923             wxString nextLine = GetFortranLine2(control, control->PositionFromLine(line+1), posStart2, posEnd, tback, wCon, true);
1924             if (wCon)
1925                 lineStr.Append(nextLine);
1926         }
1927     }
1928     return lineStr;
1929 }
1930 
CutBracketsLevel2(const wxString & str)1931 wxString ConstrHighlighter::CutBracketsLevel2(const wxString& str)
1932 {
1933     wxString retStr = str;
1934     int pos = str.Find('(');
1935     if (pos == wxNOT_FOUND)
1936         return retStr;
1937 
1938     std::vector<int> cutStart;
1939     std::vector<int> cutEnd;
1940     int level = 0;
1941     for (size_t i=pos; i<str.Len(); i++)
1942     {
1943         if (str.GetChar(i) == '(')
1944         {
1945             if (level == 1)
1946             {
1947                 cutStart.push_back(i);
1948                 cutEnd.push_back(wxString::npos);
1949             }
1950             level++;
1951         }
1952         else if (str.GetChar(i) == ')')
1953         {
1954             if (level == 2)
1955                 cutEnd[cutEnd.size()-1] = i;
1956             level--;
1957         }
1958     }
1959 
1960     for (int i=int(cutStart.size())-1; i>=0; i--)
1961     {
1962         if (cutEnd[i] != int(wxString::npos))
1963             retStr = retStr.Mid(0,cutStart[i]) + _T(" ") + retStr.Mid(cutEnd[i]+1);
1964         else
1965             retStr = retStr.Mid(0,cutStart[i]) + _T(" ");
1966     }
1967     return retStr;
1968 }
1969 
FindLimitPos(cbStyledTextCtrl * control,const FConstruct & fcon,int posStart,SearchDirection sdir)1970 int ConstrHighlighter::FindLimitPos(cbStyledTextCtrl* control, const FConstruct& fcon, int posStart, SearchDirection sdir)
1971 {
1972     int pEnd = (sdir == sdirBack) ? 0 : control->GetLength();
1973     int rpEnd = pEnd;
1974     FConstruct::FConstructType ct = fcon.GetType();
1975     if (ct == FConstruct::ctIf || ct == FConstruct::ctDo || ct == FConstruct::ctSelectGroup ||
1976         ct == FConstruct::ctCritical || ct == FConstruct::ctForall || ct == FConstruct::ctEnum ||
1977         ct == FConstruct::ctType || ct == FConstruct::ctAssiciate || ct == FConstruct::ctBlock ||
1978         ct == FConstruct::ctTeam )
1979     {
1980         wxString str1, str2, str3;
1981         int str1Pos, str2Pos, str3Pos;
1982 
1983         if (sdir == sdirBack)
1984         {
1985             wxString word1 = _T("subroutine");
1986             wxString word2;
1987             wxString word3;
1988             FConstruct::FCLid flid1 = FConstruct::fclSub_sub;
1989             int cp1 = FindFKeyword(control, posStart, pEnd, flid1, word1, word2, word3,
1990                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
1991             if (cp1 == wxSCI_INVALID_POSITION)
1992                 cp1 = rpEnd;
1993             else
1994                 pEnd = cp1 + 10;
1995 
1996             word1 = _T("function");
1997             word2 = wxEmptyString;
1998             word3 = wxEmptyString;
1999             flid1 = FConstruct::fclFun_fun;
2000             int cp2 = FindFKeyword(control, posStart, pEnd, flid1, word1, word2, word3,
2001                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2002             if (cp2 == wxSCI_INVALID_POSITION)
2003                 cp2 = rpEnd;
2004             else
2005                 pEnd = cp2 + 8;
2006 
2007             word1 = _T("program");
2008             word2 = wxEmptyString;
2009             word3 = wxEmptyString;
2010             flid1 = FConstruct::fclProg_prog;
2011             int cp3 = FindFKeyword(control, posStart, pEnd, flid1, word1, word2, word3,
2012                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2013             if (cp3 == wxSCI_INVALID_POSITION)
2014                 cp3 = rpEnd;
2015 
2016             return std::max(std::max(cp1,cp2),cp3);
2017         }
2018         else
2019         {
2020             wxString word1 = _T("end");
2021             wxString word2 = _T("subroutine");
2022             wxString word3;
2023             FConstruct::FCLid flid1 = FConstruct::fclSub_end_sub;
2024             int cp1 = FindFKeyword(control, posStart, pEnd, flid1, word1, word2, word3,
2025                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2026             if (cp1 == wxSCI_INVALID_POSITION)
2027                 cp1 = rpEnd;
2028             else
2029                 pEnd = cp1;
2030 
2031             word1 = _T("end");
2032             word2 = _T("function");
2033             word3 = wxEmptyString;
2034             flid1 = FConstruct::fclFun_fun;
2035             int cp2 = FindFKeyword(control, posStart, pEnd, flid1, word1, word2, word3,
2036                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2037             if (cp2 == wxSCI_INVALID_POSITION)
2038                 cp2 = rpEnd;
2039             else
2040                 pEnd = cp2;
2041 
2042             word1 = _T("end");
2043             word2 = _T("program");
2044             word3 = wxEmptyString;
2045             flid1 = FConstruct::fclProg_prog;
2046             int cp3 = FindFKeyword(control, posStart, pEnd, flid1, word1, word2, word3,
2047                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2048             if (cp3 == wxSCI_INVALID_POSITION)
2049                 cp3 = rpEnd;
2050 
2051             return std::min(std::min(cp1,cp2),cp3);
2052         }
2053     }
2054     else if (ct == FConstruct::ctProgramGroup || ct == FConstruct::ctInterface)
2055     {
2056         wxString str1, str2, str3;
2057         int str1Pos, str2Pos, str3Pos;
2058 
2059         if (sdir == sdirBack)
2060         {
2061             wxString word1 = _T("module");
2062             wxString word2;
2063             wxString word3;
2064             FConstruct::FCLid flid1 = FConstruct::fclMod_module;
2065             int cp1 = FindFKeyword(control, posStart, pEnd, flid1, word1, word2, word3,
2066                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2067             if (cp1 == wxSCI_INVALID_POSITION)
2068                 cp1 = rpEnd;
2069             else
2070                 pEnd = cp1 + 6;
2071 
2072             word1 = _T("end");
2073             word2 = _T("module");
2074             word3 = wxEmptyString;
2075             flid1 = FConstruct::fclMod_end_module;
2076             int cp2 = FindFKeywordFull(control, posStart, pEnd, flid1, word1, word2, word3,
2077                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2078             if (cp2 == wxSCI_INVALID_POSITION)
2079                 cp2 = rpEnd;
2080             else
2081                 pEnd = cp2 + 3;
2082 
2083             word1 = _T("submodule");
2084             word2 = wxEmptyString;
2085             word3 = wxEmptyString;
2086             flid1 = FConstruct::fclSubmod_submod;
2087             int cp3 = FindFKeyword(control, posStart, pEnd, flid1, word1, word2, word3,
2088                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2089             if (cp3 == wxSCI_INVALID_POSITION)
2090                 cp3 = rpEnd;
2091 
2092             return std::max(std::max(cp1,cp2),cp3);
2093         }
2094         else
2095         {
2096             wxString word1 = _T("end");
2097             wxString word2 = _T("module");
2098             wxString word3;
2099             FConstruct::FCLid flid1 = FConstruct::fclMod_end_module;
2100 
2101             int cp1 = FindFKeywordFull(control, posStart, pEnd, flid1, word1, word2, word3,
2102                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2103             if (cp1 != wxSCI_INVALID_POSITION)
2104             {
2105                 pEnd = cp1;
2106                 cp1 = GetWordsEnd(str1, str1Pos, str2, str2Pos, str3, str3Pos);
2107             }
2108 
2109             word1 = _T("module");
2110             word2 = wxEmptyString;
2111             word3 = wxEmptyString;
2112             flid1 = FConstruct::fclMod_module;
2113 
2114             int cp2 = FindFKeyword(control, posStart, pEnd, flid1, word1, word2, word3,
2115                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2116             if (cp2 != wxSCI_INVALID_POSITION)
2117                 pEnd = cp2;
2118             word1 = _T("end");
2119             word2 = _T("submodule");
2120             word3 = wxEmptyString;
2121             flid1 = FConstruct::fclSubmod_end_submod;
2122 
2123             int cp3 = FindFKeywordFull(control, posStart, pEnd, flid1, word1, word2, word3,
2124                                           str1, str1Pos, str2, str2Pos, str3, str3Pos);
2125             if (cp3 != wxSCI_INVALID_POSITION)
2126                 cp3 = GetWordsEnd(str1, str1Pos, str2, str2Pos, str3, str3Pos);
2127             if (cp1 == wxSCI_INVALID_POSITION)
2128                 cp1 = rpEnd;
2129             if (cp2 == wxSCI_INVALID_POSITION)
2130                 cp2 = rpEnd;
2131             if (cp3 == wxSCI_INVALID_POSITION)
2132                 cp3 = rpEnd;
2133 
2134             return std::min(std::min(cp1,cp2),cp3);
2135         }
2136     }
2137     return rpEnd;
2138 }
2139 
2140 
2141