#include "Browser.h" bool MatchCib(const String& s, const String& match) { if(IsNull(match)) return true; int q = ToUpper(s).Find(match); return q > 0 && !iscid(s[q - 1]) || q == 0; } bool MatchPm(const String& fn, const String& pm) { if(IsNull(pm)) return true; return fn.StartsWith(pm); } bool MatchPm(int file, const String& pm) { if(IsNull(pm)) return true; return GetCppFile(file).StartsWith(pm); } bool MatchPm(const Array& n, const String& pm) { if(IsNull(pm)) return true; for(int i = 0; i < n.GetCount(); i++) if(MatchPm(n[i].file, pm)) return true; return false; } bool HasItem(const Array& n, const String& m) { if(IsNull(m)) return true; for(int i = 0; i < n.GetCount(); i++) if(n[i].uname.StartsWith(m)) return true; return false; } struct ScopeLess { bool operator()(const String& a, const String& b) const { if((*a == '<') != (*b == '<')) return *a > *b; return a < b; } }; String CodeBrowser::GetPm() { String pm; if(TheIde() && range) if(range == 1) pm = TheIde()->IdeGetNestFolder(); else { pm = TheIde()->IdeGetFileName(); if(range == 2) pm = GetFileFolder(pm); } return pm; } String GetFileText(const String& s) { return '<' + GetFileName(GetFileFolder(s)) + '/' + GetFileName(s) + '>'; } void CodeBrowser::Load() { String find = ToUpper((String)~search); String match = ToUpper((String)~search_scope); String pm = GetPm(); Vector txt; Vector ndx; Index fi; Index fs; for(int i = 0; i < CodeBase().GetCount(); i++) { String s = CodeBase().GetKey(i); const Array& n = CodeBase()[i]; if(s.GetCount()) if(MatchCib(s, match) && (MatchCib(s, find) || HasItem(n, find)) && MatchPm(n, pm)) { txt.Add(s); ndx.Add(s); } for(int i = 0; i < n.GetCount(); i++) { int f = n[i].file; if(fi.Find(f) < 0) { String s = GetFileText(GetCppFile(f)); if(s.StartsWith(pm) && MatchCib(s, match) && (IsNull(find) || MatchCib(s, find) || n[i].uname.StartsWith(find))) { txt.Add(s); ndx.Add(f); fs.Add(s); fi.Add(f); } } } } const Workspace& wspc = GetIdeWorkspace(); for(int i = 0; i < wspc.GetCount(); i++) { String pn = wspc[i]; const Package& p = wspc.GetPackage(i); String pp = PackageDirectory(pn); for(int j = 0; j < p.GetCount(); j++) if(!p[j].separator) { String fn = AppendFileName(pp, p[j]); String s = GetFileText(AppendFileName(pn, p[j])); if(fs.Find(s) < 0 && (IsNull(find) || MatchCib(s, find)) && MatchCib(s, match) && MatchPm(fn, pm)) { int f = GetCppFileIndex(SourcePath(pn, p[j])); txt.Add(s); ndx.Add(f); fs.Add(s); } } } IndexSort(txt, ndx, ScopeLess()); Value key = scope.GetKey(); int sc = scope.GetCursorSc(); scope.Clear(); for(int i = 0; i < txt.GetCount(); i++) scope.Add(IsString(ndx[i]) ? ndx[i] : Null, txt[i], ndx[i]); if(scope.FindSetCursor(key)) scope.ScCursor(sc); // clear.Enable(IsSearch()); } int ItemCompare(const Value& v1, const Value& v2) { const CppItemInfo& a = ValueTo(v1); const CppItemInfo& b = ValueTo(v2); int q = a.inherited - b.inherited; if(q) return q; q = SgnCompare(GetCppFile(a.file), GetCppFile(b.file)); return q ? q : a.line - b.line; } int ItemCompareLexical(const Value& v1, const Value& v2) { const CppItemInfo& a = ValueTo(v1); const CppItemInfo& b = ValueTo(v2); int q = (int)b.IsType() - (int)a.IsType(); if(q) return q; q = SgnCompare(a.name, b.name); if(q) return q; return SgnCompare(a.qitem, b.qitem); } void GatherMethods(const String& type, VectorMap& inherited, bool g) { int q = CodeBase().Find(type); if(q < 0) return; const Array& n = CodeBase()[q]; for(int i = 0; i < n.GetCount(); i = FindNext(n, i)) { const CppItem& m = n[i]; if(m.IsType()) { Vector base = Split(m.qptype, ';'); for(int i = 0; i < base.GetCount(); i++) GatherMethods(base[i], inherited, true); } if(m.IsCode() && g) { bool& virt = inherited.GetAdd(m.qitem); virt = virt || m.virt; } } } void CodeBrowser::LoadScope() { String find = ToUpper((String)~search); Value key = item.GetKey(); int sc = item.GetCursorSc(); item.Clear(); if(!scope.IsCursor()) return; Value x = scope.Get(2); int file = IsNumber(x) ? (int)x : -1; String scope = file < 0 ? String(x) : String(); int q = CodeBase().Find(scope); bool filematch = file >= 0 && MatchCib(GetFileText(GetCppFile(file)), find); bool scopematch = !filematch && MatchCib(scope, find); if(q >= 0) { const Array& n = CodeBase()[q]; VectorMap inherited; if(file < 0) GatherMethods(scope, inherited, false); Index set; for(int i = 0; i < n.GetCount(); i = file < 0 ? FindNext(n, i) : i + 1) { CppItemInfo m; (CppItem&) m = n[i]; if((find.GetCount() && m.uname.StartsWith(find) || filematch && m.file == file || scopematch) && set.Find(m.qitem) < 0) { set.Add(m.qitem); int q = inherited.Find(m.qitem); if(q >= 0) { m.over = true; m.virt = m.virt || inherited[q]; } item.Add(m.qitem, RawToValue(m)); } } } item.Sort(1, sort ? ItemCompareLexical : ItemCompare); if(item.FindSetCursor(key)) item.ScCursor(sc); // clear.Enable(IsSearch()); } String CodeBrowser::GetCodeRef(int i) const { if(scope.IsCursor()) return MakeCodeRef(scope.GetKey(), item.Get(i, 0)); return Null; } String CodeBrowser::GetCodeRef() const { return item.IsCursor() ? GetCodeRef(item.GetCursor()) : String(); } const CppItemInfo& CodeBrowser::GetItemInfo(int i) const { return ValueTo(item.Get(i, 1)); } const CppItemInfo& CodeBrowser::GetItemInfo() const { return GetItemInfo(item.GetCursor()); } int SearchItemFilter(int c) { c = ToUpper(c); return IsAlNum(c) || c == '/' || c == '.' || c == '<' || c == '>' || c == '_' ? c : 0; } void CodeBrowser::Goto(const String& coderef, const String& rfile) { if(IsNull(coderef)) { item.KillCursor(); scope.FindSetCursor(GetFileText(rfile), 1); return; } else if(coderef != GetCodeRef()) { if(!IsNull(search_scope)) { Load(); LoadScope(); } String sc, im; SplitCodeRef(coderef, sc, im); if(IsNull(sc)) { const CppItem *m = GetCodeRefItem(coderef, rfile); if(m) scope.FindSetCursor(m->file, 2); } else scope.FindSetCursor(sc); item.FindSetCursor(im); } } void CodeBrowser::Search() { Load(); if(!scope.IsCursor() || !item.IsCursor()) scope.SetCursor(0); } bool CodeBrowser::Key(dword key, int count) { // clear.Enable(IsSearch()); if(key == K_UP || key == K_DOWN) { if(search.HasFocus()) { int l, h; search.GetSelection(l, h); Value v = ~search; if(item.IsCursor()) item.Key(key, count); else if(key == K_UP) item.GoEnd(); else item.GoBegin(); WhenKeyItem(); search <<= v; search.SetFocus(); search.SetSelection(l, h); return true; } if(search_scope.HasFocus()) { scope.Key(key, count); return true; } } return false; } bool CodeBrowser::IsSearch() const { return !IsNull(search) || !IsNull(search_scope); } void CodeBrowser::ClearSearch() { if(!IsSearch()) return; search_scope <<= search <<= Null; Load(); WhenClear(); } void CodeBrowser::SetRange(int r) { if(range == r) r = 0; range = r; for(int i = 0; i < 3; i++) rangebutton[i] <<= range == i + 1; Load(); } CodeBrowser::CodeBrowser() { scope.AddKey(); scope.AddColumn("Scope"); scope.WhenSel = THISBACK(LoadScope); scope.NoHeader().NoGrid(); search_scope <<= THISBACK(Load); search_scope.SetFilter(SearchItemFilter); search_scope.NullText("Search type or header "); item.AddKey(); item.AddColumn("Item").SetDisplay(display).Margin(2); item.NoHeader(); item.SetLineCy(BrowserFont().Info().GetHeight() + 3); search.NullText("Find "); search.SetFilter(SearchItemFilter); search <<= THISBACK(Search); // search.AddFrame(clear); // clear.SetImage(BrowserImg::Clear()); // clear.NoWantFocus(); // clear <<= THISBACK(ClearSearch); range = 0; static const char *tip[] = { "Nest", "Package", "File" }; for(int i = 0; i < 3; i++) rangebutton[i].SetImage(BrowserImg::Get(BrowserImg::I_range_nest + i)).Tip(tip[i]) <<= THISBACK1(SetRange, i + 1); SetRange(0); sort.Tip("Order by names"); sort.SetImage(BrowserImg::Sort()); sort <<= THISBACK(LoadScope); }