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