ultimatepp/uppsrc/ide/Browser/CodeBrowser.cpp
cxl d33cae1971 theide: Syntax highlighting fix, Navigator fix
git-svn-id: svn://ultimatepp.org/upp/trunk@1231 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2009-05-24 18:09:57 +00:00

352 lines
8.5 KiB
C++

#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<CppItem>& 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<CppItem>& 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<String> txt;
Vector<Value> ndx;
Index<int> fi;
Index<String> fs;
for(int i = 0; i < CodeBase().GetCount(); i++) {
String s = CodeBase().GetKey(i);
const Array<CppItem>& 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<CppItemInfo>(v1);
const CppItemInfo& b = ValueTo<CppItemInfo>(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<CppItemInfo>(v1);
const CppItemInfo& b = ValueTo<CppItemInfo>(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<String, bool>& inherited, bool g)
{
int q = CodeBase().Find(type);
if(q < 0) return;
const Array<CppItem>& n = CodeBase()[q];
for(int i = 0; i < n.GetCount(); i = FindNext(n, i)) {
const CppItem& m = n[i];
if(m.IsType()) {
Vector<String> 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);
if(q >= 0) {
const Array<CppItem>& n = CodeBase()[q];
VectorMap<String, bool> inherited;
if(file < 0)
GatherMethods(scope, inherited, false);
Index<String> 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) && 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<CppItemInfo>(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);
}