1 #include "ide.h"
2
3 #define LLOG(x) // DLOG(x)
4
ResolveUvsConflict()5 void Ide::ResolveUvsConflict() {
6 String result;
7 editor.NextUndo();
8 bool copy = true;
9 for(int i = 0; i < editor.GetLineCount(); i++) {
10 String ln = editor.GetUtf8Line(i);
11 if(strncmp(ln, "$uvs: ", 6) == 0) {
12 ln = ln.Mid(6);
13 if(ln == "YOUR DELETE")
14 copy = false;
15 else
16 if(ln == "END YOUR DELETE")
17 copy = true;
18 else
19 if(ln == "REPOSITORY DELETE")
20 copy = false;
21 else
22 if(ln == "END REPOSITORY DELETE")
23 copy = true;
24 else
25 if(ln != "REPOSITORY INSERT" &&
26 ln != "YOUR INSERT" &&
27 ln != "END YOUR INSERT" &&
28 ln != "END REPOSITORY INSERT" &&
29 ln != "PENDING CONFLICT") {
30 Exclamation("Cannot resolve uvs conflict -&conflicting modifications found");
31 editor.SetCursor(editor.GetPos64(i));
32 return;
33 }
34 }
35 else
36 if(copy)
37 result << ln << "\r\n";
38 }
39 editor.SelectAll();
40 editor.Paste(result.ToWString());
41 }
42
GotoPos(String path,int line)43 void Ide::GotoPos(String path, int line)
44 {
45 LLOG("GotoPos " << path << ':' << line);
46 if(path.GetCount()) {
47 AddHistory();
48 if(IsDesignerFile(path))
49 DoEditAsText(path);
50 EditFile(path);
51 }
52 editor.SetCursor(editor.GetPos64(line - 1));
53 editor.TopCursor(4);
54 editor.SetFocus();
55 AddHistory();
56 }
57
GotoCpp(const CppItem & pos)58 void Ide::GotoCpp(const CppItem& pos)
59 {
60 GotoPos(GetSourceFilePath(pos.file), pos.line);
61 }
62
CheckCodeBase()63 void Ide::CheckCodeBase()
64 {
65 InvalidateFileTimeCache();
66 CodeBaseSync();
67 }
68
RescanCode()69 void Ide::RescanCode()
70 {
71 /*
72 TimeStop tm;
73 for(int i = 0; i < 10; i++)
74 ReQualifyCodeBase();
75 LOG(tm);
76 PutConsole(AsString(tm));
77 //*/
78 //*
79 SaveFile();
80 TimeStop t;
81 console.Clear();
82 RescanCodeBase();
83 SyncRefsShowProgress = true;
84 SyncRefs();
85 editor.SyncNavigator();
86 //*/
87 }
88
OpenTopic(const String & topic,const String & createafter,bool before)89 void Ide::OpenTopic(const String& topic, const String& createafter, bool before)
90 {
91 TopicLink tl = ParseTopicLink(topic);
92 if(tl) {
93 EditFile(AppendFileName(PackageDirectory(tl.package), tl.group + ".tpp"));
94 if(designer) {
95 TopicEditor *te = dynamic_cast<TopicEditor *>(&designer->DesignerCtrl());
96 if(te)
97 te->GoTo(tl.topic, tl.label, createafter, before);
98 }
99 }
100 }
101
OpenTopic(const String & topic)102 void Ide::OpenTopic(const String& topic)
103 {
104 OpenTopic(topic, String(), false);
105 }
106
OpenATopic()107 void Ide::OpenATopic()
108 {
109 String t = doc.GetCurrent();
110 if(!t.StartsWith("topic:"))
111 return;
112 OpenTopic(t);
113 }
114
IdeFlushFile()115 void Ide::IdeFlushFile()
116 {
117 FlushFile();
118 }
119
IdeOpenTopicFile(const String & file)120 void Ide::IdeOpenTopicFile(const String& file)
121 {
122 EditFile(GetFileFolder(file));
123 if(designer) {
124 TopicEditor *te = dynamic_cast<TopicEditor *>(&designer->DesignerCtrl());
125 if(te)
126 te->GoTo(GetFileTitle(file), "", "", false);
127 }
128 }
129
130 struct FileStat {
131 int count;
132 int len;
133 int lines;
134 int oldest;
135 int newest;
136 int days;
137
AddFileStat138 void Add(const FileStat& a) {
139 count += a.count;
140 len += a.len;
141 lines += a.lines;
142 oldest = max(a.oldest, oldest);
143 newest = min(a.newest, newest);
144 days += a.days;
145 }
146
FileStatFileStat147 FileStat() { count = 0; len = lines = 0; oldest = 0; newest = INT_MAX; days = 0; }
148 };
149
StatLen(int len)150 String StatLen(int len)
151 {
152 return Format("%d.%d KB", len >> 10, (len & 1023) / 103);
153 }
154
StatDate(int d)155 String StatDate(int d)
156 {
157 return String().Cat() << d << " days";
158 }
159
sPut(const String & name,String & qtf,const FileStat & fs)160 void sPut(const String& name, String& qtf, const FileStat& fs)
161 {
162 qtf << "::@W " << DeQtf(Nvl(name, ".<none>"))
163 << ":: [> " << fs.count
164 << ":: " << fs.lines
165 << ":: " << (fs.count ? fs.lines / fs.count : 0)
166 << ":: " << StatLen(fs.len)
167 << ":: " << StatLen(fs.len ? fs.len / fs.count : 0)
168 << ":: " << StatDate(fs.oldest)
169 << ":: " << StatDate(fs.newest)
170 << ":: " << (fs.count ? fs.days / fs.count : 0) << " days]";
171 }
172
sPut(String & qtf,ArrayMap<String,FileStat> & pfs,ArrayMap<String,FileStat> & all)173 void sPut(String& qtf, ArrayMap<String, FileStat>& pfs, ArrayMap<String, FileStat>& all) {
174 FileStat pall;
175 for(int i = 0; i < pfs.GetCount(); i++) {
176 FileStat& fs = pfs[i];
177 sPut(pfs.GetKey(i), qtf, fs);
178 pall.Add(fs);
179 all.GetAdd(pfs.GetKey(i)).Add(fs);
180 }
181 sPut("All files", qtf, pall);
182 qtf << "}}&&";
183 }
184
185
ShowQTF(const String & qtf,const char * title)186 void ShowQTF(const String& qtf, const char *title)
187 {
188 RichText txt = ParseQTF(qtf);
189 ClearClipboard();
190 AppendClipboard(ParseQTF(qtf));
191
192 WithStatLayout<TopWindow> dlg;
193 CtrlLayoutOK(dlg, title);
194 dlg.stat = qtf;
195 dlg.Sizeable().Zoomable();
196 dlg.Run();
197 }
198
Licenses()199 void Ide::Licenses()
200 {
201 Progress pi;
202 const Workspace& wspc = IdeWorkspace();
203 pi.SetTotal(wspc.GetCount());
204 VectorMap<String, String> license_package;
205 for(int i = 0; i < wspc.GetCount(); i++) {
206 String n = wspc[i];
207 pi.SetText(n);
208 if(pi.StepCanceled()) return;
209 String l = LoadFile(SourcePath(n, "Copying"));
210 if(l.GetCount())
211 MergeWith(license_package.GetAdd(l), ", ", n);
212 }
213 if(license_package.GetCount() == 0) {
214 Exclamation("No license files ('Copying') have been found.");
215 return;
216 }
217 String qtf;
218 for(int i = 0; i < license_package.GetCount(); i++) {
219 bool m = license_package[i].Find(',') >= 0;
220 qtf << (m ? "Packages [* \1" : "Package [* \1")
221 << license_package[i]
222 << (m ? "\1] have" : "\1] has")
223 << " following licence notice:&"
224 << "{{@Y [C1 " << DeQtf(license_package.GetKey(i)) << "]}}&&";
225 }
226
227 ShowQTF(qtf, "Licenses");
228 }
229
Statistics()230 void Ide::Statistics()
231 {
232 Vector< ArrayMap<String, FileStat> > stat;
233 Progress pi;
234 const Workspace& wspc = IdeWorkspace();
235 pi.SetTotal(wspc.GetCount());
236 Date now = GetSysDate();
237 for(int i = 0; i < wspc.GetCount(); i++) {
238 const Package& pk = wspc.GetPackage(i);
239 String n = wspc[i];
240 pi.SetText(n);
241 if(pi.StepCanceled()) return;
242 ArrayMap<String, FileStat>& pfs = stat.Add();
243 for(int i = 0; i < pk.GetCount(); i++)
244 if(!pk[i].separator) {
245 String file = SourcePath(n, pk[i]);
246 if(FileExists(file)) {
247 FileStat& fs = pfs.GetAdd(GetFileExt(file));
248 int d = minmax(now - FileGetTime(file), 0, 9999);
249 fs.oldest = max(d, fs.oldest);
250 fs.newest = min(d, fs.newest);
251 String data = LoadFile(file);
252 for(const char *s = data; *s; s++)
253 if(*s == '\n')
254 fs.lines++;
255 fs.len += data.GetCount();
256 fs.days += d;
257 fs.count++;
258 }
259 }
260 }
261 String qtf = "[1 ";
262 ArrayMap<String, FileStat> all;
263 String tab = "{{45:20:25:20:35:30:30:30:30@L [* ";
264 String hdr = "]:: [= Files:: Lines:: - avg.:: Length:: - avg.:: Oldest:: Newest:: Avg. age]";
265 for(int i = 0; i < wspc.GetCount(); i++) {
266 qtf << tab << DeQtf(wspc[i]) << hdr;
267 sPut(qtf, stat[i], all);
268 }
269
270 qtf << tab << "All packages" << hdr;
271 sPut(qtf, all, all);
272
273 ShowQTF(qtf, "Statistics");
274 }
275
FormatElapsedTime(double run)276 String FormatElapsedTime(double run)
277 {
278 String rtime;
279 double hrs = floor(run / 3600);
280 if(hrs > 0)
281 rtime << Format("%0n hours, ", hrs);
282 int minsec = fround(run - 3600 * hrs);
283 int min = minsec / 60, sec = minsec % 60;
284 if(min || hrs)
285 rtime << Format("%d min, ", min);
286 rtime << Format("%d sec", sec);
287 return rtime;
288 }
289
AlterText(WString (* op)(const WString & in))290 void Ide::AlterText(WString (*op)(const WString& in))
291 {
292 if(designer || !editor.IsSelection() || editor.IsReadOnly())
293 return;
294 editor.NextUndo();
295 WString w = editor.GetSelectionW();
296 editor.RemoveSelection();
297 int l = editor.GetCursor();
298 editor.Paste((*op)(w));
299 editor.SetSelection(l, editor.GetCursor64());
300 }
301
TextToUpper()302 void Ide::TextToUpper()
303 {
304 AlterText(UPP::ToUpper);
305 }
306
TextToLower()307 void Ide::TextToLower()
308 {
309 AlterText(UPP::ToLower);
310 }
311
TextToAscii()312 void Ide::TextToAscii()
313 {
314 AlterText(UPP::ToAscii);
315 }
316
TextInitCaps()317 void Ide::TextInitCaps()
318 {
319 AlterText(UPP::InitCaps);
320 }
321
sSwapCase(const WString & s)322 static WString sSwapCase(const WString& s)
323 {
324 WStringBuffer r;
325 r.SetCount(s.GetCount());
326 for(int i = 0; i < s.GetCount(); i++)
327 r[i] = IsUpper(s[i]) ? ToLower(s[i]) : ToUpper(s[i]);
328 return WString(r);
329 }
330
SwapCase()331 void Ide::SwapCase()
332 {
333 AlterText(sSwapCase);
334 }
335
sCString(const WString & s)336 static WString sCString(const WString& s)
337 {
338 return AsCString(s.ToString()).ToWString();
339 }
340
ToCString()341 void Ide::ToCString()
342 {
343 AlterText(sCString);
344 }
345
sComment(const WString & s)346 static WString sComment(const WString& s)
347 {
348 return "/*" + s + "*/";
349 }
350
ToComment()351 void Ide::ToComment()
352 {
353 AlterText(sComment);
354 }
355
sCommentLines(const WString & s)356 static WString sCommentLines(const WString& s)
357 {
358 String r;
359 StringStream ss(s.ToString());
360 for(;;) {
361 String line = ss.GetLine();
362 if(ss.IsError())
363 return s;
364 else
365 if(!line.IsVoid())
366 r << "//" << line << "\n";
367 if(ss.IsEof())
368 break;
369 }
370 return r.ToWString();
371 }
372
CommentLines()373 void Ide::CommentLines()
374 {
375 AlterText(sCommentLines);
376 }
377
sUncomment(const WString & s)378 static WString sUncomment(const WString& s)
379 {
380 WString h = s;
381 h.Replace("/*", "");
382 h.Replace("//", "");
383 h.Replace("*/", "");
384 return h;
385 }
386
UnComment()387 void Ide::UnComment()
388 {
389 AlterText(sUncomment);
390 }
391
ReformatComment()392 void Ide::ReformatComment()
393 {
394 editor.ReformatComment();
395 }
396
Times()397 void Ide::Times()
398 {
399 WithStatisticsLayout<TopWindow> statdlg;
400 CtrlLayout(statdlg, "Elapsed times");
401 statdlg.ok.Ok();
402 statdlg.ok << [&] { statdlg.Break(); };
403 statdlg.SetTimeCallback(-1000, statdlg.Breaker(IDRETRY), 50);
404 do
405 {
406 int session_time = int(GetSysTime() - start_time);
407 int idle_time = int(session_time - editor.GetStatEditTime() - stat_build_time);
408 statdlg.session_time <<= FormatElapsedTime(session_time);
409 statdlg.edit_time <<= FormatElapsedTime(editor.GetStatEditTime());
410 statdlg.build_time <<= FormatElapsedTime(stat_build_time);
411 statdlg.idle_time <<= FormatElapsedTime(idle_time);
412 }
413 while(statdlg.Run() == IDRETRY);
414 }
415
416 INITBLOCK {
417 RegisterGlobalConfig("svn-msgs");
418 }
419
420 void RepoSyncDirs(const Vector<String>& working)
421 {
422 // if(!CheckSvn())
423 // return;
424 Ptr<Ctrl> f = Ctrl::GetFocusCtrl();
425 RepoSync repo;
426 String repocfg = ConfigFile("repo.cfg");
427 repo.SetMsgs(LoadFile(repocfg));
428 for(int i = 0; i < working.GetCount(); i++)
429 repo.Dir(working[i]);
430 repo.DoSync();
431 SaveFile(repocfg, repo.GetMsgs());
432 if(f)
433 f->SetFocus();
434 }
435
SyncRepoDirs(const Vector<String> & working)436 void Ide::SyncRepoDirs(const Vector<String>& working)
437 {
438 SaveFile();
439 RepoSyncDirs(working);
440 ScanWorkspace();
441 SyncWorkspace();
442 }
443
SyncRepo()444 void Ide::SyncRepo(){
445 Vector<String> d = RepoDirs();
446 if(d.GetCount())
447 SyncRepoDirs(d);
448 else
449 SyncRepoDirs(RepoDirs(true));
450 }
451
SyncRepoDir(const String & working)452 void Ide::SyncRepoDir(const String& working)
453 {
454 SyncRepoDirs(Vector<String>() << working);
455 }
456
GotoDirDiffLeft(int line,DirDiffDlg * df)457 void Ide::GotoDirDiffLeft(int line, DirDiffDlg *df)
458 {
459 EditFile(df->GetLeftFile());
460 editor.SetCursor(editor.GetPos64(line));
461 editor.SetFocus();
462 }
463
GotoDirDiffRight(int line,DirDiffDlg * df)464 void Ide::GotoDirDiffRight(int line, DirDiffDlg *df)
465 {
466 EditFile(df->GetRightFile());
467 editor.SetCursor(editor.GetPos64(line));
468 editor.SetFocus();
469 }
470
DoDirDiff()471 void Ide::DoDirDiff()
472 {
473 Index<String> dir;
474 Vector<String> d = GetUppDirs();
475 for(int i = 0; i < d.GetCount(); i++)
476 dir.FindAdd(d[i]);
477 FindFile ff(ConfigFile("*.bm"));
478 while(ff) {
479 VectorMap<String, String> var;
480 LoadVarFile(ff.GetPath(), var);
481 Vector<String> p = Split(var.Get("UPP", String()), ';');
482 for(int i = 0; i < p.GetCount(); i++)
483 dir.FindAdd(p[i]);
484 ff.Next();
485 }
486 String n = GetFileFolder(editfile);
487 if(n.GetCount())
488 dir.FindAdd(n);
489 SortIndex(dir);
490
491 static DirDiffDlg dlg;
492 dlg.diff.WhenLeftLine = THISBACK1(GotoDirDiffLeft, &dlg);
493 dlg.diff.WhenRightLine = THISBACK1(GotoDirDiffRight, &dlg);
494 for(int i = 0; i < dir.GetCount(); i++) {
495 dlg.Dir1AddList(dir[i]);
496 dlg.Dir2AddList(dir[i]);
497 }
498 if(d.GetCount())
499 dlg.Dir1(d[0]);
500 if(!dlg.IsOpen()) {
501 dlg.SetFont(veditorfont);
502 dlg.Maximize();
503 dlg.Title("Compare directories");
504 dlg.OpenMain();
505 }
506 else
507 dlg.SetFocus();
508 }
509
DoPatchDiff()510 void Ide::DoPatchDiff()
511 {
512 String patch = SelectFileOpen("Patch files (*.diff *.patch)\t*.diff *.patch\nAll files\t*.*");
513 if(IsNull(patch))
514 return;
515 Index<String> dir;
516 if(editfile.GetCount())
517 dir.Add(GetFileFolder(editfile));
518 Vector<String> d = GetUppDirs();
519 for(int i = 0; i < d.GetCount(); i++)
520 dir.FindAdd(d[i]);
521 static PatchDiff dlg;
522 dlg.diff.WhenLeftLine = THISBACK1(GotoDirDiffLeft, &dlg);
523 if(!dlg.IsOpen()) {
524 dlg.SetFont(veditorfont);
525 dlg.Maximize();
526 if(dlg.Open(patch, dir.GetKeys()))
527 dlg.OpenMain();
528 }
529 else
530 dlg.SetFocus();
531 }
532
AsErrors()533 void Ide::AsErrors()
534 {
535 ClearErrorsPane();
536 SetBottom(BERRORS);
537 String s = editor.IsSelection() ? editor.GetSelection() : editor.Get();
538 StringStream ss(s);
539 while(!ss.IsEof())
540 ConsoleLine(ss.GetLine(), true);
541 SetErrorEditor();
542 }
543
RemoveDs()544 void Ide::RemoveDs()
545 {
546 if(designer || editor.IsReadOnly())
547 return;
548 static Index<String> ds = { "DLOG", "DDUMP", "DDUMPC", "DDUMPM", "DTIMING",
549 "DLOGHEX", "DDUMPHEX", "DTIMESTOP", "DHITCOUNT" };
550 editor.NextUndo();
551 int l = 0;
552 int h = editor.GetLineCount() - 1;
553 int ll, hh;
554 if(editor.GetSelection(ll, hh)) {
555 l = editor.GetLine(ll);
556 h = editor.GetLine(hh);
557 }
558 for(int i = h; i >= l; i--) {
559 String ln = editor.GetUtf8Line(i);
560 try {
561 CParser p(ln);
562 if(p.IsId()) {
563 String id = p.ReadId();
564 if(ds.Find(id) >= 0 && p.Char('(')) {
565 int pos = editor.GetPos(i);
566 int end = min(editor.GetLength(), editor.GetPos(i) + editor.GetLineLength(i) + 1);
567 editor.Remove(editor.GetPos(i), end - pos);
568 }
569 }
570 }
571 catch(CParser::Error) {}
572 }
573 editor.GotoLine(l);
574 }
575
LaunchAndroidSDKManager(const AndroidSDK & androidSDK)576 void Ide::LaunchAndroidSDKManager(const AndroidSDK& androidSDK)
577 {
578 One<Host> host = CreateHost(darkmode, disable_uhd);
579 IGNORE_RESULT(host->Execute(androidSDK.GetLauchSDKManagerCmd()));
580 }
581
LaunchAndroidAVDManager(const AndroidSDK & androidSDK)582 void Ide::LaunchAndroidAVDManager(const AndroidSDK& androidSDK)
583 {
584 One<Host> host = CreateHost(darkmode, disable_uhd);
585 IGNORE_RESULT(host->Execute(androidSDK.GetLauchAVDManagerCmd()));
586 }
587
LauchAndroidDeviceMonitor(const AndroidSDK & androidSDK)588 void Ide::LauchAndroidDeviceMonitor(const AndroidSDK& androidSDK)
589 {
590 One<Host> host = CreateHost(darkmode, disable_uhd);
591 IGNORE_RESULT(host->Execute(androidSDK.MonitorPath()));
592 }
593