From 78dc90e9c2cbfd714fa055ba47736dede3c90fa3 Mon Sep 17 00:00:00 2001 From: Mirek Fidler Date: Wed, 20 Jul 2022 16:14:13 +0200 Subject: [PATCH] Developing indexer --- uppsrc/Core/Util.h | 4 +- uppsrc/CtrlLib/EditField.cpp | 6 +- uppsrc/ide/Assist.cpp | 30 +- uppsrc/ide/Assist.h | 30 +- uppsrc/ide/AssistDisplay.cpp | 53 ++- uppsrc/ide/Browser/Base.cpp | 2 +- uppsrc/ide/Browser/CodeBrowser.cpp | 2 +- uppsrc/ide/Browser/CodeRef.cpp | 4 +- uppsrc/ide/Browser/ItemDisplay.cpp | 4 +- uppsrc/ide/Browser/Move.cpp | 2 +- uppsrc/ide/Browser/TopicBase.cpp | 1 + uppsrc/ide/Browser/TopicI.cpp | 2 +- uppsrc/ide/Core/Core.h | 13 +- uppsrc/ide/Core/Hdepend.cpp | 45 ++- uppsrc/ide/Core/Ide.cpp | 8 +- uppsrc/ide/Core/Workspace.cpp | 2 +- uppsrc/ide/IncludeTrick.cpp | 3 +- uppsrc/ide/Navigator.cpp | 6 + uppsrc/ide/Navigator2.cpp | 596 +++++++++++++++++++++++++++++ uppsrc/ide/clang/AutoComplete.cpp | 5 +- uppsrc/ide/clang/CurrentFile.cpp | 19 +- uppsrc/ide/clang/Indexer.cpp | 169 ++++++++ uppsrc/ide/clang/Signature.cpp | 20 +- uppsrc/ide/clang/Visitor.cpp | 77 ++-- uppsrc/ide/clang/blitz.cpp | 1 + uppsrc/ide/clang/clang.cpp | 10 +- uppsrc/ide/clang/clang.h | 66 ++-- uppsrc/ide/clang/clang.upp | 4 +- uppsrc/ide/clang/todo.txt | 61 ++- uppsrc/ide/ide.cpp | 26 +- uppsrc/ide/ide.h | 1 + uppsrc/ide/ide.upp | 1 + uppsrc/ide/idefile.cpp | 1 - uppsrc/ide/main.cpp | 4 +- 34 files changed, 1059 insertions(+), 219 deletions(-) create mode 100644 uppsrc/ide/Navigator2.cpp create mode 100644 uppsrc/ide/clang/Indexer.cpp create mode 100644 uppsrc/ide/clang/blitz.cpp diff --git a/uppsrc/Core/Util.h b/uppsrc/Core/Util.h index c2b8b71a2..fcc551c4a 100644 --- a/uppsrc/Core/Util.h +++ b/uppsrc/Core/Util.h @@ -25,10 +25,10 @@ public: }; struct TimeStopper { - const char *name; + String name; TimeStop tm; - TimeStopper(const char *name) : name(name) {} + TimeStopper(const String& name) : name(name) {} ~TimeStopper() { RLOG(name << " " << tm); } }; diff --git a/uppsrc/CtrlLib/EditField.cpp b/uppsrc/CtrlLib/EditField.cpp index a4fae995a..3830bd22d 100644 --- a/uppsrc/CtrlLib/EditField.cpp +++ b/uppsrc/CtrlLib/EditField.cpp @@ -1068,8 +1068,10 @@ EditField& EditField::SetFont(Font _font) EditField& EditField::SetColor(Color c) { - SetColorAttr(ATTR_TEXTCOLOR, c); - Refresh(); + if(GetColorAttr(ATTR_TEXTCOLOR) != c) { + SetColorAttr(ATTR_TEXTCOLOR, c); + Refresh(); + } return *this; } diff --git a/uppsrc/ide/Assist.cpp b/uppsrc/ide/Assist.cpp index 1976a5f7b..f6ccd0d3d 100644 --- a/uppsrc/ide/Assist.cpp +++ b/uppsrc/ide/Assist.cpp @@ -69,7 +69,8 @@ AssistEditor::AssistEditor() NoFindReplace(); WhenUpdate << [=] { - annotate_trigger.KillSet(100, [=] { SyncCurrentFile(); }); + annotating = true; + annotate_trigger.KillSet(500, [=] { SyncCurrentFile(); }); }; } @@ -460,6 +461,10 @@ CurrentFileContext AssistEditor::CurrentContext(int& line_delta) cfx.content.Clear(); } } +#ifdef _DEBUG + if(cfx.content.GetCount()) + SaveFile(ConfigFile("pseudo_header_src.cpp"), cfx.content); +#endif return cfx; } @@ -478,6 +483,9 @@ void AssistEditor::SyncCurrentFile(CurrentFileContext& cfx, int line_delta) m.id); } } + annotating = false; + if(!navigator_global) + Search(); }); } @@ -490,11 +498,11 @@ void AssistEditor::SyncCurrentFile() void AssistEditor::NewFile() { + SyncHeaders(); int line_delta; CurrentFileContext cfx = CurrentContext(line_delta); SyncCurrentFile(cfx, line_delta); SetAutoCompleteFile(cfx); - SyncHeaders(); } void AssistEditor::Assist(bool macros) @@ -744,7 +752,7 @@ void AssistEditor::AssistInsert() else { String txt = f.name; int param_count; - ParseSignature(f.name, f.signature, ¶m_count); + ParsePretty(f.name, f.signature, ¶m_count); if(param_count >= 0) txt << "()"; if(f.signature.EndsWith("::")) @@ -803,21 +811,7 @@ bool AssistEditor::Key(dword key, int count) Exclamation("No annotation for this line."); } if(key == K_F11) { - HdependTimeDirty(); - VectorMap> deps; - { - TIMESTOP("Scan"); - const Workspace& wspc = GetIdeWorkspace(); - 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 path = SourcePath(n, pk.file[i]); - deps.GetAdd(path) = pick(HdependGetDependencies(path)); - } - } - } - DDUMPM(deps); + StartIndexing(theide->GetCurrentIncludePath(), theide->GetCurrentDefines()); } #endif if(popup.IsOpen()) { diff --git a/uppsrc/ide/Assist.h b/uppsrc/ide/Assist.h index 246a2aae3..7fe7bc8b7 100644 --- a/uppsrc/ide/Assist.h +++ b/uppsrc/ide/Assist.h @@ -9,7 +9,13 @@ struct Navigator { bool operator<(const NavLine& b) const; }; - struct NavItem { + 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; @@ -30,13 +36,11 @@ struct Navigator { bool impl; bool decl; int8 pass; + Vector linefo; - - void Set(const CppItem& m); + */ }; - enum KindEnum { KIND_LINE = 123, KIND_NEST, KIND_FILE, KIND_SRCFILE }; - struct ScopeDisplay : Display { Navigator *navigator; @@ -52,23 +56,22 @@ struct Navigator { }; struct NavigatorDisplay : Display { - const Vector& item; + const Vector& item; int DoPaint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const; virtual void PaintBackground(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const; virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const; virtual Size GetStdSize(const Value& q) const; - NavigatorDisplay(const Vector& item) : item(item) {} + NavigatorDisplay(const Vector& item) : item(item) {} }; Ide *theide; Array nitem; - VectorMap > gitem; - Vector litem; - Array nest_item; - VectorMap > linefo; + Vector litem; + Array nest_item; // list separators with nest (scope) or file + VectorMap > linefo; // TODO remove? NavigatorDisplay navidisplay; bool navigating; TimeCallback search_trigger; @@ -86,7 +89,6 @@ struct Navigator { ScopeDisplay scope_display; void TriggerSearch(); - void NavGroup(bool local); void Search(); void Scope(); void ListLineEnabled(int i, bool& b); @@ -103,9 +105,6 @@ struct Navigator { void GoToNavLine(); void SyncCursor(); - static bool SortByLines(const NavItem *a, const NavItem *b); - static bool SortByNames(const NavItem *a, const NavItem *b); - typedef Navigator CLASSNAME; Navigator(); @@ -152,6 +151,7 @@ struct AssistEditor : CodeEditor, Navigator { } assist_display; RichTextCtrl annotation_popup; + bool annotating = false; Vector annotations; int assist_cursor; diff --git a/uppsrc/ide/AssistDisplay.cpp b/uppsrc/ide/AssistDisplay.cpp index ca7c738ce..56dd05319 100644 --- a/uppsrc/ide/AssistDisplay.cpp +++ b/uppsrc/ide/AssistDisplay.cpp @@ -27,6 +27,38 @@ Image CxxIcon(int kind) return BrowserImg::unknown(); } +int PaintCpp(Draw& w, const Rect& r, int kind, const String& name, const String& pretty, Color ink, bool focuscursor, bool retval_last) +{ + int x = r.left; + + Image img = CxxIcon(kind); + Size isz = img.GetSize(); + w.DrawImage(x + (DPI(16) - isz.cx) / 2, r.top + (r.GetHeight() - isz.cy) / 2, img); + + x += DPI(16); + int y = r.top + (r.GetHeight() - Draw::GetStdFontCy()) / 2; + +#ifdef _DEBUG + String ks = " [" + AsString(kind) + "] "; + w.DrawText(x, y, ks); + x += GetTextSize(ks, StdFont()).cx; +#endif + + Vector n = ParsePretty(name, pretty); + int count = n.GetCount(); + if(retval_last) + 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; + break; + } + PaintText(w, x, y, pretty, n, 0, count, focuscursor, ink, false); + return x; +} + void AssistEditor::AssistDisplay::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const { int ii = q; @@ -34,26 +66,7 @@ void AssistEditor::AssistDisplay::Paint(Draw& w, const Rect& r, const Value& q, AutoCompleteItem& m = editor->assist_item[editor->assist_item_ndx[ii]]; w.DrawRect(r, paper); - bool focuscursor = (style & (FOCUS|CURSOR)) == (FOCUS|CURSOR) || (style & SELECT); - - int x = r.left; - int ry = r.top + r.GetHeight() / 2; - Image img = CxxIcon(m.kind); - Size isz = img.GetSize(); - w.DrawImage(x + (DPI(16) - isz.cx) / 2, r.top + (r.GetHeight() - isz.cy) / 2, img); - - x += DPI(16); - int y = ry - Draw::GetStdFontCy() / 2; - #ifdef _DEBUG - String ks = " [" + AsString(m.kind) + "] "; - w.DrawText(x, y, ks); - x += GetTextSize(ks, StdFont()).cx; - #endif - int x0 = x; - Vector n = ParseSignature(m.name, m.signature); - - int starti = 0; - PaintText(w, x, y, m.signature, n, starti, n.GetCount(), focuscursor, ink, false); + PaintCpp(w, r, m.kind, m.name, m.signature, ink, (style & (FOCUS|CURSOR)) == (FOCUS|CURSOR) || (style & SELECT)); } } diff --git a/uppsrc/ide/Browser/Base.cpp b/uppsrc/ide/Browser/Base.cpp index 0c02b6adf..53bd09b40 100644 --- a/uppsrc/ide/Browser/Base.cpp +++ b/uppsrc/ide/Browser/Base.cpp @@ -1,4 +1,4 @@ -#include "Browser.h" +#include #include diff --git a/uppsrc/ide/Browser/CodeBrowser.cpp b/uppsrc/ide/Browser/CodeBrowser.cpp index 9e17442d0..880cb4ec7 100644 --- a/uppsrc/ide/Browser/CodeBrowser.cpp +++ b/uppsrc/ide/Browser/CodeBrowser.cpp @@ -1,4 +1,4 @@ -#include "Browser.h" +#include bool MatchCib(const String& s, const String& match) { diff --git a/uppsrc/ide/Browser/CodeRef.cpp b/uppsrc/ide/Browser/CodeRef.cpp index 56eb5c5bf..50fb94bba 100644 --- a/uppsrc/ide/Browser/CodeRef.cpp +++ b/uppsrc/ide/Browser/CodeRef.cpp @@ -346,7 +346,7 @@ void TopicEditor::InsertItem() String DecoratedItem(const String& name, const String& pretty) { String qtf = "[%00-00K "; - Vector n = ParseSignature(name, pretty); + Vector n = ParsePretty(name, pretty); /* TODO if(pari < 0) { if(m.virt) @@ -435,7 +435,7 @@ String CreateQtf(const AnnotationItem& m, const String& lang, bool onlyhdr = fal qtf << "[s3%" << lang << " "; if(!str) { - Vector n = ParseSignature(m.name, m.pretty); + Vector n = ParsePretty(m.name, m.pretty); if(!str) { bool was; for(const auto& h : n) diff --git a/uppsrc/ide/Browser/ItemDisplay.cpp b/uppsrc/ide/Browser/ItemDisplay.cpp index 36e0ad7c0..20e099325 100644 --- a/uppsrc/ide/Browser/ItemDisplay.cpp +++ b/uppsrc/ide/Browser/ItemDisplay.cpp @@ -4,8 +4,8 @@ void PaintText(Draw& w, int& x, int y, const char *text, const Vector struct MoveTopicDlg : public WithMoveTopicLayout { typedef MoveTopicDlg CLASSNAME; diff --git a/uppsrc/ide/Browser/TopicBase.cpp b/uppsrc/ide/Browser/TopicBase.cpp index 00be89c57..9616c3938 100644 --- a/uppsrc/ide/Browser/TopicBase.cpp +++ b/uppsrc/ide/Browser/TopicBase.cpp @@ -239,6 +239,7 @@ void SyncRefs() SyncRefsShowProgress = true; return; } + TIMESTOP("SyncRefs"); Progress pi; pi.AlignText(ALIGN_LEFT); Vector upp = GetUppDirs(); diff --git a/uppsrc/ide/Browser/TopicI.cpp b/uppsrc/ide/Browser/TopicI.cpp index 14e0c11d8..72c89dccf 100644 --- a/uppsrc/ide/Browser/TopicI.cpp +++ b/uppsrc/ide/Browser/TopicI.cpp @@ -1,4 +1,4 @@ -#include "Browser.h" +#include bool IsTopicFile(const char *path) { diff --git a/uppsrc/ide/Core/Core.h b/uppsrc/ide/Core/Core.h index d4b56c711..a220d1d49 100644 --- a/uppsrc/ide/Core/Core.h +++ b/uppsrc/ide/Core/Core.h @@ -58,7 +58,7 @@ class Hdepend { ArrayMap map; Vector incdir; // include directories VectorMap > depends; // externally forced dependecies - bool cache_time = false; + bool console = true; void Include(const char *trm, Info& info, const String& filedir, bool bydefine); void ScanFile(const String& path, int map_index); @@ -69,8 +69,8 @@ class Hdepend { void GetMacroIndex(Index& dest, int ix); public: - void SetDirs(Vector&& id) { incdir = pick(id); map.Clear(); } - void SetDirs(const String& includes) { incdir = pick(Split(includes, ';')); map.Clear(); } + void SetDirs(Vector&& id); + void SetDirs(const String& includes); void TimeDirty(); void ClearDependencies() { depends.Clear(); } @@ -85,7 +85,7 @@ public: const Vector& GetDefines(const String& path); Vector GetDependencies(const String& path, bool bydefine_too = true); const Vector& GetAllFiles() { return map.GetKeys(); } - void CacheTime() { cache_time = true; } + void NoConsole() { console = false; } }; class IdeContext @@ -153,8 +153,8 @@ public: virtual ~IdeContext() {} }; -IdeContext *TheIde(); -void TheIde(IdeContext *context); +Ide *TheIde(); +void TheIde(Ide *context); bool IsVerbose(); void PutConsole(const char *s); @@ -391,7 +391,6 @@ public: File() { Init(); } File(const String& s) : String(s) { Init(); } - rval_default(File); }; struct Config { String name; diff --git a/uppsrc/ide/Core/Hdepend.cpp b/uppsrc/ide/Core/Hdepend.cpp index b6e9cac32..8c8965e7e 100644 --- a/uppsrc/ide/Core/Hdepend.cpp +++ b/uppsrc/ide/Core/Hdepend.cpp @@ -85,7 +85,7 @@ void Hdepend::ScanFile(const String& path, int map_index) auto Id = [&](const char *id) { int n = strlen(id); - if(memcmp(term, id, n) == 0 && findarg(term[n], ' ', '\t')) { + if(memcmp(term, id, n) == 0 && findarg(term[n], ' ', '\t') >= 0) { term += n + 1; return true; } @@ -160,6 +160,7 @@ void Hdepend::ScanFile(const String& path, int map_index) if(p.Char('#') && p.Id("define") && p.IsId() && id == p.ReadId()) info.guarded = true; } + term = p.GetPtr(); } catch(CParser::Error) {} } @@ -268,29 +269,19 @@ int Hdepend::File(const String& f) Info& info = map[ii]; if(info.flag) return ii; info.flag = true; - if(cache_time) { + Time file_time = FileGetTime(path); + if(IsNull(file_time) || file_time == info.time) { if(info.timedirty) { - info.time = FileGetTime(path); for(int i = 0; i < info.depend.GetCount(); i++) File(map.GetKey(info.depend[i])); info.timedirty = false; } } else { - Time file_time = FileGetTime(path); - if(IsNull(file_time) || file_time == info.time) { - if(info.timedirty) { - for(int i = 0; i < info.depend.GetCount(); i++) - File(map.GetKey(info.depend[i])); - info.timedirty = false; - } - } - else { - info.time = file_time; - if(info.time > GetSysTime() + 10) - PutConsole(String().Cat() << "WARNING: " << path << " has invalid (future) time " << info.time); - ScanFile(path, ii); - } + info.time = file_time; + if(console && info.time > GetSysTime() + 10) + PutConsole(String().Cat() << "WARNING: " << path << " has invalid (future) time " << info.time); + ScanFile(path, ii); } return ii; } @@ -355,6 +346,19 @@ void Hdepend::ClearMacroFlag() map[i].macroflag = false; } +void Hdepend::SetDirs(Vector&& id) +{ + if(incdir != id) { + incdir = pick(id); + map.Clear(); + } +} + +void Hdepend::SetDirs(const String& includes) +{ + SetDirs(pick(Split(includes, ';'))); +} + void Hdepend::TimeDirty() { for(int i = 0; i < map.GetCount(); i++) @@ -376,7 +380,7 @@ Time Hdepend::FileTime(const String& path) FindFile ff(dep[i]); if(ff) { Time tm = ff.GetLastWriteTime(); - if(tm > GetSysTime() + 10) + if(console && tm > GetSysTime() + 10) PutConsole(String().Cat() << "WARNING: " << dep[i] << " has invalid (future) time " << tm); if(tm > h) h = tm; @@ -398,8 +402,9 @@ bool Hdepend::BlitzApproved(const String& path) return true; for(int i = 0; i < info.depend.GetCount(); i++) if(!info.bydefine[i] && !map[info.depend[i]].CanBlitz()) { - PutVerbose(String().Cat() << map.GetKey(info.depend[i]) - << "(1) : blocks BLITZ of " << path); + if(console) + PutVerbose(String().Cat() << map.GetKey(info.depend[i]) + << "(1) : blocks BLITZ of " << path); return false; } return true; diff --git a/uppsrc/ide/Core/Ide.cpp b/uppsrc/ide/Core/Ide.cpp index b7ed42eba..77ab53611 100644 --- a/uppsrc/ide/Core/Ide.cpp +++ b/uppsrc/ide/Core/Ide.cpp @@ -1,9 +1,9 @@ -#include "Core.h" +#include -static IdeContext *the_ide; +static Ide *the_ide; -IdeContext *TheIde() { return the_ide; } -void TheIde(IdeContext *context) { the_ide = context; } +Ide *TheIde() { return the_ide; } +void TheIde(Ide *context) { the_ide = context; } bool IsVerbose() { return the_ide ? the_ide->IsVerbose() : false; } void PutConsole(const char *s) { if(the_ide) the_ide->PutConsole(s); } diff --git a/uppsrc/ide/Core/Workspace.cpp b/uppsrc/ide/Core/Workspace.cpp index 4de53cc74..f5e4a88a7 100644 --- a/uppsrc/ide/Core/Workspace.cpp +++ b/uppsrc/ide/Core/Workspace.cpp @@ -10,7 +10,7 @@ bool IsCSourceFile(const char *path) bool IsCHeaderFile(const char *path) { String ext = ToLower(GetFileExt(path)); - return ext == ".h" || ext == ".hpp" || ext == ".hh" || ext == ".hxx"; + return ext == ".h" || ext == ".hpp" || ext == ".hh" || ext == ".hxx" || ext == ".i"; } bool IsFullDirectory(const String& d) { diff --git a/uppsrc/ide/IncludeTrick.cpp b/uppsrc/ide/IncludeTrick.cpp index 367958948..f72758f0c 100644 --- a/uppsrc/ide/IncludeTrick.cpp +++ b/uppsrc/ide/IncludeTrick.cpp @@ -5,11 +5,12 @@ void AssistEditor::SyncHeaders() { // hdepend.CacheTime(); + TIMESTOP("SyncHeaders"); hdepend.TimeDirty(); hdepend.SetDirs(theide->GetCurrentIncludePath() + ";" + GetClangInternalIncludes()); master_source.Clear(); String editfile = NormalizePath(theide->editfile); - if(editfile.GetCount() && !IsSourceFile(editfile)) { + if(editfile.GetCount() && IsCHeaderFile(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 diff --git a/uppsrc/ide/Navigator.cpp b/uppsrc/ide/Navigator.cpp index fe335aa10..506fc08ff 100644 --- a/uppsrc/ide/Navigator.cpp +++ b/uppsrc/ide/Navigator.cpp @@ -1,3 +1,7 @@ +#if 0 + +// TODO: remove + #include "ide.h" #define LTIMING(x) // RTIMING(x) @@ -750,3 +754,5 @@ void Navigator::NaviSort() sorting = !sorting; Search(); } + +#endif diff --git a/uppsrc/ide/Navigator2.cpp b/uppsrc/ide/Navigator2.cpp new file mode 100644 index 000000000..e5ceaa434 --- /dev/null +++ b/uppsrc/ide/Navigator2.cpp @@ -0,0 +1,596 @@ +#include "ide.h" + +#define LTIMING(x) // RTIMING(x) + +String FormatNest(String nest) +{ + int q = nest.Find("@"); + if(q >= 0) { + nest.Trim(q); + nest << "[anonymous]"; + } + return nest; +} + +int CharFilterNavigator(int c) +{ + return c == ':' ? '.' : IsAlNum(c) || c == '_' || c == '.' ? c : 0; +} + +void PaintTeXt(Draw& w, int& x, int y, const String& text, Font font, Color ink) +{ + static int maxascent = MaxAscent(StdFont()); + Size sz = GetTextSize(text, font); + w.DrawText(x, y + maxascent - font.GetAscent(), text, font, ink); + x += sz.cx; +} + +int DrawFileName0(Draw& w, const Rect& r, const String& h, Color ink, int x) +{ + if(h.GetCount() == 0) + return 0; + int q = h.Find("\xff"); + String ns; + String fn = h; + if(q >= 0) { + ns = h.Mid(0, q) + ' '; + fn = h.Mid(q + 1); + } + String s = GetFileName(GetFileFolder(h)) + "/"; + x += r.left; + if(ns.GetCount()) { + PaintTeXt(w, x, r.top, ns, StdFont().Bold(), ink); + PaintTeXt(w, x, r.top, "(", StdFont(), ink); + } + PaintTeXt(w, x, r.top, s, StdFont(), ink); + s = GetFileName(h); + PaintTeXt(w, x, r.top, s, StdFont().Bold(), ink); + if(ns.GetCount()) + PaintTeXt(w, x, r.top, ")", StdFont(), ink); + return x - r.left; +} + +Size GetDrawFileNameSize(const String& h) +{ + NilDraw w; + return Size(DrawFileName0(w, Size(999999, 999999), h, Null, 0), StdFont().Bold().GetCy()); +} + +void DrawFileName(Draw& w, const Rect& r, const String& h, Color ink) +{ + DrawFileName0(w, r, h, ink, min(r.GetWidth() - GetDrawFileNameSize(h).cx, 0)); +} + +int PaintFileName(Draw& w, const Rect& r, String h, Color ink) +{ + if(*h == '\xff') + h.Remove(0, 1); + return DrawFileName0(w, r, h, ink, 0); +} + +Navigator::Navigator() +: navidisplay(litem) +{ + scope_display.navigator = this; + scope.NoHeader(); + scope.AddColumn().SetDisplay(scope_display); + scope.NoWantFocus(); + scope.WhenSel = THISBACK(Scope); + scope.WhenLeftDouble = THISBACK(ScopeDblClk); + + list.NoHeader(); + list.AddRowNumColumn().SetDisplay(navidisplay); + 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()); + + search <<= THISBACK(TriggerSearch); + search.SetFilter(CharFilterNavigator); + search.WhenEnter = THISBACK(NavigatorEnter); + + sortitems.Image(BrowserImg::Sort()); + sortitems <<= THISBACK(NaviSort); + sorting = false; + + dlgmode = false; +} + +void Navigator::SyncCursor() +{ + String k = "(" + GetKeyDesc(IdeKeys::AK_GOTO().key[0]) + ") "; + search.NullText("Symbol/lineno " + k); + search.Tip(IsNull(search) ? String() : "Clear " + k); + + if(!navigating && theide->editfile.GetCount()) { + navlines.KillCursor(); + int q = linefo.Find(GetSourceFileIndex(theide->editfile)); + if(q < 0) + return; + navigating = true; + SortedVectorMap& m = linefo[q]; + q = m.FindUpperBound(GetCurrentLine() + 1) - 1; + if(q >= 0 && q < m.GetCount()) + 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(); + 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 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); + const NavLine& l = q.To(); + x += r.left; + String p = GetSourceFilePath(l.file); + int y = r.top + (r.GetHeight() - StdFont().GetCy()) / 2; + PaintTeXt(w, x, y, GetFileName(GetFileFolder(p)) + "/", StdFont(), ink); + PaintTeXt(w, x, y, GetFileName(p), StdFont().Bold(), ink); + PaintTeXt(w, x, y, " (", StdFont(), ink); + PaintTeXt(w, x, y, AsString(l.line), StdFont().Bold(), ink); + PaintTeXt(w, x, y, ")", StdFont(), ink); + return x - r.left; +} + +void Navigator::LineDisplay::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const +{ + DoPaint(w, r, q, ink, paper, style, min(r.GetWidth() - GetStdSize(q).cx, 0)); +} + +Size Navigator::LineDisplay::GetStdSize(const Value& q) const +{ + NilDraw w; + 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(); + 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::GetNavLines(const NavItem& m) +{ + _DBG_ + Vector l; +/* + CodeBaseLock __; + int q = CodeBase().Find(m.nest); + if(q < 0 || IsNull(m.qitem)) + return l; + const Array& 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) + return; + navigating = true; + int ii = list.GetCursor(); + if(theide && ii >= 0 && ii < litem.GetCount()) { + int ln = GetCurrentLine() + 1; + const NavItem& m = *litem[ii]; + if(m.kind == KIND_LINE || IsNull(search)) { + theide->GotoPos(Null, m.line); + if(m.kind == KIND_LINE) { // Go to line - restore file view + search.Clear(); + Search(); + navigating = false; + } + SyncCursor(); + } + else + if(m.kind == KIND_SRCFILE) { + theide->AddHistory(); + theide->EditFile(m.id); + theide->AddHistory(); + } + else { + Vector 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); + } + } + } + navigating = false; +} + +void Navigator::ScopeDblClk() +{ + if(!scope.IsCursor()) + return; + String h = scope.GetKey(); + if((byte)*h == 0xff) + theide->GotoPos(h.Mid(1), 1); + else { + list.GoBegin(); + Navigate(); + } +} + +void Navigator::NavigatorClick() +{ + if(dlgmode) + return; + int q = list.GetClickPos().y; + if(q >= 0 && q < list.GetCount()) + Navigate(); +} + +void Navigator::NavigatorEnter() +{ + if(list.GetCount()) { + list.GoBegin(); + Navigate(); + } +} + +void Ide::ToggleNavigator() +{ + editor.Navigator(!editor.navigator); +} + +void Ide::SearchCode() +{ + if(!editor.navigator) + editor.Navigator(true); + if(!IsNull(~editor.search)) { + editor.search.Clear(); + editor.Search(); + editor.SetFocus(); + } + else { + String h = editor.GetWord(); + if(h.GetCount()) { + editor.search <<= h; + editor.search.SelectAll(); + editor.Search(); + } + editor.search.SetFocus(); + } +} + +//TODO: What is this? +void Ide::SwitchHeader() { + int c = filelist.GetCursor(); + if(c < 0) return; + String currfile = filelist[c]; + const char *ext = GetFileExtPos(currfile); + if(!stricmp(ext, ".h") || !stricmp(ext, ".hpp") + || !stricmp(ext, ".lay") || !stricmp(ext, ".iml")) { + int f = filelist.Find(ForceExt(currfile, ".cpp")); + if(f < 0) f = filelist.Find(ForceExt(currfile, ".c")); + if(f < 0) f = filelist.Find(ForceExt(currfile, ".cc")); + if(f >= 0) filelist.SetCursor(f); + } +} + +void Navigator::NavigatorDisplay::PaintBackground(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const +{ + int ii = q; + if(ii < 0 || ii >= item.GetCount()) + return; + const NavItem& m = *item[ii]; + bool focuscursor = (style & (FOCUS|CURSOR)) == (FOCUS|CURSOR) || (style & SELECT); + if(findarg(m.kind, KIND_FILE, KIND_NEST) >= 0) + w.DrawRect(r, focuscursor ? paper : m.kind == KIND_NEST ? Blend(SColorMark, SColorPaper, 220) + : SColorFace); + else + w.DrawRect(r, paper); +} + + +int Navigator::NavigatorDisplay::DoPaint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const +{ + int ii = q; + if(ii < 0 || ii >= item.GetCount()) + return 0; + const NavItem& m = *item[ii]; + bool focuscursor = (style & (FOCUS|CURSOR)) == (FOCUS|CURSOR) || (style & SELECT); + + int x = r.left; + int y = (r.GetHeight() - Draw::GetStdFontCy()) / 2; + + if(findarg(m.kind, KIND_FILE, KIND_NEST) >= 0) { + w.DrawRect(r, focuscursor ? paper : m.kind == KIND_NEST ? Blend(SColorMark, SColorPaper, 220) + : SColorFace); + if(findarg(m.kind, KIND_FILE) >= 0) + return PaintFileName(w, r, m.pretty, ink); + String h = FormatNest(m.pretty); + w.DrawText(x, y, h, StdFont().Bold(), ink); + return GetTextSize(h, StdFont().Bold()).cx; + } + + w.DrawRect(r, paper); + + if(m.kind == KIND_SRCFILE) + return PaintFileName(w, r, m.pretty, ink); + + if(m.kind == KIND_LINE) { + w.DrawText(x, y, m.pretty, StdFont().Bold(), ink); + return GetTextSize(m.pretty, StdFont().Bold()).cx; + } + + return PaintCpp(w, r, m.kind, m.name, m.pretty, ink, focuscursor, true); +} + +void Navigator::NavigatorDisplay::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const +{ + DoPaint(w, r, q, ink, paper, style); +} + +Size Navigator::NavigatorDisplay::GetStdSize(const Value& q) const +{ + NilDraw w; + return Size(DoPaint(w, Size(999999, 999999), q, White(), White(), 0), Draw::GetStdFontCy()); +} + +void Navigator::TriggerSearch() +{ + search_trigger.KillSet(100, THISBACK(Search)); +} + +void Navigator::Search() +{ + sortitems.Check(sorting); + int sc = scope.GetScroll(); + String key = scope.GetKey(); + String s = TrimBoth(~search); + String search_name, search_nest; + bool wholeclass = false; + bool both = false; + navigator_global = false; + if(s.Find('.') >= 0) { + Vector h = Split((String)~search, '.'); + if(*s.Last() == '.') + search_nest = Join(h, "::"); + else { + search_name = h.Pop(); + if(h.GetCount()) + search_nest = Join(h, "::"); + } + wholeclass = *s == '.' && search_nest.GetCount(); + } + else { + search_name = search_nest = ~search; + both = true; + } + s = Join(Split(s, '.'), "::") + (s.EndsWith(".") ? "::" : ""); + int lineno = StrInt(s); + nitem.Clear(); + Index nests; + if(IsNull(theide->editfile)) + return; + int fileii = GetSourceFileIndex(theide->editfile); + if(!IsNull(lineno)) { + NavItem& m = nitem.Add(); + m.pretty = "Go to line " + AsString(lineno); + m.kind = KIND_LINE; + m.line = lineno; + nests.Add(Null); + } + else + if(IsNull(s) && !sorting) { + bool sch = GetFileExt(theide->editfile) == ".sch"; + Ide *theide = TheIde(); + if(theide) + for(const AnnotationItem& m : theide->editor.annotations) { + NavItem& n = nitem.Add(); + (AnnotationItem&)n = m; + nests.FindAdd(n.nest); + } + SortIndex(nests); + } + else { // TODO: Sort codeindex paths, add files in that order to make things stable + navigator_global = true; + String usearch_nest = ToUpper(search_nest); + String usearch_name = ToUpper(search_name); + Index visited; + 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 + (AnnotationItem&)n = m; + } + } + else + if((pass == 0 ? m.name.StartsWith(search_name) : m.uname.Find(usearch_name) >= 0) && + (pass == 0 ? m.nest.Find(search_nest) >= 0 : m.unest.Find(usearch_nest) >= 0)) { + visited.Add(m.id); + NavItem& n = nitem.Add(); + (AnnotationItem&)n = m; + nests.FindAdd(n.nest); + } + } + + SortIndex(nests); + const Workspace& wspc = GetIdeWorkspace(); + String s = ToUpper(TrimBoth(~search)); + for(int i = 0; i < wspc.GetCount(); i++) { + const Package& p = wspc.GetPackage(i); + for(int j = 0; j < p.GetCount(); j++) { + if(!p[j].separator && ToUpper(p[j]).Find(s) >= 0) { + NavItem& m = nitem.Add(); + m.kind = KIND_SRCFILE; + m.pretty = wspc[i] + "/" + p[j]; + m.id = SourcePath(wspc[i], p[j]); + m.line = 0; + nests.FindAdd(""); + } + } + } + } + scope.Clear(); + scope.Add(Null); + for(String n : nests) + scope.Add(n); + scope.ScrollTo(sc); + if(!navigator_global || !scope.FindSetCursor(key)) + scope.GoBegin(); +} + +int Navigator::ScopeDisplay::DoPaint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const +{ + w.DrawRect(r, paper); + if(IsNull(q)) { + const char *txt = "* "; + int x = 0; + w.DrawText(r.left, r.top, txt, StdFont().Bold().Italic(), + style & CURSOR ? ink : HighlightSetup::GetHlStyle(HighlightSetup::INK_KEYWORD).color); + x += GetTextSize(txt, StdFont().Bold().Italic()).cx; + int ii = navigator->list.GetCursor(); + if(ii >= 0 && ii < navigator->litem.GetCount()) { + const NavItem& m = *navigator->litem[ii]; + String txt = m.nest; + if(IsCppCode(m.kind)) + txt << "::" << m.name; + w.DrawText(r.left + x, r.top, txt, StdFont().Bold(), ink); + x += GetTextSize(txt, StdFont().Bold()).cx; + } + return x; + } + String h = q; + if(*h == '\xff') // TODO + return PaintFileName(w, r, h, ink); + else + h = FormatNest(h); + w.DrawText(r.left, r.top, h, StdFont(), ink); + return GetTextSize(h, StdFont()).cx; +} + +void Navigator::ScopeDisplay::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const +{ + DoPaint(w, r, q, ink, paper, style); +} + +Size Navigator::ScopeDisplay::GetStdSize(const Value& q) const +{ + NilDraw w; + return Size(DoPaint(w, Size(999999, 999999), q, White(), White(), 0), StdFont().Bold().GetCy()); +} + +void Navigator::Scope() +{ + LTIMING("FINALIZE"); + litem.Clear(); + nest_item.Clear(); + linefo.Clear(); + String sc = scope.GetKey(); + String nest; + for(const NavItem& n : nitem) { + if(IsNull(sc) || n.nest == sc) { + if(!sorting && n.nest != nest) { + NavItem& m = nest_item.Add(); + m.kind = KIND_NEST; // TODO: KIND_FILE + nest = m.pretty = n.nest; + litem.Add(&m); + } + litem.Add(&n); + } + } + + // TODO sorting + + int lsc = list.GetScroll(); + list.Clear(); + list.SetVirtualCount(litem.GetCount()); + list.ScrollTo(lsc); +} + +void Navigator::ListLineEnabled(int i, bool& b) +{ + if(i >= 0 && i < litem.GetCount()) { + int kind = litem[i]->kind; + if(findarg(kind, KIND_FILE, KIND_NEST) >= 0) + b = false; + } +} + +void Navigator::NaviSort() +{ + sorting = !sorting; + Search(); +} diff --git a/uppsrc/ide/clang/AutoComplete.cpp b/uppsrc/ide/clang/AutoComplete.cpp index 3c47041bd..7b1fcd6b9 100644 --- a/uppsrc/ide/clang/AutoComplete.cpp +++ b/uppsrc/ide/clang/AutoComplete.cpp @@ -62,7 +62,6 @@ void AutocompleteThread() f.includes != parsed_file.includes || f.defines != parsed_file.defines || !clang.tu) { parsed_file = f; - clang.Dispose(); TIMESTOP("Autocomplete parse"); autocomplete_parsing = true; clang.Parse(fn, f.content, f.includes, f.defines, @@ -79,10 +78,10 @@ void AutocompleteThread() CXCodeCompleteResults *results; { TIMESTOP("clang_codeCompleteAt"); - autocomplete_parsing = false; + autocomplete_parsing = true; results = clang_codeCompleteAt(clang.tu, fn, autocomplete_pos.y, autocomplete_pos.x, &ufile, 1, macros ? CXCodeComplete_IncludeMacros : 0); - autocomplete_parsing = true; + autocomplete_parsing = false; } DumpDiagnostics(clang.tu); if(results) { diff --git a/uppsrc/ide/clang/CurrentFile.cpp b/uppsrc/ide/clang/CurrentFile.cpp index 8492cd0c3..d640411cf 100644 --- a/uppsrc/ide/clang/CurrentFile.cpp +++ b/uppsrc/ide/clang/CurrentFile.cpp @@ -9,20 +9,6 @@ int64 current_file_serial; int64 current_file_done_serial; Event&> annotations_done; -struct CurrentFileVisitor : ClangVisitor { - Vector item; - virtual void Item() { - AnnotationItem& r = item.Add(); - r.kind = GetKind(); - r.name = GetName(); - r.line = GetLine(); - r.id = GetId(); - r.pretty = GetPretty(); - r.definition = IsDefinition(); - r.nspace = GetNamespace(); - } -}; - void CurrentFileThread() { MemoryIgnoreLeaksBlock __; @@ -34,7 +20,7 @@ void CurrentFileThread() auto DoAnnotations = [&] { if(!clang.tu || !annotations_done) return; - CurrentFileVisitor v; + ClangVisitor v; v.Do(clang.tu); // DumpDiagnostics(clang.tu); Ctrl::Call([&] { @@ -42,7 +28,7 @@ void CurrentFileThread() parsed_file.real_filename == current_file.real_filename && parsed_file.includes == current_file.includes && serial == current_file_serial) - annotations_done(v.item); + annotations_done(v.item[0]); current_file_done_serial = serial; }); }; @@ -64,7 +50,6 @@ void CurrentFileThread() f.includes != parsed_file.includes || f.defines != parsed_file.defines || !clang.tu) { // TODO: same is in autocomplete parsed_file = f; - clang.Dispose(); { TIMESTOP("CurrentFile parse"); current_file_parsing = true; diff --git a/uppsrc/ide/clang/Indexer.cpp b/uppsrc/ide/clang/Indexer.cpp new file mode 100644 index 000000000..c74195011 --- /dev/null +++ b/uppsrc/ide/clang/Indexer.cpp @@ -0,0 +1,169 @@ +#include "clang.h" + +#define LTIMING(x) +#define LTIMESTOP(x) +#define LLOG(x) + +struct BlitzMaker { + Time time; + String blitz; + Vector individual; + + void Do(const String& pk_name, const Vector>& file, Hdepend& hdepend); +}; + +void BlitzFile(String& blitz, const String& sourceFile, Hdepend& hdepend, int index) +{ + blitz << "\r\n" + << "#define BLITZ_INDEX__ F" << index << "\r\n" + << "#include \"" << sourceFile << "\"\r\n"; + const Vector& d = hdepend.GetDefines(sourceFile); + for(int i = 0; i < d.GetCount(); i++) + blitz << "#ifdef " << d[i] << "\r\n" + << "#undef " << d[i] << "\r\n" + << "#endif\r\n"; + blitz << "#undef BLITZ_INDEX__\r\n"; +} + +void BlitzMaker::Do(const String& pk_name, const Vector>& file, Hdepend& hdepend) +{ + 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& WriteCodeIndex() +{ + DTIMING("WriteCodeIndex"); + static ArrayMap m; + return m; +} + +const ArrayMap& CodeIndex() +{ + return WriteCodeIndex(); +} + +static std::atomic indexer_pkgi; +static std::atomic running_indexers; +static Index visited_files; +static Mutex visited_files_mutex; + +bool IsIndexing() +{ + 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> pk_files; + Index 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 doing_files; + v.WhenFile = [&](const String& path) { + return pk_files_index.Find(path) >= 0; + }; + { + DTIMING("Visitor"); + v.Do(clang.tu); + } + + { + 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("======= 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; + } + 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"); + LLOG("Done"); +} + +void StartIndexing(const String& includes, const String& defines) +{ + { + Mutex::Lock __(visited_files_mutex); + visited_files.Clear(); + } + indexer_pkgi = 0; + if(!IsIndexing()) { + for(int i = 0; i < CPU_Cores(); i++) // TODO: CPU_Cores? + Thread::StartNice([=] { Indexer(includes, defines); }); + } +} diff --git a/uppsrc/ide/clang/Signature.cpp b/uppsrc/ide/clang/Signature.cpp index 3a319600d..85605bd5f 100644 --- a/uppsrc/ide/clang/Signature.cpp +++ b/uppsrc/ide/clang/Signature.cpp @@ -177,7 +177,7 @@ String CleanupPretty(const String& signature) return r; } -Vector ParseSignature(const String& name, const String& signature, int *fn_info) +Vector ParsePretty(const String& name, const String& signature, int *fn_info) { Vector part; int name_len = name.GetLength(); @@ -233,15 +233,13 @@ Vector ParseSignature(const String& name, const String& signature, p.type = ITEM_CPP_TYPE; } else - if(IsCppType(id)) { - p.type = ITEM_CPP_TYPE; - if(lastidi >= 0 && par == 0) - was_type = true; + if(IsCppKeyword(id)) { + if(id == "virtual") + part.Drop(); + else + p.type = ITEM_CPP; } else - if(IsCppKeyword(id)) - p.type = ITEM_CPP; - else if(param) { if(lastidi >= 0 && par == 0) was_type = true; @@ -301,10 +299,10 @@ Vector ParseSignature(const String& name, const String& signature, Image CxxIcon(int kind); -String SignatureQtf(const String& name, const String& signature, int pari) +String SignatureQtf(const String& name, const String& pretty, int pari) { String qtf = "[%00-00K "; - Vector n = ParseSignature(name, signature); + Vector n = ParsePretty(name, pretty); for(int i = 0; i < n.GetCount(); i++) { ItemTextPart& p = n[i]; qtf << "["; @@ -331,7 +329,7 @@ String SignatureQtf(const String& name, const String& signature, int pari) break; } qtf << ' '; - qtf << '\1' << signature.Mid(p.pos, p.len) << '\1'; + qtf << '\1' << pretty.Mid(p.pos, p.len) << '\1'; qtf << ']'; } return qtf + "]"; diff --git a/uppsrc/ide/clang/Visitor.cpp b/uppsrc/ide/clang/Visitor.cpp index 2e1a1e330..ce07c41f3 100644 --- a/uppsrc/ide/clang/Visitor.cpp +++ b/uppsrc/ide/clang/Visitor.cpp @@ -2,9 +2,8 @@ // #define DUMPTREE -bool ClangVisitor::ProcessNode(CXCursor c) +bool ClangVisitor::ProcessNode(CXCursor cursor) { - cursor = c; CXSourceLocation cxlocation = clang_getCursorLocation(cursor); CXCursorKind cursorKind = clang_getCursorKind(cursor); @@ -16,23 +15,40 @@ bool ClangVisitor::ProcessNode(CXCursor c) DDUMP(SourceLocation(cxlocation)); #endif - if(!clang_Location_isFromMainFile(cxlocation)) + bool position_loaded = false; + unsigned line; + unsigned column; + unsigned offset; + String path; + + auto LoadPosition = [&] { + if(position_loaded) return; + CXFile file; + clang_getExpansionLocation(cxlocation, &file, &line, &column, &offset); + path = FetchString(clang_getFileName(file)); + position_loaded = true; + }; + + 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, CXCursor_Destructor, CXCursor_CXXMethod, CXCursor_ClassTemplate, CXCursor_ClassTemplatePartialSpecialization, CXCursor_UnexposedDecl, CXCursor_UsingDeclaration, CXCursor_VarDecl, CXCursor_EnumConstantDecl, CXCursor_TypeAliasTemplateDecl, CXCursor_EnumDecl, CXCursor_ConversionFunction) < 0; + } String m; CXCursor parent = clang_getCursorSemanticParent(cursor); CXCursorKind parentKind = clang_getCursorKind(parent); - name = GetCursorSpelling(cursor); - type = GetTypeSpelling(cursor); + String name = GetCursorSpelling(cursor); + String type = GetTypeSpelling(cursor); String pid = FetchString(clang_getCursorPrettyPrinted(cursor, pp_id)); - + #ifdef DUMPTREE _DBG_ CXCursor ref = clang_getCursorReferenced(cursor); @@ -49,16 +65,18 @@ bool ClangVisitor::ProcessNode(CXCursor c) #endif CXCursor p = parent; - scope.Clear(); - nspace.Clear(); + String scope; + String nspace; for(;;) { CXCursorKind k = clang_getCursorKind(p); - if(findarg(k, CXCursor_Namespace, CXCursor_ClassTemplate, CXCursor_StructDecl, CXCursor_UnionDecl, CXCursor_ClassDecl) < 0) - break; - String q = GetCursorSpelling(p); - scope = scope.GetCount() ? q + "::" + scope : q; - if(k == CXCursor_Namespace) - nspace = nspace.GetCount() ? q + "::" + nspace : q; + if(k != CXCursor_EnumDecl) { + if(findarg(k, CXCursor_Namespace, CXCursor_ClassTemplate, CXCursor_StructDecl, CXCursor_UnionDecl, CXCursor_ClassDecl) < 0) + break; + String q = GetCursorSpelling(p); + scope = scope.GetCount() ? q + "::" + scope : q; + if(k == CXCursor_Namespace) + nspace = nspace.GetCount() ? q + "::" + nspace : q; + } p = clang_getCursorSemanticParent(p); } int q = scope.Find('('); // 'Struct::(unnamed enum at C:\u\upp.src\upptst\Annotations\main.cpp:47:2)' @@ -67,7 +85,7 @@ bool ClangVisitor::ProcessNode(CXCursor c) if(scope.GetCount() && *scope.Last() != ':') scope << "::"; - annotation = true; + bool annotation = true; if(findarg(parentKind, CXCursor_FunctionTemplate, CXCursor_FunctionDecl, CXCursor_CXXMethod, CXCursor_Constructor, CXCursor_Destructor) >= 0) annotation = false; // local variable @@ -76,6 +94,8 @@ bool ClangVisitor::ProcessNode(CXCursor c) case CXCursor_StructDecl: case CXCursor_UnionDecl: case CXCursor_ClassDecl: + m = type; + break; case CXCursor_FunctionTemplate: case CXCursor_FunctionDecl: case CXCursor_Constructor: @@ -109,17 +129,22 @@ bool ClangVisitor::ProcessNode(CXCursor c) break; } if(annotation && m.GetCount()) { - CXFile file; - unsigned line_; - unsigned column_; - unsigned offset_; - clang_getExpansionLocation(cxlocation, &file, &line_, &column_, &offset_); - line = line_; - column = column_; - kind = cursorKind; - pretty = CleanupPretty(FetchString(clang_getCursorPrettyPrinted(cursor, pp_pretty))); - id = CleanupId(m); - Item(); + LoadPosition(); + AnnotationItem& r = item.GetAdd(path).Add(); + r.kind = cursorKind; + r.name = name; + r.line = line; + 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("::"); + } + r.uname = ToUpper(name); + r.unest = ToUpper(r.nest); } return true; } diff --git a/uppsrc/ide/clang/blitz.cpp b/uppsrc/ide/clang/blitz.cpp new file mode 100644 index 000000000..8033541c3 --- /dev/null +++ b/uppsrc/ide/clang/blitz.cpp @@ -0,0 +1 @@ +#include "clang.h" diff --git a/uppsrc/ide/clang/clang.cpp b/uppsrc/ide/clang/clang.cpp index a7acf5ce6..037cbc621 100644 --- a/uppsrc/ide/clang/clang.cpp +++ b/uppsrc/ide/clang/clang.cpp @@ -77,6 +77,8 @@ void Clang::Dispose() bool Clang::Parse(const String& filename, const String& content, const String& includes_, const String& defines, dword options) { if(!index) return false; + + Dispose(); String cmdline; @@ -99,10 +101,12 @@ bool Clang::Parse(const String& filename, const String& content, const String& i for(const String& s : args) argv.Add(~s); - - CXUnsavedFile ufile = { ~filename, ~content, (unsigned)content.GetCount() }; - tu = clang_parseTranslationUnit(index, nullptr, argv, argv.GetCount(), &ufile, 1, options); + CXUnsavedFile ufile = { ~filename, ~content, (unsigned)content.GetCount() }; + tu = clang_parseTranslationUnit(index, nullptr, argv, argv.GetCount(), + options & PARSE_FILE ? nullptr : &ufile, + options & PARSE_FILE ? 0 : 1, + options); // DumpDiagnostics(tu); diff --git a/uppsrc/ide/clang/clang.h b/uppsrc/ide/clang/clang.h index 0ae02701b..f6495f74d 100644 --- a/uppsrc/ide/clang/clang.h +++ b/uppsrc/ide/clang/clang.h @@ -32,8 +32,9 @@ enum AdditionalKinds { KIND_COMPLETE, }; -Image CxxIcon(int kind); // TODO: Move here -String SignatureQtf(const String& name, const String& signature, int pari); +Image CxxIcon(int kind); // TODO: Move here +int PaintCpp(Draw& w, const Rect& r, int kind, const String& name, const String& pretty, Color ink, bool focuscursor, bool retval_last = false); +String SignatureQtf(const String& name, const String& pretty, int pari); bool IsStruct(int kind); bool IsTemplate(int kind); @@ -64,12 +65,12 @@ struct ItemTextPart : Moveable { int pari; }; -Vector ParseSignature(const String& name, const String& signature, int *fn_info = NULL); +Vector ParsePretty(const String& name, const String& signature, int *fn_info = NULL); struct AutoCompleteItem : Moveable { String parent; String name; - String signature; + String signature; // TODO: rename to pretty int kind; int priority; }; @@ -78,10 +79,15 @@ struct AnnotationItem : Moveable { int kind; int line; bool definition; - String name; - String id; - String pretty; - String nspace; + String name; // Method + String id; // Upp::Class::Method(Upp::Point p) + String pretty; // void Class::Method(Point p) + String nspace; // Upp + String uname; // METHOD + String nest; // Upp::Class + String unest; // UPP::CLASS + + ~AnnotationItem() { DHITCOUNT("AnnotationItem"); } }; struct CurrentFileContext { @@ -92,6 +98,8 @@ struct CurrentFileContext { String content; }; +enum { PARSE_FILE = 0x80000000 }; + struct Clang { CXIndex index = nullptr; CXTranslationUnit tu = nullptr; @@ -121,36 +129,14 @@ class ClangVisitor { bool initialized = false; CXPrintingPolicy pp_id, pp_pretty; - CXCursor cursor; - int kind; - String name; - String id; - String type; - String scope; - String nspace; - String pretty; - bool annotation; - int line; - int column; - bool ProcessNode(CXCursor c); friend CXChildVisitResult clang_visitor(CXCursor cursor, CXCursor p, CXClientData clientData); public: - virtual void Item() = 0; - - int GetKind() const { return kind; } - String GetId() const { return id; } - String GetName() const { return name; } - String GetType() const { return type; } - String GetScope() const { return scope; } - String GetNamespace() const { return nspace; } - String GetPretty() const { return pretty; } - bool IsDefinition() const { return clang_isCursorDefinition(cursor); } - bool IsAnnotation() const { return annotation; } - int GetLine() const { return line; } - int GetColumn() const { return column; } + VectorMap> item; + + Gate WhenFile; void Do(CXTranslationUnit tu); ~ClangVisitor(); @@ -167,4 +153,18 @@ void StartAutoComplete(const CurrentFileContext& ctx, int line, int column, bool Event&> done); void CancelAutoComplete(); + +struct FileAnnotation { + String defines; + String includes; + Time time; + + Vector items; +}; + +bool IsIndexing(); +void StartIndexing(const String& includes, const String& defines); + +const ArrayMap& CodeIndex(); + #endif diff --git a/uppsrc/ide/clang/clang.upp b/uppsrc/ide/clang/clang.upp index ca8e0ebb4..c334e278f 100644 --- a/uppsrc/ide/clang/clang.upp +++ b/uppsrc/ide/clang/clang.upp @@ -11,6 +11,7 @@ file clang.h, todo.txt, help.txt, + blitz.cpp, util.cpp, macros.cpp, CxxIcon.cpp, @@ -19,5 +20,6 @@ file Codebase.cpp, Visitor.cpp, AutoComplete.cpp, - CurrentFile.cpp; + CurrentFile.cpp, + Indexer.cpp; diff --git a/uppsrc/ide/clang/todo.txt b/uppsrc/ide/clang/todo.txt index 8dabc3d1d..ad6f0bc51 100644 --- a/uppsrc/ide/clang/todo.txt +++ b/uppsrc/ide/clang/todo.txt @@ -8,14 +8,10 @@ - failed AC keeps running (sites[i]. instead of ->) -- writing to text is slow (IsSource detection?) - - background thread problem - MSVC -- Enum annotations - - optimise loading - TPP HELP WINDOW->EDITOR - go to active label @@ -36,6 +32,61 @@ - this is just a test +- OpenWind.h autocomplete + +- server_methods.i + +- fixups? + +- enum annotation popup (Ctrl::) + +- .txt is pulsing all time + +- Remove template < > in autocomplete + +- newly created file looks like parsing until first function(?) + +- current file indexing + +- check editor mode + +- navlines + +- navigator - GotoDesignerFile + +- i < items crash at start occassionally + +- * 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 + +LATER: + +- slow .txt + +- optimise hdepend (then maybe remove .h limitation for syncheaders) - \ No newline at end of file + +DONE: + +- Upp:: missing from Vector + +- class Ctrl + +- class Logc + +- writing to text is slow (IsSource detection?) + +- .txt keeps syncing + +- Enum annotations + diff --git a/uppsrc/ide/ide.cpp b/uppsrc/ide/ide.cpp index 17e0aa58b..ee99d5511 100644 --- a/uppsrc/ide/ide.cpp +++ b/uppsrc/ide/ide.cpp @@ -361,7 +361,6 @@ void Ide::DeactivateBy(Ctrl *new_focus) DeactivationSave(true); SaveFile(); DeactivationSave(false); - editor.SyncHeaders(); } TopWindow::DeactivateBy(new_focus); } @@ -657,32 +656,19 @@ void Ide::SyncClang() auto Animate = [=](int& animator, int& dir, bool animate) -> Color { if(animator <= 0 && !animate) return Null; if(animate) - dir = clamp(dir, -1, 1); + animator = 20; else - dir = -3; - if(animator >= 15) - dir = -1; - if(animator <= 0) - dir = 1; - if(phase != animate_phase) - animator = max(animator + dir, 0); - Color bg; - if(IsDarkTheme()) - bg = GrayColor(70 + animator); - else { - bg = SColorLtFace(); - auto C = [&](int c) { return clamp(c - animator, 0, 255); }; - bg = Color(C(bg.GetR()), C(bg.GetG()), C(bg.GetG())); - } - return bg; + animator -= 3; + return Blend(IsDarkTheme() ? GrayColor(70) : SColorLtFace(), Color(198, 170, 0), animator); }; - Color bg = Animate(animate_current_file, animate_current_file_dir, IsCurrentFileParsing()); + Color bg = Animate(animate_current_file, animate_current_file_dir, editor.annotating || IsCurrentFileParsing()); if(!IsNull(bg)) { int cx = editor.GetBarSize().cx; for(int i = 0; i < cx; i++) - a.Add(bg); + a.Add(i > cx - DPI(6) ? bg : Null); } editor.AnimateBar(pick(a)); + editor.search.SetColor(Animate(animate_indexer, animate_indexer_dir, IsIndexing())); display.Animate(Animate(animate_autocomplete, animate_autocomplete_dir, IsAutocompleteParsing())); animate_phase = phase; } diff --git a/uppsrc/ide/ide.h b/uppsrc/ide/ide.h index 98255d897..e49f36716 100644 --- a/uppsrc/ide/ide.h +++ b/uppsrc/ide/ide.h @@ -724,6 +724,7 @@ public: int animate_current_file = 0, animate_current_file_dir = 0; int animate_autocomplete = 0, animate_autocomplete_dir = 0; + int animate_indexer = 0, animate_indexer_dir = 0; int animate_phase = 0; // ------------------------------------ diff --git a/uppsrc/ide/ide.upp b/uppsrc/ide/ide.upp index df3204993..b3a573654 100644 --- a/uppsrc/ide/ide.upp +++ b/uppsrc/ide/ide.upp @@ -54,6 +54,7 @@ file GoToLine.cpp, Swaps.cpp, ParamInfo.cpp, + Navigator2.cpp, Navigator.cpp, Annotations.cpp, Virtuals.cpp, diff --git a/uppsrc/ide/idefile.cpp b/uppsrc/ide/idefile.cpp index ec0fb8bbd..50fa2d113 100644 --- a/uppsrc/ide/idefile.cpp +++ b/uppsrc/ide/idefile.cpp @@ -303,7 +303,6 @@ void Ide::SaveFile(bool always) { issaving++; SaveFile0(always); - editor.SyncHeaders(); issaving--; } diff --git a/uppsrc/ide/main.cpp b/uppsrc/ide/main.cpp index deb9d99df..14be2da31 100644 --- a/uppsrc/ide/main.cpp +++ b/uppsrc/ide/main.cpp @@ -333,8 +333,10 @@ void AppMain___() ide.SaveLastMain(); ide.isscanning++; ide.MakeTitle(); - if(!ide.IsEditorMode()) + if(!ide.IsEditorMode()) { SyncRefs(); + StartIndexing(ide.GetCurrentIncludePath(), ide.GetCurrentDefines()); + } ide.FileSelected(); ide.isscanning--; ide.MakeTitle();