1 #include "autoinsert.h"
2 
3 #ifndef CB_PRECOMP
4     #include <configmanager.h>
5 #endif
6 #include <algorithm>
7 
8 #include "fortranfileext.h"
9 
10 extern FortranFileExt g_FortranFileExt;
11 
AutoInsert()12 AutoInsert::AutoInsert()
13 {
14     // ctor
15     m_NameMap[_T("if")] = _T("if (...) then");
16     m_NameMap[_T("do")] = _T("do ...");
17     m_NameMap[_T("subroutine")] = _T("subroutine");
18     m_NameMap[_T("function")] = _T("function");
19     m_NameMap[_T("interface")] = _T("interface");
20     m_NameMap[_T("associate")] = _T("associate");
21     m_NameMap[_T("block")] = _T("block");
22     m_NameMap[_T("critical")] = _T("critical");
23     m_NameMap[_T("module")] = _T("module");
24     m_NameMap[_T("program")] = _T("program");
25     m_NameMap[_T("select")] = _T("select ...");
26     m_NameMap[_T("type")] = _T("type");
27     m_NameMap[_T("where")] = _T("where (...)");
28     m_NameMap[_T("enum")] = _T("enum");
29     m_NameMap[_T("forall")] = _T("forall (...)");
30     m_NameMap[_T("submodule")] = _T("submodule");
31     m_NameMap[_T("team")] = _T("change team (...)");
32 
33     int opt = wxRE_ADVANCED | wxRE_ICASE | wxRE_NOSUB;
34     m_RegMap[_T("if")] = new wxRegEx(_T("^([\\s\\t]*)([0-9]*)([\\s\\t]*)(([a-z0-9_]+)(\\s*):(\\s*))?(if)(\\s*)(\\(.*\\))(\\s*)then\\y.*"), opt);
35     m_RegMap[_T("endif")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(if)\\y"), opt);
36     m_RegMap[_T("do")] = new wxRegEx(_T("^([\\s\\t]*)([0-9]*)([\\s\\t]*)(([a-z0-9_]+)(\\s*)(:)(\\s*))?(do)(\\y)"), opt);
37     m_RegMap[_T("enddo")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(do)\\y"), opt);
38     m_RegMap[_T("subroutine")] = new wxRegEx(_T("(.*)subroutine(\\s+)([a-z0-9_]+)(\\s*)(\\(.*[\\)&]+)"), opt);
39     m_RegMap[_T("endsubroutine")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(subroutine)\\y"), opt);
40     m_RegMap[_T("function")] = new wxRegEx(_T("(.*)function(\\s+)([a-z0-9_]+)(\\s*)(\\(.*[\\)&]+)"), opt);
41     m_RegMap[_T("endfunction")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(function)\\y"), opt);
42     m_RegMap[_T("interface")] = new wxRegEx(_T("^[\\s\\t]*(abstract(\\s*))?interface(\\y)"), opt);
43     m_RegMap[_T("endinterface")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(interface)\\y"), opt);
44     m_RegMap[_T("associate")] = new wxRegEx(_T("^([\\s\\t]*)([0-9]*)([\\s\\t]*)(([a-z0-9_]+)(\\s*)(:)(\\s*))?(associate)(\\s*)(\\(.*\\))"), opt);
45     m_RegMap[_T("endassociate")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(associate)\\y"), opt);
46     m_RegMap[_T("block")] = new wxRegEx(_T("^([\\s\\t]*)([0-9]*)([\\s\\t]*)(([a-z0-9_]+)(\\s*)(:)(\\s*))?(block)\\y"), opt);
47     m_RegMap[_T("endblock")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(block)\\y"), opt);
48     m_RegMap[_T("critical")] = new wxRegEx(_T("^([\\s\\t]*)([0-9]*)([\\s\\t]*)(([a-z0-9_]+)(\\s*)(:)(\\s*))?(critical)\\y"), opt);
49     m_RegMap[_T("endcritical")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(critical)\\y"), opt);
50     m_RegMap[_T("module")] = new wxRegEx(_T("^[\\s\\t]*(module)(\\s+)((?!procedure[\\s:]+)[a-z0-9_]+)\\y"), opt);
51     m_RegMap[_T("endmodule")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(module)\\y"), opt);
52     m_RegMap[_T("program")] = new wxRegEx(_T("^[\\s\\t]*program\\y"), opt);
53     m_RegMap[_T("endprogram")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(program)\\y"), opt);
54     m_RegMap[_T("select")] = new wxRegEx(_T("^([\\s\\t]*)([0-9]*)([\\s\\t]*)(([a-z0-9_]+)(\\s*)(:)(\\s*))?(select)(\\s*)(case|type)(\\s*)(\\(.*\\))"), opt);
55     m_RegMap[_T("endselect")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(select)\\y"), opt);
56     m_RegMap[_T("type")] = new wxRegEx(_T("^([\\s\\t]*)(type)(\\s*)((\\s*,\\s*([a-z0-9_]+))*\\s*::)?(\\s*)([a-z0-9_]+)\\y"), opt);
57     m_RegMap[_T("endtype")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(type)\\y"), opt);
58     m_RegMap[_T("where")] = new wxRegEx(_T("^([\\s\\t]*)([0-9]*)([\\s\\t]*)(([a-z0-9_]+)(\\s*)(:)(\\s*))?(where)(\\s*)(\\(.*\\))(\\s*)(!(.*))?$"), opt);
59     m_RegMap[_T("endwhere")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(where)\\y"), opt);
60     m_RegMap[_T("enum")] = new wxRegEx(_T("^[\\s\\t]*enum\\y"), opt);
61     m_RegMap[_T("endenum")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(enum)\\y"), opt);
62     m_RegMap[_T("forall")] = new wxRegEx(_T("^([\\s\\t]*)([0-9]*)([\\s\\t]*)(([a-z0-9_]+)(\\s*)(:)(\\s*))?(forall)(\\s*)(\\(.*\\))(\\s*)(!(.*))?$"), opt);
63     m_RegMap[_T("endforall")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(forall)\\y"), opt);
64     m_RegMap[_T("submodule")] = new wxRegEx(_T("^[\\s\\t]*(submodule)(\\s*)(\\([a-z0-9_]+\\))(\\s*)([a-z0-9_]+)"), opt);
65     m_RegMap[_T("endsubmodule")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(submodule)\\y"), opt);
66     m_RegMap[_T("team")] = new wxRegEx(_T("^([\\s\\t]*)([0-9]*)([\\s\\t]*)(([a-z0-9_]+)(\\s*)(:)(\\s*))?(change)(\\s*)(team)(\\s*)(\\(.*\\))"), opt);
67     m_RegMap[_T("endteam")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(team)\\y"), opt);
68 
69     m_RegMap[_T("end")] = new wxRegEx(_T("^[\\s\\t]*[0-9]*[\\s\\t]*\\y(end)\\y(([\\s\\t]*)!(.*))?([\\s\\t]*)$"), opt);
70     m_RegMap[_T("endunit")] = new wxRegEx(_T("^[\\s\\t]*(end)(\\s*)(subroutine|function|program)\\y"), opt);
71     m_RegMap[_T("contains")] = new wxRegEx(_T("^[\\s\\t]*(contains)([\\s\\t]*)$"), opt);
72 
73     m_RulesWereChanged = false;
74     ReadAIOptions();
75 }
76 
~AutoInsert()77 AutoInsert::~AutoInsert()
78 {
79     // dtor
80     std::map<wxString,wxRegEx*>::iterator it;
81 
82     for (it = m_RegMap.begin(); it != m_RegMap.end(); ++it)
83         delete(it->second);
84 }
85 
EditRule(const wxString & statementName,int aiType,bool doAddName,bool alignToStatement)86 void AutoInsert::EditRule(const wxString& statementName, int aiType, bool doAddName, bool alignToStatement)
87 {
88     wxString statm = FindKey(statementName);
89     if (!statm.IsEmpty() && m_NameMap.count(statm) > 0)
90     {
91         if (m_AITMap[statm] != GetAIT(aiType))
92         {
93             m_AITMap[statm] = GetAIT(aiType);
94             m_RulesWereChanged = true;
95         }
96         if (m_DoAddNameMap[statm] != doAddName)
97         {
98             m_DoAddNameMap[statm] = doAddName;
99             m_RulesWereChanged = true;
100         }
101         if (m_AlignTSMap[statm] != alignToStatement)
102         {
103             m_AlignTSMap[statm] = alignToStatement;
104             m_RulesWereChanged = true;
105         }
106     }
107 }
108 
GetNameMap()109 const std::map<wxString,wxString>* AutoInsert::GetNameMap()
110 {
111     return &m_NameMap;
112 }
113 
GetItemValues(const wxString & statementName,int & aiType,bool & doAddName,bool & alignToStatement)114 bool AutoInsert::GetItemValues(const wxString& statementName, int& aiType, bool& doAddName, bool& alignToStatement)
115 {
116     wxString key = FindKey(statementName);
117     if (key.IsEmpty())
118         return false;
119 
120     AutoInsertType ait = m_AITMap[key];
121     aiType = GetAITInt(ait);
122 
123     doAddName = m_DoAddNameMap[key];
124     alignToStatement = m_AlignTSMap[key];
125 
126     return true;
127 }
128 
GetItemChoices(const wxString & statementName,wxArrayString & aiTypeStrArr,wxArrayString & alignStrArr,bool & addNameEnabled)129 bool AutoInsert::GetItemChoices(const wxString& statementName, wxArrayString& aiTypeStrArr,
130                             wxArrayString& alignStrArr, bool& addNameEnabled)
131 {
132     aiTypeStrArr.Empty();
133     alignStrArr.Empty();
134     addNameEnabled = true;
135     wxString key = FindKey(statementName);
136     if (key.IsEmpty())
137         return false;
138 
139     alignStrArr.Add(_T("to statement"));
140     alignStrArr.Add(_T("to name"));
141 
142     if (key == _T("if"))
143     {
144         aiTypeStrArr.Add(_T("end if"));
145         aiTypeStrArr.Add(_T("endif"));
146         aiTypeStrArr.Add(_T("EndIf"));
147         aiTypeStrArr.Add(_T("--none--"));
148     }
149     else if(key == _T("do"))
150     {
151         aiTypeStrArr.Add(_T("end do"));
152         aiTypeStrArr.Add(_T("enddo"));
153         aiTypeStrArr.Add(_T("EndDo"));
154         aiTypeStrArr.Add(_T("--none--"));
155     }
156     else if(key == _T("subroutine"))
157     {
158         aiTypeStrArr.Add(_T("end subroutine"));
159         aiTypeStrArr.Add(_T("endsubroutine"));
160         aiTypeStrArr.Add(_T("EndSubroutine"));
161         aiTypeStrArr.Add(_T("--none--"));
162 
163         alignStrArr.Empty();
164     }
165     else if(key == _T("function"))
166     {
167         aiTypeStrArr.Add(_T("end function"));
168         aiTypeStrArr.Add(_T("endfunction"));
169         aiTypeStrArr.Add(_T("EndFunction"));
170         aiTypeStrArr.Add(_T("--none--"));
171 
172         alignStrArr.Empty();
173     }
174     else if(key == _T("interface"))
175     {
176         aiTypeStrArr.Add(_T("end interface"));
177         aiTypeStrArr.Add(_T("endinterface"));
178         aiTypeStrArr.Add(_T("EndInterface"));
179         aiTypeStrArr.Add(_T("--none--"));
180 
181         alignStrArr.Empty();
182     }
183     else if(key == _T("associate"))
184     {
185         aiTypeStrArr.Add(_T("end associate"));
186         aiTypeStrArr.Add(_T("endassociate"));
187         aiTypeStrArr.Add(_T("EndAssociate"));
188         aiTypeStrArr.Add(_T("--none--"));
189     }
190     else if(key == _T("block"))
191     {
192         aiTypeStrArr.Add(_T("end block"));
193         aiTypeStrArr.Add(_T("endblock"));
194         aiTypeStrArr.Add(_T("EndBlock"));
195         aiTypeStrArr.Add(_T("--none--"));
196     }
197     else if(key == _T("critical"))
198     {
199         aiTypeStrArr.Add(_T("end critical"));
200         aiTypeStrArr.Add(_T("endcritical"));
201         aiTypeStrArr.Add(_T("EndCritical"));
202         aiTypeStrArr.Add(_T("--none--"));
203     }
204     else if(key == _T("module"))
205     {
206         aiTypeStrArr.Add(_T("end module"));
207         aiTypeStrArr.Add(_T("endmodule"));
208         aiTypeStrArr.Add(_T("EndModule"));
209         aiTypeStrArr.Add(_T("--none--"));
210 
211         alignStrArr.Empty();
212     }
213     else if(key == _T("program"))
214     {
215         aiTypeStrArr.Add(_T("end program"));
216         aiTypeStrArr.Add(_T("endprogram"));
217         aiTypeStrArr.Add(_T("EndProgram"));
218         aiTypeStrArr.Add(_T("--none--"));
219 
220         alignStrArr.Empty();
221     }
222     else if(key == _T("select"))
223     {
224         aiTypeStrArr.Add(_T("end select"));
225         aiTypeStrArr.Add(_T("endselect"));
226         aiTypeStrArr.Add(_T("EndSelect"));
227         aiTypeStrArr.Add(_T("--none--"));
228     }
229     else if(key == _T("type"))
230     {
231         aiTypeStrArr.Add(_T("end type"));
232         aiTypeStrArr.Add(_T("endtype"));
233         aiTypeStrArr.Add(_T("EndType"));
234         aiTypeStrArr.Add(_T("--none--"));
235 
236         alignStrArr.Empty();
237     }
238     else if(key == _T("where"))
239     {
240         aiTypeStrArr.Add(_T("end where"));
241         aiTypeStrArr.Add(_T("endwhere"));
242         aiTypeStrArr.Add(_T("EndWhere"));
243         aiTypeStrArr.Add(_T("--none--"));
244     }
245     else if(key == _T("enum"))
246     {
247         aiTypeStrArr.Add(_T("end enum"));
248         aiTypeStrArr.Add(_T("endenum"));
249         aiTypeStrArr.Add(_T("EndEnum"));
250         aiTypeStrArr.Add(_T("--none--"));
251 
252         alignStrArr.Empty();
253         addNameEnabled = false;
254     }
255     else if(key == _T("forall"))
256     {
257         aiTypeStrArr.Add(_T("end forall"));
258         aiTypeStrArr.Add(_T("endforall"));
259         aiTypeStrArr.Add(_T("EndForall"));
260         aiTypeStrArr.Add(_T("--none--"));
261     }
262     else if(key == _T("submodule"))
263     {
264         aiTypeStrArr.Add(_T("end submodule"));
265         aiTypeStrArr.Add(_T("endsubmodule"));
266         aiTypeStrArr.Add(_T("EndSubmodule"));
267         aiTypeStrArr.Add(_T("--none--"));
268 
269         alignStrArr.Empty();
270     }
271     else if(key == _T("team"))
272     {
273         aiTypeStrArr.Add(_T("end team"));
274         aiTypeStrArr.Add(_T("endteam"));
275         aiTypeStrArr.Add(_T("EndTeam"));
276         aiTypeStrArr.Add(_T("--none--"));
277     }
278     return true;
279 }
280 
GetAIT(int aiT)281 AutoInsert::AutoInsertType AutoInsert::GetAIT(int aiT)
282 {
283     if (aiT == 0)
284         return aitSeparate;
285     else if (aiT == 1)
286         return aitTogether;
287     else if (aiT == 2)
288         return aitTogetherCap;
289 
290     return aitNone;
291 }
292 
GetAITInt(AutoInsert::AutoInsertType aiT)293 int AutoInsert::GetAITInt(AutoInsert::AutoInsertType aiT)
294 {
295     if (aiT == aitSeparate)
296         return 0;
297     else if (aiT == aitTogether)
298         return 1;
299     else if (aiT == aitTogetherCap)
300         return 2;
301 
302     return 3;
303 }
304 
FindKey(const wxString & statementName)305 wxString AutoInsert::FindKey(const wxString& statementName)
306 {
307     std::map<wxString,wxString>::const_iterator it;
308     wxString key;
309 
310     for (it = m_NameMap.begin(); it != m_NameMap.end(); ++it)
311     {
312         if (it->second == statementName)
313         {
314             key = it->first;
315             break;
316         }
317     }
318     return key;
319 }
320 
MakeAutoInsert(cbEditor * ed)321 void AutoInsert::MakeAutoInsert(cbEditor* ed)
322 {
323     // Function should be called after 'Enter' only.
324     // Is assumed that current line is empty (or only spaces).
325     cbStyledTextCtrl* stc = ed->GetControl();
326     if (!stc)
327         return;
328 
329     FortranSourceForm fsForm;
330     if (!g_FortranFileExt.IsFileFortran(ed->GetFilename(), fsForm))
331         return;
332     if (fsForm == fsfFixed)
333         return;
334     if(!IsAtLineEnd(stc))
335         return;
336     wxString lineStr;
337     GetLine(stc, lineStr);
338     if (lineStr.IsEmpty())
339         return;
340 
341     wxString firstName;
342     int firstNameIndent;
343     int keyStartPos;
344     int keyIndent;
345     if (!GetIndentAndPos(stc, lineStr, firstName, firstNameIndent, keyStartPos, keyIndent)
346         && !(lineStr.Length() >= 4 && lineStr.Mid(lineStr.Length()-4).Lower().IsSameAs(_T("then"))))
347         return;
348 
349     wxString statementLineStr = lineStr.Mid(keyStartPos);
350     wxString word = GetWord(statementLineStr,0);
351     wxString wordLw = word.Lower();
352     if (wordLw.IsSameAs(_T("end")))
353         return;
354 
355     std::map<wxString,wxString>::const_iterator it;
356     wxString key;
357 
358     for (it = m_NameMap.begin(); it != m_NameMap.end(); ++it)
359     {
360         if (wordLw.IsSameAs(it->first))
361         {
362             key = it->first;
363             break;
364         }
365     }
366 
367     wxString statementLineStrLw = statementLineStr.Lower();
368     if (key.IsEmpty() ||
369         key.IsSameAs(_T("type"))) // situation: "type(tname) function myfunc(..."
370     {
371         wxString funw = _T("function");
372         int wstart = statementLineStrLw.Find(funw);
373         if (wstart != wxNOT_FOUND)
374         {
375             wxString funword = GetWord(statementLineStrLw,wstart);
376             if (funword.IsSameAs(funw))
377             {
378                 key = funw;
379                 keyStartPos += wstart;
380                 word = GetWord(statementLineStr,wstart);
381             }
382         }
383     }
384 
385     if ( key.IsSameAs(_T("module")) || // take care for "module subroutine Name()"
386          (key.IsEmpty() &&
387           (wordLw.IsSameAs(_T("pure")) || wordLw.IsSameAs(_T("impure"))
388            || wordLw.IsSameAs(_T("elemental"))
389            || wordLw.IsSameAs(_T("recursive")) || wordLw.IsSameAs(_T("non_recursive")))) )
390     {
391         wxString reststr = statementLineStrLw.Mid(wordLw.Length()+1).Trim(false);
392         wxString secword = GetWord(reststr,0);
393         if (secword.IsSameAs(_T("procedure")))
394             return;
395         else if (secword.IsSameAs(_T("subroutine")) || secword.IsSameAs(_T("function")))
396         {
397             key = secword;
398             int wstart = statementLineStrLw.Find(secword);
399             keyStartPos += wstart;
400             word = GetWord(statementLineStr,wstart);
401         }
402     }
403 
404     if (key.IsEmpty() || key.IsSameAs(_T("if")))
405     {
406         wxString thw = _T("then");
407         if (statementLineStrLw.EndsWith(thw))
408         {
409             wxString thword = GetWord(statementLineStrLw,statementLineStrLw.Length()-4);
410             if (thword.IsSameAs(thw))
411             {
412                 GetFortranLine(stc, lineStr);
413                 if (!GetIndentAndPos(stc, lineStr, firstName, firstNameIndent, keyStartPos, keyIndent))
414                     return;
415                 word = GetWord(lineStr, keyStartPos);
416                 wordLw = word.Lower();
417                 if (wordLw.IsSameAs(_T("if")))
418                     key = _T("if");
419             }
420         }
421         else
422             key = wxEmptyString;
423     }
424 
425     if (key.IsEmpty() && wordLw.IsSameAs(_T("change")))
426     {
427         wxString secword = GetWord(statementLineStrLw,7);
428         if (secword.IsSameAs(_T("team")))
429             key = _T("team");
430     }
431 
432     if (key.IsEmpty())
433         return;
434 
435     wxString lineRest = lineStr.Mid(keyStartPos+key.Len()).Trim(false);
436     if (lineRest.IsEmpty() && !key.IsSameAs(_T("interface")) && !key.IsSameAs(_T("block")) && !key.IsSameAs(_T("critical"))
437         && !key.IsSameAs(_T("do")) && !key.IsSameAs(_T("program")))
438         return; // unfinished statements or something else
439 
440     if (key.IsSameAs(_T("team")))
441     {
442         lineRest = lineStr.Mid(keyStartPos+6).Trim(false).Mid(4).Trim(false);
443     }
444 
445     if (key.IsSameAs(_T("where")) || key.IsSameAs(_T("forall")) || key.IsSameAs(_T("team")))
446     {
447         if (!lineRest.StartsWith(_T("(")))
448             return; // something is wrong with syntax
449         else
450         {
451             int cl = FindEndBracket(lineRest,0);
452             if (cl == wxNOT_FOUND)
453                 return; // we don't consider case when "where ( bla bla"
454             else if (cl+1 < int(lineRest.Length()))
455                 return; // there are some symbols after "where (bla bla)". It is not "where" construct
456         }
457     }
458     else if (key.IsSameAs(_T("type")))
459     {
460         if (lineRest.StartsWith(_T("(")))
461             return; // here is declaration
462         if (GetWord(lineRest,0).Lower().IsSameAs(_T("is")))
463             return; // "type is ..." statement
464     }
465     else if (key.IsEmpty() || m_AITMap[key] == aitNone)
466         return;
467 
468     if (!DoEndStatementIsRequired(stc, key))
469         return;
470 
471     wxString addStr;
472     if (m_AITMap[key] == aitSeparate)
473     {
474         if (islower(word.GetChar(0)))
475             addStr << _T("end ") << key;
476         else if (islower(word.GetChar(1)))
477             addStr << _T("End ") << key.Mid(0,1).Upper() << key.Mid(1);
478         else
479             addStr << _T("END ") << key.Upper();
480     }
481     else if (m_AITMap[key] == aitTogether)
482     {
483         if (islower(word.GetChar(0)))
484             addStr << _T("end") << key;
485         else if (islower(word.GetChar(1)))
486             addStr << _T("End") << key;
487         else
488             addStr << _T("END") << key.Upper();
489     }
490     else if (m_AITMap[key] == aitTogetherCap)
491     {
492         if (islower(word.GetChar(0)))
493             addStr << _T("end") << key;
494         else if (islower(word.GetChar(1)))
495             addStr << _T("End") << key.Mid(0,1).Upper() << key.Mid(1);
496         else
497             addStr << _T("END") << key.Upper();
498     }
499 
500     if (m_DoAddNameMap[key])
501     {
502         if (   key.IsSameAs(_T("subroutine")) || key.IsSameAs(_T("function"))
503             || key.IsSameAs(_T("program")) || key.IsSameAs(_T("module"))
504             || key.IsSameAs(_T("submodule")) || key.IsSameAs(_T("interface")))
505         {
506             wxString name = GetWord(lineRest,0);
507             if (name.Length() > 0 && (isalnum(name.GetChar(0)) || (name.GetChar(0) == '_')))
508                 addStr << _T(" ") << name;
509         }
510         else if (key.IsSameAs(_T("type")))
511         {
512             if (lineRest.StartsWith(_T(",")))
513             {
514                 int idx = lineRest.Find(_T("::"));
515                 if (idx != wxNOT_FOUND)
516                     lineRest = lineRest.Mid(idx).Trim(false);
517                 else
518                     return; // something is wrong
519             }
520             wxString name = GetWord(lineRest,0);
521             if (name.Length() > 0 && (isalnum(name.GetChar(0)) || (name.GetChar(0) == '_')))
522                 addStr << _T(" ") << name;
523         }
524         else if (!firstName.IsEmpty() &&
525             (  key.IsSameAs(_T("do")) || key.IsSameAs(_T("if"))
526             || key.IsSameAs(_T("associate")) || key.IsSameAs(_T("block"))
527             || key.IsSameAs(_T("critical")) || key.IsSameAs(_T("select"))
528             || key.IsSameAs(_T("forall")) || key.IsSameAs(_T("where"))
529             || key.IsSameAs(_T("team")) )
530                  )
531         {
532             addStr << _T(" ") << firstName;
533         }
534     }
535 
536     int nspace = 0;
537     if (!m_AlignTSMap[key] && !firstName.IsEmpty() &&
538         (  key.IsSameAs(_T("do")) || key.IsSameAs(_T("if"))
539         || key.IsSameAs(_T("associate")) || key.IsSameAs(_T("block"))
540         || key.IsSameAs(_T("critical")) || key.IsSameAs(_T("select"))
541         || key.IsSameAs(_T("forall")) || key.IsSameAs(_T("where"))
542         || key.IsSameAs(_T("team")) )
543         )
544     {
545         nspace = firstNameIndent;
546     }
547     else
548         nspace = keyIndent;
549 
550     // Insert
551     wxString spacStr;
552     spacStr.Append(' ',nspace);
553     addStr.Prepend(_T("\n")+spacStr);
554 
555     stc->InsertText(stc->GetCurrentPos(),addStr);
556 }
557 
GetWord(const wxString & line,size_t posStart)558 wxString AutoInsert::GetWord(const wxString& line, size_t posStart)
559 {
560     bool found = false;
561     wxString wordBefore;
562     size_t idx = 0;
563     if (posStart > 0)
564     {
565         for (size_t i=posStart-1; true; i--)
566         {
567             if (!isalnum(line.GetChar(i)) && (line.GetChar(i) != '_'))
568             {
569                 found = true;
570                 idx = i+1;
571                 break;
572             }
573             else if (i == 0)
574                 break;
575         }
576         if (found)
577             wordBefore = line.Mid(idx,posStart-idx);
578         else
579             wordBefore = line.Mid(0,posStart);
580     }
581 
582     found = false;
583     for (size_t i=posStart; i<line.Length(); i++)
584     {
585         if (!isalnum(line.GetChar(i)) && (line.GetChar(i) != '_'))
586         {
587             found = true;
588             idx = i;
589             break;
590         }
591     }
592 
593     if (found)
594         return wordBefore+line.Mid(posStart,idx-posStart);
595     return wordBefore+line.Mid(posStart);
596 }
597 
FindEndBracket(const wxString str,size_t istart) const598 int AutoInsert::FindEndBracket(const wxString str, size_t istart) const
599 {
600     int level = 0;
601     for (size_t i=istart; i<str.Length(); i++)
602     {
603         if (str.GetChar(i) == '(')
604             level+=1;
605         else if (str.GetChar(i) == ')')
606         {
607             level-=1;
608             if (level == 0)
609                 return int(i);
610         }
611     }
612     return wxNOT_FOUND;
613 }
614 
DoEndStatementIsRequired(cbStyledTextCtrl * stc,const wxString & key)615 bool AutoInsert::DoEndStatementIsRequired(cbStyledTextCtrl* stc, const wxString& key)
616 {
617     if (m_RegMap.count(key) < 1)
618         return false;
619     wxRegEx* reCur = m_RegMap[key];
620     wxRegEx* reEndCur1 = m_RegMap[_T("end") + key];
621     wxRegEx* reEndCur2 = NULL;
622 
623     wxRegEx* reFinish1 = NULL;
624     wxRegEx* reFinish2 = NULL;
625     wxRegEx* reFinBack1 = NULL;
626     wxRegEx* reFinBack2 = NULL;
627     wxRegEx* reFinBack3 = NULL;
628     bool isSubprog = false;
629     bool noLevels = false;
630     if (key.IsSameAs(_T("if")) || key.IsSameAs(_T("do"))
631         || key.IsSameAs(_T("associate")) || key.IsSameAs(_T("block")) || key.IsSameAs(_T("critical"))
632         || key.IsSameAs(_T("select")) || key.IsSameAs(_T("where"))
633         || key.IsSameAs(_T("forall")) || key.IsSameAs(_T("change")))
634     {
635         // limit search until the end of unit
636         reFinish1 = m_RegMap[_T("end")];
637         reFinish2 = m_RegMap[_T("endunit")];
638         reFinBack1 = m_RegMap[_T("function")];
639         reFinBack2 = m_RegMap[_T("subroutine")];
640         reFinBack3 = m_RegMap[_T("program")];
641     }
642     else if (key.IsSameAs(_T("function")) || key.IsSameAs(_T("subroutine")))
643     {
644         reEndCur2 = m_RegMap[_T("end")];
645         reFinish1 = m_RegMap[_T("endmodule")];
646         reFinish2 = m_RegMap[_T("endsubmodule")];
647         isSubprog = true;
648     }
649     else if (key.IsSameAs(_T("module")) || key.IsSameAs(_T("submodule")) || key.IsSameAs(_T("program")))
650     {
651         reEndCur2 = m_RegMap[_T("end")];
652         reFinish1 = m_RegMap[_T("module")];
653         reFinish2 = m_RegMap[_T("submodule")];
654         isSubprog = true;
655     }
656     else if (key.IsSameAs(_T("type")) || key.IsSameAs(_T("enum")))
657     {
658         noLevels = true;
659         reFinish1 = m_RegMap[_T("end")];
660         reFinish2 = m_RegMap[_T("endunit")];
661     }
662 
663     bool isIf = false;
664     if (key.IsSameAs(_T("if")))
665         isIf = true;
666 
667     int line = stc->LineFromPosition(stc->GetCurrentPos()) + 1;
668     int lcount = stc->GetLineCount();
669     lcount = std::min(lcount,line+10000); // limit search for very long files
670     wxString str;
671 
672     if (isSubprog)
673     {
674         while (line < lcount)
675         {
676             str = stc->GetLine(line);
677 
678             if (   (reFinish1 && reFinish1->Matches(str))
679                 || (reFinish2 && reFinish2->Matches(str)))
680                 break;
681             else if (m_RegMap[_T("function")]->Matches(str) || m_RegMap[_T("subroutine")]->Matches(str)
682                         || m_RegMap[_T("module")]->Matches(str) || m_RegMap[_T("submodule")]->Matches(str)
683                         || m_RegMap[_T("program")]->Matches(str) || m_RegMap[_T("endinterface")]->Matches(str))
684                 break;
685             else if (reEndCur1->Matches(str) || (reEndCur2 && reEndCur2->Matches(str)))
686             {
687                 return false;
688             }
689             else
690             {
691                 str = str.BeforeFirst('!').Trim();
692                 if (!str.IsEmpty())
693                     return false;
694             }
695             line += 1;
696         }
697         return true;
698     }
699     else if (noLevels)
700     {
701         while (line < lcount)
702         {
703             str = stc->GetLine(line);
704 
705             if (   (reFinish1 && reFinish1->Matches(str))
706                 || (reFinish2 && reFinish2->Matches(str)))
707                 break;
708             else if (m_RegMap[_T("function")]->Matches(str) || m_RegMap[_T("subroutine")]->Matches(str)
709                         || m_RegMap[_T("module")]->Matches(str) || m_RegMap[_T("submodule")]->Matches(str)
710                         || m_RegMap[_T("program")]->Matches(str))
711                 break;
712             else if (   m_RegMap[_T("type")]->Matches(str) || m_RegMap[_T("enum")]->Matches(str)
713                      || m_RegMap[_T("interface")]->Matches(str))
714                 break;
715             else if (reEndCur1->Matches(str))
716                 return false;
717             else if (   m_RegMap[_T("if")]->Matches(str) || m_RegMap[_T("do")]->Matches(str)
718                      || m_RegMap[_T("associate")]->Matches(str) || m_RegMap[_T("block")]->Matches(str)
719                      || m_RegMap[_T("critical")]->Matches(str) || m_RegMap[_T("select")]->Matches(str)
720                      || m_RegMap[_T("where")]->Matches(str) || m_RegMap[_T("forall")]->Matches(str))
721             {
722                 break;
723             }
724             line += 1;
725         }
726         return true;
727     }
728     else if (key.IsSameAs(_T("interface")))
729     {
730         wxRegEx* reFin1 = m_RegMap[_T("contains")];
731         wxRegEx* reFin2 = m_RegMap[_T("do")];
732         wxRegEx* reFin3 = m_RegMap[_T("if")];
733         wxRegEx* reFin4 = m_RegMap[_T("interface")];
734         //wxRegEx* reFin5 = m_RegMap[_T("module")];
735         wxRegEx* reFin6 = m_RegMap[_T("submodule")];
736         wxRegEx* reFin7 = m_RegMap[_T("program")];
737         wxRegEx* reFin8 = m_RegMap[_T("block")];
738         wxRegEx* reFin9 = m_RegMap[_T("critical")];
739         wxRegEx* reFin10 = m_RegMap[_T("associate")];
740         wxRegEx* reFin11 = m_RegMap[_T("block")];
741         wxRegEx* reFin12 = m_RegMap[_T("select")];
742         wxRegEx* reFin13 = m_RegMap[_T("where")];
743         wxRegEx* reFin14 = m_RegMap[_T("forall")];
744         wxRegEx* reFin15 = m_RegMap[_T("team")];
745 
746         while (line < lcount)
747         {
748             str = stc->GetLine(line);
749 
750             if (reFin1->Matches(str) || reFin2->Matches(str) || reFin3->Matches(str) || reFin4->Matches(str)
751                 || reFin6->Matches(str) || reFin7->Matches(str) || reFin8->Matches(str)
752                 || reFin9->Matches(str) || reFin10->Matches(str) || reFin11->Matches(str) || reFin12->Matches(str)
753                 || reFin13->Matches(str) || reFin14->Matches(str) || reFin15->Matches(str)
754                 )
755                 break;
756             else if (reEndCur1->Matches(str))
757                 return false;
758 
759             line += 1;
760         }
761         return true;
762     }
763 
764     //Determine level below
765     int level = 0;
766     while (line < lcount)
767     {
768         if (isIf)
769         {
770             GetLine(stc, str, line);
771             if (str.Len() >= 4)
772             {
773                 wxString eth = str.Mid(str.Len()-4,4).Lower();
774                 if (eth.IsSameAs(_T("then")))
775                     GetFortranLine(stc,str,line);
776             }
777         }
778         else
779             str = stc->GetLine(line);
780 
781         if (   (reFinish1 && reFinish1->Matches(str))
782                  || (reFinish2 && reFinish2->Matches(str)))
783             break;
784         else if (reCur->Matches(str))
785             level += 1;
786         else if (reEndCur1->Matches(str) || (reEndCur2 && reEndCur2->Matches(str)))
787         {
788             level -= 1;
789         }
790         line += 1;
791     }
792 
793     if (level == 0)
794         return true;
795 
796     //Determine level above
797     int level_down = level;
798     level = 0;
799     line = stc->LineFromPosition(stc->GetCurrentPos()) - 2;
800     int lfin = std::max(0,line-1000); // limit search for very long subprograms
801     while (line >= lfin)
802     {
803         if (isIf)
804         {
805             GetLine(stc, str, line);
806             if (str.Len() >= 4)
807             {
808                 wxString eth = str.Mid(str.Len()-4,4).Lower();
809                 if (eth.IsSameAs(_T("then")))
810                     GetFortranLine(stc,str,line);
811             }
812         }
813         else
814             str = stc->GetLine(line);
815 
816         if (   (reFinish1 && reFinish1->Matches(str))
817                  || (reFinish2 && reFinish2->Matches(str)))
818             break;
819         else if (   (reFinBack1 && reFinBack1->Matches(str))
820                  || (reFinBack2 && reFinBack2->Matches(str))
821                  || (reFinBack3 && reFinBack3->Matches(str)) )
822             break;
823         else if (reCur->Matches(str))
824             level += 1;
825         else if (reEndCur1->Matches(str) || (reEndCur2 && reEndCur2->Matches(str)))
826         {
827             level -= 1;
828         }
829         line -= 1;
830     }
831     if ((level_down+level) != 0)
832         return false;
833     return true;
834 }
835 
GetIndentAndPos(cbStyledTextCtrl * stc,const wxString & lineStr,wxString & firstName,int & firstNameIndent,int & keyStartPos,int & keyIndent)836 bool AutoInsert::GetIndentAndPos(cbStyledTextCtrl* stc, const wxString& lineStr, wxString& firstName, int& firstNameIndent, int& keyStartPos, int& keyIndent)
837 {
838     bool inLabel = false;
839     bool wasCh = false;
840     bool inName = false;
841     bool wasInName = false;
842     bool haveNameEnd = false;
843     int nsPos = -1;
844     int nfPos = 0;
845     int curIndent = 0;
846     firstName = wxEmptyString;
847     firstNameIndent = 0;
848     keyStartPos = 0;
849     keyIndent = 0;
850     size_t lineStrLen = lineStr.Length();
851 
852     for (size_t i=0; i<lineStrLen; i++)
853     {
854         wxChar ch = lineStr.GetChar(i);
855         if (!wasCh)
856         {
857             if (ch == _T('\n'))
858                 firstNameIndent = 0;
859             else if (ch == '\t')
860                 firstNameIndent += stc->GetTabWidth();
861             else if (isdigit(ch) || ch == ' ')
862                 firstNameIndent += 1;
863         }
864 
865         if (ch == _T('\n'))
866             curIndent = 0;
867         else
868             curIndent += 1;
869 
870         if (!wasCh && isdigit(ch))
871         {
872             inLabel = true;
873         }
874         else if (inLabel)
875         {
876             if (ch == ' ' || ch == '\t')
877                 inLabel = false;
878             else if (!isdigit(ch))
879                 return false; // something is wrong
880         }
881         else if ((inName || wasInName) && (ch == ':'))
882         {
883             if (i+1<lineStrLen && lineStr.GetChar(i+1) == ':')
884                 break;
885             else
886             {
887                 haveNameEnd = true;
888                 nfPos = i;
889                 break;
890             }
891         }
892         else if (inName && !isalnum(ch) && (ch != '_'))
893         {
894             inName = false;
895             if (isblank(ch))
896                 wasInName = true;
897             else
898                 break;
899         }
900         else if (!inLabel && !inName && !wasInName && (isalpha(ch) || (ch == '_')))
901         {
902             wasCh = true;
903             inName = true;
904             nsPos = i;
905         }
906         else if (wasInName && !isblank(ch))
907             break;
908         else if (!isalnum(ch) && (ch != '_') && (ch != '&') && !isblank(ch))
909             break;
910     }
911 
912     wxString statementLineStr;
913     if (haveNameEnd)
914     {
915         firstName = lineStr.Mid(nsPos,nfPos-nsPos).Trim();
916         keyIndent = curIndent;
917         for (size_t i=nfPos+1; i<lineStrLen; i++)
918         {
919             wxChar ch = lineStr.GetChar(i);
920             if ( (ch == _T('\n')) || ( (stc->GetEOLMode() == wxSCI_EOL_CR) && (ch == _T('\r')) ) )
921                 keyIndent = 0;
922             else if (ch == '\t')
923                 keyIndent += stc->GetTabWidth();
924             else if (ch == ' ')
925                 keyIndent += 1;
926             else
927             {
928                 keyStartPos = i;
929                 break;
930             }
931         }
932         if (keyStartPos == 0)
933             return false;
934     }
935     else
936     {
937         if (nsPos == -1)
938             return false;
939 
940         keyIndent = firstNameIndent;
941         keyStartPos = nsPos;
942     }
943     return true;
944 }
945 
IsAtLineEnd(cbStyledTextCtrl * stc)946 bool AutoInsert::IsAtLineEnd(cbStyledTextCtrl* stc)
947 {
948     int pos = stc->GetCurrentPos();
949     int line = stc->LineFromPosition(pos);
950     int posLE = stc->GetLineEndPosition(line);
951     wxString str = stc->GetTextRange(pos, posLE).Trim();
952     return str.IsEmpty();
953 }
954 
GetLine(cbStyledTextCtrl * stc,wxString & lineStr,int line)955 void AutoInsert::GetLine(cbStyledTextCtrl* stc, wxString& lineStr, int line)
956 {
957     if (line == -1)
958     {
959         int pos = stc->GetCurrentPos();
960         line = stc->LineFromPosition(pos) - 1;
961     }
962     int posLS = stc->PositionFromLine(line);
963     int posLE = stc->GetLineEndPosition(line);
964     for (int i=posLS; i<posLE; i++)
965     {
966         int style = stc->GetStyleAt(i);
967         if (style == wxSCI_F_COMMENT)
968         {
969             posLE = i; // here begins comment
970             break;
971         }
972     }
973     lineStr = stc->GetTextRange(posLS, posLE).Trim();
974 }
975 
GetFortranLine(cbStyledTextCtrl * stc,wxString & lineStr,int line)976 void AutoInsert::GetFortranLine(cbStyledTextCtrl* stc, wxString& lineStr, int line)
977 {
978     if (line == -1)
979     {
980         int pos = stc->GetCurrentPos();
981         line = stc->LineFromPosition(pos) - 1;
982     }
983     GetLine(stc, lineStr, line);
984 
985     for (int i=line-1; i>0; i--)
986     {
987         wxString lineStrBefore;
988         GetLine(stc, lineStrBefore, i);
989         if (lineStrBefore.EndsWith(_T("&")))
990         {
991             lineStr.Prepend(lineStrBefore.Mid(0, lineStrBefore.Length()-1).Append(_T(" \n")));
992         }
993         else
994             break;
995     }
996 }
997 
ReadAIOptions()998 void AutoInsert::ReadAIOptions()
999 {
1000     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("fortran_project"));
1001     std::map<wxString,wxString>::const_iterator it;
1002 
1003     for (it = m_NameMap.begin(); it != m_NameMap.end(); ++it)
1004     {
1005         wxString key = it->first;
1006         wxString strType = _T("/ainsert_type_") + key;
1007         wxString strAlign = _T("/ainsert_align_") + key;
1008         wxString strName = _T("/ainsert_name_") + key;
1009 
1010         int aiTInt = cfg->ReadInt(strType, 0);
1011         m_AITMap[key] = GetAIT(aiTInt);
1012         m_AlignTSMap[key] = cfg->ReadBool(strAlign, true);
1013         m_DoAddNameMap[key] = cfg->ReadBool(strName, false);
1014     }
1015 }
1016 
WriteAIOptions()1017 void AutoInsert::WriteAIOptions()
1018 {
1019     if (!m_RulesWereChanged)
1020         return;
1021 
1022     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("fortran_project"));
1023     std::map<wxString,AutoInsertType>::const_iterator it;
1024 
1025     for (it = m_AITMap.begin(); it != m_AITMap.end(); ++it)
1026     {
1027         wxString key = it->first;
1028         wxString strType = _T("/ainsert_type_") + key;
1029         wxString strAlign = _T("/ainsert_align_") + key;
1030         wxString strName = _T("/ainsert_name_") + key;
1031 
1032         int aiTInt = GetAITInt(m_AITMap[key]);
1033         cfg->Write(strType, aiTInt);
1034         cfg->Write(strAlign, m_AlignTSMap[key]);
1035         cfg->Write(strName, m_DoAddNameMap[key]);
1036     }
1037 }
1038 
1039 
1040 
1041