developing indexer/navigator

This commit is contained in:
Mirek Fidler 2022-07-25 12:55:16 +02:00
parent 43276ce7d1
commit ba681dbc3b
28 changed files with 466 additions and 535 deletions

View file

@ -311,36 +311,6 @@ void CoWork::SetPoolSize(int n)
p.InitThreads(n);
}
void CoWork::Pipe(int stepi, Function<void ()>&& fn)
{
Mutex::Lock __(stepmutex);
auto& q = step.At(stepi);
LLOG("Step " << stepi << ", count: " << q.GetCount() << ", running: " << steprunning.GetCount());
q.AddHead(pick(fn));
if(!steprunning.At(stepi, false)) {
steprunning.At(stepi) = true;
*this & [=]() {
LLOG("Starting step " << stepi << " processor");
stepmutex.Enter();
for(;;) {
Function<void ()> f;
auto& q = step[stepi];
LLOG("StepWork " << stepi << ", todo:" << q.GetCount());
if(q.GetCount() == 0)
break;
f = pick(q.Tail());
q.DropTail();
stepmutex.Leave();
f();
stepmutex.Enter();
}
steprunning.At(stepi) = false;
stepmutex.Leave();
LLOG("Exiting step " << stepi << " processor");
};
}
}
void CoWork::Reset()
{
try {

View file

@ -57,11 +57,6 @@ public:
Atomic index;
// experimental pipe support
Mutex stepmutex;
Array<BiVector<Function<void ()>>> step;
Vector<bool> steprunning;
public:
static bool TrySchedule(Function<void ()>&& fn);
static bool TrySchedule(const Function<void ()>& fn) { return TrySchedule(clone(fn)); }
@ -83,7 +78,6 @@ public:
int Next() { return ++index - 1; }
int GetScheduledCount() const { return todo; }
void Pipe(int stepi, Function<void ()>&& lambda); // experimental
static void FinLock();

View file

@ -415,7 +415,7 @@ typedef StaticMutex StaticCriticalSection;
#endif
// Auxiliary multithreading - this is not using/cannot use U++ heap, so does not need cleanup.
// Used to resolve some host platform issues.
// Used to resolve some host platform issues. Do not use.
#ifdef PLATFORM_WIN32
#define auxthread_t DWORD

View file

@ -38,7 +38,7 @@ AssistEditor::AssistEditor()
navigatorpane.Add(search.TopPos(0, cy).HSizePos(0, cy + 4));
navigatorpane.Add(sortitems.TopPos(0, cy).RightPos(0, cy));
navigatorpane.Add(navigator_splitter.VSizePos(cy, 0).HSizePos());
navigator_splitter.Vert() << scope << list << navlines;
navigator_splitter.Vert() << scope << list;
navigator_splitter.SetPos(1500, 0);
navigator_splitter.SetPos(9500, 1);
@ -816,7 +816,7 @@ bool AssistEditor::Key(dword key, int count)
Exclamation("No annotation for this line.");
}
if(key == K_F11) {
StartIndexing(theide->GetCurrentIncludePath(), theide->GetCurrentDefines());
Indexer::Start(theide->main, theide->GetCurrentIncludePath(), theide->GetCurrentDefines());
}
#endif
if(popup.IsOpen()) {

View file

@ -12,33 +12,7 @@ struct Navigator {
enum KindEnum { KIND_LINE = -4000, KIND_NEST, KIND_FILE, KIND_SRCFILE };
struct NavItem : AnnotationItem {
// int priority = 0; // for sorting based on search accuracy
/* int decl_line = 0;
int decl_file = 0;
String nest;
String qitem;
String name;
String uname;
String natural;
String type;
String pname;
String ptype;
String tname;
String ctname;
byte access;
byte kind;
int16 at;
int line;
int file;
int decl_line; // header position
int decl_file;
bool impl;
bool decl;
int8 pass;
Vector<NavLine> linefo;
*/
String path;
};
struct ScopeDisplay : Display {
@ -71,7 +45,6 @@ struct Navigator {
Array<NavItem> nitem;
Vector<const NavItem *> litem;
Array<NavItem> nest_item; // list separators with nest (scope) or file
VectorMap<int, SortedVectorMap<int, int> > linefo; // TODO remove?
NavigatorDisplay navidisplay;
bool navigating;
TimeCallback search_trigger;
@ -83,7 +56,6 @@ struct Navigator {
ArrayCtrl scope;
ArrayCtrl list;
ArrayCtrl navlines;
EditString search;
ScopeDisplay scope_display;
@ -94,15 +66,10 @@ struct Navigator {
void ListLineEnabled(int i, bool& b);
void NaviSort();
Vector<NavLine> GetNavLines(const NavItem& m);
void Navigate();
void ScopeDblClk();
void NavigatorClick();
void NavigatorEnter();
void SyncLines();
void SyncNavLines();
void GoToNavLine();
void SyncCursor();
typedef Navigator CLASSNAME;

View file

@ -8,6 +8,7 @@ Image CxxIcon(int kind)
case CXCursor_EnumConstantDecl: return BrowserImg::type_enum();
case CXCursor_ClassDecl: return BrowserImg::type_struct();
case CXCursor_StructDecl: return BrowserImg::type_struct();
case CXCursor_ClassTemplate: return BrowserImg::template_struct();
case CXCursor_FunctionTemplate: return BrowserImg::template_function();
case CXCursor_ConversionFunction: return BrowserImg::function();
case CXCursor_FieldDecl: return BrowserImg::instance_data();
@ -50,9 +51,18 @@ int PaintCpp(Draw& w, const Rect& r, int kind, const String& name, const String&
for(int i = 0; i < n.GetCount(); i++)
if(n[i].type == ITEM_NAME) {
PaintText(w, x, y, pretty, n, i, count - i, focuscursor, ink, false);
w.DrawText(x, y, "", StdFont(), SGray());
x += GetTextSize("", StdFont()).cx;
count = i;
while(count) { // remove trailing spaces
const ItemTextPart& p = n[count - 1];
if(p.len == 1 && pretty[p.pos] == ' ')
count--;
else
break;
}
if(count) {
w.DrawText(x, y, "", StdFont(), SGray());
x += GetTextSize("", StdFont()).cx;
}
break;
}
PaintText(w, x, y, pretty, n, 0, count, focuscursor, ink, false);

View file

@ -2,11 +2,16 @@
String CacheDir()
{
String dir;
#ifdef PLATFORM_WIN32
return ConfigFile("cache");
dir = ConfigFile("cache");
#else
return ConfigFile(".cache/upp.cache");
dir = ConfigFile(".cache/upp.cache");
#endif
ONCELOCK {
RealizeDirectory(dir);
}
return dir;
}
String CacheFile(const char *name)
@ -16,4 +21,5 @@ String CacheFile(const char *name)
void ReduceCache(int mb_limit)
{
// TODO
}

View file

@ -10,43 +10,8 @@ void AssistEditor::SyncHeaders()
hdepend.SetDirs(theide->GetCurrentIncludePath() + ";" + GetClangInternalIncludes());
master_source.Clear();
String editfile = NormalizePath(theide->editfile);
if(editfile.GetCount() && IsCHeaderFile(editfile)) {
DLOG("============= " << editfile);
for(int pass = 0; pass < 2; pass++) { // all packages in second pass
const Workspace& wspc = GetIdeWorkspace();
for(int i = 0; i < wspc.GetCount(); i++) { // find package of included file
const Package& pk = wspc.GetPackage(i);
String pk_name = wspc[i];
auto Chk = [&] {
for(int i = 0; i < pk.file.GetCount(); i++) {
String path = SourcePath(pk_name, pk.file[i]);
if(!PathIsEqual(editfile, path) && IsSourceFile(path)) {
if(FindIndex(hdepend.GetDependencies(path), editfile) >= 0 && GetFileLength(path) < 200000) {
master_source = path;
DDUMP(master_source);
return true;
}
}
}
return false;
};
if(pass) {
if(Chk())
return;
}
else
for(int i = 0; i < pk.file.GetCount(); i++) {
if(PathIsEqual(editfile, SourcePath(pk_name, pk.file[i]))) {
if(Chk())
return;
break;
}
}
}
}
}
if(editfile.GetCount() && IsCHeaderFile(editfile))
master_source = FindMasterSource(hdepend, GetIdeWorkspace(), editfile);
}
bool AssistEditor::DoIncludeTrick(Index<String>& visited, int level, StringBuffer& out, String path, const String& target_path, int& line_delta)
@ -57,16 +22,12 @@ bool AssistEditor::DoIncludeTrick(Index<String>& visited, int level, StringBuffe
return false;
visited.Add(path);
FileIn in(path);
DDUMP(target_path);
while(!in.IsEof()) {
String l = in.GetLine();
String tl = TrimLeft(l);
if(!comment && tl.TrimStart("#include") && (*tl == ' ' || *tl == '\t')) {
DDUMP(tl);
String ipath = hdepend.FindIncludeFile(tl, filedir);
DDUMP(ipath);
if(ipath.GetCount()) {
DDUMP(HdependGetDependencies(ipath));
if(NormalizePath(ipath) == NormalizePath(target_path))
return true;
int q = out.GetCount();

View file

@ -8,8 +8,8 @@ struct NavDlg : WithJumpLayout<TopWindow>, Navigator {
virtual int GetCurrentLine();
void GoTo();
void Ok() { if(navlines.IsCursor()) Break(IDOK); }
void ListSel() { navlines.GoBegin(); }
void Ok() { Break(IDOK); }
void ListSel() {}
void Serialize(Stream& s);
@ -35,7 +35,6 @@ NavDlg::NavDlg()
Icon(IdeImg::Navigator());
list.WhenSel << THISBACK(ListSel);
list.WhenLeftDouble = THISBACK(Ok);
navlines.WhenLeftDouble = THISBACK(Ok);
}
bool NavDlg::Key(dword key, int count)
@ -52,10 +51,11 @@ bool NavDlg::Key(dword key, int count)
void NavDlg::GoTo()
{
if(navlines.IsCursor()) {
// TODO
/* if(navlines.IsCursor()) {
const NavLine& l = navlines.Get(0).To<NavLine>();
theide->GotoPos(GetSourceFilePath(l.file), l.line);
}
}*/
}
int NavDlg::GetCurrentLine()

View file

@ -887,7 +887,7 @@ String Ide::GetCurrentIncludePath()
Host host;
CreateHost(host, false, false);
One<Builder> b = CreateBuilder(&host);
Index<String> cfg = PackageConfig(wspc, GetPackageIndex(), GetMethodVars(method), mainconfigparam, host, *b);
Index<String> cfg = PackageConfig(wspc, max(GetPackageIndex(), 0), GetMethodVars(method), mainconfigparam, host, *b);
Index<String> pkg_config;
for(int i = 0; i < wspc.GetCount(); i++) {
const Package& pkg = wspc.GetPackage(i);

View file

@ -83,13 +83,8 @@ Navigator::Navigator()
list.SetLineCy(max(16, GetStdFontCy()));
list.NoWantFocus();
list.WhenLeftClick = THISBACK(NavigatorClick);
list.WhenSel = THISBACK(SyncNavLines);
list.WhenLineEnabled = THISBACK(ListLineEnabled);
navlines.NoHeader().NoWantFocus();
navlines.WhenLeftClick = THISBACK(GoToNavLine);
navlines.AddColumn().SetDisplay(Single<LineDisplay>());
search <<= THISBACK(TriggerSearch);
search.SetFilter(CharFilterNavigator);
search.WhenEnter = THISBACK(NavigatorEnter);
@ -107,8 +102,10 @@ void Navigator::SyncCursor()
search.NullText("Symbol/lineno " + k);
search.Tip(IsNull(search) ? String() : "Clear " + k);
// TODO
/*
if(!navigating && theide->editfile.GetCount()) {
navlines.KillCursor();
int q = linefo.Find(GetSourceFileIndex(theide->editfile));
if(q < 0)
return;
@ -119,46 +116,11 @@ void Navigator::SyncCursor()
list.SetCursor(m[q]);
navigating = false;
}
SyncLines();
*/
if(scope.IsCursor())
scope.RefreshRow(scope.GetCursor());
}
void Navigator::SyncLines()
{
if(IsNull(theide->editfile) || navigating)
return;
int ln = GetCurrentLine() + 1;
int fi = GetSourceFileIndex(theide->editfile);
int q = -1;
for(int i = 0; i < navlines.GetCount(); i++) {
const NavLine& l = navlines.Get(i, 0).To<NavLine>();
if(l.file == fi && l.line <= ln && i < navlines.GetCount())
q = i;
}
if(dlgmode)
navlines.GoBegin();
else
if(q >= 0)
navlines.SetCursor(q);
}
void Navigator::SyncNavLines()
{
int sc = navlines.GetScroll();
navlines.Clear();
int ii = list.GetCursor();
if(ii >= 0 && ii < litem.GetCount()) {
Vector<NavLine> l = GetNavLines(*litem[ii]);
for(int i = 0; i < l.GetCount(); i++) {
String p = GetSourceFilePath(l[i].file);
navlines.Add(RawToValue(l[i]));
}
navlines.ScrollTo(sc);
SyncLines();
}
}
int Navigator::LineDisplay::DoPaint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style, int x) const
{
w.DrawRect(r, paper);
@ -185,52 +147,6 @@ Size Navigator::LineDisplay::GetStdSize(const Value& q) const
return Size(DoPaint(w, Size(999999, 999999), q, White(), White(), 0, 0), StdFont().Bold().GetCy());
}
void Navigator::GoToNavLine()
{
if(dlgmode)
return;
int ii = navlines.GetClickPos().y;
if(ii >= 0 && ii < navlines.GetCount() && theide) {
const NavLine& l = navlines.Get(ii, 0).To<NavLine>();
theide->GotoPos(GetSourceFilePath(l.file), l.line);
}
}
bool Navigator::NavLine::operator<(const NavLine& b) const
{
String p1 = GetSourceFilePath(file);
String p2 = GetSourceFilePath(b.file);
return CombineCompare/*(!impl, !b.impl)*/
(GetFileExt(p2), GetFileExt(p1)) // .h > .c
(GetFileName(p1), GetFileName(p2))
(p1, p2)
(line, b.line) < 0;
}
Vector<Navigator::NavLine> Navigator::GetNavLines(const NavItem& m)
{
_DBG_
Vector<NavLine> l;
/*
CodeBaseLock __;
int q = CodeBase().Find(m.nest);
if(q < 0 || IsNull(m.qitem))
return l;
const Array<CppItem>& a = CodeBase()[q];
for(int i = 0; i < a.GetCount(); i++) {
const CppItem& mm = a[i];
if(mm.qitem == m.qitem) {
NavLine& nl = l.Add();
nl.impl = mm.impl;
nl.file = mm.file;
nl.line = mm.line;
}
}
Sort(l);
*/
return l;
}
void Navigator::Navigate()
{
if(navigating)
@ -256,20 +172,7 @@ void Navigator::Navigate()
theide->AddHistory();
}
else {
Vector<NavLine> l = GetNavLines(m);
int q = l.GetCount() - 1;
for(int i = 0; i < l.GetCount(); i++)
if(GetSourceFilePath(l[i].file) == NormalizeSourcePath(theide->editfile) && l[i].line == ln) {
q = (i + l.GetCount() + 1) % l.GetCount();
break;
}
if(q >= 0 && q < l.GetCount()) {
String path = GetSourceFilePath(l[q].file);
// TODO:
_DBG_
// if(!theide->GotoDesignerFile(path, m.nest, m.name, l[q].line))
// theide->GotoPos(path, l[q].line);
}
theide->GotoPos(m.path, m.line);
}
}
navigating = false;
@ -432,7 +335,7 @@ void Navigator::Search()
wholeclass = *s == '.' && search_nest.GetCount();
}
else {
search_name = search_nest = ~search;
search_name = ~search;
both = true;
}
s = Join(Split(s, '.'), "::") + (s.EndsWith(".") ? "::" : "");
@ -460,23 +363,26 @@ void Navigator::Search()
for(const AnnotationItem& m : theide->editor.annotations) {
NavItem& n = nitem.Add();
(AnnotationItem&)n = m;
n.path = theide->editfile;
nests.FindAdd(n.nest = Nest(m, theide->editfile));
}
SortIndex(nests);
}
else { // TODO: Sort codeindex paths, add files in that order to make things stable
else {
navigator_global = true;
String usearch_nest = ToUpper(search_nest);
String usearch_name = ToUpper(search_name);
Index<String> visited;
SortByKey(CodeIndex());
for(int pass = 0; pass < 2; pass++)
for(const auto& f : ~CodeIndex())
for(const AnnotationItem& m : f.value.items) {
int q = visited.Find(m.id);
if(q >= 0) { // replace definition (.cpp) with declaration (.h)
AnnotationItem& n = nitem[q];
if(n.definition && !m.definition) { // file: make it stable
if(q >= 0) { // replace declaration (.h) with definition (.cpp)
NavItem& n = nitem[q];
if(!n.definition && m.definition) {
(AnnotationItem&)n = m;
n.path = f.key;
}
}
else
@ -485,6 +391,7 @@ void Navigator::Search()
visited.Add(m.id);
NavItem& n = nitem.Add();
(AnnotationItem&)n = m;
n.path = f.key;
nests.FindAdd(n.nest = Nest(m, theide->editfile));
}
}
@ -560,7 +467,6 @@ void Navigator::Scope()
LTIMING("FINALIZE");
litem.Clear();
nest_item.Clear();
linefo.Clear();
String sc = scope.GetKey();
String nest;
for(const NavItem& n : nitem)
@ -569,7 +475,6 @@ void Navigator::Scope()
NavItem& m = nest_item.Add();
m.kind = KIND_NEST;
nest = m.pretty = n.nest;
DDUMP(n.nest);
litem.Add(&m);
}
litem.Add(&n);

View file

@ -1,4 +1,5 @@
#include "ide.h"
struct UppHubNest : Moveable<UppHubNest> {
int tier = -1;
String name;

View file

@ -3,7 +3,7 @@
#define LLOG(x)
bool autocomplete_parsing;
Semaphore autocomplete_event;
CoEvent autocomplete_event;
CurrentFileContext autocomplete_file;
bool do_autocomplete;
bool autocomplete_macros;
@ -121,7 +121,7 @@ void SetAutoCompleteFile(const CurrentFileContext& ctx)
{
GuiLock __;
autocomplete_file = ctx;
autocomplete_event.Release();
autocomplete_event.Broadcast();
}
void StartAutoComplete(const CurrentFileContext& ctx, int line, int column, bool macros,
@ -136,7 +136,7 @@ void StartAutoComplete(const CurrentFileContext& ctx, int line, int column, bool
autocomplete_serial = serial++;
autocomplete_done = done;
autocomplete_file = ctx;
autocomplete_event.Release();
autocomplete_event.Broadcast();
}
void CancelAutoComplete()

View file

@ -1,129 +0,0 @@
#include "clang.h"
// TODO: Remove
#define LLOG(x)
CXChildVisitResult current_file_visitor2( CXCursor cursor, CXCursor p, CXClientData clientData )
{
#if 0
auto Dump = [&] {
#if 1
SourceLocation location(cxlocation);
LOG("=====================");
// DDUMP(location);
// DDUMP((int)cursorKind);
DDUMP(GetCursorKindName(cursorKind));
DDUMP(name);
DDUMP(type);
DDUMP(pid);
DDUMP(CleanupId(pid));
DDUMP(scope);
DDUMP(nspace);
DDUMP(clang_isCursorDefinition(cursor));
#endif
};
static Index<unsigned> visited;
unsigned h = clang_hashCursor(cursor);
if(visited.Find(h) >= 0)
return CXChildVisit_Continue;
visited.Add(h);
#endif
CXSourceLocation cxlocation = clang_getCursorLocation( cursor );
SourceLocation location = cxlocation;
// if( clang_Location_isFromMainFile( location ) == 0 )
// return CXChildVisit_Continue;
CXCursor parent = clang_getCursorSemanticParent(cursor);
CXCursorKind cursorKind = clang_getCursorKind(cursor);
CXCursorKind parentKind = clang_getCursorKind(parent);
unsigned int curLevel = *( reinterpret_cast<unsigned int*>(clientData));
unsigned int nextLevel = curLevel + 1;
if(curLevel > 100000 && curLevel - 100000 > 2)
return CXChildVisit_Continue;
String name = GetCursorSpelling(cursor);
String type = GetTypeSpelling(cursor);
String display = FetchString(clang_getCursorDisplayName(cursor));
String scope = GetTypeSpelling(parent);
if(scope.GetCount())
scope << "::";
String m;
auto Dump = [&] {
#if 0
LOG("=====================");
DDUMP(GetCursorKindName(cursorKind));
DDUMP(GetCursorSpelling(cursor));
DDUMP(GetTypeSpelling(cursor));
DDUMP(FetchString(clang_getCursorDisplayName(cursor)));
DDUMP(clang_isCursorDefinition(cursor));
// DDUMP(FetchString(clang_getCursorPrettyPrinted(cursor, NULL)));
DDUMP(GetCursorKindName(parentKind));
DDUMP(GetCursorSpelling(parent));
DDUMP(GetTypeSpelling(parent));
// DDUMP(location);
#endif
};
bool valid = clang_Location_isFromMainFile(cxlocation);
if(valid) {
switch(cursorKind) {
case CXCursor_FieldDecl:
case CXCursor_VarDecl:
case CXCursor_CXXMethod:
m << scope << display;
break;
case CXCursor_StructDecl:
m = type << "::struct";
break;
case CXCursor_UnionDecl:
m = type << "::union";
break;
case CXCursor_ClassDecl:
m = type << "::class";
break;
case CXCursor_FunctionDecl:
m = display;
break;
case CXCursor_EnumDecl:
case CXCursor_EnumConstantDecl:
// case CXCursor_ParmDecl:
case CXCursor_TypedefDecl:
case CXCursor_Namespace:
case CXCursor_Constructor:
case CXCursor_Destructor:
case CXCursor_ConversionFunction:
case CXCursor_FunctionTemplate:
case CXCursor_ClassTemplate:
case CXCursor_UnexposedDecl:
// case CXCursor_NamespaceAlias:
break;
default:
valid = false;
break;
}
}
if(valid) {
Dump();
if(m.GetCount())
LLOG(">> " << GetCursorKindName(cursorKind) << ": " << m);
}
clang_visitChildren(cursor, current_file_visitor2, &nextLevel);
return CXChildVisit_Continue;
}
// TODO: Remove
void CurrentFileVisit(CXTranslationUnit tu)
{
CXCursor rootCursor = clang_getTranslationUnitCursor(tu);
unsigned int treeLevel = 0;
clang_visitChildren(rootCursor, current_file_visitor2, &treeLevel);
}

View file

@ -3,7 +3,7 @@
#define LLOG(x)
bool current_file_parsing;
Semaphore current_file_event; // TODO?
CoEvent current_file_event;
CurrentFileContext current_file;
int64 current_file_serial;
int64 current_file_done_serial;
@ -44,7 +44,6 @@ void CurrentFileThread()
}
if(f.filename.GetCount()) {
String fn = f.filename;
DDUMP(fn);
if(!IsSourceFile(fn))
fn.Cat(".cpp");
if(f.filename != parsed_file.filename || f.real_filename != parsed_file.real_filename ||
@ -54,7 +53,6 @@ void CurrentFileThread()
{
TIMESTOP("CurrentFile parse");
current_file_parsing = true;
DDUMP(fn);
clang.Parse(fn, f.content, f.includes, f.defines,
CXTranslationUnit_DetailedPreprocessingRecord|
CXTranslationUnit_PrecompiledPreamble|
@ -91,7 +89,7 @@ void SetCurrentFile(const CurrentFileContext& ctx, Event<const Vector<Annotation
GuiLock __;
current_file = ctx;
annotations_done = done;
current_file_event.Release();
current_file_event.Broadcast();
current_file_serial++;
}

View file

@ -1,5 +1,7 @@
#include "clang.h"
// TODO: remove
#if 0
case FUNCTIONTEMPLATE:
bk = BrowserImg::template_function();

View file

@ -1,8 +1,48 @@
#include "clang.h"
#define LTIMING(x)
#define LTIMESTOP(x)
#define LLOG(x)
#define LTIMESTOP(x) TIMESTOP(x)
#define LLOG(x) DLOG(x)
String FindMasterSource(Hdepend& hdepend, const Workspace& wspc, const String& header_file)
{
DDUMP(header_file);
String master_source;
for(int pass = 0; pass < 2; pass++) { // all packages in second pass
for(int i = 0; i < wspc.GetCount(); i++) { // find package of included file
const Package& pk = wspc.GetPackage(i);
String pk_name = wspc[i];
auto Chk = [&] {
for(int i = 0; i < pk.file.GetCount(); i++) {
String path = SourcePath(pk_name, pk.file[i]);
if(!PathIsEqual(header_file, path) && IsSourceFile(path)) {
DDUMP(hdepend.GetDependencies(path));
if(FindIndex(hdepend.GetDependencies(path), header_file) >= 0 && GetFileLength(path) < 200000) {
master_source = path;
return true;
}
}
}
return false;
};
if(pass) {
if(Chk())
return master_source;
}
else
for(int i = 0; i < pk.file.GetCount(); i++) {
if(PathIsEqual(header_file, SourcePath(pk_name, pk.file[i]))) {
if(Chk())
return master_source;
break;
}
}
}
}
return master_source;
}
void AnnotationItem::Serialize(Stream& s)
{
@ -16,16 +56,27 @@ void AnnotationItem::Serialize(Stream& s)
% uname
% nest
% unest;
}
struct BlitzMaker {
Time time;
String blitz;
Vector<String> individual;
void FileAnnotation::Serialize(Stream& s)
{
s % defines
% includes
% time
% items;
}
void Do(const String& pk_name, const Vector<Tuple<String, bool>>& file, Hdepend& hdepend);
};
String CachedAnnotationPath(const String& source_file, const String& defines, const String& includes, const String& master = Null)
{
// TODO: master file?
Sha1Stream s;
s << source_file
<< defines
<< includes
<< master
;
return CacheFile(GetFileTitle(source_file) + "$" + s.FinishString() + ".code_index");
}
void BlitzFile(String& blitz, const String& sourceFile, Hdepend& hdepend, int index)
{
@ -40,145 +91,234 @@ void BlitzFile(String& blitz, const String& sourceFile, Hdepend& hdepend, int in
blitz << "#undef BLITZ_INDEX__\r\n";
}
void BlitzMaker::Do(const String& pk_name, const Vector<Tuple<String, bool>>& file, Hdepend& hdepend)
ArrayMap<String, FileAnnotation>& CodeIndex()
{
blitz.Clear();
individual.Clear();
time = Null;
int index = 1;
for(const auto& m : file) {
if(IsCSourceFile(m.a)) {
Time filetime = hdepend.FileTime(m.a);
time = max(Nvl(time, filetime), filetime);
if(hdepend.BlitzApproved(m.a) && !m.b)
BlitzFile(blitz, m.a, hdepend, index++);
else
individual.Add(m.a);
}
}
}
ArrayMap<String, FileAnnotation>& WriteCodeIndex()
{
DTIMING("WriteCodeIndex");
static ArrayMap<String, FileAnnotation> m;
return m;
}
const ArrayMap<String, FileAnnotation>& CodeIndex()
void DumpIndex()
{
return WriteCodeIndex();
GuiLock __;
FileOut out(ConfigFile("current_index.dump"));
ArrayMap<String, FileAnnotation>& x = CodeIndex();
for(const auto& m : ~x) {
out << m.key << "\n";
for(const auto& n : m.value.items)
out << '\t' << n.name << " " << n.id << " " << n.pretty << "\n";
}
}
static std::atomic<int> indexer_pkgi;
static std::atomic<int> running_indexers;
static Index<String> visited_files;
static Mutex visited_files_mutex;
CoEvent Indexer::event;
Hdepend Indexer::hdepend;
Mutex Indexer::mutex;
Vector<Indexer::Job> Indexer::jobs;
int Indexer::jobi;
std::atomic<int> Indexer::running_indexers;
Workspace Indexer::wspc;
VectorMap<String, String> Indexer::master_file;
bool IsIndexing()
void Indexer::IndexerThread()
{
return running_indexers;
}
void Indexer(const String& includes, const String& defines)
{
static Hdepend hdepend; // shared between threads
static Mutex hdepend_mutex;
ONCELOCK {
hdepend.NoConsole();
};
Clang clang;
int tm0 = msecs();
running_indexers++;
for(;;) {
BlitzMaker m;
String pk_name;
Vector<Tuple<String, bool>> pk_files;
Index<String> pk_files_index;
{
GuiLock __;
const Workspace& wspc = GetIdeWorkspace();
int pkgi = indexer_pkgi++;
if(pkgi >= wspc.GetCount())
break;
LTIMING("Indexer Fetch");
pk_name = wspc[pkgi];
const Package& pk = wspc.GetPackage(pkgi);
for(int i = 0; i < pk.GetCount(); i++) {
String path = SourcePath(pk_name, pk[i]);
pk_files.Add({ path, pk[i].noblitz });
pk_files_index.Add(path);
}
}
{
Mutex::Lock __(hdepend_mutex);
m.Do(pk_name, pk_files, hdepend);
}
// TODO: Check time
auto ProcessResults = [&] {
ClangVisitor v;
Index<String> doing_files;
v.WhenFile = [&](const String& path) {
return pk_files_index.Find(path) >= 0;
};
while(!Thread::IsShutdownThreads()) {
Clang clang;
int tm0 = msecs();
running_indexers++;
for(;;) {
Job job;
{
DTIMING("Visitor");
v.Do(clang.tu);
Mutex::Lock __(mutex);
if(jobi >= jobs.GetCount())
break;
job = jobs[jobi++];
}
{
GuiLock __;
DTIMING("Process files");
for(int i = 0; i < v.item.GetCount(); i++) {
DTIMING("Process file");
FileAnnotation& f = WriteCodeIndex().GetAdd(v.item.GetKey(i));
f.defines = defines;
f.includes = includes;
DTIMING("Process file pick");
f.items = pick(v.item[i]);
}
LTIMESTOP("Parsing " + job.path + " " + AsString(job.file_times));
clang.Parse(job.path, job.blitz, job.includes, job.defines,
CXTranslationUnit_DetailedPreprocessingRecord|
CXTranslationUnit_KeepGoing|
CXTranslationUnit_SkipFunctionBodies|
(job.blitz.GetCount() ? 0 : PARSE_FILE));
DumpDiagnostics(clang.tu);
}
};
LTIMESTOP("======= Indexing " + pk_name);
for(const String& fn : m.individual) {
LTIMESTOP("Indexing " + fn);
clang.Parse(fn, Null, includes, defines,
CXTranslationUnit_DetailedPreprocessingRecord|
CXTranslationUnit_KeepGoing|
PARSE_FILE);
if(clang.tu)
ProcessResults();
if(Thread::IsShutdownThreads())
break;
ClangVisitor v;
if(clang.tu) {
DumpDiagnostics(clang.tu);
String current_file;
bool do_file = false;
VectorMap<String, bool> do_file_cache;
v.WhenFile = [&](const String& path) {
if(IsNull(path))
return false;
if(current_file != path) {
current_file = path;
if(IsNull(path) || path.EndsWith("$$$blitz.cpp"))
do_file = false;
else
if(IsCSourceFile(path))
do_file = true;
else {
current_file = path;
int q = do_file_cache.Find(path);
if(q < 0) {
Mutex::Lock __(mutex);
do_file = job.file_times.Find(master_file.Get(NormalizePath(path), Null)) >= 0;
do_file_cache.Add(path, do_file);
}
else
do_file = do_file_cache[q];
}
}
return do_file;
};
v.Do(clang.tu);
}
for(const auto& m : ~job.file_times) {
FileAnnotation f;
f.defines = job.defines;
f.includes = job.includes;
int q = v.item.Find(m.key);
if(q >= 0)
f.items = pick(v.item[q]);
else
f.items.Clear();
f.time = job.file_times.Get(m.key, Time::Low());
SaveChangedFile(CachedAnnotationPath(m.key, f.defines, f.includes, Null), StoreAsString(f), true);
GuiLock __;
CodeIndex().GetAdd(m.key) = pick(f);
}
}
if(Thread::IsShutdownThreads())
break;
LTIMESTOP("Indexing BLITZ " + pk_name);
clang.Parse(ConfigFile(pk_name + "$$$blitz.cpp"), m.blitz, includes, defines,
CXTranslationUnit_DetailedPreprocessingRecord|
CXTranslationUnit_KeepGoing);
if(clang.tu)
ProcessResults();
if(Thread::IsShutdownThreads())
break;
if(--running_indexers == 0) {
LLOG("Done everything " << (msecs() - tm0) / 1000.0 << " s");
DumpIndex(); // TODO remove
}
event.Wait(500);
}
if(--running_indexers == 0)
LLOG("Done everything " << (msecs() - tm0) / 1000.0 << " s");
LLOG("Done");
}
void StartIndexing(const String& includes, const String& defines)
void Indexer::Start(const String& main, const String& includes, const String& defines)
{
{
Mutex::Lock __(visited_files_mutex);
visited_files.Clear();
}
indexer_pkgi = 0;
if(!IsIndexing()) {
DLOG("Indexer::Start =============================== ");
ONCELOCK {
for(int i = 0; i < CPU_Cores(); i++) // TODO: CPU_Cores?
Thread::StartNice([=] { Indexer(includes, defines); });
Thread::StartNice([=] { Indexer::IndexerThread(); });
}
Thread::Start([=] {
{
GuiLock __;
DTIMING("Load workspace");
wspc.Scan(main);
}
{
DTIMING("Create indexer jobs");
Mutex::Lock __(mutex);
hdepend.NoConsole();
hdepend.SetDirs(includes);
jobs.Clear();
master_file.Clear();
for(int pi = 0; pi < wspc.GetCount(); pi++) {
String pk_name = wspc[pi];
const Package& pk = wspc.GetPackage(pi);
for(int i = 0; i < pk.GetCount(); i++) {
String path = NormalizePath(SourcePath(pk_name, pk[i]));
if(IsCSourceFile(path)) {
master_file.Add(path, path);
for(String p : hdepend.GetDependencies(path)) {
p = NormalizePath(p);
if(master_file.Find(p) < 0)
master_file.Add(p, path);
}
}
}
}
for(String path : master_file.GetKeys()) {
FileAnnotation0 f;
{
GuiLock __;
f = CodeIndex().GetAdd(path);
}
if(f.includes != includes || f.defines != defines) {
String h = LoadFile(CachedAnnotationPath(path, defines, includes, Null));
if(h.GetCount()) {
FileAnnotation m;
if(LoadFromString(m, h)) {
m.time = m.time;
GuiLock __;
CodeIndex().GetAdd(path) = pick(m);
}
}
}
}
{ // remove files that are not in project anymore
GuiLock __;
for(int i = 0; i < CodeIndex().GetCount(); i++)
if(master_file.Find(CodeIndex().GetKey(i)) < 0)
CodeIndex().Unlink(i);
CodeIndex().Sweep();
}
jobi = 0;
for(int pi = 0; pi < wspc.GetCount(); pi++) {
String blitz;
VectorMap<String, Time> blitz_files;
String pk_name = wspc[pi];
const Package& pk = wspc.GetPackage(pi);
auto AddJob = [&](const String& path) -> Job& {
Job& job = jobs.Add();
job.includes = includes;
job.defines = defines;
job.path = path;
return job;
};
for(int i = 0; i < pk.GetCount(); i++) {
String path = NormalizePath(SourcePath(pk_name, pk[i]));
if(IsCSourceFile(path)) {
Time time = hdepend.FileTime(path);
FileAnnotation0 f;
{
GuiLock __;
f = CodeIndex().GetAdd(path);
}
DLOG("===========");
DDUMP(path);
DDUMP(time);
DDUMP(f.time);
if(f.defines != defines || f.includes != includes || f.time != time) {
if(hdepend.BlitzApproved(path) && !pk[i].noblitz) {
BlitzFile(blitz, path, hdepend, i);
blitz_files.Add(path, time);
}
else
AddJob(path).file_times.Add(path, time);
}
}
}
if(blitz.GetCount()) {
Job& job = AddJob(ConfigFile(pk_name + "$$$blitz.cpp"));
job.blitz = blitz;
job.file_times = pick(blitz_files); // the path is fake, file does not exist
}
}
}
event.Broadcast();
});
}

View file

@ -53,17 +53,18 @@ String CleanupId(const char *s)
return s[0] == 'o' && s[1] == 'p' && s[2] == 'e' && s[3] == 'r' &&
s[4] == 'a' && s[5] == 't' && s[6] == 'o' && s[7] == 'r';
};
if(was_id)
mm.Cat(' ');
if(!operator_def) // because of conversion operators e.g. Foo::operator bool()
name_pos = mm.GetCount();
if(id.GetCount() == 8 && IsOperator(id))
operator_def = true;
if(id.GetCount() > 8) {
if(id.GetCount() > 8) { // conversion operator?
const char *s = ~id + id.GetCount() - 8;
operator_def = IsOperator(s) && !iscid(s[-1]);
}
if(function && (IsBasicType(id) || !IsCppKeyword(id))) // TODO optimize this (IsCppKeywordNoType)
was_param_type = true;
if(was_id)
mm.Cat(' ');
name_pos = mm.GetCount();
mm.Cat(id);
was_id = true;
was_name = true;
@ -90,13 +91,13 @@ String CleanupId(const char *s)
if(*s == '~' && !operator_def) // prevent culling of 'return value' in destructor
destructor = true;
if(*s == '(') {
function = true;
was_param_type = false;
operator_def = false;
if(name_pos && !destructor) {
String h = String(mm).Mid(name_pos);
mm = h;
}
function = true;
was_param_type = false;
operator_def = false;
}
if(*s == ',')
was_param_type = false;
@ -209,7 +210,7 @@ Vector<ItemTextPart> ParsePretty(const String& name, const String& signature, in
p.type = ITEM_NUMBER;
}
else
if(iscid(*s)) {
if(iscid(*s) || (*s == '~' && *name == '~')) {
if(strncmp(s, name, name_len) == 0 && !iscid(s[name_len])) { // need strncmp because of e.g. operator++
p.type = ITEM_NAME;
n = name_len;
@ -222,7 +223,8 @@ Vector<ItemTextPart> ParsePretty(const String& name, const String& signature, in
*fn_info = 0;
}
}
else {
else
if(*s != '~') {
String id;
n = 0;
while(iscid(s[n]))
@ -248,6 +250,8 @@ Vector<ItemTextPart> ParsePretty(const String& name, const String& signature, in
if(param && fn_info)
*fn_info = 1;
}
else // should not happen, but be safe
s++;
}
else
if(sOperatorTab[*s]) {

View file

@ -31,6 +31,7 @@ bool ClangVisitor::ProcessNode(CXCursor cursor)
if(WhenFile)
LoadPosition();
if(!(WhenFile ? WhenFile(path) : clang_Location_isFromMainFile(cxlocation))) {
return findarg(cursorKind, CXCursor_StructDecl, CXCursor_UnionDecl, CXCursor_ClassDecl,
CXCursor_FunctionTemplate, CXCursor_FunctionDecl, CXCursor_Constructor,
@ -134,15 +135,32 @@ bool ClangVisitor::ProcessNode(CXCursor cursor)
r.kind = cursorKind;
r.name = name;
r.line = line;
// DDUMP(m);
r.id = CleanupId(m);
r.pretty = CleanupPretty(FetchString(clang_getCursorPrettyPrinted(cursor, pp_pretty)));
r.definition = clang_isCursorDefinition(cursor);
r.nspace = nspace;
int q = FindId(r.id, r.name);
if(q >= 0) {
r.nest = r.id.Mid(0, q);
r.nest.TrimEnd("::");
// DDUMP(FetchString(clang_getCursorPrettyPrinted(cursor, pp_pretty)));
// DDUMP(r.pretty);
// DDUMP(r.id);
// DDUMP(r.name);
// DDUMP(scope);
if(findarg(r.kind, CXCursor_Constructor, CXCursor_Destructor) >= 0) {
int q = r.id.Find('(');
if(q >= 0) {
q = r.id.ReverseFind("::", q);
if(q >= 0)
r.nest = r.id.Mid(0, q);
}
}
else {
int q = FindId(r.id, r.name);
if(q >= 0) {
r.nest = r.id.Mid(0, q);
r.nest.TrimEnd("::");
}
}
// DDUMP(r.nest);
r.uname = ToUpper(name);
r.unest = ToUpper(r.nest);
}

View file

@ -1,6 +1,7 @@
#include "clang.h"
#define LLOG(x)
#define LTIMESTOP(x) TIMESTOP(x)
String FetchString(CXString cs)
{
@ -78,6 +79,8 @@ bool Clang::Parse(const String& filename, const String& content, const String& i
{
if(!index) return false;
// LTIMESTOP("Parse " << filename << " " << includes_ << " " << defines);
Dispose();
String cmdline;

View file

@ -6,6 +6,15 @@
using namespace Upp;
class CoEvent {
Mutex lock;
ConditionVariable cv;
public:
void Wait(int timeout_ms) { lock.Enter(); cv.Wait(lock, timeout_ms); lock.Leave(); }
void Broadcast() { cv.Broadcast(); }
};
String FetchString(CXString cs);
String GetCursorKindName(CXCursorKind cursorKind);
String GetCursorSpelling(CXCursor cursor);
@ -153,18 +162,45 @@ void StartAutoComplete(const CurrentFileContext& ctx, int line, int column, bool
Event<const Vector<AutoCompleteItem>&> done);
void CancelAutoComplete();
String FindMasterSource(Hdepend& hdepend, const Workspace& wspc, const String& header_file);
struct FileAnnotation {
String defines;
struct FileAnnotation0 {
String defines = "<not_loaded>";
String includes;
Time time;
Vector<AnnotationItem> items;
};
bool IsIndexing();
void StartIndexing(const String& includes, const String& defines);
struct FileAnnotation : FileAnnotation0 {
Vector<AnnotationItem> items;
void Serialize(Stream& s);
};
const ArrayMap<String, FileAnnotation>& CodeIndex();
ArrayMap<String, FileAnnotation>& CodeIndex();
class Indexer {
struct Job : Moveable<Job> {
String path;
String blitz;
String includes;
String defines;
WithDeepCopy<VectorMap<String, Time>> file_times;
};
static CoEvent event;
static Workspace wspc;
static Hdepend hdepend;
static Mutex mutex;
static Vector<Job> jobs;
static int jobi;
static std::atomic<int> running_indexers;
static VectorMap<String, String> master_file; // header -> first file that includes it
static void IndexerThread();
public:
static void Start(const String& main, const String& includes, const String& defines);
static bool IsRunning() { return running_indexers; }
};
#endif

View file

@ -17,9 +17,8 @@ file
CxxIcon.cpp,
Signature.cpp,
clang.cpp,
Codebase.cpp,
Visitor.cpp,
AutoComplete.cpp,
CurrentFile.cpp,
Visitor.cpp,
Indexer.cpp;

View file

@ -28,12 +28,8 @@
- aux files / autocomplete
- this is just a test
- OpenWind.h autocomplete
- server_methods.i
- fixups?
- enum annotation popup (Ctrl::)
@ -46,25 +42,17 @@
- check editor mode
- navlines
- navigator - GotoDesignerFile
- * nest in navigator local file
- remove $blitz items
- constructor/destructor name is not bold (check destructor in navigator display)
- PaintCpp ending spaces in navigator
- Error output: (): x += GetTextSize(" Ôćĺ ", StdFont());
- x += GetTextSize(" Ôćĺ ", StdFont()) - autocomplete fails on UTF8
- immediate reparse (probably Update?)
- Navigator -> (constructor does not have return value)
- navlines
- local file navigation off by 1 line
@ -72,7 +60,45 @@
- operator bool - wrong nest (Core/Speller.cpp)
- constructor - worng nest(Core/Speller.cpp)
- Speller.cpp - Speller type has {}, Line too
- Core/String.h - empty macros at the start in navigator
- Core/String.h - operator const void *() - wrong highlighting (all bold)
- Core/String.h - conversion operators wrong nests
- for .txt file, navigator keeps showing previous local file
- StringBuffer does not work in debugger pdb
- Speller.cpp: structures have wrong nest (missing itself)
- check dialog mode
- void Navigator::SyncCursor()
- void NavDlg::GoTo()
- Hdepend NoConsole
- AltC static method(); (header->source) retains static
- Vector<Job> Indexer::jobs; should be: Vector<Indexer::Job> Indexer::jobs;
- indexer TabBar missing
- when scope is selected in navigator, search should be ingored
- unicode is very long because { 123 , 41234234
- use codeindex info for file annotations
- save file annotation to codeindex
- rescan everything function
- C:\u\llvm_ide\uppsrc\plugin\z\lib\compress.c (22:24) unknown type name 'dest' - do we need CBLITZ?
LATER:
@ -85,6 +111,18 @@ LATER:
DONE:
- destructor name is not bold (clang/visitor.cpp)
- constructor - worng nest(Core/Speller.cpp)
- AString type [31] - wrong icon
- * nest in navigator local file
- PaintCpp ending spaces in navigator
- Navigator -> (constructor does not have return value)
- Upp:: missing from Vector
- class Ctrl

View file

@ -668,7 +668,7 @@ void Ide::SyncClang()
a.Add(i > cx - DPI(6) ? bg : Null);
}
editor.AnimateBar(pick(a));
editor.search.SetBackground(Animate(animate_indexer, animate_indexer_dir, IsIndexing()));
editor.search.SetBackground(Animate(animate_indexer, animate_indexer_dir, Indexer::IsRunning()));
display.Animate(Animate(animate_autocomplete, animate_autocomplete_dir, IsAutocompleteParsing()));
animate_phase = phase;
}
@ -792,3 +792,8 @@ void Ide::DiffFiles(const char *lname, const String& l, const char *rname, const
diff.Set(lname, LoadConflictFile(l), rname, LoadConflictFile(r));
diff.Execute();
}
void Ide::TriggerIndexer()
{
Indexer::Start(main, GetCurrentIncludePath(), GetCurrentDefines());
}

View file

@ -1244,7 +1244,9 @@ public:
void MacroTarget(EscEscape& e);
String GetAndroidSdkPath();
void TriggerIndexer();
typedef Ide CLASSNAME;
enum {

View file

@ -813,7 +813,6 @@ LAYOUT(JumpLayout, 692, 496)
ITEM(Upp::Button, ok, SetLabel(t_("OK")).RightPosZ(76, 64).TopPosZ(4, 24))
ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).RightPosZ(8, 64).TopPosZ(4, 24))
UNTYPED(scope, LeftPosZ(4, 176).VSizePosZ(32, 104))
UNTYPED(navlines, LeftPosZ(4, 176).BottomPosZ(4, 96))
UNTYPED(list, HSizePosZ(184, 8).VSizePosZ(32, 4))
END_LAYOUT

View file

@ -398,6 +398,7 @@ void Ide::SaveFile0(bool always)
SyncUsc();
MakeTitle();
TriggerIndexer();
}
void Ide::FlushFile() {

View file

@ -331,7 +331,7 @@ void AppMain___()
ide.MakeTitle();
if(!ide.IsEditorMode()) {
SyncRefs();
StartIndexing(ide.GetCurrentIncludePath(), ide.GetCurrentDefines());
ide.TriggerIndexer();
}
ide.FileSelected();
ide.isscanning--;
@ -366,6 +366,7 @@ void AppMain___()
}
#endif
#endif
Ctrl::ShutdownThreads();
}
#ifdef flagPEAKMEM