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