#include "ide.h" void Ide::RunArgs() { WithRunLayout dlg; CtrlLayoutOKCancel(dlg, "Run options"); dlg.Sizeable().Zoomable(); #ifndef PLATFORM_POSIX dlg.consolemode.Hide(); dlg.console_lable.Hide(); #endif SelectDirButton dir_browse("Run in folder"); dir_browse.Attach(dlg.dir); dlg.dir = rundir.ToWString(); dlg.arg <<= runarg; { StringStream ss(recent_runarg); dlg.arg.SerializeList(ss); } SaveFileButton stdout_browse("Save STDOUT as"); stdout_browse.Type("Text files (*.txt)", "*.txt").AllFilesType(); stdout_browse.Attach(dlg.stdout_file); { StringStream ss(recent_stdout_file); dlg.stdout_file.SerializeList(ss); dlg.stdout_file <<= stdout_file; } dlg.runmode <<= runmode; dlg.external = runexternal; dlg.consolemode = consolemode; dlg.utf8 <<= console_utf8; dlg.runmode <<= dlg.Breaker(222); for(;;) { bool b = ~dlg.runmode == RUN_FILE; dlg.stdout_file_lbl.Enable(b); dlg.stdout_file.Enable(b); int rm = ~dlg.runmode; dlg.stdout_file.Enable(rm == RUN_FILE || rm == RUN_FILE_CONSOLE); dlg.utf8.Enable(rm != RUN_WINDOW); switch(dlg.Run()) { case IDOK: rundir = ~dlg.dir; runarg = ~dlg.arg; runmode = ~dlg.runmode; runexternal = dlg.external; consolemode = dlg.consolemode; console_utf8 = ~dlg.utf8; stdout_file = ~dlg.stdout_file; dlg.arg.AddHistory(); { StringStream ss; dlg.arg.SerializeList(ss); recent_runarg = ss; } { StringStream ss; dlg.stdout_file.SerializeList(ss); recent_stdout_file = ss; } return; case IDCANCEL: return; } } } One Ide::CreateHostRunDir() { One h = CreateHost(false); if(IsNull(rundir)) h->ChDir(GetFileFolder(target)); else h->ChDir(rundir); return h; } bool Ide::ShouldHaveConsole() { return decode(consolemode, 0, FindIndex(SplitFlags(mainconfigparam, true), "GUI") < 0, 1, true, false); } void Ide::BuildAndExecute() { if(Build()) { String targetExt = GetFileExt(target); if(targetExt == ".apk") ExecuteApk(); else ExecuteBinary(); } } void Ide::ExecuteBinary() { int time = msecs(); One h = CreateHostRunDir(); h->ChDir(Nvl(rundir, GetFileFolder(target))); String cmdline; if(!runexternal) cmdline << '\"' << h->GetHostPath(target) << "\" "; cmdline << ToSystemCharset(runarg); int exitcode; switch(runmode) { case RUN_WINDOW: HideBottom(); h->Launch(cmdline, ShouldHaveConsole()); break; case RUN_CONSOLE: ShowConsole(); PutConsole(String().Cat() << "Executing: " << cmdline); console.Sync(); exitcode = h->ExecuteWithInput(cmdline, console_utf8); PutConsole("Finished in " + GetPrintTime(time) + ", exit code: " + AsString(exitcode)); break; case RUN_FILE: { HideBottom(); String fn; if(IsNull(stdout_file)) fn = ForceExt(target, ".ol"); else fn = stdout_file; FileOut out(fn); if(!out) { PromptOK("Unable to open output file [* " + DeQtf(stdout_file) + "] !"); return; } if(h->Execute(cmdline, out, console_utf8) >= 0) { out.Close(); EditFile(fn); } } } } class SelectAndroidDeviceDlg : public WithSelectAndroidDeviceLayout { typedef SelectAndroidDeviceDlg CLASSNAME; public: SelectAndroidDeviceDlg(AndroidSDK* sdk); int GetDeviceCount() const { return devicesArray.GetCount(); } String GetSelectedSerial() const; private: void LoadDevices(); void OnRefresh(); private: AndroidSDK* sdk; }; SelectAndroidDeviceDlg::SelectAndroidDeviceDlg(AndroidSDK* sdk) : sdk(sdk) { CtrlLayoutOKCancel(*this, "Android device selection"); devicesArray.AddColumn("Serial Number"); devicesArray.AddColumn("State"); refresh <<= THISBACK(OnRefresh); LoadDevices(); } String SelectAndroidDeviceDlg::GetSelectedSerial() const { int row = devicesArray.IsCursor() ? devicesArray.GetCursor() : 0; return devicesArray.GetCount() ? devicesArray.Get(row, 0) : ""; } void SelectAndroidDeviceDlg::LoadDevices() { Vector devices = sdk->FindDevices(); for(int i = 0; i < devices.GetCount(); i++) { devicesArray.Add(devices[i].GetSerial(), devices[i].GetState()); } if(devicesArray.GetCount()) { devicesArray.GoBegin(); ok.Enable(); } else ok.Disable(); } void SelectAndroidDeviceDlg::OnRefresh() { devicesArray.Clear(); LoadDevices(); } void Ide::ExecuteApk() { AndroidSDK sdk(GetAndroidSdkPath(), true); if(!sdk.Validate()) return; SelectAndroidDeviceDlg select(&sdk); if(select.GetDeviceCount() != 1 && select.Run() != IDOK) return; if(!select.GetDeviceCount()) return; One host = CreateHost(false); Apk apk(target, sdk); String packageName = apk.FindPackageName(); String activityName = apk.FindLaunchableActivity(); Adb adb = sdk.MakeAdb(); adb.SetSerial(select.GetSelectedSerial()); host->Execute(adb.MakeInstallCmd(target)); if(!packageName.IsEmpty() && !activityName.IsEmpty()) host->Execute(adb.MakeLaunchOnDeviceCmd(packageName, activityName)); } void Ide::BuildAndDebug0(const String& srcfile) { if(Build()) { One h = CreateHostRunDir(); h->ChDir(GetFileFolder(target)); VectorMap bm = GetMethodVars(method); String dbg = bm.Get("DEBUGGER", Null); if(IsNull(dbg)) { if(bm.Get("BUILDER", Null) == "MSC71") { String sln = ForceExt(target, ".sln"); if(GetFileLength(sln) > 0) h->Launch("devenv \"" + h->GetHostPath(sln) + "\" " // + "\"" + h->GetHostPath(srcfile) + "\"" //TRC, 2011/09/26: wrong devenv argument ); else h->Launch("devenv \"" + h->GetHostPath(target) //+ "\" \"" + h->GetHostPath(srcfile) //TRC, 2011/09/26: wrong devenv argument + "\" /debugexe " ); return; } dbg = "gdb"; } else h->Launch('\"' + dbg + "\" \"" // + h->GetHostPath(srcfile) + ' ' + h->GetHostPath(target) + "\"", true); } } void Ide::BuildAndExtDebug() { BuildAndDebug0(Null); } void Ide::BuildAndExtDebugFile() { BuildAndDebug0(editfile); } One GdbCreate(One&& host, const String& exefile, const String& cmdline, bool console); One Gdb_MI2Create(One&& host, const String& exefile, const String& cmdline, bool console); #ifdef PLATFORM_WIN32 One CdbCreate(One&& host, const String& exefile, const String& cmdline); One PdbCreate(One&& host, const String& exefile, const String& cmdline); #endif void Ide::BuildAndDebug(bool runto) { VectorMap bm = GetMethodVars(method); String builder = bm.Get("BUILDER", ""); // TODO: implement debugging on android if(builder == "ANDROID") { BuildAndExecute(); return; } if(!Build()) return; if(!FileExists(target)) return; if(designer && !editfile_isfolder) EditAsText(); One host = CreateHostRunDir(); host->ChDir(Nvl(rundir, GetFileFolder(target))); HideBottom(); editor.Disable(); bool console = ShouldHaveConsole(); if(findarg(builder, "GCC", "CLANG") >= 0) { debugger = GdbCreate(pick(host), target, runarg, console); } #ifdef PLATFORM_WIN32 else debugger = PdbCreate(pick(host), target, runarg); #endif if(!debugger) { IdeEndDebug(); SetBar(); editor.Enable(); return; } debuglock = 0; const Workspace& wspc = IdeWorkspace(); for(int i = 0; i < wspc.GetCount(); i++) { const Package& pk = wspc.GetPackage(i); String n = wspc[i]; for(int i = 0; i < pk.file.GetCount(); i++) { String file = SourcePath(n, pk.file[i]); LineInfo& ln = Filedata(file).lineinfo; for(int i = 0; i < ln.GetCount(); i++) { LineInfoRecord& lr = ln[i]; if(!lr.breakpoint.IsEmpty()) if(!debugger->SetBreakpoint(file, lr.lineno, lr.breakpoint)) { lr.breakpoint = "\xe"; if(PathIsEqual(file, editfile)) editor.SetBreakpoint(lr.lineno, "\xe"); } } } } SetBar(); editor.Enable(); if(runto) { if(!debugger->RunTo()) IdeEndDebug(); } else debugger->Run(); } void Ide::DebugClearBreakpoints() { const Workspace& wspc = IdeWorkspace(); for(int i = 0; i < wspc.GetCount(); i++) { const Package& pk = wspc.GetPackage(i); String n = wspc[i]; for(int i = 0; i < pk.file.GetCount(); i++) { String file = SourcePath(n, pk.file[i]); LineInfo& ln = Filedata(file).lineinfo; if(debugger) for(int i = 0; i < ln.GetCount(); i++) { const LineInfoRecord& lr = ln[i]; if(!lr.breakpoint.IsEmpty()) debugger->SetBreakpoint(file, lr.lineno, ""); } ClearBreakpoints(ln); } } editor.ClearBreakpoints(); } void Ide::OnBreakpoint(int i) { if(!editfile.IsEmpty() && !designer && debugger) { String q = editor.GetBreakpoint(i); if(q[0] != 0xe && !debugger->SetBreakpoint(editfile, i, q)) { auto event = editor.WhenBreakpoint; editor.WhenBreakpoint = {}; if(!q.IsEmpty()) editor.SetBreakpoint(i, Null); else editor.SetBreakpoint(i, "1"); editor.WhenBreakpoint = event; } } } void Ide::DebugToggleBreak() { if(editfile.IsEmpty() || designer) return; int ln = editor.GetCursorLine(); String brk = editor.GetBreakpoint(ln); if(!brk.IsEmpty()) editor.SetBreakpoint(ln, Null); else editor.SetBreakpoint(ln, "1"); editor.RefreshFrame(); } void Ide::ConditionalBreak() { if(editfile.IsEmpty() || designer) return; int ln = editor.GetCursorLine(); String brk = editor.GetBreakpoint(ln); if(brk == "\xe") brk = "1"; Index cfg = PackageConfig(IdeWorkspace(), 0, GetMethodVars(method), mainconfigparam, *CreateHost(true), *CreateBuilder(~CreateHostRunDir())); #ifdef PLATFORM_WIN32 if(cfg.Find("MSC") >= 0) { if(EditPDBExpression("Conditional breakpoint", brk, NULL)) editor.SetBreakpoint(ln, brk); } else #endif if(EditText(brk, "Conditional breakpoint", "Condition")) editor.SetBreakpoint(ln, brk); editor.RefreshFrame(); } void Ide::StopDebug() { if(debugger) debugger->Stop(); console.Kill(); PosSync(); } bool Ide::EditorTip(CodeEditor::MouseTip& mt) { if(!debugger) return false; DR_LOG("EditorTip"); int pos = mt.pos; String e; String sep; while(pos >= 0) { String b = editor.ReadIdBackPos(pos, false); if(b.GetCount() == 0) break; e = b + sep + e; sep = "."; while(pos > 0 && editor.GetChar(pos - 1) == ' ') pos--; if(pos > 0 && editor.GetChar(pos - 1) == '.') --pos; else if(pos >= 2 && editor.GetChar(pos - 1) == ':' && editor.GetChar(pos - 2) == ':') { pos -= 2; sep = "::"; } else if(pos >= 2 && editor.GetChar(pos - 1) == '>' && editor.GetChar(pos - 2) == '-') pos -= 2; else break; while(pos > 0 && editor.GetChar(pos - 1) == ' ') pos--; } DR_LOG("debugger->Tip"); return debugger->Tip(e, mt); }