1 
2 #include "formatindent.h"
3 
4 #ifndef CB_PRECOMP
5     #include <wx/tokenzr.h>
6 
7     #include <projectmanager.h>
8     #include <cbproject.h>
9     #include <editormanager.h>
10     #include <configmanager.h>
11     #include "cbeditor.h"
12 #endif
13 #include <vector>
14 
15 #include "formatindentdlg.h"
16 #include "fortranfileext.h"
17 
18 extern FortranFileExt g_FortranFileExt;
19 
20 // constructor
FormatIndent()21 FormatIndent::FormatIndent()
22 {
23 }
24 
25 // destructor
~FormatIndent()26 FormatIndent::~FormatIndent()
27 {
28 }
29 
Format()30 void FormatIndent::Format()
31 {
32     FormatIndentDlg fidlg(Manager::Get()->GetAppWindow());
33     if (fidlg.ShowModal() == wxID_OK)
34     {
35         FormatIndentDlg::FormatIndentScope scope;
36         scope = fidlg.GetFormatScope();
37         if (scope == FormatIndentDlg::fisProject)
38             FormatProject();
39         else if (scope == FormatIndentDlg::fisCurrentFile)
40             FormatActiveFile();
41         else
42             FormatSelection();
43     }
44 }
45 
FormatProject()46 void FormatIndent::FormatProject()
47 {
48     cbProject* project = Manager::Get()->GetProjectManager()->GetActiveProject();
49     if (!project)
50     {
51         cbMessageBox(_("No active project was found!"), _("Error"), wxICON_ERROR);
52         return;
53     }
54 
55     wxArrayString nonFFiles;
56     for (FilesList::iterator it = project->GetFilesList().begin(); it != project->GetFilesList().end(); ++it)
57     {
58         ProjectFile* pf = *it;
59         FortranSourceForm fsForm;
60         bool isF = g_FortranFileExt.IsFileFortran(pf->file.GetFullPath(), fsForm);
61         if (isF && fsForm == fsfFree)
62             FormatFile(pf->file.GetFullPath());
63         else
64             nonFFiles.Add(pf->file.GetFullName());
65     }
66 
67     if (nonFFiles.size() > 0)
68     {
69         wxString mstr;
70         if (nonFFiles.size() == 1)
71         {
72             mstr = _("File \"") + nonFFiles[0] + _("\" was not recognized as a free-form Fortran file.");
73             mstr << _(" The indent formating was not applied for it.");
74         }
75         else
76         {
77             mstr = _("Files");
78             size_t i=0;
79             size_t imax=5;
80             while (i < nonFFiles.size() && i < imax)
81             {
82                 mstr << _("\n\"") << nonFFiles[i] << _T("\"");
83                 i++;
84             }
85             if (nonFFiles.size() > imax)
86                 mstr << _T("...\n");
87             else
88                 mstr << _T("\n");
89             mstr << wxString::Format(_T("(%d "), int(nonFFiles.size())) << _("files) ");
90             mstr << _("were not recognized as the free-form Fortran files.");
91             mstr << _(" The indent formating was not applied for them.");
92             cbMessageBox(mstr, _("Info"), wxICON_INFORMATION);
93         }
94     }
95 }
96 
FormatActiveFile()97 void FormatIndent::FormatActiveFile()
98 {
99 	if (!Manager::Get()->GetEditorManager())
100         return;
101     cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
102     if (!ed)
103         return;
104     cbStyledTextCtrl* control = ed->GetControl();
105     if( wxSCI_LEX_FORTRAN != control->GetLexer() )
106 	{
107         if( cbMessageBox( wxT("Are you sure \n") + ed->GetFilename() +
108             wxT("\nis a Fortran Free Format Source File?\nContinue to Format the Indent?"), _("Error Message"),
109             wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT ) != wxID_YES )
110             return;
111 	}
112 
113     FormatFile(ed->GetFilename());
114 }
115 
FormatFile(const wxString & filename)116 void FormatIndent::FormatFile(const wxString &filename)
117 {
118     cbEditor* ed = Manager::Get()->GetEditorManager()->IsBuiltinOpen(filename);
119     bool wasOpened = true;
120 
121     if (!ed)
122     {
123         // File is not open.  We must open it.
124         ed = Manager::Get()->GetEditorManager()->Open(filename);
125         if (!ed)
126             return;
127         wasOpened = false;
128     }
129 
130     cbStyledTextCtrl* control = ed->GetControl();
131     if (control->GetReadOnly())
132     {
133         cbMessageBox(_("The file is read-only!"), _("Error"), wxICON_ERROR);
134         return;
135     }
136 
137     wxString eolChars = GetEOLChars(control);
138 
139     ReadConfig();
140     const int pos_cur = control->GetCurrentPos();
141     wxString text = control->GetText();
142     wxString formattedText;
143     FormatText(text, 0, eolChars, formattedText);
144 
145     bool changed = m_IndentEstimator.BuffersDiffer(formattedText, text);
146     if (changed)
147     {
148         ReplaceTextInEditor(formattedText, false, control);
149         control->GotoPos(pos_cur);
150     }
151     else if (!changed && !wasOpened)
152         Manager::Get()->GetEditorManager()->Close(filename);
153 
154 }
155 
FormatSelection()156 void FormatIndent::FormatSelection()
157 {
158     if (!Manager::Get()->GetEditorManager())
159         return;
160     cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
161     if (!ed)
162         return;
163     cbStyledTextCtrl* control = ed->GetControl();
164     if (control->GetReadOnly())
165     {
166         cbMessageBox(_("The file is read-only!"), _("Error"), wxICON_ERROR);
167         return;
168     }
169 
170     ReadConfig();
171     int pos_selStart = control->GetSelectionStart();
172     int pos_selEnd = control->GetSelectionEnd();
173     int indexLineStart = 0, indexLineEnd = 0;
174     int nLines = control->GetLineCount();
175 
176     if( pos_selStart != pos_selEnd )
177     {
178         indexLineStart = control->LineFromPosition( pos_selStart );
179         control->GotoLine( indexLineStart );
180         pos_selStart = control->GetCurrentPos();
181         indexLineEnd = control->LineFromPosition( pos_selEnd );
182         if( indexLineEnd == nLines )
183         {
184             control->GotoLine(indexLineEnd);
185             control->LineEnd();
186         }
187         else
188         {
189             control->GotoLine(indexLineEnd + 1);
190         }
191         pos_selEnd = control->GetCurrentPos();
192         control->SetSelectionStart(pos_selStart);
193         control->SetSelectionEnd(pos_selEnd);
194         wxString text = control->GetTextRange(pos_selStart, pos_selEnd);
195         wxString eolChars = GetEOLChars(control);
196 
197         nLines = indexLineEnd + 1;
198         int indentW = ed->GetLineIndentInSpaces( indexLineStart );
199         int tabW = control->GetTabWidth();
200         int indentNum = indentW / tabW;
201         if( (indentW % tabW) > 0 )
202             indentNum++;
203 
204         wxString formattedText;
205         FormatText(text, indentNum, eolChars, formattedText);
206 
207         bool changed = m_IndentEstimator.BuffersDiffer(formattedText, text);
208         if (changed)
209         {
210             ReplaceTextInEditor(formattedText, true, control);
211         }
212     }
213 }
214 
ReadConfig()215 void FormatIndent::ReadConfig()
216 {
217     ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("fortran_project"));
218     if (cfg->ReadBool(_T("/indent_same_as_editor"), true))
219     {
220         cbEditor* ed = Manager::Get()->GetEditorManager()->GetBuiltinActiveEditor();
221         if (!ed)
222             return;
223         cbStyledTextCtrl* control = ed->GetControl();
224         if (!control)
225             return;
226         if (control->GetUseTabs())
227             m_IndentStr = _T("\t");
228         else
229         {
230             int tabWidth = control->GetTabWidth();
231             m_IndentStr = wxString(_T(' '), tabWidth);
232         }
233     }
234     else
235     {
236         if (cfg->ReadBool(_T("/indent_use_tabs"), false))
237             m_IndentStr = _T("\t");
238         else
239         {
240             int tabWidth = cfg->ReadInt(_T("/indent_tab_width"), 4);
241             m_IndentStr = wxString(_T(' '), tabWidth);
242         }
243     }
244     m_TrimFromRight = cfg->ReadBool(_T("/indent_trim_right"), true);
245 
246     m_IndentEstimator.ReadConfig();
247 }
248 
FormatText(const wxString & textIn,int indentStart,const wxString & eolChars,wxString & formattedText)249 void FormatIndent::FormatText(const wxString& textIn, int indentStart, const wxString& eolChars, wxString& formattedText)
250 {
251     wxString str = textIn;
252     str.Replace(_T("\r\n"), _T("\n"));
253     str.Replace(_T("\r"), _T("\n"));
254     wxStringTokenizer tokenizer(str, _T("\n"), wxTOKEN_RET_EMPTY_ALL);
255     std::vector<wxString> textLines;
256     while (tokenizer.HasMoreTokens())
257         textLines.push_back(tokenizer.GetNextToken());
258 
259     int indentNum = indentStart;
260     int nLines = textLines.size();
261 
262 
263     m_IndentEstimator.Initialize(indentNum);
264 
265     IsMultiLines isMultiLines;
266     wxString tmpLine;
267     wxString tmpMultiLines;
268 
269     int indentNumNext;
270 
271     ///formattedText
272     for(int i=0; i < nLines; ++i)
273     {
274         tmpLine = textLines[i];
275 
276         if(m_IndentEstimator.GetIsHasPreprocessor(tmpLine))
277         {
278             if (!isMultiLines.haveMultiLines)
279             {
280                 if(m_TrimFromRight)
281                     tmpLine.Trim(); //trim from right
282                 if( i < nLines-1 )
283                     tmpLine += eolChars;
284                 formattedText += tmpLine;
285             }
286             continue;
287         }
288 
289         tmpLine = tmpLine.Trim(false); // trim from left
290         if(m_IndentEstimator.GetIsHasLineContinuation(tmpLine))
291         {
292             wxString tempLine = tmpLine;
293 
294             if(!isMultiLines.haveMultiLines)
295             {
296                 isMultiLines.haveMultiLines = true;
297                 isMultiLines.iFirstLineNo = i;
298                 tmpMultiLines.Empty();
299             }
300 
301             m_IndentEstimator.CutStringAndComment(tempLine);
302             m_IndentEstimator.DelLineContinuation(tempLine);
303 
304             if(tempLine.Len() > 0)
305             {
306                 if(wxT('&') == tempLine[0])
307                     tempLine = tempLine.Mid(1);
308             }
309             tmpMultiLines += tempLine;
310             continue ;
311         }
312 
313         indentNumNext = indentNum;
314 
315         if(isMultiLines.haveMultiLines)
316         {
317             isMultiLines.iEndLineNo = i;
318 
319             wxString tempLine = tmpLine;
320 
321             if(tempLine.Len() > 0)
322             {
323                 if(wxT('&') == tempLine[0])
324                     tempLine = tempLine.Mid(1);
325             }
326 
327             tmpMultiLines += tempLine;
328             m_IndentEstimator.GetFortranIndentLine(tmpMultiLines, indentNum, indentNumNext);
329 
330             for(int j = isMultiLines.iFirstLineNo; j <= isMultiLines.iEndLineNo; ++j)
331             {
332                 if(m_IndentEstimator.GetIsHasPreprocessor(textLines[j]))
333                 {
334                     tempLine = textLines[j];
335                     if(m_TrimFromRight)
336                         tempLine.Trim(); //trim from right
337                     if(j < nLines-1)
338                         tempLine += eolChars;
339                     formattedText += tempLine;
340                 }
341                 else
342                 {
343                     tempLine = textLines[j].Trim(false); // trim from left
344 
345                     if(m_TrimFromRight)
346                         tempLine.Trim(); //trim from right
347                     if(j < nLines-1)
348                         tempLine += eolChars;
349 
350                     if(j != isMultiLines.iFirstLineNo)
351                         indentNum += 1;
352 
353                     for(int k=0; k < indentNum; ++k)
354                         formattedText += m_IndentStr;
355 
356                     formattedText += tempLine;
357                     indentNum = indentNumNext;
358                 }
359             }
360 
361             isMultiLines.reset();
362         }
363         else
364         {
365             if(tmpLine.Len() == 0 && i < nLines-1)
366                 tmpLine += eolChars;
367             else
368             {
369                 if(m_TrimFromRight)
370                 {
371                     tmpLine.Trim(); //trim from right
372                 }
373                 if(i < nLines-1)
374                     tmpLine += eolChars;
375                 m_IndentEstimator.GetFortranIndentLine(tmpLine, indentNum, indentNumNext);
376 
377                 for(int k = 0; k < indentNum; ++k)
378                     formattedText += m_IndentStr;
379             }
380 
381             formattedText += tmpLine;
382             indentNum = indentNumNext;
383         }
384     }
385 }
386 
ReplaceTextInEditor(const wxString & text,bool isSelection,cbStyledTextCtrl * control)387 void FormatIndent::ReplaceTextInEditor(const wxString& text, bool isSelection, cbStyledTextCtrl* control)
388 {
389     if (isSelection)
390         control->ReplaceSelection(text);
391     else
392         control->SetText(text);
393 }
394 
GetEOLChars(cbStyledTextCtrl * control)395 wxString FormatIndent::GetEOLChars(cbStyledTextCtrl* control)
396 {
397     wxString eolChars;
398     switch (control->GetEOLMode())
399     {
400         case wxSCI_EOL_CRLF:
401             eolChars = _T("\r\n");
402             break;
403 
404         case wxSCI_EOL_CR:
405             eolChars = _T("\r");
406             break;
407 
408         case wxSCI_EOL_LF:
409             eolChars = _T("\n");
410             break;
411     }
412     return eolChars;
413 }
414