diff --git a/uppsrc/RichText/TxtData.cpp b/uppsrc/RichText/TxtData.cpp index 29b015ee4..9383cf71c 100644 --- a/uppsrc/RichText/TxtData.cpp +++ b/uppsrc/RichText/TxtData.cpp @@ -484,7 +484,7 @@ String RichCellPos::ToString() const { String s; s << "pos: " << pos << ", textlen: " << textlen << ", size: " << tabsize << ", tabpos: " << tabpos - << ", tablen: " << tablen << ", cellpos: " << cellpos << ", celllen: " << celllen << ", level: " << level; + << ", tablen: " << tablen << ", cellpos: " << cellpos << ", level: " << level; return s; } diff --git a/uppsrc/ide/ClangTidy.cpp b/uppsrc/ide/ClangTidy.cpp new file mode 100644 index 000000000..791554a7e --- /dev/null +++ b/uppsrc/ide/ClangTidy.cpp @@ -0,0 +1,125 @@ +#include "ide.h" + +struct ClangTidyDlg : WithClangTidy { + static String path; + static Index options; + static Index groups; + + static bool HasClangTidy(); + + struct OptionWithLink : Option { + RichTextCtrl text; + }; + + ArrayMap checks; + + void Group(); + + ClangTidyDlg(); +}; + +String ClangTidyDlg::path; +Index ClangTidyDlg::options; +Index ClangTidyDlg::groups; + +ClangTidyDlg::ClangTidyDlg() +{ + CtrlLayoutOKCancel(*this, "Clang Tidy"); + + group.AddColumn("Group"); + group.NoHeader(); + group.Add(AttrText("All").Italic().NormalInk(SLtBlue())); + for(String s : groups) + group.Add(s); + + group.WhenSel = [=] { + Group(); + }; + + option.NoHeader(); + option.AddKey(); + option.AddColumn(); + option.NoCursor(); + + for(String s : options) { + OptionWithLink& opt = checks.Add(s); + opt.NoWantFocus(); + opt << opt.text.NoSb().VCenter().HSizePos(DPI(18), 0).VSizePos(); + String txt = "[g"; + if(s.TrimStart("clang-analyzer-")) // TODO: Improve + txt << "^https://clang.llvm.org/extra/clang-tidy/checks/clang-analyzer/" + s + "^"; + else { + int q = s.Find('-'); + if(q >= 0) + txt << "^https://clang.llvm.org/extra/clang-tidy/checks/" << s.Mid(0, q) << "/" << s.Mid(q + 1) << ".html^"; + } + txt << " \1" << s; + opt.text <<= txt; + } +} + +void ClangTidyDlg::Group() +{ + String st; + if(group.GetCursor() > 0) + st = group.GetKey(); + + option.Clear(); + for(auto m : ~checks) + if(m.key.StartsWith(st)) { + option.Add(m.key); + option.SetCtrl(option.GetCount() - 1, 0, m.value, false); + } +} + +bool ClangTidyDlg::HasClangTidy() +{ + ONCELOCK { +#ifdef PLATFORM_WIN32 + for(String p : Split(GetMethodVars("CLANGx64").Get("PATH", ""), ';')) { + p << "/clang-tidy.exe"; +#else + String p = "clang-tidy"; +#endif + String s = Sys(p + " -checks=* --list-checks"); + if(s.GetCount()) { + path = p; + for(String l : Split(s, '\n')) { + l = TrimBoth(l); + if(*l.Last() != ':') // Ignore "Enabled checks:" + options.FindAdd(l); + } + + for(String s : options) { + int q = s.Find('.'); + if(q < 0) + q = s.Find('-'); + if(q >= 0) + s.Trim(q); + groups.FindAdd(s); + } + } +#ifdef PLATFORM_WIN32 + } +#endif + } + return path.GetCount() && options.GetCount(); +} + + +bool Ide::HasClangTidy() +{ + return ClangTidyDlg::HasClangTidy(); +} + +void Ide::ClangTidy() +{ + if(!HasClangTidy()) { + Exclamation("No clang-tidy..."); + return; + } + + ClangTidyDlg dlg; + + dlg.Execute(); +} diff --git a/uppsrc/ide/ide.h b/uppsrc/ide/ide.h index 6fd366b15..5bda6634c 100644 --- a/uppsrc/ide/ide.h +++ b/uppsrc/ide/ide.h @@ -1299,6 +1299,9 @@ public: void MacroAllPackages(EscEscape& e); void MacroTarget(EscEscape& e); + void ClangTidy(); + bool HasClangTidy(); + String GetAndroidSdkPath(); void TriggerIndexer0(); diff --git a/uppsrc/ide/ide.key b/uppsrc/ide/ide.key index 6fdff4fb4..b6de97ed2 100644 --- a/uppsrc/ide/ide.key +++ b/uppsrc/ide/ide.key @@ -74,6 +74,7 @@ KEY(DEBUGTO, "Run to cursor (in debugger)", K_CTRL_F10) KEY(DEBUGEXT, "Debug externally", K_ALT_F5) KEY(DEBUGFILEEXT, "Debug file externally", K_SHIFT|K_ALT_F5) KEY(VALGRIND, "Test in Valgrind", 0) +KEY(CLANGTIDY, "Clang Tidy", 0) KEY(BREAKPOINT, "Toggle breakpoint", K_F9) KEY(CONDBREAKPOINT, "Conditional breakpoint..", K_ALT_F9) KEY(CLEARBREAKPOINTS, "Clear all breakpoints", K_CTRL_F9|K_SHIFT) diff --git a/uppsrc/ide/ide.lay b/uppsrc/ide/ide.lay index 58b21aae8..2dd8a2cc1 100644 --- a/uppsrc/ide/ide.lay +++ b/uppsrc/ide/ide.lay @@ -1028,3 +1028,10 @@ LAYOUT(SeqLayout, 764, 544) ITEM(Upp::EditString, postfix, LeftPosZ(708, 48).TopPosZ(8, 19)) END_LAYOUT +LAYOUT(ClangTidy, 556, 588) + ITEM(Upp::ArrayCtrl, group, LeftPosZ(8, 184).TopPosZ(8, 528)) + ITEM(Upp::ArrayCtrl, option, LeftPosZ(196, 348).TopPosZ(8, 528)) + ITEM(Upp::Button, ok, SetLabel(t_("OK")).RightPosZ(76, 64).BottomPosZ(8, 24)) + ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).RightPosZ(8, 64).BottomPosZ(8, 24)) +END_LAYOUT + diff --git a/uppsrc/ide/ide.upp b/uppsrc/ide/ide.upp index 6e5e56533..1562286ff 100644 --- a/uppsrc/ide/ide.upp +++ b/uppsrc/ide/ide.upp @@ -103,6 +103,7 @@ file Build.cpp, Debug.cpp, Valgrind.cpp, + ClangTidy.cpp, Export.cpp, Repo readonly separator, urepo.h, diff --git a/uppsrc/ide/idebar.cpp b/uppsrc/ide/idebar.cpp index 7853fc82c..6f21e981b 100644 --- a/uppsrc/ide/idebar.cpp +++ b/uppsrc/ide/idebar.cpp @@ -850,6 +850,9 @@ void Ide::DebugMenu(Bar& menu) menu.Add(b, AK_VALGRIND, THISBACK(Valgrind)) .Help("Build application & run in valgring"); #endif + + if(HasClangTidy()) + menu.Add(AK_CLANGTIDY, [=] { ClangTidy(); }); menu.Separator(); } diff --git a/uppsrc/ide/main.cpp b/uppsrc/ide/main.cpp index 764806779..a73d2e26c 100644 --- a/uppsrc/ide/main.cpp +++ b/uppsrc/ide/main.cpp @@ -406,7 +406,7 @@ void AppMain___() ide.disable_custom_caption2 = ide.disable_custom_caption; ide.SetupBars(); - + #ifdef PLATFORM_COCOA if(!ide.macos_update_icon) Ctrl::SetAlwaysUseBundledIcon();